Skip to content

Commit 9e75a4b

Browse files
committed
C++: Implement a model for _strnextc and its variants.
1 parent 98d73bf commit 9e75a4b

File tree

4 files changed

+61
-0
lines changed

4 files changed

+61
-0
lines changed

cpp/ql/src/semmle/code/cpp/models/Models.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ private import implementations.Strftime
1818
private import implementations.Strtok
1919
private import implementations.Strset
2020
private import implementations.Strcrement
21+
private import implementations.Strnextc
2122
private import implementations.StdContainer
2223
private import implementations.StdPair
2324
private import implementations.StdMap
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* Provides implementation classes modeling `strnextc` and various similar functions.
3+
* See `semmle.code.cpp.models.Models` for usage information.
4+
*/
5+
6+
import semmle.code.cpp.models.interfaces.ArrayFunction
7+
import semmle.code.cpp.models.interfaces.Taint
8+
import semmle.code.cpp.models.interfaces.Alias
9+
import semmle.code.cpp.models.interfaces.SideEffect
10+
11+
/**
12+
* The function `strnextc` and its variants.
13+
*/
14+
private class Strnextc extends TaintFunction, ArrayFunction, AliasFunction, SideEffectFunction {
15+
Strnextc() { this.hasGlobalName(["_strnextc", "_wcsnextc", "_mbsnextc", "_mbsnextc_l"]) }
16+
17+
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
18+
input.isParameterDeref(0) and output.isReturnValue()
19+
}
20+
21+
override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 }
22+
23+
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
24+
25+
override predicate parameterNeverEscapes(int index) { index = 0 }
26+
27+
override predicate parameterEscapesOnlyViaReturn(int index) { none() }
28+
29+
override predicate parameterIsAlwaysReturned(int index) { none() }
30+
31+
override predicate hasOnlySpecificReadSideEffects() { any() }
32+
33+
override predicate hasOnlySpecificWriteSideEffects() { any() }
34+
35+
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
36+
i = 0 and buffer = true
37+
}
38+
}

cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6032,6 +6032,14 @@
60326032
| taint.cpp:616:26:616:30 | clean | taint.cpp:616:10:616:16 | call to _strdec | TAINT |
60336033
| taint.cpp:617:7:617:11 | ref arg dest3 | taint.cpp:618:8:618:12 | dest3 | |
60346034
| taint.cpp:618:8:618:12 | dest3 | taint.cpp:618:7:618:12 | * ... | TAINT |
6035+
| taint.cpp:625:33:625:38 | source | taint.cpp:628:17:628:22 | source | |
6036+
| taint.cpp:628:7:628:15 | call to _strnextc | taint.cpp:628:3:628:23 | ... = ... | |
6037+
| taint.cpp:628:7:628:15 | call to _strnextc | taint.cpp:629:8:629:8 | c | |
6038+
| taint.cpp:628:7:628:15 | call to _strnextc | taint.cpp:630:10:630:10 | c | |
6039+
| taint.cpp:628:17:628:22 | source | taint.cpp:628:7:628:15 | call to _strnextc | TAINT |
6040+
| taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:631:2:631:18 | ... = ... | |
6041+
| taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:632:7:632:7 | c | |
6042+
| taint.cpp:631:16:631:17 | | taint.cpp:631:6:631:14 | call to _strnextc | TAINT |
60356043
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
60366044
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
60376045
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |

cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,4 +616,18 @@ void test__strdec(const unsigned char* source, unsigned char* clean, unsigned ch
616616
dest3 = _strdec(source, clean);
617617
sink(dest3); // $ ast,ir
618618
sink(*dest3); // $ ast,ir
619+
}
620+
621+
// --- strnextc ---
622+
623+
unsigned int _strnextc(const char*);
624+
625+
void test__strnextc(const char* source) {
626+
unsigned c = 0;
627+
do {
628+
c = _strnextc(source);
629+
sink(c); // $ ast,ir
630+
} while(c != '\0');
631+
c = _strnextc("");
632+
sink(c);
619633
}

0 commit comments

Comments
 (0)