diff --git a/cpp/ql/src/semmle/code/cpp/models/Models.qll b/cpp/ql/src/semmle/code/cpp/models/Models.qll index 82998e9ccbc..7ec66b3a2e9 100644 --- a/cpp/ql/src/semmle/code/cpp/models/Models.qll +++ b/cpp/ql/src/semmle/code/cpp/models/Models.qll @@ -18,6 +18,7 @@ private import implementations.Strftime private import implementations.Strtok private import implementations.Strset private import implementations.Strcrement +private import implementations.Strnextc private import implementations.StdContainer private import implementations.StdPair private import implementations.StdMap diff --git a/cpp/ql/src/semmle/code/cpp/models/implementations/Strnextc.qll b/cpp/ql/src/semmle/code/cpp/models/implementations/Strnextc.qll new file mode 100644 index 00000000000..fc8ac17b5f6 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/models/implementations/Strnextc.qll @@ -0,0 +1,38 @@ +/** + * Provides implementation classes modeling `strnextc` and various similar functions. + * See `semmle.code.cpp.models.Models` for usage information. + */ + +import semmle.code.cpp.models.interfaces.ArrayFunction +import semmle.code.cpp.models.interfaces.Taint +import semmle.code.cpp.models.interfaces.Alias +import semmle.code.cpp.models.interfaces.SideEffect + +/** + * The function `strnextc` and its variants. + */ +private class Strnextc extends TaintFunction, ArrayFunction, AliasFunction, SideEffectFunction { + Strnextc() { this.hasGlobalName(["_strnextc", "_wcsnextc", "_mbsnextc", "_mbsnextc_l"]) } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isParameterDeref(0) and output.isReturnValue() + } + + override predicate hasArrayWithNullTerminator(int bufParam) { bufParam = 0 } + + override predicate hasArrayInput(int bufParam) { bufParam = 0 } + + override predicate parameterNeverEscapes(int index) { index = 0 } + + override predicate parameterEscapesOnlyViaReturn(int index) { none() } + + override predicate parameterIsAlwaysReturned(int index) { none() } + + override predicate hasOnlySpecificReadSideEffects() { any() } + + override predicate hasOnlySpecificWriteSideEffects() { any() } + + override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { + i = 0 and buffer = true + } +} diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected index b0eabbf5ca9..9f038101d67 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/localTaint.expected @@ -6032,6 +6032,16 @@ | taint.cpp:616:26:616:30 | clean | taint.cpp:616:10:616:16 | call to _strdec | TAINT | | taint.cpp:617:7:617:11 | ref arg dest3 | taint.cpp:618:8:618:12 | dest3 | | | taint.cpp:618:8:618:12 | dest3 | taint.cpp:618:7:618:12 | * ... | TAINT | +| taint.cpp:625:33:625:38 | source | taint.cpp:628:17:628:22 | source | | +| taint.cpp:628:7:628:15 | call to _strnextc | taint.cpp:628:3:628:25 | ... = ... | | +| taint.cpp:628:7:628:15 | call to _strnextc | taint.cpp:629:8:629:8 | c | | +| taint.cpp:628:7:628:15 | call to _strnextc | taint.cpp:630:10:630:10 | c | | +| taint.cpp:628:17:628:22 | source | taint.cpp:628:17:628:24 | ... ++ | | +| taint.cpp:628:17:628:24 | ... ++ | taint.cpp:628:7:628:15 | call to _strnextc | TAINT | +| taint.cpp:628:17:628:24 | ... ++ | taint.cpp:628:17:628:22 | source | TAINT | +| taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:631:2:631:18 | ... = ... | | +| taint.cpp:631:6:631:14 | call to _strnextc | taint.cpp:632:7:632:7 | c | | +| taint.cpp:631:16:631:17 | | taint.cpp:631:6:631:14 | call to _strnextc | TAINT | | vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | | | vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | | | vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | | diff --git a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp index 91024f543bd..44d84c0c0b0 100644 --- a/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp +++ b/cpp/ql/test/library-tests/dataflow/taint-tests/taint.cpp @@ -616,4 +616,18 @@ void test__strdec(const unsigned char* source, unsigned char* clean, unsigned ch dest3 = _strdec(source, clean); sink(dest3); // $ ast,ir sink(*dest3); // $ ast,ir +} + +// --- strnextc --- + +unsigned int _strnextc(const char*); + +void test__strnextc(const char* source) { + unsigned c = 0; + do { + c = _strnextc(source++); + sink(c); // $ ast,ir + } while(c != '\0'); + c = _strnextc(""); + sink(c); } \ No newline at end of file