diff --git a/cpp/ql/src/Critical/MissingCheckScanf.ql b/cpp/ql/src/Critical/MissingCheckScanf.ql new file mode 100644 index 00000000000..3ad7f2b99c0 --- /dev/null +++ b/cpp/ql/src/Critical/MissingCheckScanf.ql @@ -0,0 +1,14 @@ +/** + * @name TODO + * @description TODO + * @kind problem + * @problem.severity TODO + * @security-severity TODO + * @precision TODO + * @id cpp/missing-check-scanf + * @tags TODO + */ + +import cpp + +select "TODO" diff --git a/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.expected b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.qlref b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.qlref new file mode 100644 index 00000000000..97e85b5abbe --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/MissingCheckScanf.qlref @@ -0,0 +1 @@ +Critical/MissingCheckScanf.ql \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp new file mode 100644 index 00000000000..2e4abdab545 --- /dev/null +++ b/cpp/ql/test/query-tests/Critical/MissingCheckScanf/test.cpp @@ -0,0 +1,195 @@ +typedef struct {} FILE; + +int scanf(const char *format, ...); +int fscanf(FILE *stream, const char *format, ...); +int sscanf(const char *s, const char *format, ...); + +void use(int i); + +void set_by_ref(int &i); +void set_by_ptr(int *i); +bool maybe(); + +FILE *get_a_stream(); +const char *get_a_string(); + +int main() +{ + // --- simple cases --- + + { + int i; + + scanf("%d", &i); // BAD: may not have written `i` + use(i); + } + + { + int i; + + if (scanf("%d", &i) == 1) // GOOD: checks return value + { + use(i); + } + } + + { + int i = 0; + + scanf("%d", &i); // GOOD: we assume the initialization of `i` is a reasonable default + use(i); + } + + // --- different scanf functions --- + + { + int i; + + fscanf(get_a_stream(), "%d", &i); // BAD: may not have written `i` + use(i); + } + + { + int i; + + sscanf(get_a_string(), "%d", &i); // BAD: may not have written `i` + use(i); + } + + // --- different ways of checking --- + + { + int i; + + if (scanf("%d", &i) >= 1) // GOOD + { + use(i); + } + } + + { + int i; + + if (scanf("%d", &i) == 1) // GOOD + { + use(i); + } + } + + { + int i; + + if (scanf("%d", &i) != 0) // GOOD (just barely) + { + use(i); + } + } + + { + int i; + + if (scanf("%d", &i) == 0) // BAD: checks return value incorrectly + { + use(i); + } + } + + { + bool b; + int i; + + b = scanf("%d", &i); // GOOD + + if (b >= 1) + { + use(i); + } + } + + { + int i, j; + + if (scanf("%d %d", &i) >= 2) // GOOD + { + use(i); + use(j); + } + } + + { + int i, j; + + if (scanf("%d %d", &i) >= 1) // BAD: checks return value incorrectly + { + use(i); + use(j); + } + } + + // --- different initialization --- + + { + int i; + i = 0; + + scanf("%d", &i); // GOOD + use(i); + } + + { + int i; + + set_by_ref(i); + scanf("%d", &i); // GOOD: we have to assume `i` was initialized + use(i); + } + + { + int i; + + set_by_ptr(&i); + scanf("%d", &i); // GOOD: we have to assume `i` was initialized + use(i); + } + + { + int i; + + if (maybe()) + { + i = 0; + } + + scanf("%d", &i); // BAD: `i` may not have been initialized + use(i); + } + + // --- weird formatting strings --- + + { + int i; + + if (scanf("%n %d", &i) >= 1) // GOOD (`%n` does not consume input) + { + use(i); + } + } + + { + int i; + + if (scanf("%% %d", &i) >= 1) // GOOD (`%%` does not consume input) + { + use(i); + } + } + + { + int i; + + if (scanf("%*d %d", &i) >= 1) // GOOD (`%*d` does not consume input) + { + use(i); + } + } +}