mirror of
https://github.com/github/codeql.git
synced 2026-04-27 17:55:19 +02:00
[CPP-340] Rename 'UnspecifiedFunctions' to 'Unspecified Functions'
Make MistypedFunctionArguments.ql more restrictive (allowing
type matching only in the presence of no-op conversions).
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>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.</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="MistypedFunctionArguments.c" />
|
||||
|
||||
</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>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -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()
|
||||
@@ -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);
|
||||
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>A function is called with fewer arguments than there are parameters of the function.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>If the called function <i>modifies</i> 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.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Call the function with the correct number of arguments.</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="TooFewArguments.c" />
|
||||
|
||||
</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>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -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()
|
||||
@@ -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);
|
||||
@@ -0,0 +1,30 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
|
||||
<overview>
|
||||
<p>A function is called with more arguments than there are parameters of the function.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
<p>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.</p>
|
||||
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>Call the function with the correct number of arguments.</p>
|
||||
|
||||
</recommendation>
|
||||
<example><sample src="TooManyArguments.c" />
|
||||
|
||||
</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>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -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()
|
||||
Reference in New Issue
Block a user