From 43549e639760c1fef87687b43531bbe94eca27b2 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 18 Mar 2019 11:03:27 -0700 Subject: [PATCH 1/5] Change names of parameters to memcpy(), as per Geoff. --- .../Memory Management/AllocaInLoop/AllocaInLoop1.cpp | 2 +- .../Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp | 2 +- .../Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp index 7d5ac6d0f0c3..54a93c511bee 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp @@ -15,7 +15,7 @@ void *__builtin_alloca(int sz); typedef unsigned long size_t; int printf(const char *restrict format, ...); -void *memcpy(void *restrict dst, const void *restrict src, size_t len); +void *memcpy(void *restrict s1, const void *restrict s2, size_t n); // case 1: alloca directly contained in an unbounded loop void foo(const struct vtype* vec, int count) { diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp index 4c698bfdc269..45b36161821d 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp @@ -12,7 +12,7 @@ extern int w1, w2; #endif int printf(const char *restrict format, ...); -void *memcpy(void *restrict dst, const void *restrict src, size_t len); +void *memcpy(void *restrict s1, const void *restrict s2, size_t n); // case 1: _alloca directly contained in an unbounded loop void foo(const struct vtype* vec, int count) { diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c index 0f137b66056e..eeeafb2f17ff 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c @@ -2,7 +2,7 @@ int printf(const char *restrict format, ...); int sprintf(char *restrict buf, const char *restrict format, ...); typedef unsigned long size_t; -void *memcpy(void *restrict dst, const void *restrict src, size_t len); +void *memcpy(void *restrict s1, const void *restrict s2, size_t n); void *malloc(size_t sz); void free(void *ptr); From 96249b88380c48dd345681e34884bbe58d7ee238 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 18 Mar 2019 16:10:35 -0700 Subject: [PATCH 2/5] [CPP-340] Create QL query for function call argument count mismatches. Update QHELP file, test and test results. --- .../Likely Typos/FutileParams.qhelp | 15 +++++++++++---- .../Likely Bugs/Likely Typos/FutileParams.ql | 19 +++++++++++-------- .../FutileParams/FutileParams.expected | 7 ++++--- .../Likely Typos/FutileParams/test.c | 10 ++++++---- 4 files changed, 32 insertions(+), 19 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp index d0d888a9aac7..0c1e345c04fa 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp @@ -5,18 +5,25 @@ -

A function is called with arguments despite having an empty parameter list. This may indicate -that the incorrect function is being called, or that the author misunderstood the function.

+

A function is called with arguments despite having been declared with an empty parameter list. +In addition, we were either unable to find a definition of the function, or found one with +an incompatible number of parameters.

+ +

This may indicate that an incorrect function is being called, or that the signature (parameter list) +of the called function is not known to the author.

In C, a function declared with an empty parameter list () is considered to have an unknown parameter list, and therefore can be called with any set of arguments. To declare a function which takes no arguments, you must use (void) as the parameter list in any forward declarations. -In C++, either style of declaration indicates that the function accepts no arguments.

+In C++, () means the same as (void), i.e., indicates that the function accepts no +arguments.

Call the function without arguments, or call a different function that expects the arguments -being passed.

+being passed. If possible, change the forward declaration of the ()-function to reflect the +arguments being passed, or change the () to (void) to indicate that no arguments +shall be passed.

diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql index bb5a99a69bc9..c3f956f6deda 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql @@ -12,11 +12,14 @@ import cpp -from Function f, FunctionCall fc -where fc.getTarget() = f - and f.getNumberOfParameters() = 0 - and not f.isVarargs() - and fc.getNumberOfArguments() != 0 - and not f instanceof BuiltInFunction - and exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit()) -select fc, "This call has arguments, but $@ is not declared with any parameters.", f, f.toString() +from FunctionCall fc, Function f + where f = fc.getTarget() and not f.isVarargs() + /* There must be a mismatch between number of call arguments and number of parameters in some + * non-implicit declaration of Function f + */ + and exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit() and fde.getNumberOfParameters() != fc.getNumberOfArguments()) + /* There must be no _definition_ of Function f whose number of parameters matches number of call arguments */ + and not exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | fde.isDefinition() and fde.getNumberOfParameters() = fc.getNumberOfArguments()) +select fc + + \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected index d6dc2222be42..4bb782dfd11d 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected @@ -1,3 +1,4 @@ -| test.c:8:3:8:16 | call to declared_empty | This call has arguments, but $@ is not declared with any parameters. | test.c:1:6:1:19 | declared_empty | declared_empty | -| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:14:3:14:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:25:6:25:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:7:3:7:16 | call to declared_empty | +| test.c:16:3:16:19 | call to not_yet_declared1 | +| test.c:19:3:19:29 | call to declared_empty_defined_with | +| test.c:24:3:24:29 | call to declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c index 9589d2a9ffc9..ef81c416343a 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c @@ -1,7 +1,6 @@ void declared_empty(); void declared_void(void); void declared_with(int); -void declared_empty_defined_with(); void test() { declared_empty(); // GOOD @@ -9,17 +8,20 @@ void test() { declared_void(); // GOOD declared_with(1); // GOOD + declared_ellipsis(); // GOOD + declared_ellipsis(2); // GOOD + undeclared(1); // GOOD not_yet_declared1(1); // BAD not_yet_declared2(1); // GOOD - declared_empty_defined_with(); // BAD [NOT DETECTED] + declared_empty_defined_with(); // BAD declared_empty_defined_with(1); // GOOD int x; - declared_empty_defined_with(&x); // BAD [NOT DETECTED] - declared_empty_defined_with(x, x); // BAD [NOT DETECTED] + declared_empty_defined_with(&x); // GOOD + declared_empty_defined_with(x, x); // BAD } void not_yet_declared1(); From f79387e7ee46932096adfd4df25d3f8042cdfd58 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 18 Mar 2019 17:23:03 -0700 Subject: [PATCH 3/5] Refine QL query by requiring that a ()-declaration be present. --- cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql index c3f956f6deda..83baeaf8a95f 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql @@ -14,6 +14,8 @@ import cpp from FunctionCall fc, Function f where f = fc.getTarget() and not f.isVarargs() + /* There must be a zero-parameter declaration */ + and exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | fde.getNumberOfParameters() = 0) /* There must be a mismatch between number of call arguments and number of parameters in some * non-implicit declaration of Function f */ From 860abf565a9d9c2e97f40ff574df812ff630c0a4 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Tue, 19 Mar 2019 12:16:08 -0700 Subject: [PATCH 4/5] Use '// GOOD' and '// BAD' annotations for query diagnostics. --- .../Memory Management/AllocaInLoop/AllocaInLoop1.cpp | 6 +++--- .../AllocaInLoop/AllocaInLoop1ms.cpp | 6 +++--- .../Memory Management/AllocaInLoop/AllocaInLoop2.c | 12 ++++++------ .../Memory Management/AllocaInLoop/AllocaInLoop3.cpp | 6 +++--- 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp index 54a93c511bee..c3866a9c649b 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1.cpp @@ -28,7 +28,7 @@ void foo(const struct vtype* vec, int count) { b1 = new char[w1]; } else { // Allocate the buffer on stack - b1 = (char*) alloca(w1); // [FLAG] + b1 = (char*) alloca(w1); // BAD } } memcpy(b1, v, w1); @@ -52,7 +52,7 @@ void bar(const struct vtype* vec, int count) { b1 = new char[w1]; } else { // Allocate the buffer on stack - b1 = (char*) alloca(w1); // [FLAG] + b1 = (char*) alloca(w1); // BAD } } } while (0); @@ -77,7 +77,7 @@ void baz(const struct vtype* vec, int count) { b1 = new char[w1]; } else { // Allocate the buffer on stack - b1 = (char*) alloca(w1); // [FLAG] + b1 = (char*) alloca(w1); // BAD } } memcpy(b1, v, w1); diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp index 45b36161821d..9ebf4f17ba16 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop1ms.cpp @@ -25,7 +25,7 @@ void foo(const struct vtype* vec, int count) { b1 = new char[w1]; } else { // Allocate the buffer on stack - b1 = (char*) _alloca(w1); // [FLAG] + b1 = (char*) _alloca(w1); // BAD } } memcpy(b1, v, w1); @@ -49,7 +49,7 @@ void bar(const struct vtype* vec, int count) { b1 = new char[w1]; } else { // Allocate the buffer on stack - b1 = (char*) _malloca(w1); // [FLAG] + b1 = (char*) _malloca(w1); // BAD } } } while (0); @@ -76,7 +76,7 @@ void baz(const struct vtype* vec, int count) { b1 = new char[w1]; } else { // Allocate the buffer on stack - b1 = (char*) _alloca(w1); // [FLAG] + b1 = (char*) _alloca(w1); // BAD } } memcpy(b1, v, w1); diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c index eeeafb2f17ff..60a4986441dc 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop2.c @@ -36,7 +36,7 @@ void foo(const struct vtype* vec, int count) { b1 = (char *)malloc(w1); } else { // Allocate the buffer on stack - b1 = (char*) alloca(w1); // [FLAG] + b1 = (char*) alloca(w1); // BAD iter = 1; } } @@ -61,7 +61,7 @@ void bar(const struct vtype* vec, int count) { b1 = (char *)malloc(w1); } else { // Allocate the buffer on stack - b1 = (char*) alloca(w1); // [DO NOT FLAG] + b1 = (char*) alloca(w1); // GOOD } } } while (0); @@ -76,7 +76,7 @@ void bar(const struct vtype* vec, int count) { // case 3: alloca called outside any loops void baz(int count) { - char *buf = (char *)alloca(32); // [DO NOT FLAG] + char *buf = (char *)alloca(32); // GOOD sprintf(buf, "Value is %d\n", count); printf("%s", buf); } @@ -94,7 +94,7 @@ void foo_ms(const struct vtype* vec, int count) { (char *)malloc(w1); } else { // Allocate the buffer on stack - b1 = (char*) _alloca(w1); // [DO NOT FLAG] + b1 = (char*) _alloca(w1); // GOOD } } memcpy(b1, v, w1); @@ -118,7 +118,7 @@ void bar_ms(const struct vtype* vec, int count) { b1 = (char *)malloc(w1); } else { // Allocate the buffer on stack - b1 = (char*) _malloca(w1); // [DO NOT FLAG] + b1 = (char*) _malloca(w1); // GOOD } } } while (0); @@ -145,7 +145,7 @@ void baz_ms(const struct vtype* vec, int count) { b1 = (char *)malloc(w1); } else { // Allocate the buffer on stack - b1 = (char*) _alloca(w1); // [DO NOT FLAG] + b1 = (char*) _alloca(w1); // GOOD } } memcpy(b1, v, w1); diff --git a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop3.cpp b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop3.cpp index 60c02958d106..8a14c58355c0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop3.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Memory Management/AllocaInLoop/AllocaInLoop3.cpp @@ -15,7 +15,7 @@ void *__builtin_alloca(int sz); // case 1: a GNU c/c++ lambda with an alloca in it char *foo(int count) { char *buf = ({ - char *b = (char *)alloca(32); // [DO NOT FLAG] + char *b = (char *)alloca(32); // GOOD sprintf(b, "Value is %d\n", count); b; }); @@ -28,7 +28,7 @@ char *bar(int count) { char *buf; do { buf = ({ - char *b = (char *)alloca(32); // [DO NOT FLAG] + char *b = (char *)alloca(32); // GOOD sprintf(b, "Value is %d\n", count); b; }); @@ -42,7 +42,7 @@ char *baz(int count) { char *buf; do { buf = ({ - char *b = (char *)alloca(32); // [FLAG] + char *b = (char *)alloca(32); // BAD sprintf(b, "Value is %d\n", count); b; }); From 93b76a3558380187a14ec9e15d9896d4ef1d7a09 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Tue, 19 Mar 2019 14:30:05 -0700 Subject: [PATCH 5/5] [CPP-340] Re-work QL query; treat undeclared C functions the same way as ()-declared functions. --- cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql | 10 +++++----- .../Likely Typos/FutileParams/FutileParams.expected | 10 ++++++---- .../Likely Bugs/Likely Typos/FutileParams/test.c | 6 ++---- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql index 83baeaf8a95f..c21afaf4ac9a 100644 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql +++ b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql @@ -17,11 +17,11 @@ from FunctionCall fc, Function f /* There must be a zero-parameter declaration */ and exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | fde.getNumberOfParameters() = 0) /* There must be a mismatch between number of call arguments and number of parameters in some - * non-implicit declaration of Function f + * declaration of Function f */ - and exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit() and fde.getNumberOfParameters() != fc.getNumberOfArguments()) - /* There must be no _definition_ of Function f whose number of parameters matches number of call arguments */ - and not exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | fde.isDefinition() and fde.getNumberOfParameters() = fc.getNumberOfArguments()) -select fc + and exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | fde.getNumberOfParameters() != fc.getNumberOfArguments()) + /* There must be no actual declaration of Function f whose number of parameters matches number of call arguments */ + and not exists ( FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit() and fde.getNumberOfParameters() = fc.getNumberOfArguments()) +select fc, "This call has arguments, but $@ is not declared with any parameters.", f, f.toString() \ No newline at end of file diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected index 4bb782dfd11d..0021164c8614 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected @@ -1,4 +1,6 @@ -| test.c:7:3:7:16 | call to declared_empty | -| test.c:16:3:16:19 | call to not_yet_declared1 | -| test.c:19:3:19:29 | call to declared_empty_defined_with | -| test.c:24:3:24:29 | call to declared_empty_defined_with | +| test.c:7:3:7:16 | call to declared_empty | This call has arguments, but $@ is not declared with any parameters. | test.c:1:6:1:19 | declared_empty | declared_empty | +| test.c:12:3:12:12 | call to undeclared | This call has arguments, but $@ is not declared with any parameters. | test.c:11:3:11:3 | undeclared | undeclared | +| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:14:3:14:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:14:3:14:19 | call to not_yet_declared1 | This call has arguments, but $@ is not declared with any parameters. | test.c:25:6:25:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:17:3:17:29 | call to declared_empty_defined_with | This call has arguments, but $@ is not declared with any parameters. | test.c:27:6:27:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:22:3:22:29 | call to declared_empty_defined_with | This call has arguments, but $@ is not declared with any parameters. | test.c:27:6:27:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c index ef81c416343a..698644c5c1cf 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c @@ -8,10 +8,8 @@ void test() { declared_void(); // GOOD declared_with(1); // GOOD - declared_ellipsis(); // GOOD - declared_ellipsis(2); // GOOD - - undeclared(1); // GOOD + undeclared(); // GOOD + undeclared(1); // BAD not_yet_declared1(1); // BAD not_yet_declared2(1); // GOOD