mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
[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.
This commit is contained in:
@@ -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
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -14,68 +14,45 @@
|
||||
|
||||
import cpp
|
||||
|
||||
predicate argTypeMayBePromoted(Type arg, Type parm) {
|
||||
pragma[inline]
|
||||
predicate argTypeMayBeImplicitlyConverted(Type arg, Type parm) {
|
||||
arg = parm
|
||||
or
|
||||
// floating-point and integral promotions
|
||||
arg instanceof FloatType and parm instanceof DoubleType
|
||||
// integral and floating-point types are implicitly convertible in C
|
||||
arg instanceof ArithmeticType and parm instanceof ArithmeticType
|
||||
or
|
||||
arg instanceof FloatType and parm instanceof LongDoubleType
|
||||
// integral values may be used to initialize pointers (but NOT array addresses)
|
||||
arg instanceof IntegralType and parm instanceof PointerType
|
||||
or
|
||||
arg instanceof DoubleType and parm instanceof LongDoubleType
|
||||
// pointers-to-void may be used for arbitrary pointers
|
||||
arg instanceof VoidPointerType and parm instanceof PointerType
|
||||
or
|
||||
arg instanceof CharType and parm instanceof IntType
|
||||
arg instanceof PointerType and parm instanceof VoidPointerType
|
||||
or
|
||||
arg instanceof CharType and parm instanceof IntType
|
||||
arg instanceof ArrayType and parm instanceof VoidPointerType
|
||||
or
|
||||
arg instanceof CharType and parm instanceof LongType
|
||||
arg instanceof VoidPointerType and parm instanceof ArrayType
|
||||
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
|
||||
// pointers to same 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
|
||||
arg.(ArrayType).getBaseType().getUnspecifiedType() = parm
|
||||
.(PointerType)
|
||||
.getBaseType()
|
||||
.getUnspecifiedType()
|
||||
or
|
||||
// handle reference types
|
||||
argTypeMayBePromoted(arg.(ReferenceType).getBaseType().getUnspecifiedType(), parm)
|
||||
arg.(PointerType).getBaseType().getUnspecifiedType() = parm
|
||||
.(ArrayType)
|
||||
.getBaseType()
|
||||
.getUnspecifiedType()
|
||||
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())
|
||||
arg.(ArrayType).getBaseType().getUnspecifiedType() = parm
|
||||
.(ArrayType)
|
||||
.getBaseType()
|
||||
.getUnspecifiedType()
|
||||
}
|
||||
|
||||
// This predicate doesn't necessarily have to exist, but if it does exist
|
||||
@@ -83,20 +60,9 @@ predicate argTypeMayBePromoted(Type arg, Type parm) {
|
||||
// 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(),
|
||||
predicate argMayBeImplicitlyConverted(Expr arg, Parameter parm) {
|
||||
argTypeMayBeImplicitlyConverted(arg.getFullyConverted().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
|
||||
@@ -110,8 +76,7 @@ where
|
||||
fde.getNumberOfParameters() = 0
|
||||
) and
|
||||
// Parameter p and its corresponding call argument must have mismatched types
|
||||
not argMayBePromoted(fc.getArgument(p.getIndex()), p)
|
||||
not argMayBeImplicitlyConverted(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()
|
||||
fc.getArgument(p.getIndex()) as arg, arg.toString(), arg.getFullyConverted().getType() as type,
|
||||
type.toString(), p, p.getTypedName()
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
.file "MistypedFunctionArguments.c"
|
||||
@@ -7,7 +7,7 @@
|
||||
* @kind problem
|
||||
* @problem.severity error
|
||||
* @precision very-high
|
||||
* @id cpp/too-few-arguments
|
||||
* @id cpp/futile-params
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
* security
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
|
||||
void one_argument(int x);
|
||||
void one_argument();
|
||||
|
||||
void calls() {
|
||||
|
||||
@@ -7,3 +6,5 @@ void calls() {
|
||||
|
||||
one_argument(1, 2); // BAD: `one_argument` will use the first argument but ignore the second
|
||||
}
|
||||
|
||||
void one_argument(int x);
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>SEI CERT C++ Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL20-C.+Explicitly+specify+void+when+a+function+accepts+no+arguments"> DCL20-C. Explicitly specify void when a function accepts no arguments </a></li>
|
||||
<li>SEI CERT C Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/DCL20-C.+Explicitly+specify+void+when+a+function+accepts+no+arguments"> DCL20-C. Explicitly specify void when a function accepts no arguments </a></li>
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
33
cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c
Normal file
33
cpp/ql/src/Likely Bugs/UnderspecifiedFunctions/tests.c
Normal file
@@ -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");
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user