diff --git a/change-notes/1.21/analysis-cpp.md b/change-notes/1.21/analysis-cpp.md index 7c12306ff4d7..f02247a485f4 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 @@ -20,5 +22,6 @@ | 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. | | 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 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/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 d0d888a9aac7..000000000000 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.qhelp +++ /dev/null @@ -1,29 +0,0 @@ - - - - - -

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.

- -

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.

- -
- -

Call the function without arguments, or call a different function that expects the arguments -being 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 bb5a99a69bc9..000000000000 --- a/cpp/ql/src/Likely Bugs/Likely Typos/FutileParams.ql +++ /dev/null @@ -1,22 +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 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() 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..320f9f9164d9 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql @@ -0,0 +1,108 @@ +/** + * @name Call to a function with one or more incompatible arguments + * @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 + * @id cpp/mistyped-function-arguments + * @tags correctness + * maintainability + */ + +import cpp + +predicate arithTypesMatch(Type arg, Type parm) { + arg = parm + or + arg.getSize() = parm.getSize() and + ( + arg instanceof IntegralOrEnumType and + parm instanceof IntegralOrEnumType + or + arg instanceof FloatingPointType and + parm instanceof FloatingPointType + ) +} + +pragma[inline] +predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) { + // arithmetic types + arithTypesMatch(arg, parm) + or + // conversion to/from pointers to void is allowed + arg instanceof VoidType + or + 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 + 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 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(), + parm.getType().getUnspecifiedType()) +} + +// 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, 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 + // 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.getExplicitlyConverted().getType().getUnspecifiedType() as atype, atype.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..134533313ac2 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooFewArguments.ql @@ -0,0 +1,45 @@ +/** + * @name Call to function with fewer arguments than declared parameters + * @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 likely to operate on + * undefined data. + * @kind problem + * @problem.severity error + * @precision very-high + * @id cpp/too-few-arguments + * @tags correctness + * maintainability + * security + */ + +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 + 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() | + 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..b0bd7746c157 --- /dev/null +++ b/cpp/ql/src/Likely Bugs/Underspecified Functions/TooManyArguments.ql @@ -0,0 +1,46 @@ +/** + * @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. + * @kind problem + * @problem.severity warning + * @precision very-high + * @id cpp/futile-params + * @tags correctness + * maintainability + */ + +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.isImplicit() and + 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 + hasZeroParamDecl(f) and + isCompiledAsC(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() | + 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 d6dc2222be42..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/FutileParams.expected +++ /dev/null @@ -1,3 +0,0 @@ -| 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 | 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/Likely Typos/FutileParams/test.c b/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c deleted file mode 100644 index 9589d2a9ffc9..000000000000 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.c +++ /dev/null @@ -1,29 +0,0 @@ -void declared_empty(); -void declared_void(void); -void declared_with(int); -void declared_empty_defined_with(); - -void test() { - declared_empty(); // GOOD - declared_empty(1); // BAD - declared_void(); // GOOD - declared_with(1); // 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(1); // GOOD - - int x; - declared_empty_defined_with(&x); // BAD [NOT DETECTED] - declared_empty_defined_with(x, x); // BAD [NOT DETECTED] -} - -void not_yet_declared1(); -void not_yet_declared2(int); -void declared_empty_defined_with(int x) { - // do nothing -} 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..6ba72c8cda1e --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.expected @@ -0,0 +1,20 @@ +| 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/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..42c4f7f94559 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooFewArguments.expected @@ -0,0 +1,4 @@ +| 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/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..bc64434578b2 --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/TooManyArguments.expected @@ -0,0 +1,2 @@ +| 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/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..f58aa823ad8f --- /dev/null +++ b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.c @@ -0,0 +1,116 @@ +void declared_empty(); +void declared_void(void); +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; + double d; +{ + return c + d; +} + +struct _s { int a, b; } s; + +int ca[4] = { 1, 2, 3, 4 }; + +void *pv; + +void test(int *argv[]) { + declared_empty(); // GOOD + declared_empty(1); // GOOD + declared_void(); // GOOD + declared_with(1); // GOOD + + undeclared(); // GOOD + undeclared(1); // GOOD + + not_yet_declared1(1); // GOOD + 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 + + 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 + + defined_with_double(2LL); // BAD + 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 + + declared_and_defined_empty(); // GOOD + declared_and_defined_empty(1); // 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]); + +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; +} + +unsigned int defined_with_ptr_ptr(unsigned int **ptr) { + return **ptr; +} +unsigned int defined_with_ptr_arr(unsigned int *ptr[]) { + return **ptr; +} + +void declared_and_defined_empty() { + return; +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp b/cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp similarity index 62% rename from cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/test.cpp rename to cpp/ql/test/query-tests/Likely Bugs/Underspecified Functions/test.cpp index 855fdaea3fd3..804cd439f2b0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Likely Typos/FutileParams/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