From 0c350dc50476f22200c98a8c3815acaac7403b50 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 18 Mar 2019 16:10:35 -0700 Subject: [PATCH 01/27] [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 5d8b84c22a44240b2381c8cc72ee7481699910f2 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 18 Mar 2019 17:23:03 -0700 Subject: [PATCH 02/27] 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 2def0ee9c1ce274d218e5796d8ea059657ed93a5 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Tue, 19 Mar 2019 14:30:05 -0700 Subject: [PATCH 03/27] [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 From 5a092d0fed30060097c191055adddcd9a385e403 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Wed, 20 Mar 2019 19:42:51 -0700 Subject: [PATCH 04/27] [CPP-340] Create three QL queries: (1) mismatched argument types, (2) too few arguments and (3) too many arguments. Create new 'UnderspecifiedFunction' folders for both queries and tests. --- .../Likely Bugs/Likely Typos/FutileParams.c | 11 ------ .../Likely Typos/FutileParams.qhelp | 36 ------------------- .../Likely Bugs/Likely Typos/FutileParams.ql | 27 -------------- .../MistypedFunctionArguments.c | 8 +++++ .../MistypedFunctionArguments.qhelp | 29 +++++++++++++++ .../MistypedFunctionArguments.ql | 30 ++++++++++++++++ .../UnderspecifiedFunctions/TooFewArguments.c | 8 +++++ .../TooFewArguments.qhelp | 35 ++++++++++++++++++ .../TooFewArguments.ql | 30 ++++++++++++++++ .../TooManyArguments.c | 9 +++++ .../TooManyArguments.qhelp | 30 ++++++++++++++++ .../TooManyArguments.ql | 29 +++++++++++++++ .../FutileParams/FutileParams.expected | 6 ---- .../FutileParams/FutileParams.qlref | 1 - .../MistypedFunctionArguments.expected | 4 +++ .../MistypedFunctionArguments.qlref | 1 + .../TooFewArguments.expected | 3 ++ .../TooFewArguments.qlref | 1 + .../TooManyArguments.expected | 5 +++ .../TooManyArguments.qlref | 1 + .../test.c | 11 ++++-- .../test.cpp | 0 22 files changed, 232 insertions(+), 83 deletions(-) delete mode 100644 cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c delete mode 100644 cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp delete mode 100644 cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref rename cpp/ql/test/query-tests/Likely Bugs/{Likely Typos/FutileParams => UnderspecifiedFunctions}/test.c (62%) rename cpp/ql/test/query-tests/Likely Bugs/{Likely Typos/FutileParams => UnderspecifiedFunctions}/test.cpp (100%) diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c deleted file mode 100644 index 1a827a6c90a3..000000000000 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.c +++ /dev/null @@ -1,11 +0,0 @@ -void no_argument(); - -void one_argument(int x); - -void calls() { - no_argument(1) // BAD: `no_argument` will accept and ignore the argument - - one_argument(1); // GOOD: `one_argument` will accept and use the argument - - no_argument(); // GOOD: `no_argument` has not been passed an argument -} \ No newline at end of file diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp deleted file mode 100644 index 0c1e345c04fa..000000000000 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -

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++, () 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. 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.

- -
- - - - - -
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • -
    -
    diff --git a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql b/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql deleted file mode 100644 index c21afaf4ac9a..000000000000 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql +++ /dev/null @@ -1,27 +0,0 @@ -/** - * @name Non-empty call to function declared without parameters - * @description A call to a function declared without parameters has arguments, which may indicate - * that the code does not follow the author's intent. - * @kind problem - * @problem.severity warning - * @precision very-high - * @id cpp/futile-params - * @tags correctness - * maintainability - */ - -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 - * declaration of Function f - */ - 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/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c new file mode 100644 index 000000000000..faff73f64fba --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c @@ -0,0 +1,8 @@ +void no_argument(); + +void three_arguments(int x, int y, int z); + +void calls() { + three_arguments(1, 2, 3); // GOOD + three_arguments(1.0f, 2, 3.0f); // BAD: arguments 1 and 3 do not match parameters +} diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp new file mode 100644 index 000000000000..f4bdb7d11d4a --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp @@ -0,0 +1,29 @@ + + + + + +

    A function is called with at least one argument whose type is incompatible with the type of + the corresponding parameter of the function being called. This may cause the called function + to behave unpredictably.

    + +

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

    + +
    + +

    Call the function with the proper argument types. In some cases, it may + suffice to provide an explicit cast of an argument to the desired (parameter) type.

    + +
    + + + + + +
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql new file mode 100644 index 000000000000..c193a835e929 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql @@ -0,0 +1,30 @@ +/** + * @name Call to a function with one or more incompatible arguments + * @description A call to a function with at least one argument whose type does + * not match the type of the corresponding function parameter. This may indicate + * that the author is not familiar with the function being called. Passing mistyped + * arguments on a stack may lead to unpredictable function behavior. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id cpp/mistyped-function-arguments + * @tags correctness + * maintainability + */ + +import cpp + +from FunctionCall fc, Function f, Parameter p +where + f = fc.getTarget() and + p = f.getAParameter() and + not f.isVarargs() and + p.getIndex() < fc.getNumberOfArguments() and + // There must be a zero-parameter declaration + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() = 0 + ) and + // Parameter p and its corresponding call argument must have mismatched types + p.getType() != fc.getArgument(p.getIndex()).getType() +select fc, "Calling $@: $@ is incompatible with $@.", f, f.toString(), fc.getArgument(p.getIndex()), + fc.getArgument(p.getIndex()).toString(), p, p.getTypedName() diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c new file mode 100644 index 000000000000..246d029e5480 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c @@ -0,0 +1,8 @@ + +void one_argument(int x); + +void calls() { + one_argument(1); // GOOD: `one_argument` will accept and use the argument + + one_argument(); // BAD: `one_argument` will receive an undefined value +} diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp new file mode 100644 index 000000000000..8eb266e3ac3a --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp @@ -0,0 +1,35 @@ + + + + + +

    A function is called with fewer arguments than there are parameters of the function.

    + +

    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, function calls generally need to provide the same number of arguments as there are + arguments to the function. (Variadic functions can accept additional arguments.) Providing + fewer arguments than there are parameters is extremely dangerous, as the called function + will nevertheless try to obtain the missing arguments' values, either from the stack + or from machine registers. As a result, the function may behave unpredictably.

    + +

    If the called function modifies a parameter corresponding to a missing argument, it + may alter the state of the program upon its return. An attacker could use this to, + for example, alter the control flow of the program to access forbidden resources.

    + +
    + +

    Call the function with the correct number of arguments.

    + +
    + + + + + +
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql new file mode 100644 index 000000000000..04ccc86d0929 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql @@ -0,0 +1,30 @@ +/** + * @name Call to function with fewer arguments than declared parameters + * @description A function call passed fewer arguments than the number of + * declared parameters of the function. This may indicate + * that the code does not follow the author's intent. It is also a vulnerability, + * since the function is like to operate on undefined data. + * @kind problem + * @problem.severity error + * @precision very-high + * @id cpp/too-few-arguments + * @tags correctness + * maintainability + */ + +import cpp + +from FunctionCall fc, Function f +where + f = fc.getTarget() and + not f.isVarargs() and + // There must be a zero-parameter declaration (explicit or implicit) + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() = 0 + ) and + // There is an explicit declaration of the function whose parameter count is larger + // than the number of call arguments + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.isImplicit() and fde.getNumberOfParameters() > fc.getNumberOfArguments() + ) +select fc, "This call has fewer arguments than required by $@.", f, f.toString() diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c new file mode 100644 index 000000000000..2ab318f70765 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c @@ -0,0 +1,9 @@ + +void one_argument(int x); + +void calls() { + + one_argument(1); // GOOD: `one_argument` will accept and use the argument + + one_argument(1, 2); // BAD: `one_argument` will use the first argument but ignore the second +} diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp new file mode 100644 index 000000000000..a473a1b16445 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp @@ -0,0 +1,30 @@ + + + + + +

    A function is called with more arguments than there are parameters of the function.

    + +

    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, function calls generally need to provide the same number of arguments as there are + arguments to the function. (Variadic functions can accept additional arguments.) Providing + more arguments than there are parameters incurs an unneeded computational overhead, both + in terms of time and of additional stack space.

    + +
    + +

    Call the function with the correct number of arguments.

    + +
    + + + + + +
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql new file mode 100644 index 000000000000..e58a64caab95 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql @@ -0,0 +1,29 @@ +/** + * @name Call to function with extraneous parameters + * @description A function call to a function passed more arguments than there are + * declared parameters of the function. This may indicate + * that the code does not follow the author's intent. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id cpp/too-many-arguments + * @tags correctness + * maintainability + */ + +import cpp + +from FunctionCall fc, Function f +where + f = fc.getTarget() and + not f.isVarargs() and + // There must be a zero-parameter declaration (explicit or implicit) + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() = 0 + ) and + // There must not exist a declaration with the number of parameters + // at least as large as the number of call arguments + not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() >= fc.getNumberOfArguments() + ) +select fc, "This call has more arguments than required by $@.", f, f.toString() 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 deleted file mode 100644 index 0021164c8614..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected +++ /dev/null @@ -1,6 +0,0 @@ -| 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/FutileParams.qlref b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref deleted file mode 100644 index f6dbe907dc59..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.qlref +++ /dev/null @@ -1 +0,0 @@ -Likely Bugs/Likely Typos/FutileParams.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected new file mode 100644 index 000000000000..7097b643f4e3 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected @@ -0,0 +1,4 @@ +| test.c:23:3:23:29 | call to declared_empty_defined_with | Calling $@: $@ is incompatible with $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:23:31:23:32 | & ... | & ... | test.c:31:38:31:38 | x | int x | +| test.c:24:3:24:29 | call to declared_empty_defined_with | Calling $@: $@ is incompatible with $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:24:31:24:34 | 3.0 | 3.0 | test.c:31:38:31:38 | x | int x | +| test.c:26:3:26:27 | call to not_declared_defined_with | Calling $@: $@ is incompatible with $@. | test.c:34:6:34:30 | not_declared_defined_with | not_declared_defined_with | test.c:26:29:26:31 | 1.0 | 1.0 | test.c:34:36:34:36 | x | int x | +| test.c:26:3:26:27 | call to not_declared_defined_with | Calling $@: $@ is incompatible with $@. | test.c:34:6:34:30 | not_declared_defined_with | not_declared_defined_with | test.c:26:37:26:38 | 2 | 2 | test.c:34:50:34:50 | z | int z | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref new file mode 100644 index 000000000000..e61361d6bfee --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref @@ -0,0 +1 @@ +Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected new file mode 100644 index 000000000000..cf232973ba35 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected @@ -0,0 +1,3 @@ +| test.c:17:3:17:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:16:3:16:3 | not_yet_declared2 | not_yet_declared2 | +| test.c:17:3:17:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:30:6:30:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:19:3:19:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref new file mode 100644 index 000000000000..710092c54d85 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref @@ -0,0 +1 @@ +Likely Bugs/Underspecified Functions/TooFewArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected new file mode 100644 index 000000000000..319d92628a02 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected @@ -0,0 +1,5 @@ +| test.c:8:3:8:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | +| test.c:13:3:13:12 | call to undeclared | This call has more arguments than required by $@. | test.c:12:3:12:3 | undeclared | undeclared | +| test.c:15:3:15:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:15:3:15:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:15:3:15:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:29:6:29:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:24:3:24:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref new file mode 100644 index 000000000000..ca44af39c2bf --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref @@ -0,0 +1 @@ +Likely Bugs/Underspecified Functions/TooManyArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c similarity index 62% rename from cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c rename to cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c index 698644c5c1cf..90247dde0ff4 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c @@ -1,6 +1,7 @@ void declared_empty(); void declared_void(void); void declared_with(int); +void declared_empty_defined_with(); void test() { declared_empty(); // GOOD @@ -13,13 +14,16 @@ void test() { not_yet_declared1(1); // BAD not_yet_declared2(1); // GOOD + not_yet_declared2(); // BAD declared_empty_defined_with(); // BAD declared_empty_defined_with(1); // GOOD int x; - declared_empty_defined_with(&x); // GOOD - declared_empty_defined_with(x, x); // BAD + declared_empty_defined_with(&x); // GOOD (type mismatch) + declared_empty_defined_with(3.0f, &x); // BAD (type mismatch) + + not_declared_defined_with(1.0, 0, 2U); // GOOD (type mismatch) } void not_yet_declared1(); @@ -27,3 +31,6 @@ void not_yet_declared2(int); void declared_empty_defined_with(int x) { // do nothing } +void not_declared_defined_with(int x, int y, int z) { + return; +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.cpp similarity index 100% rename from cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp rename to cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.cpp From 29af56d21b7fe74bc8560274d4ea43485c2e2911 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Sun, 24 Mar 2019 19:42:05 -0700 Subject: [PATCH 05/27] [CPP-340] Refine the test query for mismatching args/params by applying C promotion rules. The following issues are now flagged: (1) passing a larger type than the receiver can accept (e.g., long long -> int) (2) passing a type of different signedness than the parameter specified. --- .../MistypedFunctionArguments.ql | 93 ++++++++++++++++++- .../TooFewArguments.ql | 1 + .../MistypedFunctionArguments.expected | 8 +- .../MistypedFunctionArguments.qlref | 2 +- .../TooFewArguments.expected | 4 +- .../TooFewArguments.qlref | 2 +- .../TooManyArguments.expected | 4 +- .../TooManyArguments.qlref | 2 +- .../UnderspecifiedFunctions/test.c | 1 + 9 files changed, 103 insertions(+), 14 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql index c193a835e929..a850c0612e45 100644 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql @@ -14,6 +14,91 @@ import cpp +predicate argTypeMayBePromoted(Type arg, Type parm) { + arg = parm + or + // floating-point and integral promotions + arg instanceof FloatType and parm instanceof DoubleType + or + arg instanceof FloatType and parm instanceof LongDoubleType + or + arg instanceof DoubleType and parm instanceof LongDoubleType + or + arg instanceof CharType and parm instanceof IntType + or + arg instanceof CharType and parm instanceof IntType + or + arg instanceof CharType and parm instanceof LongType + or + arg instanceof CharType and parm instanceof LongLongType + or + arg instanceof ShortType and parm instanceof IntType + or + arg instanceof ShortType and parm instanceof LongType + or + arg instanceof ShortType and parm instanceof LongLongType + or + arg instanceof IntType and parm instanceof LongType + or + arg instanceof IntType and parm instanceof LongLongType + or + arg instanceof LongType and parm instanceof LongLongType + or + arg instanceof Enum and parm instanceof IntType + or + arg instanceof Enum and parm instanceof LongType + or + arg instanceof Enum and parm instanceof LongLongType + or + // enums are usually sized as ints + arg instanceof IntType and parm instanceof Enum + or + // pointer types + arg.(PointerType).getBaseType().getUnspecifiedType() = parm + .getUnspecifiedType() + .(PointerType) + .getBaseType() + .getUnspecifiedType() + or + // void * parameters accept arbitrary pointer arguments + arg instanceof PointerType and + parm.(PointerType).getBaseType().getUnspecifiedType() instanceof VoidType + or + // handle reference types + argTypeMayBePromoted(arg.(ReferenceType).getBaseType().getUnspecifiedType(), parm) + or + argTypeMayBePromoted(arg, parm.(ReferenceType).getBaseType().getUnspecifiedType()) + or + // array-to-pointer decay + argTypeMayBePromoted(arg.(ArrayType).getBaseType().getUnspecifiedType(), + parm.(PointerType).getBaseType().getUnspecifiedType()) + or + // pointer-to-array promotion (C99) + argTypeMayBePromoted(arg.(PointerType).getBaseType().getUnspecifiedType(), + parm.(ArrayType).getBaseType().getUnspecifiedType()) +} + +// This predicate doesn't necessarily have to exist, but if it does exist +// then it must be inline to make sure we don't enumerate all pairs of +// compatible types. +// Its body could also just be hand-inlined where it's used. +pragma[inline] +predicate argMayBePromoted(Expr arg, Parameter parm) { + argTypeMayBePromoted(arg.getExplicitlyConverted().getType().getUnspecifiedType(), + parm.getType().getUnspecifiedType()) + or + // The value 0 is often passed in to indicate NULL, or to initialize an arbitrary integer type. + // we will allow all literal values for simplicity. Pointer parameters are sometime passed + // special-case literals such as -1, -2, etc. + arg.(Literal).getType() instanceof IntegralType and + ( + parm.getType().getUnspecifiedType() instanceof PointerType + or + parm.getType().getUnspecifiedType() instanceof IntegralType and + arg.(Literal).getType().getSize() <= parm.getType().getUnspecifiedType().getSize() + ) +} + from FunctionCall fc, Function f, Parameter p where f = fc.getTarget() and @@ -25,6 +110,8 @@ where fde.getNumberOfParameters() = 0 ) and // Parameter p and its corresponding call argument must have mismatched types - p.getType() != fc.getArgument(p.getIndex()).getType() -select fc, "Calling $@: $@ is incompatible with $@.", f, f.toString(), fc.getArgument(p.getIndex()), - fc.getArgument(p.getIndex()).toString(), p, p.getTypedName() + not argMayBePromoted(fc.getArgument(p.getIndex()), p) +select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(), + fc.getArgument(p.getIndex()), fc.getArgument(p.getIndex()).toString(), + fc.getArgument(p.getIndex()).getType(), fc.getArgument(p.getIndex()).getType().toString(), p, + p.getTypedName() diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql index 04ccc86d0929..2a7b9a0e7ab0 100644 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql @@ -10,6 +10,7 @@ * @id cpp/too-few-arguments * @tags correctness * maintainability + * security */ import cpp diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected index 7097b643f4e3..aa962619687a 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected @@ -1,4 +1,4 @@ -| test.c:23:3:23:29 | call to declared_empty_defined_with | Calling $@: $@ is incompatible with $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:23:31:23:32 | & ... | & ... | test.c:31:38:31:38 | x | int x | -| test.c:24:3:24:29 | call to declared_empty_defined_with | Calling $@: $@ is incompatible with $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:24:31:24:34 | 3.0 | 3.0 | test.c:31:38:31:38 | x | int x | -| test.c:26:3:26:27 | call to not_declared_defined_with | Calling $@: $@ is incompatible with $@. | test.c:34:6:34:30 | not_declared_defined_with | not_declared_defined_with | test.c:26:29:26:31 | 1.0 | 1.0 | test.c:34:36:34:36 | x | int x | -| test.c:26:3:26:27 | call to not_declared_defined_with | Calling $@: $@ is incompatible with $@. | test.c:34:6:34:30 | not_declared_defined_with | not_declared_defined_with | test.c:26:37:26:38 | 2 | 2 | test.c:34:50:34:50 | z | int z | +| test.c:23:3:23:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:23:31:23:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:32:38:32:38 | x | int x | +| test.c:24:3:24:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:24:31:24:34 | 3.0 | 3.0 | file://:0:0:0:0 | float | float | test.c:32:38:32:38 | x | int x | +| test.c:26:3:26:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:35:6:35:30 | not_declared_defined_with | not_declared_defined_with | test.c:26:29:26:31 | 1.0 | 1.0 | file://:0:0:0:0 | double | double | test.c:35:36:35:36 | x | int x | +| test.c:27:3:27:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:35:6:35:30 | not_declared_defined_with | not_declared_defined_with | test.c:27:29:27:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:35:36:35:36 | x | int x | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref index e61361d6bfee..e2e24d78bc38 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref @@ -1 +1 @@ -Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected index cf232973ba35..ac56c76fb3cc 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected @@ -1,3 +1,3 @@ | test.c:17:3:17:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:16:3:16:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:17:3:17:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:30:6:30:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:19:3:19:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:17:3:17:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:31:6:31:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:19:3:19:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref index 710092c54d85..cfc3bd165a23 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref @@ -1 +1 @@ -Likely Bugs/Underspecified Functions/TooFewArguments.ql +Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected index 319d92628a02..06c5439ecc64 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected @@ -1,5 +1,5 @@ | test.c:8:3:8:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | | test.c:13:3:13:12 | call to undeclared | This call has more arguments than required by $@. | test.c:12:3:12:3 | undeclared | undeclared | | test.c:15:3:15:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:15:3:15:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:15:3:15:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:29:6:29:22 | not_yet_declared1 | not_yet_declared1 | -| test.c:24:3:24:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:31:6:31:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:15:3:15:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:30:6:30:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:24:3:24:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref index ca44af39c2bf..9438d5ad537b 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref @@ -1 +1 @@ -Likely Bugs/Underspecified Functions/TooManyArguments.ql +Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c index 90247dde0ff4..0fa1097fc119 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c @@ -24,6 +24,7 @@ void test() { declared_empty_defined_with(3.0f, &x); // BAD (type mismatch) not_declared_defined_with(1.0, 0, 2U); // GOOD (type mismatch) + not_declared_defined_with(4LL, 0, 2); // GOOD (type mismatch) } void not_yet_declared1(); From cb5bbd219764f5c70ce8e94360a5e13031176377 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Fri, 29 Mar 2019 20:19:45 -0700 Subject: [PATCH 06/27] [CPP-340] When warning about mismatched parameters, follow what C compilers do. Various integral and floating-point types are treated as mutually implicitly convertible. Remaining warnings deal with misuse of pointer and array types. --- .../MistypedFunctionArguments.c | 7 +- .../MistypedFunctionArguments.o | Bin 0 -> 1720 bytes .../MistypedFunctionArguments.ql | 93 ++++++------------ .../MistypedFunctionArguments.s | 1 + .../TooFewArguments.ql | 2 +- .../TooManyArguments.c | 5 +- .../TooManyArguments.qhelp | 2 +- .../UnderspecifiedFunctions/tests.c | 33 +++++++ .../MistypedFunctionArguments.expected | 11 ++- .../TooFewArguments.expected | 7 +- .../TooManyArguments.expected | 10 +- .../UnderspecifiedFunctions/test.c | 34 ++++++- 12 files changed, 117 insertions(+), 88 deletions(-) create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.o create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.s create mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c index faff73f64fba..fa3235a6e3fe 100644 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c @@ -1,8 +1,7 @@ -void no_argument(); - void three_arguments(int x, int y, int z); void calls() { - three_arguments(1, 2, 3); // GOOD - three_arguments(1.0f, 2, 3.0f); // BAD: arguments 1 and 3 do not match parameters + int three = 3; + three_arguments(1, 2, three); // GOOD + three_arguments(1, 2, &three); // BAD } diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.o b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.o new file mode 100644 index 0000000000000000000000000000000000000000..5d4064e871cbf611b42cb07aa3896e8bf85112c5 GIT binary patch literal 1720 zcmb`HPiqrV5Wr`%+N!ORiU*+z>qR5lM^c5BqLMV^50Vw@6F8Hoqd~^l}0tAX~3ev9XN`Z z0=(Cc{9@=9VHRefRp0;ef!01|@bZaDztZx5V$?M3SATPSyzTzykRLoggj%`0V&q!w zz?FfqByNcO!s1d8hK0StvdG`O8e!~kj=G>|&mVxclhx*Dr%xQr8C*r zneyqW%pPVCNEdqGWAI~`wyLL25~$_!`Nkd0uN_3wssMtIrur`9oSw% zel~WW;j<&Vf|^B5%54N`9M-mcx%<@VR0G$RTLZV`Z3cbEmAch&qxn5drR7{Xv&v8tPD`-!CPjsI%sK17hKMPWhxG5&mvpT5S-%^dj43&vSZ~kj{<-(XpfjqV4-2>_MOA1;QOjN7U}M z7JO;h+aSVpr)xg(tiChq|BsG=^>lWVC##5zgwH_~MY-&gokyj2P(+Q(TQ!7t3Z6tu z`|u}pUh&I{C%=S4wVpK8BQDo5pq_tQU%*=GnMaKa?|&^0(dYfyuEbb8^;chO0ke^CvD=S=gbe+jN -
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c new file mode 100644 index 000000000000..3c44536ac622 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c @@ -0,0 +1,33 @@ +//void three_arguments(); +void three_arguments(int x, char y, int *z); +void pointer_arguments(float *x, void *y, int **z); +void array_argument(int arr[6]); +void array_argument2(char arr[6]); +int var; +void *pv; +double d = 3732.70e13L; +extern unsigned long long *ull; + +extern void *a[3]; + +void calls() { + three_arguments(*ull, 2, &var); // BAD: arguments 1 and 3 do not match parameters + three_arguments(&ull, 2, &var); // BAD: arguments 1 and 3 do not match parameters + three_arguments(&var, 2, &var); // BAD: arguments 1 and 3 do not match parameters + three_arguments(var, 2, 3.0f); // BAD: arguments 1 and 3 do not match parameters + + pointer_arguments(20, 0, 0); // BAD + pointer_arguments(pv, &var, &pv); // GOOD + pointer_arguments(&pv, &var, pv); // BAD + pointer_arguments(&var, a, &pv); // BAD + pointer_arguments(&var, &pv, a); // BAD + + array_argument(&var); + array_argument(pv); + array_argument(10); + array_argument("Hello"); + + array_argument2("Hello"); + +} + diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected index aa962619687a..a8ce8fe0506c 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected @@ -1,4 +1,7 @@ -| test.c:23:3:23:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:23:31:23:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:32:38:32:38 | x | int x | -| test.c:24:3:24:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:24:31:24:34 | 3.0 | 3.0 | file://:0:0:0:0 | float | float | test.c:32:38:32:38 | x | int x | -| test.c:26:3:26:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:35:6:35:30 | not_declared_defined_with | not_declared_defined_with | test.c:26:29:26:31 | 1.0 | 1.0 | file://:0:0:0:0 | double | double | test.c:35:36:35:36 | x | int x | -| test.c:27:3:27:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:35:6:35:30 | not_declared_defined_with | not_declared_defined_with | test.c:27:29:27:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:35:36:35:36 | x | int x | +| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | +| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | +| test.c:32:3:32:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:32:31:32:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:46:38:46:38 | x | int x | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:61:6:61:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | +| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | +| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:62:6:62:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected index ac56c76fb3cc..6b56644df7ca 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected @@ -1,3 +1,4 @@ -| test.c:17:3:17:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:16:3:16:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:17:3:17:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:31:6:31:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:19:3:19:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | +| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:28:3:28:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:56:10:56:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:59:5:59:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected index 06c5439ecc64..89ae7d04771e 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected @@ -1,5 +1,5 @@ -| test.c:8:3:8:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | -| test.c:13:3:13:12 | call to undeclared | This call has more arguments than required by $@. | test.c:12:3:12:3 | undeclared | undeclared | -| test.c:15:3:15:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:15:3:15:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:15:3:15:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:30:6:30:22 | not_yet_declared1 | not_yet_declared1 | -| test.c:24:3:24:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:32:6:32:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:16:3:16:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | +| test.c:21:3:21:12 | call to undeclared | This call has more arguments than required by $@. | test.c:20:3:20:3 | undeclared | undeclared | +| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:23:3:23:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:44:6:44:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:33:3:33:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c index 0fa1097fc119..16f10479f66c 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c @@ -2,6 +2,14 @@ void declared_empty(); void declared_void(void); void declared_with(int); void declared_empty_defined_with(); +void declared_with_pointers(); +void declared_with_array(); + +struct _s { int a, b; } s; + +int ca[4] = { 1, 2, 3, 4 }; + +void *pv; void test() { declared_empty(); // GOOD @@ -14,17 +22,23 @@ void test() { not_yet_declared1(1); // BAD not_yet_declared2(1); // GOOD + not_yet_declared2(ca); // BAD not_yet_declared2(); // BAD declared_empty_defined_with(); // BAD declared_empty_defined_with(1); // GOOD int x; - declared_empty_defined_with(&x); // GOOD (type mismatch) - declared_empty_defined_with(3.0f, &x); // BAD (type mismatch) + declared_empty_defined_with(&x); // BAD + declared_empty_defined_with(3.0f, &x); // BAD - not_declared_defined_with(1.0, 0, 2U); // GOOD (type mismatch) - not_declared_defined_with(4LL, 0, 2); // GOOD (type mismatch) + not_declared_defined_with(1.0, 0, 2U); // GOOD + not_declared_defined_with(4LL, 0, 2.5e9); // GOOD + + declared_with_pointers(pv, ca); // GOOD + declared_with_pointers(3.5e15, 0); // BAD + declared_with_array("Hello"); // GOOD + declared_with_array(&x); // BAD } void not_yet_declared1(); @@ -35,3 +49,15 @@ void declared_empty_defined_with(int x) { void not_declared_defined_with(int x, int y, int z) { return; } + +int dereference(); + +int caller(void) { + return dereference(); // BAD +} + +int dereference(int *x) { return *x; } + +void declared_with_pointers(int *x, void *y); +void declared_with_array(char a [6]); + From 2ea9f81c7f1a8c844f1d48b7b0063462a43b949a Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Fri, 29 Mar 2019 20:27:25 -0700 Subject: [PATCH 07/27] [CPP-340] Refer to C coding standard, not C++. --- .../MistypedFunctionArguments.o | Bin 1720 -> 0 bytes .../MistypedFunctionArguments.qhelp | 2 +- .../MistypedFunctionArguments.s | 1 - .../TooFewArguments.qhelp | 2 +- .../UnderspecifiedFunctions/tests.c | 33 ------------------ 5 files changed, 2 insertions(+), 36 deletions(-) delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.o delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.s delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.o b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.o deleted file mode 100644 index 5d4064e871cbf611b42cb07aa3896e8bf85112c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1720 zcmb`HPiqrV5Wr`%+N!ORiU*+z>qR5lM^c5BqLMV^50Vw@6F8Hoqd~^l}0tAX~3ev9XN`Z z0=(Cc{9@=9VHRefRp0;ef!01|@bZaDztZx5V$?M3SATPSyzTzykRLoggj%`0V&q!w zz?FfqByNcO!s1d8hK0StvdG`O8e!~kj=G>|&mVxclhx*Dr%xQr8C*r zneyqW%pPVCNEdqGWAI~`wyLL25~$_!`Nkd0uN_3wssMtIrur`9oSw% zel~WW;j<&Vf|^B5%54N`9M-mcx%<@VR0G$RTLZV`Z3cbEmAch&qxn5drR7{Xv&v8tPD`-!CPjsI%sK17hKMPWhxG5&mvpT5S-%^dj43&vSZ~kj{<-(XpfjqV4-2>_MOA1;QOjN7U}M z7JO;h+aSVpr)xg(tiChq|BsG=^>lWVC##5zgwH_~MY-&gokyj2P(+Q(TQ!7t3Z6tu z`|u}pUh&I{C%=S4wVpK8BQDo5pq_tQU%*=GnMaKa?|&^0(dYfyuEbb8^;chO0ke^CvD=S=gbe+jN -
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.s b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.s deleted file mode 100644 index f4ea6be47056..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.s +++ /dev/null @@ -1 +0,0 @@ - .file "MistypedFunctionArguments.c" diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp index 8eb266e3ac3a..20085880b14c 100644 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp @@ -30,6 +30,6 @@
    -
  • SEI CERT C++ Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c deleted file mode 100644 index 3c44536ac622..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c +++ /dev/null @@ -1,33 +0,0 @@ -//void three_arguments(); -void three_arguments(int x, char y, int *z); -void pointer_arguments(float *x, void *y, int **z); -void array_argument(int arr[6]); -void array_argument2(char arr[6]); -int var; -void *pv; -double d = 3732.70e13L; -extern unsigned long long *ull; - -extern void *a[3]; - -void calls() { - three_arguments(*ull, 2, &var); // BAD: arguments 1 and 3 do not match parameters - three_arguments(&ull, 2, &var); // BAD: arguments 1 and 3 do not match parameters - three_arguments(&var, 2, &var); // BAD: arguments 1 and 3 do not match parameters - three_arguments(var, 2, 3.0f); // BAD: arguments 1 and 3 do not match parameters - - pointer_arguments(20, 0, 0); // BAD - pointer_arguments(pv, &var, &pv); // GOOD - pointer_arguments(&pv, &var, pv); // BAD - pointer_arguments(&var, a, &pv); // BAD - pointer_arguments(&var, &pv, a); // BAD - - array_argument(&var); - array_argument(pv); - array_argument(10); - array_argument("Hello"); - - array_argument2("Hello"); - -} - From 59a54df1494a2107250981fefd7fd7fe3794a445 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Fri, 29 Mar 2019 20:30:40 -0700 Subject: [PATCH 08/27] [CPP-340] cpp/too-many-arguments should remain as cpp/futile-params. --- .../src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql index e58a64caab95..39684fe3acc5 100644 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql @@ -6,7 +6,7 @@ * @kind problem * @problem.severity warning * @precision very-high - * @id cpp/too-many-arguments + * @id cpp/futile-params * @tags correctness * maintainability */ From 8a653b9adc453a70539974b1b869c06547cfd984 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Fri, 29 Mar 2019 20:34:49 -0700 Subject: [PATCH 09/27] [CPP-340] Fix TooFewArguments.c to actually provide a ()-prototype. --- .../Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c index 246d029e5480..93251746fd32 100644 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c +++ b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c @@ -1,8 +1,9 @@ - -void one_argument(int x); +void one_argument(); void calls() { one_argument(1); // GOOD: `one_argument` will accept and use the argument one_argument(); // BAD: `one_argument` will receive an undefined value } + +void one_argument(int x); From 3ec988c39b9caf6b575a60a2bec0dd7db575d3bb Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 1 Apr 2019 18:39:46 -0700 Subject: [PATCH 10/27] [CPP-340] Rename 'UnspecifiedFunctions' to 'Unspecified Functions' Make MistypedFunctionArguments.ql more restrictive (allowing type matching only in the presence of no-op conversions). --- cpp/config/suites/c/correctness | 4 +- cpp/config/suites/cpp/correctness | 4 +- .../MistypedFunctionArguments.c | 7 ++ .../MistypedFunctionArguments.qhelp | 29 +++++ .../MistypedFunctionArguments.ql | 109 ++++++++++++++++++ .../TooFewArguments.c | 9 ++ .../TooFewArguments.qhelp | 35 ++++++ .../TooFewArguments.ql | 31 +++++ .../TooManyArguments.c | 10 ++ .../TooManyArguments.qhelp | 30 +++++ .../TooManyArguments.ql | 29 +++++ .../MistypedFunctionArguments.expected | 11 ++ .../MistypedFunctionArguments.qlref | 1 + .../TooFewArguments.expected | 4 + .../TooFewArguments.qlref | 1 + .../TooManyArguments.expected | 5 + .../TooManyArguments.qlref | 1 + .../Underspecified Functions/test.c | 63 ++++++++++ .../Underspecified Functions/test.cpp | 8 ++ 19 files changed, 389 insertions(+), 2 deletions(-) create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.c create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qhelp create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.c create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qhelp create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.c create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qhelp create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.qlref create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp diff --git a/cpp/config/suites/c/correctness b/cpp/config/suites/c/correctness index 442e618854d4..b13c4f61752e 100644 --- a/cpp/config/suites/c/correctness +++ b/cpp/config/suites/c/correctness @@ -6,6 +6,7 @@ + semmlecode-cpp-queries/Likely Bugs/Arithmetic/IntMultToLong.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/ImplicitDowncastFromBitfield.ql: /Correctness/Dangerous Conversions ++ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use @@ -15,7 +16,8 @@ + semmlecode-cpp-queries/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/CompareWhereAssignMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors -+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/FutileParams.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors diff --git a/cpp/config/suites/cpp/correctness b/cpp/config/suites/cpp/correctness index 00ad7a1ad07d..d1079bdcf608 100644 --- a/cpp/config/suites/cpp/correctness +++ b/cpp/config/suites/cpp/correctness @@ -7,6 +7,7 @@ + semmlecode-cpp-queries/Likely Bugs/Conversion/NonzeroValueCastToPointer.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/ImplicitDowncastFromBitfield.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Likely Bugs/Conversion/CastArrayPointerArithmetic.ql: /Correctness/Dangerous Conversions ++ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql: /Correctness/Dangerous Conversions + semmlecode-cpp-queries/Security/CWE/CWE-253/HResultBooleanConversion.ql: /Correctness/Dangerous Conversions # Consistent Use + semmlecode-cpp-queries/Critical/ReturnValueIgnored.ql: /Correctness/Consistent Use @@ -16,7 +17,8 @@ + semmlecode-cpp-queries/Likely Bugs/Likely Typos/AssignWhereCompareMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/CompareWhereAssignMeant.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ExprHasNoEffect.ql: /Correctness/Common Errors -+ semmlecode-cpp-queries/Likely Bugs/Likely Typos/FutileParams.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooFewArguments.ql: /Correctness/Common Errors ++ semmlecode-cpp-queries/Likely Bugs/Underspecified Functions/TooManyArguments.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/ShortCircuitBitMask.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Likely Typos/MissingEnumCaseInSwitch.ql: /Correctness/Common Errors + semmlecode-cpp-queries/Likely Bugs/Arithmetic/FloatComparison.ql: /Correctness/Common Errors diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.c b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.c new file mode 100644 index 000000000000..fa3235a6e3fe --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.c @@ -0,0 +1,7 @@ +void three_arguments(int x, int y, int z); + +void calls() { + int three = 3; + three_arguments(1, 2, three); // GOOD + three_arguments(1, 2, &three); // BAD +} diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qhelp b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qhelp new file mode 100644 index 000000000000..6dd3f0eff48d --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qhelp @@ -0,0 +1,29 @@ + + + + + +

    A function is called with at least one argument whose type is incompatible with the type of + the corresponding parameter of the function being called. This may cause the called function + to behave unpredictably.

    + +

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

    + +
    + +

    Call the function with the proper argument types. In some cases, it may + suffice to provide an explicit cast of an argument to the desired (parameter) type.

    + +
    + + + + + +
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql new file mode 100644 index 000000000000..2ee6826843ec --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -0,0 +1,109 @@ +/** + * @name Call to a function with one or more incompatible arguments + * @description A call to a function with at least one argument whose type does + * not match the type of the corresponding function parameter. This may indicate + * that the author is not familiar with the function being called. Passing mistyped + * arguments on a stack may lead to unpredictable function behavior. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id cpp/mistyped-function-arguments + * @tags correctness + * maintainability + */ + +import cpp + +pragma[inline] +int sizeofInt() { result = any(IntType pt).getSize() } + +pragma[inline] +predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { + arg = parm + or + // arithmetic types + arg instanceof ArithmeticType and + parm instanceof ArithmeticType and + arg.getSize() = parm.getSize() and + ( + ( + arg instanceof IntegralType and + parm instanceof IntegralType + ) + or + ( + arg instanceof FloatingPointType and + parm instanceof FloatingPointType + ) + ) + or + // pointers to void are ok + arg instanceof VoidType + or + parm instanceof VoidType +} + +pragma[inline] +predicate argTypeMayBeUsed(Type arg, Type parm) { + arg = parm + or + // float will be promoted to double, and so it should correspond + // to the prototype + arg instanceof FloatType and parm instanceof DoubleType + or + // integral types are promoted "up to" (unsigned) int, but not long long. + arg instanceof IntegralType and + parm instanceof IntegralType and + arg.getSize() <= sizeofInt() and + parm.getSize() <= sizeofInt() + or + /* + * // we allow interoperability between long long and pointer + * arg.getSize() = parm.getSize() and + * ( + * (arg instanceof IntegralType and parm instanceof PointerType) + * or + * (arg instanceof PointerType and parm instanceof IntegralType) + * ) + * or + */ + + // pointers to compatible types + pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), + parm.(PointerType).getBaseType().getUnspecifiedType()) + or + pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), + parm.(ArrayType).getBaseType().getUnspecifiedType()) + or + pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(), + parm.(PointerType).getBaseType().getUnspecifiedType()) + or + pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(), + parm.(ArrayType).getBaseType().getUnspecifiedType()) +} + +// This predicate doesn't necessarily have to exist, but if it does exist +// then it must be inline to make sure we don't enumerate all pairs of +// compatible types. +// Its body could also just be hand-inlined where it's used. +pragma[inline] +predicate argMayBeUsed(Expr arg, Parameter parm) { + argTypeMayBeUsed(arg.getFullyConverted().getType().getUnspecifiedType(), + parm.getType().getUnspecifiedType()) +} + +from FunctionCall fc, Function f, Parameter p +where + f = fc.getTarget() and + p = f.getAParameter() and + not f.isVarargs() and + p.getIndex() < fc.getNumberOfArguments() and + // There must be a zero-parameter declaration + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() = 0 + ) and + // Parameter p and its corresponding call argument must have mismatched types + not argMayBeUsed(fc.getArgument(p.getIndex()), p) +select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(), + fc.getArgument(p.getIndex()) as arg, arg.toString(), arg.getFullyConverted().getType() as type, + type.toString(), p, p.getTypedName() diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.c b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.c new file mode 100644 index 000000000000..93251746fd32 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.c @@ -0,0 +1,9 @@ +void one_argument(); + +void calls() { + one_argument(1); // GOOD: `one_argument` will accept and use the argument + + one_argument(); // BAD: `one_argument` will receive an undefined value +} + +void one_argument(int x); diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qhelp b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qhelp new file mode 100644 index 000000000000..20085880b14c --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.qhelp @@ -0,0 +1,35 @@ + + + + + +

    A function is called with fewer arguments than there are parameters of the function.

    + +

    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, function calls generally need to provide the same number of arguments as there are + arguments to the function. (Variadic functions can accept additional arguments.) Providing + fewer arguments than there are parameters is extremely dangerous, as the called function + will nevertheless try to obtain the missing arguments' values, either from the stack + or from machine registers. As a result, the function may behave unpredictably.

    + +

    If the called function modifies a parameter corresponding to a missing argument, it + may alter the state of the program upon its return. An attacker could use this to, + for example, alter the control flow of the program to access forbidden resources.

    + +
    + +

    Call the function with the correct number of arguments.

    + +
    + + + + + +
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql new file mode 100644 index 000000000000..575428a2fbe0 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql @@ -0,0 +1,31 @@ +/** + * @name Call to function with fewer arguments than declared parameters + * @description A function call passed fewer arguments than the number of + * declared parameters of the function. This may indicate + * that the code does not follow the author's intent. It is also a vulnerability, + * since the function is like to operate on undefined data. + * @kind problem + * @problem.severity error + * @precision very-high + * @id cpp/too-few-params + * @tags correctness + * maintainability + * security + */ + +import cpp + +from FunctionCall fc, Function f +where + f = fc.getTarget() and + not f.isVarargs() and + // There must be a zero-parameter declaration (explicit or implicit) + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() = 0 + ) and + // There is an explicit declaration of the function whose parameter count is larger + // than the number of call arguments + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.isImplicit() and fde.getNumberOfParameters() > fc.getNumberOfArguments() + ) +select fc, "This call has fewer arguments than required by $@.", f, f.toString() diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.c b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.c new file mode 100644 index 000000000000..fa35f028706d --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.c @@ -0,0 +1,10 @@ +void one_argument(); + +void calls() { + + one_argument(1); // GOOD: `one_argument` will accept and use the argument + + one_argument(1, 2); // BAD: `one_argument` will use the first argument but ignore the second +} + +void one_argument(int x); diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qhelp b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qhelp new file mode 100644 index 000000000000..43200aa0ae91 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.qhelp @@ -0,0 +1,30 @@ + + + + + +

    A function is called with more arguments than there are parameters of the function.

    + +

    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, function calls generally need to provide the same number of arguments as there are + arguments to the function. (Variadic functions can accept additional arguments.) Providing + more arguments than there are parameters incurs an unneeded computational overhead, both + in terms of time and of additional stack space.

    + +
    + +

    Call the function with the correct number of arguments.

    + +
    + + + + + +
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql new file mode 100644 index 000000000000..39684fe3acc5 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql @@ -0,0 +1,29 @@ +/** + * @name Call to function with extraneous parameters + * @description A function call to a function passed more arguments than there are + * declared parameters of the function. This may indicate + * that the code does not follow the author's intent. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id cpp/futile-params + * @tags correctness + * maintainability + */ + +import cpp + +from FunctionCall fc, Function f +where + f = fc.getTarget() and + not f.isVarargs() and + // There must be a zero-parameter declaration (explicit or implicit) + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() = 0 + ) and + // There must not exist a declaration with the number of parameters + // at least as large as the number of call arguments + not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + fde.getNumberOfParameters() >= fc.getNumberOfArguments() + ) +select fc, "This call has more arguments than required by $@.", f, f.toString() diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected new file mode 100644 index 000000000000..508d80b7ed3c --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -0,0 +1,11 @@ +| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | +| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | +| test.c:32:3:32:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:32:31:32:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:46:38:46:38 | x | int x | +| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:49:6:49:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:29:36:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:49:36:49:36 | x | int x | +| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:49:6:49:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:37:36:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | double | double | test.c:49:50:49:50 | z | int z | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:61:43:61:43 | y | void * y | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:61:6:61:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:61:6:61:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:61:43:61:43 | y | void * y | +| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | +| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:62:6:62:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qlref new file mode 100644 index 000000000000..e61361d6bfee --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.qlref @@ -0,0 +1 @@ +Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected new file mode 100644 index 000000000000..6b56644df7ca --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -0,0 +1,4 @@ +| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | +| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:28:3:28:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:56:10:56:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:59:5:59:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.qlref new file mode 100644 index 000000000000..710092c54d85 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.qlref @@ -0,0 +1 @@ +Likely Bugs/Underspecified Functions/TooFewArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected new file mode 100644 index 000000000000..89ae7d04771e --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -0,0 +1,5 @@ +| test.c:16:3:16:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | +| test.c:21:3:21:12 | call to undeclared | This call has more arguments than required by $@. | test.c:20:3:20:3 | undeclared | undeclared | +| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:23:3:23:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:44:6:44:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:33:3:33:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.qlref new file mode 100644 index 000000000000..ca44af39c2bf --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.qlref @@ -0,0 +1 @@ +Likely Bugs/Underspecified Functions/TooManyArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c new file mode 100644 index 000000000000..9763d3936afe --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -0,0 +1,63 @@ +void declared_empty(); +void declared_void(void); +void declared_with(int); +void declared_empty_defined_with(); +void declared_with_pointers(); +void declared_with_array(); + +struct _s { int a, b; } s; + +int ca[4] = { 1, 2, 3, 4 }; + +void *pv; + +void test() { + declared_empty(); // GOOD + declared_empty(1); // BAD + declared_void(); // GOOD + declared_with(1); // GOOD + + undeclared(); // GOOD + undeclared(1); // BAD + + not_yet_declared1(1); // BAD + not_yet_declared2(1); // GOOD + not_yet_declared2(ca); // BAD + not_yet_declared2(); // BAD + + declared_empty_defined_with(); // BAD + declared_empty_defined_with(1); // GOOD + + int x; + declared_empty_defined_with(&x); // BAD + declared_empty_defined_with(3, &x); // BAD + + not_declared_defined_with(-1, 0, 2U); // GOOD + not_declared_defined_with(4LL, 0, 2.5e9f); // BAD + + declared_with_pointers(pv, ca); // GOOD + declared_with_pointers(3.5e15, 0); // BAD + declared_with_array("Hello"); // GOOD + declared_with_array(&x); // BAD +} + +void not_yet_declared1(); +void not_yet_declared2(int); +void declared_empty_defined_with(int x) { + // do nothing +} +void not_declared_defined_with(int x, int y, int z) { + return; +} + +int dereference(); + +int caller(void) { + return dereference(); // BAD +} + +int dereference(int *x) { return *x; } + +void declared_with_pointers(int *x, void *y); +void declared_with_array(char a [6]); + diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp new file mode 100644 index 000000000000..855fdaea3fd3 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp @@ -0,0 +1,8 @@ +void cpp_varargs(...); +void bar(); + +void test() { + cpp_varargs(); // GOOD + cpp_varargs(1); // GOOD + __builtin_constant_p("something"); // GOOD: builtin +} \ No newline at end of file From bd139829ea912c9736b9173f6a515176524657bb Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 1 Apr 2019 18:44:49 -0700 Subject: [PATCH 11/27] [CPP-340] Delete old 'UnspecifiedFunctions' folders --- .../MistypedFunctionArguments.c | 7 -- .../MistypedFunctionArguments.qhelp | 29 ------- .../MistypedFunctionArguments.ql | 82 ------------------- .../UnderspecifiedFunctions/TooFewArguments.c | 9 -- .../TooFewArguments.qhelp | 35 -------- .../TooFewArguments.ql | 31 ------- .../TooManyArguments.c | 10 --- .../TooManyArguments.qhelp | 30 ------- .../TooManyArguments.ql | 29 ------- .../MistypedFunctionArguments.expected | 7 -- .../MistypedFunctionArguments.qlref | 1 - .../TooFewArguments.expected | 4 - .../TooFewArguments.qlref | 1 - .../TooManyArguments.expected | 5 -- .../TooManyArguments.qlref | 1 - .../UnderspecifiedFunctions/test.c | 63 -------------- .../UnderspecifiedFunctions/test.cpp | 8 -- 17 files changed, 352 deletions(-) delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp delete mode 100644 cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.cpp diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c deleted file mode 100644 index fa3235a6e3fe..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.c +++ /dev/null @@ -1,7 +0,0 @@ -void three_arguments(int x, int y, int z); - -void calls() { - int three = 3; - three_arguments(1, 2, three); // GOOD - three_arguments(1, 2, &three); // BAD -} diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp deleted file mode 100644 index 6dd3f0eff48d..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qhelp +++ /dev/null @@ -1,29 +0,0 @@ - - - - - -

    A function is called with at least one argument whose type is incompatible with the type of - the corresponding parameter of the function being called. This may cause the called function - to behave unpredictably.

    - -

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

    - -
    - -

    Call the function with the proper argument types. In some cases, it may - suffice to provide an explicit cast of an argument to the desired (parameter) type.

    - -
    - - - - - -
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • -
    -
    diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql deleted file mode 100644 index 17f60ccba976..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @name Call to a function with one or more incompatible arguments - * @description A call to a function with at least one argument whose type does - * not match the type of the corresponding function parameter. This may indicate - * that the author is not familiar with the function being called. Passing mistyped - * arguments on a stack may lead to unpredictable function behavior. - * @kind problem - * @problem.severity warning - * @precision very-high - * @id cpp/mistyped-function-arguments - * @tags correctness - * maintainability - */ - -import cpp - -pragma[inline] -predicate argTypeMayBeImplicitlyConverted(Type arg, Type parm) { - arg = parm - or - // integral and floating-point types are implicitly convertible in C - arg instanceof ArithmeticType and parm instanceof ArithmeticType - or - // integral values may be used to initialize pointers (but NOT array addresses) - arg instanceof IntegralType and parm instanceof PointerType - or - // pointers-to-void may be used for arbitrary pointers - arg instanceof VoidPointerType and parm instanceof PointerType - or - arg instanceof PointerType and parm instanceof VoidPointerType - or - arg instanceof ArrayType and parm instanceof VoidPointerType - or - arg instanceof VoidPointerType and parm instanceof ArrayType - or - // pointers to same types - arg.(PointerType).getBaseType().getUnspecifiedType() = parm - .(PointerType) - .getBaseType() - .getUnspecifiedType() - or - arg.(ArrayType).getBaseType().getUnspecifiedType() = parm - .(PointerType) - .getBaseType() - .getUnspecifiedType() - or - arg.(PointerType).getBaseType().getUnspecifiedType() = parm - .(ArrayType) - .getBaseType() - .getUnspecifiedType() - or - arg.(ArrayType).getBaseType().getUnspecifiedType() = parm - .(ArrayType) - .getBaseType() - .getUnspecifiedType() -} - -// This predicate doesn't necessarily have to exist, but if it does exist -// then it must be inline to make sure we don't enumerate all pairs of -// compatible types. -// Its body could also just be hand-inlined where it's used. -pragma[inline] -predicate argMayBeImplicitlyConverted(Expr arg, Parameter parm) { - argTypeMayBeImplicitlyConverted(arg.getFullyConverted().getType().getUnspecifiedType(), - parm.getType().getUnspecifiedType()) -} - -from FunctionCall fc, Function f, Parameter p -where - f = fc.getTarget() and - p = f.getAParameter() and - not f.isVarargs() and - p.getIndex() < fc.getNumberOfArguments() and - // There must be a zero-parameter declaration - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - fde.getNumberOfParameters() = 0 - ) and - // Parameter p and its corresponding call argument must have mismatched types - not argMayBeImplicitlyConverted(fc.getArgument(p.getIndex()), p) -select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(), - fc.getArgument(p.getIndex()) as arg, arg.toString(), arg.getFullyConverted().getType() as type, - type.toString(), p, p.getTypedName() diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c deleted file mode 100644 index 93251746fd32..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.c +++ /dev/null @@ -1,9 +0,0 @@ -void one_argument(); - -void calls() { - one_argument(1); // GOOD: `one_argument` will accept and use the argument - - one_argument(); // BAD: `one_argument` will receive an undefined value -} - -void one_argument(int x); diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp deleted file mode 100644 index 20085880b14c..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qhelp +++ /dev/null @@ -1,35 +0,0 @@ - - - - - -

    A function is called with fewer arguments than there are parameters of the function.

    - -

    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, function calls generally need to provide the same number of arguments as there are - arguments to the function. (Variadic functions can accept additional arguments.) Providing - fewer arguments than there are parameters is extremely dangerous, as the called function - will nevertheless try to obtain the missing arguments' values, either from the stack - or from machine registers. As a result, the function may behave unpredictably.

    - -

    If the called function modifies a parameter corresponding to a missing argument, it - may alter the state of the program upon its return. An attacker could use this to, - for example, alter the control flow of the program to access forbidden resources.

    - -
    - -

    Call the function with the correct number of arguments.

    - -
    - - - - - -
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • -
    -
    diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql deleted file mode 100644 index 8d031eed0da0..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @name Call to function with fewer arguments than declared parameters - * @description A function call passed fewer arguments than the number of - * declared parameters of the function. This may indicate - * that the code does not follow the author's intent. It is also a vulnerability, - * since the function is like to operate on undefined data. - * @kind problem - * @problem.severity error - * @precision very-high - * @id cpp/futile-params - * @tags correctness - * maintainability - * security - */ - -import cpp - -from FunctionCall fc, Function f -where - f = fc.getTarget() and - not f.isVarargs() and - // There must be a zero-parameter declaration (explicit or implicit) - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - fde.getNumberOfParameters() = 0 - ) and - // There is an explicit declaration of the function whose parameter count is larger - // than the number of call arguments - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.isImplicit() and fde.getNumberOfParameters() > fc.getNumberOfArguments() - ) -select fc, "This call has fewer arguments than required by $@.", f, f.toString() diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c deleted file mode 100644 index fa35f028706d..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.c +++ /dev/null @@ -1,10 +0,0 @@ -void one_argument(); - -void calls() { - - one_argument(1); // GOOD: `one_argument` will accept and use the argument - - one_argument(1, 2); // BAD: `one_argument` will use the first argument but ignore the second -} - -void one_argument(int x); diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp deleted file mode 100644 index 43200aa0ae91..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qhelp +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -

    A function is called with more arguments than there are parameters of the function.

    - -

    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, function calls generally need to provide the same number of arguments as there are - arguments to the function. (Variadic functions can accept additional arguments.) Providing - more arguments than there are parameters incurs an unneeded computational overhead, both - in terms of time and of additional stack space.

    - -
    - -

    Call the function with the correct number of arguments.

    - -
    - - - - - -
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • -
    -
    diff --git a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql deleted file mode 100644 index 39684fe3acc5..000000000000 --- a/cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @name Call to function with extraneous parameters - * @description A function call to a function passed more arguments than there are - * declared parameters of the function. This may indicate - * that the code does not follow the author's intent. - * @kind problem - * @problem.severity warning - * @precision very-high - * @id cpp/futile-params - * @tags correctness - * maintainability - */ - -import cpp - -from FunctionCall fc, Function f -where - f = fc.getTarget() and - not f.isVarargs() and - // There must be a zero-parameter declaration (explicit or implicit) - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - fde.getNumberOfParameters() = 0 - ) and - // There must not exist a declaration with the number of parameters - // at least as large as the number of call arguments - not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - fde.getNumberOfParameters() >= fc.getNumberOfArguments() - ) -select fc, "This call has more arguments than required by $@.", f, f.toString() diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected deleted file mode 100644 index a8ce8fe0506c..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.expected +++ /dev/null @@ -1,7 +0,0 @@ -| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | -| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | -| test.c:32:3:32:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:32:31:32:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:46:38:46:38 | x | int x | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:61:6:61:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | -| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | -| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:62:6:62:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref deleted file mode 100644 index e2e24d78bc38..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.qlref +++ /dev/null @@ -1 +0,0 @@ -Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected deleted file mode 100644 index 6b56644df7ca..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.expected +++ /dev/null @@ -1,4 +0,0 @@ -| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:28:3:28:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:56:10:56:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:59:5:59:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref deleted file mode 100644 index cfc3bd165a23..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooFewArguments.qlref +++ /dev/null @@ -1 +0,0 @@ -Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected deleted file mode 100644 index 89ae7d04771e..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.expected +++ /dev/null @@ -1,5 +0,0 @@ -| test.c:16:3:16:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | -| test.c:21:3:21:12 | call to undeclared | This call has more arguments than required by $@. | test.c:20:3:20:3 | undeclared | undeclared | -| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:23:3:23:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:44:6:44:22 | not_yet_declared1 | not_yet_declared1 | -| test.c:33:3:33:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref deleted file mode 100644 index 9438d5ad537b..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/TooManyArguments.qlref +++ /dev/null @@ -1 +0,0 @@ -Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c deleted file mode 100644 index 16f10479f66c..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.c +++ /dev/null @@ -1,63 +0,0 @@ -void declared_empty(); -void declared_void(void); -void declared_with(int); -void declared_empty_defined_with(); -void declared_with_pointers(); -void declared_with_array(); - -struct _s { int a, b; } s; - -int ca[4] = { 1, 2, 3, 4 }; - -void *pv; - -void test() { - declared_empty(); // GOOD - declared_empty(1); // BAD - declared_void(); // GOOD - declared_with(1); // GOOD - - undeclared(); // GOOD - undeclared(1); // BAD - - not_yet_declared1(1); // BAD - not_yet_declared2(1); // GOOD - not_yet_declared2(ca); // BAD - not_yet_declared2(); // BAD - - declared_empty_defined_with(); // BAD - declared_empty_defined_with(1); // GOOD - - int x; - declared_empty_defined_with(&x); // BAD - declared_empty_defined_with(3.0f, &x); // BAD - - not_declared_defined_with(1.0, 0, 2U); // GOOD - not_declared_defined_with(4LL, 0, 2.5e9); // GOOD - - declared_with_pointers(pv, ca); // GOOD - declared_with_pointers(3.5e15, 0); // BAD - declared_with_array("Hello"); // GOOD - declared_with_array(&x); // BAD -} - -void not_yet_declared1(); -void not_yet_declared2(int); -void declared_empty_defined_with(int x) { - // do nothing -} -void not_declared_defined_with(int x, int y, int z) { - return; -} - -int dereference(); - -int caller(void) { - return dereference(); // BAD -} - -int dereference(int *x) { return *x; } - -void declared_with_pointers(int *x, void *y); -void declared_with_array(char a [6]); - diff --git a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.cpp deleted file mode 100644 index 855fdaea3fd3..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/UnderspecifiedFunctions/test.cpp +++ /dev/null @@ -1,8 +0,0 @@ -void cpp_varargs(...); -void bar(); - -void test() { - cpp_varargs(); // GOOD - cpp_varargs(1); // GOOD - __builtin_constant_p("something"); // GOOD: builtin -} \ No newline at end of file From 96b8bdfeb57f6ffd2a1a847017e4b64382703d5a Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 1 Apr 2019 19:15:27 -0700 Subject: [PATCH 12/27] [CPP-340] Add new queries to analysis-cpp.md; correct id of TooFewArguments.ql --- change-notes/1.21/analysis-cpp.md | 3 +++ .../Likely Bugs/Underspecified Functions/TooFewArguments.ql | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/change-notes/1.21/analysis-cpp.md b/change-notes/1.21/analysis-cpp.md index 733a8eb9531f..f0f2d5a83394 100644 --- a/change-notes/1.21/analysis-cpp.md +++ b/change-notes/1.21/analysis-cpp.md @@ -6,6 +6,8 @@ | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| +| `()`-declared function called with too few arguments (`cpp/too-few-arguments`) | Correctness | Find all cases where the number of arguments is less than the number of parameters of the function, provided the function is also properly declared/defined elsewhere. | +| `()`-declared function called with mismatched arguments (`cpp/mismatched-function-arguments`) | Correctness | Find all cases where the types of arguments do not match the types of parameters of the function, provided the function is also properly declared/defined elsewhere. | ## Changes to existing queries @@ -18,5 +20,6 @@ | Resource not released in destructor (`cpp/resource-not-released-in-destructor`) | Fewer false positive results | Resource allocation and deallocation functions are now determined more accurately. | | Comparison result is always the same | Fewer false positive results | The range analysis library is now more conservative about floating point values being possibly `NaN` | | Wrong type of arguments to formatting function (`cpp/wrong-type-format-argument`) | More correct results and fewer false positive results | This query now more accurately identifies wide and non-wide string/character format arguments on different platforms. Platform detection has also been made more accurate for the purposes of this query. | +| `()`-declared function called with too many arguments (`cpp/futile-params`) | Improved coverage | Query has been generalized to find all cases where the number of arguments exceedes the number of parameters of the function, provided the function is also properly declared/defined elsewhere. | ## Changes to QL libraries diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql index 575428a2fbe0..2a7b9a0e7ab0 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql @@ -7,7 +7,7 @@ * @kind problem * @problem.severity error * @precision very-high - * @id cpp/too-few-params + * @id cpp/too-few-arguments * @tags correctness * maintainability * security From e4ce8347bc14cd53aabe162f4402cd2d19306ffd Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Wed, 3 Apr 2019 16:19:37 -0700 Subject: [PATCH 13/27] [CPP-340] Simplify MistypedFunctionArguments.ql and reduce its precision from very-high to high. --- .../MistypedFunctionArguments.ql | 32 ++----------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index 2ee6826843ec..f8870434ef77 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -6,7 +6,7 @@ * arguments on a stack may lead to unpredictable function behavior. * @kind problem * @problem.severity warning - * @precision very-high + * @precision high * @id cpp/mistyped-function-arguments * @tags correctness * maintainability @@ -14,9 +14,6 @@ import cpp -pragma[inline] -int sizeofInt() { result = any(IntType pt).getSize() } - pragma[inline] predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { arg = parm @@ -47,39 +44,16 @@ pragma[inline] predicate argTypeMayBeUsed(Type arg, Type parm) { arg = parm or - // float will be promoted to double, and so it should correspond - // to the prototype - arg instanceof FloatType and parm instanceof DoubleType - or - // integral types are promoted "up to" (unsigned) int, but not long long. + // we treat signed and unsigned versions of integer types as compatible. arg instanceof IntegralType and - parm instanceof IntegralType and - arg.getSize() <= sizeofInt() and - parm.getSize() <= sizeofInt() + parm instanceof IntegralType or - /* - * // we allow interoperability between long long and pointer - * arg.getSize() = parm.getSize() and - * ( - * (arg instanceof IntegralType and parm instanceof PointerType) - * or - * (arg instanceof PointerType and parm instanceof IntegralType) - * ) - * or - */ - // pointers to compatible types pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), parm.(PointerType).getBaseType().getUnspecifiedType()) or pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), parm.(ArrayType).getBaseType().getUnspecifiedType()) - or - pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(), - parm.(PointerType).getBaseType().getUnspecifiedType()) - or - pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(), - parm.(ArrayType).getBaseType().getUnspecifiedType()) } // This predicate doesn't necessarily have to exist, but if it does exist From ef54b012e0f80d1f9cbf89df069d89c61dda5578 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Fri, 5 Apr 2019 15:43:38 -0700 Subject: [PATCH 14/27] [CPP-340] Fixed .expected file to match new query. --- .../Underspecified Functions/MistypedFunctionArguments.expected | 1 - 1 file changed, 1 deletion(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index 508d80b7ed3c..a9661b060773 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,7 +1,6 @@ | test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | | test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | | test.c:32:3:32:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:32:31:32:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:46:38:46:38 | x | int x | -| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:49:6:49:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:29:36:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:49:36:49:36 | x | int x | | test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:49:6:49:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:37:36:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | double | double | test.c:49:50:49:50 | z | int z | | test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | | test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:61:43:61:43 | y | void * y | From dc7497835e20d12c368d5bb3b6c08b4cc57d7607 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Wed, 10 Apr 2019 09:55:37 -0700 Subject: [PATCH 15/27] [CPP-340] Make the query more strict (again). --- .../MistypedFunctionArguments.ql | 51 +++++++++++-------- .../MistypedFunctionArguments.expected | 26 ++++++---- .../TooFewArguments.expected | 6 +-- .../TooManyArguments.expected | 4 +- .../Underspecified Functions/test.c | 21 ++++++++ 5 files changed, 72 insertions(+), 36 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index f8870434ef77..972b7f7c71d7 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -23,15 +23,11 @@ predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { parm instanceof ArithmeticType and arg.getSize() = parm.getSize() and ( - ( - arg instanceof IntegralType and - parm instanceof IntegralType - ) + arg instanceof IntegralType and + parm instanceof IntegralType or - ( - arg instanceof FloatingPointType and - parm instanceof FloatingPointType - ) + arg instanceof FloatingPointType and + parm instanceof FloatingPointType ) or // pointers to void are ok @@ -44,16 +40,23 @@ pragma[inline] predicate argTypeMayBeUsed(Type arg, Type parm) { arg = parm or - // we treat signed and unsigned versions of integer types as compatible. + // float arguments will have been promoted to double, + // and the parameter must match this + arg instanceof DoubleType and + parm instanceof DoubleType + or + // integral arguments are promoted to int (but not long long). arg instanceof IntegralType and - parm instanceof IntegralType + arg.getSize() = 4 and + parm instanceof IntegralType and + parm.getSize() = 4 or // pointers to compatible types pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), - parm.(PointerType).getBaseType().getUnspecifiedType()) + parm.(PointerType).getBaseType().getUnderlyingType().getUnspecifiedType()) or pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), - parm.(ArrayType).getBaseType().getUnspecifiedType()) + parm.(ArrayType).getBaseType().getUnderlyingType().getUnspecifiedType()) } // This predicate doesn't necessarily have to exist, but if it does exist @@ -62,8 +65,16 @@ predicate argTypeMayBeUsed(Type arg, Type parm) { // Its body could also just be hand-inlined where it's used. pragma[inline] predicate argMayBeUsed(Expr arg, Parameter parm) { - argTypeMayBeUsed(arg.getFullyConverted().getType().getUnspecifiedType(), - parm.getType().getUnspecifiedType()) + argTypeMayBeUsed(arg.getFullyConverted().getType().getUnderlyingType().getUnspecifiedType(), + parm.getType().getUnderlyingType().getUnspecifiedType()) +} + +// True if function was ()-declared, but not (void)-declared +pragma[inline] +predicate hasZeroParamDecl(Function f) { + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 + ) } from FunctionCall fc, Function f, Parameter p @@ -72,12 +83,10 @@ where p = f.getAParameter() and not f.isVarargs() and p.getIndex() < fc.getNumberOfArguments() and - // There must be a zero-parameter declaration - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - fde.getNumberOfParameters() = 0 - ) and + hasZeroParamDecl(f) and // Parameter p and its corresponding call argument must have mismatched types not argMayBeUsed(fc.getArgument(p.getIndex()), p) -select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(), - fc.getArgument(p.getIndex()) as arg, arg.toString(), arg.getFullyConverted().getType() as type, - type.toString(), p, p.getTypedName() +select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@", f, f.toString(), + fc.getArgument(p.getIndex()) as arg, arg.toString(), + arg.getFullyConverted().getType().getUnderlyingType().getUnspecifiedType() as atype, + atype.toString(), p, p.getTypedName() diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index a9661b060773..897237c6561a 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,10 +1,16 @@ -| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | -| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:45:24:45:26 | p#0 | int p#0 | -| test.c:32:3:32:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:32:31:32:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:46:38:46:38 | x | int x | -| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:49:6:49:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:37:36:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | double | double | test.c:49:50:49:50 | z | int z | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:61:43:61:43 | y | void * y | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:61:6:61:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:61:34:61:34 | x | int * x | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:61:6:61:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:61:43:61:43 | y | void * y | -| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | -| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:62:6:62:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:62:31:62:31 | a | char[6] a | +| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:54:24:54:26 | p#0 | int p#0 | +| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:54:6:54:22 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:54:24:54:26 | p#0 | int p#0 | +| test.c:32:3:32:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:55:6:55:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:32:31:32:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:55:38:55:38 | x | int x | +| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:58:6:58:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:29:36:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:58:36:58:36 | x | int x | +| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:58:6:58:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:37:36:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | double | double | test.c:58:50:58:50 | z | int z | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:70:34:70:34 | x | int * x | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:70:43:70:43 | y | void * y | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:70:6:70:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:70:34:70:34 | x | int * x | +| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:70:6:70:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:70:43:70:43 | y | void * y | +| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:71:31:71:31 | a | char[6] a | +| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:71:6:71:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:71:31:71:31 | a | char[6] a | +| test.c:43:3:43:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:73:7:73:24 | defined_with_float | defined_with_float | test.c:43:22:43:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:73:32:73:32 | f | float f | +| test.c:44:3:44:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:73:7:73:24 | defined_with_float | defined_with_float | test.c:44:22:44:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:73:32:73:32 | f | float f | +| test.c:47:3:47:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:77:8:77:26 | defined_with_double | defined_with_double | test.c:47:23:47:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:77:35:77:35 | d | double d | +| test.c:49:3:49:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:81:11:81:32 | defined_with_long_long | defined_with_long_long | test.c:49:26:49:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:81:44:81:45 | ll | long long ll | +| test.c:50:3:50:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:81:11:81:32 | defined_with_long_long | defined_with_long_long | test.c:50:26:50:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:81:44:81:45 | ll | long long ll | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected index 6b56644df7ca..0a7da4a539cd 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -1,4 +1,4 @@ | test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:45:6:45:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:28:3:28:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:56:10:56:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:59:5:59:15 | dereference | dereference | +| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:54:6:54:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:28:3:28:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:55:6:55:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:65:10:65:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:68:5:68:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected index 89ae7d04771e..4c10cc7488c0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -1,5 +1,5 @@ | test.c:16:3:16:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | | test.c:21:3:21:12 | call to undeclared | This call has more arguments than required by $@. | test.c:20:3:20:3 | undeclared | undeclared | | test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:23:3:23:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:44:6:44:22 | not_yet_declared1 | not_yet_declared1 | -| test.c:33:3:33:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:46:6:46:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:53:6:53:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:33:3:33:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:55:6:55:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c index 9763d3936afe..beb5dba69c81 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -39,6 +39,15 @@ void test() { declared_with_pointers(3.5e15, 0); // BAD declared_with_array("Hello"); // GOOD declared_with_array(&x); // BAD + + defined_with_float(2.f); // BAD + defined_with_float(2.0); // BAD + + defined_with_double(2.f); // GOOD + defined_with_double('c'); // BAD + + defined_with_long_long('c'); // BAD + defined_with_long_long(3); // BAD } void not_yet_declared1(); @@ -61,3 +70,15 @@ int dereference(int *x) { return *x; } void declared_with_pointers(int *x, void *y); void declared_with_array(char a [6]); +float defined_with_float(float f) { + return f; +} + +double defined_with_double(double d) { + return d; +} + +long long defined_with_long_long(long long ll) { + return ll; +} + \ No newline at end of file From d76138f189600f397aeb869ee6908474a9604729 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Wed, 10 Apr 2019 10:51:22 -0700 Subject: [PATCH 16/27] [CPP-340] Remove use of getUnderlyingType() predicate as it does not appear necessary. Correct comment to refer to arguments rather than parameters. --- .../MistypedFunctionArguments.ql | 10 +++++----- .../Underspecified Functions/TooManyArguments.ql | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index 972b7f7c71d7..9d869feab38a 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -53,10 +53,10 @@ predicate argTypeMayBeUsed(Type arg, Type parm) { or // pointers to compatible types pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), - parm.(PointerType).getBaseType().getUnderlyingType().getUnspecifiedType()) + parm.(PointerType).getBaseType().getUnspecifiedType()) or pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), - parm.(ArrayType).getBaseType().getUnderlyingType().getUnspecifiedType()) + parm.(ArrayType).getBaseType().getUnspecifiedType()) } // This predicate doesn't necessarily have to exist, but if it does exist @@ -65,8 +65,8 @@ predicate argTypeMayBeUsed(Type arg, Type parm) { // Its body could also just be hand-inlined where it's used. pragma[inline] predicate argMayBeUsed(Expr arg, Parameter parm) { - argTypeMayBeUsed(arg.getFullyConverted().getType().getUnderlyingType().getUnspecifiedType(), - parm.getType().getUnderlyingType().getUnspecifiedType()) + argTypeMayBeUsed(arg.getFullyConverted().getType().getUnspecifiedType(), + parm.getType().getUnspecifiedType()) } // True if function was ()-declared, but not (void)-declared @@ -88,5 +88,5 @@ where not argMayBeUsed(fc.getArgument(p.getIndex()), p) select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@", f, f.toString(), fc.getArgument(p.getIndex()) as arg, arg.toString(), - arg.getFullyConverted().getType().getUnderlyingType().getUnspecifiedType() as atype, + arg.getFullyConverted().getType().getUnspecifiedType() as atype, atype.toString(), p, p.getTypedName() diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql index 39684fe3acc5..3ed40c76d3b3 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql @@ -1,5 +1,5 @@ /** - * @name Call to function with extraneous parameters + * @name Call to function with extraneous arguments * @description A function call to a function passed more arguments than there are * declared parameters of the function. This may indicate * that the code does not follow the author's intent. From b58f414ede7ededa71c0890c504bcb080a8cb379 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Fri, 12 Apr 2019 17:25:33 -0700 Subject: [PATCH 17/27] [CPP-340] Add more test case; exclude K&R definitions of functions when looking up ()-declarations; refactor QL code. --- .../MistypedFunctionArguments.ql | 60 +++++++++++-------- .../TooFewArguments.ql | 23 +++++-- .../TooManyArguments.ql | 21 +++++-- .../MistypedFunctionArguments.expected | 36 ++++++----- .../TooFewArguments.expected | 8 +-- .../TooManyArguments.expected | 10 ++-- .../Underspecified Functions/test.c | 12 ++++ .../Underspecified Functions/test.cpp | 3 + 8 files changed, 114 insertions(+), 59 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index 9d869feab38a..557305d26207 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -14,23 +14,26 @@ import cpp -pragma[inline] -predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { - arg = parm - or - // arithmetic types +predicate arithTypesMatch(Type arg, Type parm) { arg instanceof ArithmeticType and parm instanceof ArithmeticType and arg.getSize() = parm.getSize() and ( - arg instanceof IntegralType and - parm instanceof IntegralType + arg instanceof IntegralOrEnumType and + parm instanceof IntegralOrEnumType or arg instanceof FloatingPointType and parm instanceof FloatingPointType ) +} +pragma[inline] +predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { + arg = parm or - // pointers to void are ok + // arithmetic types + arithTypesMatch(arg, parm) + or + // conversion to/from pointers to void is allowed arg instanceof VoidType or parm instanceof VoidType @@ -40,23 +43,22 @@ pragma[inline] predicate argTypeMayBeUsed(Type arg, Type parm) { arg = parm or - // float arguments will have been promoted to double, - // and the parameter must match this - arg instanceof DoubleType and - parm instanceof DoubleType - or - // integral arguments are promoted to int (but not long long). - arg instanceof IntegralType and - arg.getSize() = 4 and - parm instanceof IntegralType and - parm.getSize() = 4 + // arithmetic types + arithTypesMatch(arg, parm) or // pointers to compatible types pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), parm.(PointerType).getBaseType().getUnspecifiedType()) or + pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(), + parm.(PointerType).getBaseType().getUnspecifiedType()) + or + // C11 arrays pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), parm.(ArrayType).getBaseType().getUnspecifiedType()) + or + pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(), + parm.(ArrayType).getBaseType().getUnspecifiedType()) } // This predicate doesn't necessarily have to exist, but if it does exist @@ -69,11 +71,17 @@ predicate argMayBeUsed(Expr arg, Parameter parm) { parm.getType().getUnspecifiedType()) } -// True if function was ()-declared, but not (void)-declared -pragma[inline] +// True if function was ()-declared, but not (void)-declared or K&R-defined predicate hasZeroParamDecl(Function f) { exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 + not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition() + ) +} + +// True if this file (or header) was compiled as a C file +predicate isCompiledAsC(Function f) { + exists(File file | file.compiledAsC() | + file = f.getFile() or file.getAnIncludedFile+() = f.getFile() ) } @@ -81,12 +89,14 @@ from FunctionCall fc, Function f, Parameter p where f = fc.getTarget() and p = f.getAParameter() and + hasZeroParamDecl(f) and + isCompiledAsC(f) and not f.isVarargs() and + not f instanceof BuiltInFunction and p.getIndex() < fc.getNumberOfArguments() and - hasZeroParamDecl(f) and // Parameter p and its corresponding call argument must have mismatched types not argMayBeUsed(fc.getArgument(p.getIndex()), p) -select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@", f, f.toString(), +select fc, "Calling $@: argument $@ of type $@ is incompatible with parameter $@.", f, f.toString(), fc.getArgument(p.getIndex()) as arg, arg.toString(), - arg.getFullyConverted().getType().getUnspecifiedType() as atype, - atype.toString(), p, p.getTypedName() + arg.getExplicitlyConverted().getType().getUnspecifiedType() as atype, atype.toString(), p, + p.getTypedName() diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql index 2a7b9a0e7ab0..c060b0adf9d9 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql @@ -15,17 +15,30 @@ import cpp +// True if function was ()-declared, but not (void)-declared or K&R-defined +predicate hasZeroParamDecl(Function f) { + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition() + ) +} + +// True if this file (or header) was compiled as a C file +predicate isCompiledAsC(Function f) { + exists(File file | file.compiledAsC() | + file = f.getFile() or file.getAnIncludedFile+() = f.getFile() + ) +} + from FunctionCall fc, Function f where f = fc.getTarget() and not f.isVarargs() and - // There must be a zero-parameter declaration (explicit or implicit) - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - fde.getNumberOfParameters() = 0 - ) and + not f instanceof BuiltInFunction and + hasZeroParamDecl(f) and + isCompiledAsC(f) and // There is an explicit declaration of the function whose parameter count is larger // than the number of call arguments exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.isImplicit() and fde.getNumberOfParameters() > fc.getNumberOfArguments() + fde.getNumberOfParameters() > fc.getNumberOfArguments() ) select fc, "This call has fewer arguments than required by $@.", f, f.toString() diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql index 3ed40c76d3b3..ac6313243611 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql @@ -13,14 +13,27 @@ import cpp +// True if function was ()-declared, but not (void)-declared or K&R-defined +predicate hasZeroParamDecl(Function f) { + exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition() + ) +} + +// True if this file (or header) was compiled as a C file +predicate isCompiledAsC(Function f) { + exists(File file | file.compiledAsC() | + file = f.getFile() or file.getAnIncludedFile+() = f.getFile() + ) +} + from FunctionCall fc, Function f where f = fc.getTarget() and not f.isVarargs() and - // There must be a zero-parameter declaration (explicit or implicit) - exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - fde.getNumberOfParameters() = 0 - ) and + not f instanceof BuiltInFunction and + hasZeroParamDecl(f) and + isCompiledAsC(f) and // There must not exist a declaration with the number of parameters // at least as large as the number of call arguments not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index 897237c6561a..bcbb2f2115b2 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,16 +1,20 @@ -| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:54:24:54:26 | p#0 | int p#0 | -| test.c:25:3:25:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:54:6:54:22 | not_yet_declared2 | not_yet_declared2 | test.c:25:21:25:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:54:24:54:26 | p#0 | int p#0 | -| test.c:32:3:32:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:55:6:55:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:32:31:32:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:55:38:55:38 | x | int x | -| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:58:6:58:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:29:36:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:58:36:58:36 | x | int x | -| test.c:36:3:36:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:58:6:58:30 | not_declared_defined_with | not_declared_defined_with | test.c:36:37:36:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | double | double | test.c:58:50:58:50 | z | int z | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:70:34:70:34 | x | int * x | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:70:43:70:43 | y | void * y | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:70:6:70:27 | declared_with_pointers | declared_with_pointers | test.c:39:26:39:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:70:34:70:34 | x | int * x | -| test.c:39:3:39:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:70:6:70:27 | declared_with_pointers | declared_with_pointers | test.c:39:34:39:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:70:43:70:43 | y | void * y | -| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:71:31:71:31 | a | char[6] a | -| test.c:41:3:41:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:71:6:71:24 | declared_with_array | declared_with_array | test.c:41:23:41:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:71:31:71:31 | a | char[6] a | -| test.c:43:3:43:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:73:7:73:24 | defined_with_float | defined_with_float | test.c:43:22:43:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:73:32:73:32 | f | float f | -| test.c:44:3:44:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:73:7:73:24 | defined_with_float | defined_with_float | test.c:44:22:44:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:73:32:73:32 | f | float f | -| test.c:47:3:47:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:77:8:77:26 | defined_with_double | defined_with_double | test.c:47:23:47:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:77:35:77:35 | d | double d | -| test.c:49:3:49:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:81:11:81:32 | defined_with_long_long | defined_with_long_long | test.c:49:26:49:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:81:44:81:45 | ll | long long ll | -| test.c:50:3:50:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@ | test.c:81:11:81:32 | defined_with_long_long | defined_with_long_long | test.c:50:26:50:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:81:44:81:45 | ll | long long ll | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:66:24:66:26 | p#0 | int p#0 | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:66:24:66:26 | p#0 | int p#0 | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:66:6:66:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:66:24:66:26 | p#0 | int p#0 | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:66:6:66:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:66:24:66:26 | p#0 | int p#0 | +| test.c:39:3:39:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:67:6:67:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:39:31:39:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:67:38:67:38 | x | int x | +| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:70:6:70:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:29:43:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:70:36:70:36 | x | int x | +| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:70:6:70:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:37:43:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:70:50:70:50 | z | int z | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:82:34:82:34 | x | int * x | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:82:43:82:43 | y | void * y | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:82:6:82:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:82:34:82:34 | x | int * x | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:82:6:82:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:82:43:82:43 | y | void * y | +| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:83:31:83:31 | a | char[6] a | +| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:83:6:83:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:83:31:83:31 | a | char[6] a | +| test.c:50:3:50:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:85:7:85:24 | defined_with_float | defined_with_float | test.c:50:22:50:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:85:32:85:32 | f | float f | +| test.c:51:3:51:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:85:7:85:24 | defined_with_float | defined_with_float | test.c:51:22:51:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:85:32:85:32 | f | float f | +| test.c:54:3:54:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:89:8:89:26 | defined_with_double | defined_with_double | test.c:54:23:54:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:89:35:89:35 | d | double d | +| test.c:56:3:56:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:11:93:32 | defined_with_long_long | defined_with_long_long | test.c:56:26:56:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:93:44:93:45 | ll | long long ll | +| test.c:57:3:57:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:11:93:32 | defined_with_long_long | defined_with_long_long | test.c:57:26:57:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:93:44:93:45 | ll | long long ll | +| test.c:59:3:59:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:89:8:89:26 | defined_with_double | defined_with_double | test.c:59:23:59:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:89:35:89:35 | d | double d | +| test.c:60:3:60:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:11:93:32 | defined_with_long_long | defined_with_long_long | test.c:60:26:60:31 | 2.499999999999999983e+50 | 2.499999999999999983e+50 | file://:0:0:0:0 | double | double | test.c:93:44:93:45 | ll | long long ll | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected index 0a7da4a539cd..1abe1120ba7a 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -1,4 +1,4 @@ -| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:24:3:24:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:26:3:26:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:54:6:54:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:28:3:28:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:55:6:55:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:65:10:65:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:68:5:68:15 | dereference | dereference | +| test.c:33:3:33:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | +| test.c:33:3:33:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:66:6:66:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:35:3:35:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:67:6:67:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:77:10:77:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:80:5:80:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected index 4c10cc7488c0..674928f53ac7 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -1,5 +1,5 @@ -| test.c:16:3:16:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | -| test.c:21:3:21:12 | call to undeclared | This call has more arguments than required by $@. | test.c:20:3:20:3 | undeclared | undeclared | -| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:23:3:23:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:23:3:23:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:53:6:53:22 | not_yet_declared1 | not_yet_declared1 | -| test.c:33:3:33:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:55:6:55:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:23:3:23:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | +| test.c:28:3:28:12 | call to undeclared | This call has more arguments than required by $@. | test.c:27:3:27:3 | undeclared | undeclared | +| test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:30:3:30:3 | not_yet_declared1 | not_yet_declared1 | +| test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:65:6:65:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:40:3:40:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:67:6:67:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c index beb5dba69c81..db5b0c5ec26d 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -5,6 +5,13 @@ void declared_empty_defined_with(); void declared_with_pointers(); void declared_with_array(); +int k_and_r_func(c,d) + char c; + double d; +{ + return c + d; +} + struct _s { int a, b; } s; int ca[4] = { 1, 2, 3, 4 }; @@ -48,6 +55,11 @@ void test() { defined_with_long_long('c'); // BAD defined_with_long_long(3); // BAD + + defined_with_double(2LL); // BAD + defined_with_long_long(2.5e50); // BAD + + k_and_r_func(2.5, &s); // GOOD } void not_yet_declared1(); diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp index 855fdaea3fd3..804cd439f2b0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp @@ -5,4 +5,7 @@ void test() { cpp_varargs(); // GOOD cpp_varargs(1); // GOOD __builtin_constant_p("something"); // GOOD: builtin + + // The following is marked "good" since we are not supposed + // to analyze C++ files. } \ No newline at end of file From 61c91b67aa64b05a3f96e1d3e00e77be382f43b9 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Sun, 14 Apr 2019 11:31:10 -0700 Subject: [PATCH 18/27] [CPP-340] Refactor MistypedFunctionArguments.ql further. --- .../MistypedFunctionArguments.ql | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index 557305d26207..7ec963d7f0f1 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -15,8 +15,8 @@ import cpp predicate arithTypesMatch(Type arg, Type parm) { - arg instanceof ArithmeticType and - parm instanceof ArithmeticType and + arg = parm + or arg.getSize() = parm.getSize() and ( arg instanceof IntegralOrEnumType and @@ -26,10 +26,9 @@ predicate arithTypesMatch(Type arg, Type parm) { parm instanceof FloatingPointType ) } + pragma[inline] predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { - arg = parm - or // arithmetic types arithTypesMatch(arg, parm) or @@ -41,8 +40,6 @@ predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { pragma[inline] predicate argTypeMayBeUsed(Type arg, Type parm) { - arg = parm - or // arithmetic types arithTypesMatch(arg, parm) or From 65130c40abf1c169e2687eaeb451dac162a6ce4f Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Tue, 16 Apr 2019 14:02:34 -0700 Subject: [PATCH 19/27] [CPP-340] Add white list (for false positive suppression) to TooManyArguments.ql --- .../Underspecified Functions/TooManyArguments.ql | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql index ac6313243611..99fca0a5454d 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql @@ -27,13 +27,24 @@ predicate isCompiledAsC(Function f) { ) } +predicate isWhitelisted(Function f) { + f instanceof BuiltInFunction + or + // The following list can be expanded as the need arises + exists(string name | name = f.getName() | + name = "static_assert" or + name = "_Static_assert" or + name = "strptime" + ) +} + from FunctionCall fc, Function f where f = fc.getTarget() and not f.isVarargs() and - not f instanceof BuiltInFunction and hasZeroParamDecl(f) and isCompiledAsC(f) and + not isWhitelisted(f) and // There must not exist a declaration with the number of parameters // at least as large as the number of call arguments not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | From 62b030d27fce8c4d768d62cea819fbe5c9458e1d Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Thu, 18 Apr 2019 17:56:41 -0700 Subject: [PATCH 20/27] [CPP-340] Add a fourth query, ArgumentsToImplicit.ql, to deal strictly with implicitly declared functions. TooManyArguments.ql will now deal with explicitly declared/prototyped functions. --- .../ArgumentsToImplicit.c | 9 ++++ .../ArgumentsToImplicit.qhelp | 29 +++++++++++ .../ArgumentsToImplicit.ql | 49 +++++++++++++++++++ .../TooManyArguments.ql | 6 ++- .../ArgumentsToImplicit.expected | 1 + .../ArgumentsToImplicit.qlref | 1 + .../TooManyArguments.expected | 1 - 7 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp create mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected create mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c new file mode 100644 index 000000000000..77164b334d30 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c @@ -0,0 +1,9 @@ + +void calls() { + + undeclared(); // GOOD + + undeclared(1); // BAD + + undeclared(1, 2); // BAD +} diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp new file mode 100644 index 000000000000..78f12ac6de56 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp @@ -0,0 +1,29 @@ + + + + + +

    An implicitly-declared function is called with arguments.

    + +

    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, an implicitly declared function is assumed to accept no arguments. Providing + these arguments incurs an unneeded computational overhead, both + in terms of time and of additional stack space.

    + +
    + +

    Call the function without any arguments.

    + +
    + + + + + +
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • +
    +
    diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql new file mode 100644 index 000000000000..96bdd36a8e19 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql @@ -0,0 +1,49 @@ +/** + * @name Call with arguments to an implicitly declared function + * @description A function call passed arguments even though the + * function in question is only implicitly declared (and + * hence accepting no arguments). This may indicate + * that the code does not follow the author's intent. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id cpp/arguments-to-implicit + * @tags correctness + * maintainability + */ + +import cpp + +// True if there is no explicit definition of the function +predicate hasNoExplicitDecl(Function f) { + not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | + not fde.isImplicit() + ) +} + +// True if this file (or header) was compiled as a C file +predicate isCompiledAsC(Function f) { + exists(File file | file.compiledAsC() | + file = f.getFile() or file.getAnIncludedFile+() = f.getFile() + ) +} + +predicate isWhitelisted(Function f) { + f instanceof BuiltInFunction + or + // The following list can be expanded as the need arises + exists(string name | name = f.getName() | + name = "static_assert" or + name = "_Static_assert" or + name = "strptime" + ) +} + +from FunctionCall fc, Function f +where + f = fc.getTarget() and + hasNoExplicitDecl(f) and + isCompiledAsC(f) and + not isWhitelisted(f) and + fc.getNumberOfArguments() > 0 +select fc, "This call to an implicitly declared function $@ has arguments.", f, f.toString() diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql index 99fca0a5454d..e866c6f60500 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql @@ -14,9 +14,13 @@ import cpp // True if function was ()-declared, but not (void)-declared or K&R-defined +// or implicitly declared (i.e., lacking a prototype) predicate hasZeroParamDecl(Function f) { exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition() + not fde.isImplicit() and + not fde.hasVoidParamList() and + fde.getNumberOfParameters() = 0 and + not fde.isDefinition() ) } diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected new file mode 100644 index 000000000000..f1cb25249c26 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected @@ -0,0 +1 @@ +| test.c:28:3:28:12 | call to undeclared | This call to an implicitly declared function $@ has arguments. | test.c:27:3:27:3 | undeclared | undeclared | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref new file mode 100644 index 000000000000..66dc368af6f2 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref @@ -0,0 +1 @@ +Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected index 674928f53ac7..7ac6b10070a5 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -1,5 +1,4 @@ | test.c:23:3:23:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | -| test.c:28:3:28:12 | call to undeclared | This call has more arguments than required by $@. | test.c:27:3:27:3 | undeclared | undeclared | | test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:30:3:30:3 | not_yet_declared1 | not_yet_declared1 | | test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:65:6:65:22 | not_yet_declared1 | not_yet_declared1 | | test.c:40:3:40:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:67:6:67:32 | declared_empty_defined_with | declared_empty_defined_with | From 36b2c14f8883150f2ce2695f89ff62effa8e8ead Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Fri, 19 Apr 2019 11:46:54 -0700 Subject: [PATCH 21/27] [CPP-340] Minor formatting tweaks --- .../Underspecified Functions/ArgumentsToImplicit.ql | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql index 96bdd36a8e19..e3ff53c63054 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql @@ -1,7 +1,7 @@ /** * @name Call with arguments to an implicitly declared function * @description A function call passed arguments even though the - * function in question is only implicitly declared (and + * function in question is only implicitly declared (and * hence accepting no arguments). This may indicate * that the code does not follow the author's intent. * @kind problem @@ -16,9 +16,7 @@ import cpp // True if there is no explicit definition of the function predicate hasNoExplicitDecl(Function f) { - not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | - not fde.isImplicit() - ) + not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit()) } // True if this file (or header) was compiled as a C file From ac58bdfc58f20a446a58ee4591e2f3cf05d67839 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Wed, 24 Apr 2019 14:54:01 -0700 Subject: [PATCH 22/27] [CPP-340] For MistypedFunctionArguments.ql, add support for pointers to pointers and pointers to arrays. --- .../MistypedFunctionArguments.ql | 20 +++++++--- .../TooFewArguments.ql | 7 ++-- .../MistypedFunctionArguments.expected | 40 +++++++++---------- .../TooFewArguments.expected | 6 +-- .../TooManyArguments.expected | 4 +- .../Underspecified Functions/test.c | 15 ++++++- 6 files changed, 58 insertions(+), 34 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index 7ec963d7f0f1..7295b1aa2efe 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -28,7 +28,7 @@ predicate arithTypesMatch(Type arg, Type parm) { } pragma[inline] -predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { +predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) { // arithmetic types arithTypesMatch(arg, parm) or @@ -38,6 +38,18 @@ predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { parm instanceof VoidType } +pragma[inline] +predicate pointerArgTypeMayBeUsed(Type arg, Type parm) { + nestedPointerArgTypeMayBeUsed(arg, parm) + or + // nested pointers + nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(), + parm.(PointerType).getBaseType().getUnspecifiedType()) + or + nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(), + parm.(PointerType).getBaseType().getUnspecifiedType()) +} + pragma[inline] predicate argTypeMayBeUsed(Type arg, Type parm) { // arithmetic types @@ -58,10 +70,8 @@ predicate argTypeMayBeUsed(Type arg, Type parm) { parm.(ArrayType).getBaseType().getUnspecifiedType()) } -// This predicate doesn't necessarily have to exist, but if it does exist -// then it must be inline to make sure we don't enumerate all pairs of -// compatible types. -// Its body could also just be hand-inlined where it's used. +// This predicate holds whenever expression `arg` may be used to initialize +// function parameter `parm` without need for run-time conversion. pragma[inline] predicate argMayBeUsed(Expr arg, Parameter parm) { argTypeMayBeUsed(arg.getFullyConverted().getType().getUnspecifiedType(), diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql index c060b0adf9d9..134533313ac2 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql @@ -1,9 +1,10 @@ /** * @name Call to function with fewer arguments than declared parameters - * @description A function call passed fewer arguments than the number of + * @description A function call is passing fewer arguments than the number of * declared parameters of the function. This may indicate - * that the code does not follow the author's intent. It is also a vulnerability, - * since the function is like to operate on undefined data. + * that the code does not follow the author's intent. It is also + * a vulnerability, since the function is likely to operate on + * undefined data. * @kind problem * @problem.severity error * @precision very-high diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index bcbb2f2115b2..c72471a356a8 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,20 +1,20 @@ -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:66:24:66:26 | p#0 | int p#0 | -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:66:24:66:26 | p#0 | int p#0 | -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:66:6:66:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:66:24:66:26 | p#0 | int p#0 | -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:66:6:66:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:66:24:66:26 | p#0 | int p#0 | -| test.c:39:3:39:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:67:6:67:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:39:31:39:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:67:38:67:38 | x | int x | -| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:70:6:70:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:29:43:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:70:36:70:36 | x | int x | -| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:70:6:70:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:37:43:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:70:50:70:50 | z | int z | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:82:34:82:34 | x | int * x | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:82:43:82:43 | y | void * y | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:82:6:82:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:82:34:82:34 | x | int * x | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:82:6:82:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:82:43:82:43 | y | void * y | -| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:83:31:83:31 | a | char[6] a | -| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:83:6:83:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:83:31:83:31 | a | char[6] a | -| test.c:50:3:50:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:85:7:85:24 | defined_with_float | defined_with_float | test.c:50:22:50:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:85:32:85:32 | f | float f | -| test.c:51:3:51:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:85:7:85:24 | defined_with_float | defined_with_float | test.c:51:22:51:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:85:32:85:32 | f | float f | -| test.c:54:3:54:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:89:8:89:26 | defined_with_double | defined_with_double | test.c:54:23:54:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:89:35:89:35 | d | double d | -| test.c:56:3:56:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:11:93:32 | defined_with_long_long | defined_with_long_long | test.c:56:26:56:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:93:44:93:45 | ll | long long ll | -| test.c:57:3:57:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:11:93:32 | defined_with_long_long | defined_with_long_long | test.c:57:26:57:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:93:44:93:45 | ll | long long ll | -| test.c:59:3:59:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:89:8:89:26 | defined_with_double | defined_with_double | test.c:59:23:59:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:89:35:89:35 | d | double d | -| test.c:60:3:60:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:11:93:32 | defined_with_long_long | defined_with_long_long | test.c:60:26:60:31 | 2.499999999999999983e+50 | 2.499999999999999983e+50 | file://:0:0:0:0 | double | double | test.c:93:44:93:45 | ll | long long ll | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:72:24:72:26 | p#0 | int p#0 | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:72:24:72:26 | p#0 | int p#0 | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:72:6:72:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:72:24:72:26 | p#0 | int p#0 | +| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:72:6:72:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:72:24:72:26 | p#0 | int p#0 | +| test.c:39:3:39:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:73:6:73:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:39:31:39:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:73:38:73:38 | x | int x | +| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:29:43:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:76:36:76:36 | x | int x | +| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:37:43:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:76:50:76:50 | z | int z | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:88:34:88:34 | x | int * x | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:88:43:88:43 | y | void * y | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:88:6:88:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:88:34:88:34 | x | int * x | +| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:88:6:88:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:88:43:88:43 | y | void * y | +| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:89:31:89:31 | a | char[6] a | +| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:89:6:89:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:89:31:89:31 | a | char[6] a | +| test.c:50:3:50:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:91:7:91:24 | defined_with_float | defined_with_float | test.c:50:22:50:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:91:32:91:32 | f | float f | +| test.c:51:3:51:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:91:7:91:24 | defined_with_float | defined_with_float | test.c:51:22:51:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:91:32:91:32 | f | float f | +| test.c:54:3:54:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:8:95:26 | defined_with_double | defined_with_double | test.c:54:23:54:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:95:35:95:35 | d | double d | +| test.c:56:3:56:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:11:99:32 | defined_with_long_long | defined_with_long_long | test.c:56:26:56:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:99:44:99:45 | ll | long long ll | +| test.c:57:3:57:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:11:99:32 | defined_with_long_long | defined_with_long_long | test.c:57:26:57:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:99:44:99:45 | ll | long long ll | +| test.c:59:3:59:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:8:95:26 | defined_with_double | defined_with_double | test.c:59:23:59:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:95:35:95:35 | d | double d | +| test.c:60:3:60:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:11:99:32 | defined_with_long_long | defined_with_long_long | test.c:60:26:60:31 | 2.499999999999999983e+50 | 2.499999999999999983e+50 | file://:0:0:0:0 | double | double | test.c:99:44:99:45 | ll | long long ll | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected index 1abe1120ba7a..93c25cdfdfe5 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -1,4 +1,4 @@ | test.c:33:3:33:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:33:3:33:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:66:6:66:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:35:3:35:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:67:6:67:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:77:10:77:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:80:5:80:15 | dereference | dereference | +| test.c:33:3:33:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:72:6:72:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:35:3:35:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:73:6:73:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:83:10:83:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:86:5:86:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected index 7ac6b10070a5..ca421651886e 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -1,4 +1,4 @@ | test.c:23:3:23:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | | test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:30:3:30:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:65:6:65:22 | not_yet_declared1 | not_yet_declared1 | -| test.c:40:3:40:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:67:6:67:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:71:6:71:22 | not_yet_declared1 | not_yet_declared1 | +| test.c:40:3:40:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:73:6:73:32 | declared_empty_defined_with | declared_empty_defined_with | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c index db5b0c5ec26d..a0fa852838a2 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -18,7 +18,7 @@ int ca[4] = { 1, 2, 3, 4 }; void *pv; -void test() { +void test(int *argv[]) { declared_empty(); // GOOD declared_empty(1); // BAD declared_void(); // GOOD @@ -60,6 +60,12 @@ void test() { defined_with_long_long(2.5e50); // BAD k_and_r_func(2.5, &s); // GOOD + + int (*parameterName)[2]; + defined_with_ptr_ptr(parameterName); // GOOD + defined_with_ptr_ptr(argv); // GOOD + defined_with_ptr_arr(parameterName); // GOOD + defined_with_ptr_arr(argv); // GOOD } void not_yet_declared1(); @@ -93,4 +99,11 @@ double defined_with_double(double d) { long long defined_with_long_long(long long ll) { return ll; } + +unsigned int defined_with_ptr_ptr(unsigned int **ptr) { + return **ptr; +} +unsigned int defined_with_ptr_arr(unsigned int *ptr[]) { + return **ptr; +} \ No newline at end of file From 4a760b15610a2aca051967339b11c921c3d22742 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Sun, 28 Apr 2019 13:49:46 -0700 Subject: [PATCH 23/27] [CPP-340] Delete ArgumentsToImplicit.ql and associated files. Reduce MistypedFunctionArguments.ql precision to `medium`. --- .../ArgumentsToImplicit.c | 9 ---- .../ArgumentsToImplicit.qhelp | 29 ------------ .../ArgumentsToImplicit.ql | 47 ------------------- .../MistypedFunctionArguments.ql | 2 +- .../ArgumentsToImplicit.expected | 1 - .../ArgumentsToImplicit.qlref | 1 - 6 files changed, 1 insertion(+), 88 deletions(-) delete mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c delete mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp delete mode 100644 cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected delete mode 100644 cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c deleted file mode 100644 index 77164b334d30..000000000000 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.c +++ /dev/null @@ -1,9 +0,0 @@ - -void calls() { - - undeclared(); // GOOD - - undeclared(1); // BAD - - undeclared(1, 2); // BAD -} diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp deleted file mode 100644 index 78f12ac6de56..000000000000 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qhelp +++ /dev/null @@ -1,29 +0,0 @@ - - - - - -

    An implicitly-declared function is called with arguments.

    - -

    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, an implicitly declared function is assumed to accept no arguments. Providing - these arguments incurs an unneeded computational overhead, both - in terms of time and of additional stack space.

    - -
    - -

    Call the function without any arguments.

    - -
    - - - - - -
  • SEI CERT C Coding Standard: DCL20-C. Explicitly specify void when a function accepts no arguments
  • -
    -
    diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql deleted file mode 100644 index e3ff53c63054..000000000000 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @name Call with arguments to an implicitly declared function - * @description A function call passed arguments even though the - * function in question is only implicitly declared (and - * hence accepting no arguments). This may indicate - * that the code does not follow the author's intent. - * @kind problem - * @problem.severity warning - * @precision very-high - * @id cpp/arguments-to-implicit - * @tags correctness - * maintainability - */ - -import cpp - -// True if there is no explicit definition of the function -predicate hasNoExplicitDecl(Function f) { - not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | not fde.isImplicit()) -} - -// True if this file (or header) was compiled as a C file -predicate isCompiledAsC(Function f) { - exists(File file | file.compiledAsC() | - file = f.getFile() or file.getAnIncludedFile+() = f.getFile() - ) -} - -predicate isWhitelisted(Function f) { - f instanceof BuiltInFunction - or - // The following list can be expanded as the need arises - exists(string name | name = f.getName() | - name = "static_assert" or - name = "_Static_assert" or - name = "strptime" - ) -} - -from FunctionCall fc, Function f -where - f = fc.getTarget() and - hasNoExplicitDecl(f) and - isCompiledAsC(f) and - not isWhitelisted(f) and - fc.getNumberOfArguments() > 0 -select fc, "This call to an implicitly declared function $@ has arguments.", f, f.toString() diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index 7295b1aa2efe..be07c0ea7f16 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -6,7 +6,7 @@ * arguments on a stack may lead to unpredictable function behavior. * @kind problem * @problem.severity warning - * @precision high + * @precision medium * @id cpp/mistyped-function-arguments * @tags correctness * maintainability diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected deleted file mode 100644 index f1cb25249c26..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.expected +++ /dev/null @@ -1 +0,0 @@ -| test.c:28:3:28:12 | call to undeclared | This call to an implicitly declared function $@ has arguments. | test.c:27:3:27:3 | undeclared | undeclared | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref deleted file mode 100644 index 66dc368af6f2..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/ArgumentsToImplicit.qlref +++ /dev/null @@ -1 +0,0 @@ -Likely Bugs/Underspecified Functions/ArgumentsToImplicit.ql From a0cfe826ee65cc4ab71d05687f170a88d935677e Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 29 Apr 2019 09:58:31 -0700 Subject: [PATCH 24/27] [CPP-340] Replace whitelist with f.getBlock() test. Fix doc comment. --- .../MistypedFunctionArguments.ql | 7 +++---- .../Underspecified Functions/TooManyArguments.ql | 13 +------------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql index be07c0ea7f16..320f9f9164d9 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -1,9 +1,8 @@ /** * @name Call to a function with one or more incompatible arguments - * @description A call to a function with at least one argument whose type does - * not match the type of the corresponding function parameter. This may indicate - * that the author is not familiar with the function being called. Passing mistyped - * arguments on a stack may lead to unpredictable function behavior. + * @description When the type of a function argument is not compatible + * with the type of the corresponding parameter, it may lead to + * unpredictable behavior. * @kind problem * @problem.severity warning * @precision medium diff --git a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql index e866c6f60500..b0bd7746c157 100644 --- a/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql @@ -31,24 +31,13 @@ predicate isCompiledAsC(Function f) { ) } -predicate isWhitelisted(Function f) { - f instanceof BuiltInFunction - or - // The following list can be expanded as the need arises - exists(string name | name = f.getName() | - name = "static_assert" or - name = "_Static_assert" or - name = "strptime" - ) -} - from FunctionCall fc, Function f where f = fc.getTarget() and not f.isVarargs() and hasZeroParamDecl(f) and isCompiledAsC(f) and - not isWhitelisted(f) and + exists(f.getBlock()) and // There must not exist a declaration with the number of parameters // at least as large as the number of call arguments not exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() | From d14696729be29c5838b667a29f520cf512fd5e5f Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 29 Apr 2019 14:05:58 -0700 Subject: [PATCH 25/27] [CPP-340] Fix end-of-line formatting for our change notes. Bring back entry accidentally deleted during previous merge. --- change-notes/1.21/analysis-cpp.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/change-notes/1.21/analysis-cpp.md b/change-notes/1.21/analysis-cpp.md index cc1cc9cbe8f2..f02247a485f4 100644 --- a/change-notes/1.21/analysis-cpp.md +++ b/change-notes/1.21/analysis-cpp.md @@ -6,8 +6,8 @@ | **Query** | **Tags** | **Purpose** | |-----------------------------|-----------|--------------------------------------------------------------------| -| `()`-declared function called with too few arguments (`cpp/too-few-arguments`) | Correctness | Find all cases where the number of arguments is less than the number of parameters of the function, provided the function is also properly declared/defined elsewhere. | -| `()`-declared function called with mismatched arguments (`cpp/mismatched-function-arguments`) | Correctness | Find all cases where the types of arguments do not match the types of parameters of the function, provided the function is also properly declared/defined elsewhere. | +| `()`-declared function called with too few arguments (`cpp/too-few-arguments`) | Correctness | Find all cases where the number of arguments is less than the number of parameters of the function, provided the function is also properly declared/defined elsewhere. | +| `()`-declared function called with mismatched arguments (`cpp/mismatched-function-arguments`) | Correctness | Find all cases where the types of arguments do not match the types of parameters of the function, provided the function is also properly declared/defined elsewhere. | ## Changes to existing queries @@ -21,6 +21,7 @@ | Resource not released in destructor (`cpp/resource-not-released-in-destructor`) | Fewer false positive results | Resource allocation and deallocation functions are now determined more accurately. | | Comparison result is always the same | Fewer false positive results | The range analysis library is now more conservative about floating point values being possibly `NaN` | | Wrong type of arguments to formatting function (`cpp/wrong-type-format-argument`) | More correct results and fewer false positive results | This query now more accurately identifies wide and non-wide string/character format arguments on different platforms. Platform detection has also been made more accurate for the purposes of this query. | -| `()`-declared function called with too many arguments (`cpp/futile-params`) | Improved coverage | Query has been generalized to find all cases where the number of arguments exceedes the number of parameters of the function, provided the function is also properly declared/defined elsewhere. | +| Wrong type of arguments to formatting function (`cpp/wrong-type-format-argument`) | Fewer false positive results | Non-standard uses of %L are now understood. | +| `()`-declared function called with too many arguments (`cpp/futile-params`) | Improved coverage | Query has been generalized to find all cases where the number of arguments exceedes the number of parameters of the function, provided the function is also properly declared/defined elsewhere. | ## Changes to QL libraries From be77eb7367e6c4a638d12cbe617c931a70739c43 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Mon, 29 Apr 2019 15:30:28 -0700 Subject: [PATCH 26/27] [CPP-340] Add new test cases to test.c; this required the .expected files to be regenerated. --- .../MistypedFunctionArguments.expected | 40 +++++++++---------- .../TooFewArguments.expected | 8 ++-- .../TooManyArguments.expected | 6 +-- .../Underspecified Functions/test.c | 11 ++++- 4 files changed, 35 insertions(+), 30 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected index c72471a356a8..6ba72c8cda1e 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -1,20 +1,20 @@ -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:72:24:72:26 | p#0 | int p#0 | -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:72:24:72:26 | p#0 | int p#0 | -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:72:6:72:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:72:24:72:26 | p#0 | int p#0 | -| test.c:32:3:32:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:72:6:72:22 | not_yet_declared2 | not_yet_declared2 | test.c:32:21:32:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:72:24:72:26 | p#0 | int p#0 | -| test.c:39:3:39:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:73:6:73:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:39:31:39:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:73:38:73:38 | x | int x | -| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:29:43:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:76:36:76:36 | x | int x | -| test.c:43:3:43:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:30 | not_declared_defined_with | not_declared_defined_with | test.c:43:37:43:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:76:50:76:50 | z | int z | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:88:34:88:34 | x | int * x | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:88:43:88:43 | y | void * y | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:88:6:88:27 | declared_with_pointers | declared_with_pointers | test.c:46:26:46:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:88:34:88:34 | x | int * x | -| test.c:46:3:46:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:88:6:88:27 | declared_with_pointers | declared_with_pointers | test.c:46:34:46:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:88:43:88:43 | y | void * y | -| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:89:31:89:31 | a | char[6] a | -| test.c:48:3:48:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:89:6:89:24 | declared_with_array | declared_with_array | test.c:48:23:48:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:89:31:89:31 | a | char[6] a | -| test.c:50:3:50:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:91:7:91:24 | defined_with_float | defined_with_float | test.c:50:22:50:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:91:32:91:32 | f | float f | -| test.c:51:3:51:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:91:7:91:24 | defined_with_float | defined_with_float | test.c:51:22:51:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:91:32:91:32 | f | float f | -| test.c:54:3:54:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:8:95:26 | defined_with_double | defined_with_double | test.c:54:23:54:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:95:35:95:35 | d | double d | -| test.c:56:3:56:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:11:99:32 | defined_with_long_long | defined_with_long_long | test.c:56:26:56:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:99:44:99:45 | ll | long long ll | -| test.c:57:3:57:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:11:99:32 | defined_with_long_long | defined_with_long_long | test.c:57:26:57:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:99:44:99:45 | ll | long long ll | -| test.c:59:3:59:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:8:95:26 | defined_with_double | defined_with_double | test.c:59:23:59:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:95:35:95:35 | d | double d | -| test.c:60:3:60:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:11:99:32 | defined_with_long_long | defined_with_long_long | test.c:60:26:60:31 | 2.499999999999999983e+50 | 2.499999999999999983e+50 | file://:0:0:0:0 | double | double | test.c:99:44:99:45 | ll | long long ll | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:76:24:76:26 | p#0 | int p#0 | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | p#0 | int p#0 | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int * | int * | test.c:76:24:76:26 | p#0 | int p#0 | +| test.c:33:3:33:19 | call to not_yet_declared2 | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | test.c:33:21:33:22 | ca | ca | file://:0:0:0:0 | int[4] | int[4] | test.c:76:24:76:26 | p#0 | int p#0 | +| test.c:40:3:40:29 | call to declared_empty_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | test.c:40:31:40:32 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:77:38:77:38 | x | int x | +| test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:29:44:31 | 4 | 4 | file://:0:0:0:0 | long long | long long | test.c:80:36:80:36 | x | int x | +| test.c:44:3:44:27 | call to not_declared_defined_with | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:80:6:80:30 | not_declared_defined_with | not_declared_defined_with | test.c:44:37:44:42 | 2500000000.0 | 2500000000.0 | file://:0:0:0:0 | float | float | test.c:80:50:80:50 | z | int z | +| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:47:26:47:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:92:34:92:34 | x | int * x | +| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:5:6:5:27 | declared_with_pointers | declared_with_pointers | test.c:47:34:47:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:92:43:92:43 | y | void * y | +| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:92:6:92:27 | declared_with_pointers | declared_with_pointers | test.c:47:26:47:31 | 3500000000000000.0 | 3500000000000000.0 | file://:0:0:0:0 | double | double | test.c:92:34:92:34 | x | int * x | +| test.c:47:3:47:24 | call to declared_with_pointers | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:92:6:92:27 | declared_with_pointers | declared_with_pointers | test.c:47:34:47:34 | 0 | 0 | file://:0:0:0:0 | int | int | test.c:92:43:92:43 | y | void * y | +| test.c:49:3:49:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:6:6:6:24 | declared_with_array | declared_with_array | test.c:49:23:49:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:93:31:93:31 | a | char[6] a | +| test.c:49:3:49:21 | call to declared_with_array | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:93:6:93:24 | declared_with_array | declared_with_array | test.c:49:23:49:24 | & ... | & ... | file://:0:0:0:0 | int * | int * | test.c:93:31:93:31 | a | char[6] a | +| test.c:51:3:51:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:7:95:24 | defined_with_float | defined_with_float | test.c:51:22:51:24 | 2.0 | 2.0 | file://:0:0:0:0 | float | float | test.c:95:32:95:32 | f | float f | +| test.c:52:3:52:20 | call to defined_with_float | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:95:7:95:24 | defined_with_float | defined_with_float | test.c:52:22:52:24 | 2.0 | 2.0 | file://:0:0:0:0 | double | double | test.c:95:32:95:32 | f | float f | +| test.c:55:3:55:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:8:99:26 | defined_with_double | defined_with_double | test.c:55:23:55:25 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:99:35:99:35 | d | double d | +| test.c:57:3:57:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:57:26:57:28 | 99 | 99 | file://:0:0:0:0 | int | int | test.c:103:44:103:45 | ll | long long ll | +| test.c:58:3:58:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:58:26:58:26 | 3 | 3 | file://:0:0:0:0 | int | int | test.c:103:44:103:45 | ll | long long ll | +| test.c:60:3:60:21 | call to defined_with_double | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:99:8:99:26 | defined_with_double | defined_with_double | test.c:60:23:60:25 | 2 | 2 | file://:0:0:0:0 | long long | long long | test.c:99:35:99:35 | d | double d | +| test.c:61:3:61:24 | call to defined_with_long_long | Calling $@: argument $@ of type $@ is incompatible with parameter $@. | test.c:103:11:103:32 | defined_with_long_long | defined_with_long_long | test.c:61:26:61:31 | 2.499999999999999983e+50 | 2.499999999999999983e+50 | file://:0:0:0:0 | double | double | test.c:103:44:103:45 | ll | long long ll | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected index 93c25cdfdfe5..42c4f7f94559 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -1,4 +1,4 @@ -| test.c:33:3:33:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:31:3:31:3 | not_yet_declared2 | not_yet_declared2 | -| test.c:33:3:33:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:72:6:72:22 | not_yet_declared2 | not_yet_declared2 | -| test.c:35:3:35:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:73:6:73:32 | declared_empty_defined_with | declared_empty_defined_with | -| test.c:83:10:83:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:86:5:86:15 | dereference | dereference | +| test.c:34:3:34:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:32:3:32:3 | not_yet_declared2 | not_yet_declared2 | +| test.c:34:3:34:19 | call to not_yet_declared2 | This call has fewer arguments than required by $@. | test.c:76:6:76:22 | not_yet_declared2 | not_yet_declared2 | +| test.c:36:3:36:29 | call to declared_empty_defined_with | This call has fewer arguments than required by $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:87:10:87:20 | call to dereference | This call has fewer arguments than required by $@. | test.c:90:5:90:15 | dereference | dereference | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected index ca421651886e..bc64434578b2 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -1,4 +1,2 @@ -| test.c:23:3:23:16 | call to declared_empty | This call has more arguments than required by $@. | test.c:1:6:1:19 | declared_empty | declared_empty | -| test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:30:3:30:3 | not_yet_declared1 | not_yet_declared1 | -| test.c:30:3:30:19 | call to not_yet_declared1 | This call has more arguments than required by $@. | test.c:71:6:71:22 | not_yet_declared1 | not_yet_declared1 | -| test.c:40:3:40:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:73:6:73:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:41:3:41:29 | call to declared_empty_defined_with | This call has more arguments than required by $@. | test.c:77:6:77:32 | declared_empty_defined_with | declared_empty_defined_with | +| test.c:72:3:72:28 | call to declared_and_defined_empty | This call has more arguments than required by $@. | test.c:114:6:114:31 | declared_and_defined_empty | declared_and_defined_empty | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c index a0fa852838a2..0c9c6320eaa0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -4,6 +4,7 @@ void declared_with(int); void declared_empty_defined_with(); void declared_with_pointers(); void declared_with_array(); +void declared_and_defined_empty(); int k_and_r_func(c,d) char c; @@ -20,7 +21,7 @@ void *pv; void test(int *argv[]) { declared_empty(); // GOOD - declared_empty(1); // BAD + declared_empty(1); // GOOD declared_void(); // GOOD declared_with(1); // GOOD @@ -66,6 +67,9 @@ void test(int *argv[]) { defined_with_ptr_ptr(argv); // GOOD defined_with_ptr_arr(parameterName); // GOOD defined_with_ptr_arr(argv); // GOOD + + declared_and_defined_empty(); // GOOD + declared_and_defined_empty(1); // BAD } void not_yet_declared1(); @@ -106,4 +110,7 @@ unsigned int defined_with_ptr_ptr(unsigned int **ptr) { unsigned int defined_with_ptr_arr(unsigned int *ptr[]) { return **ptr; } - \ No newline at end of file + +void declared_and_defined_empty() { + return; +} From 17066cfe3ee420cdf0cba57bfeac8ee2f7cb3c17 Mon Sep 17 00:00:00 2001 From: Ziemowit Laski Date: Tue, 30 Apr 2019 13:21:36 -0700 Subject: [PATCH 27/27] [CPP-340] Adjust annotations in test.c file. --- .../query-tests/Likely Bugs/Underspecified Functions/test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c index 0c9c6320eaa0..f58aa823ad8f 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -26,9 +26,9 @@ void test(int *argv[]) { declared_with(1); // GOOD undeclared(); // GOOD - undeclared(1); // BAD + undeclared(1); // GOOD - not_yet_declared1(1); // BAD + not_yet_declared1(1); // GOOD not_yet_declared2(1); // GOOD not_yet_declared2(ca); // BAD not_yet_declared2(); // BAD