mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
[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.
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
* @id cpp/too-few-arguments
|
||||
* @tags correctness
|
||||
* maintainability
|
||||
* security
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -1 +1 @@
|
||||
Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql
|
||||
Likely Bugs/UnderspecifiedFunctions/MistypedFunctionArguments.ql
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -1 +1 @@
|
||||
Likely Bugs/Underspecified Functions/TooFewArguments.ql
|
||||
Likely Bugs/UnderspecifiedFunctions/TooFewArguments.ql
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -1 +1 @@
|
||||
Likely Bugs/Underspecified Functions/TooManyArguments.ql
|
||||
Likely Bugs/UnderspecifiedFunctions/TooManyArguments.ql
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user