Skip to content

Commit f1fe2de

Browse files
author
Nikita Kraiouchkine
committed
Implement Expressions package
1 parent b21f35b commit f1fe2de

23 files changed

+663
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# EXP37-C: Pass the correct number of arguments to the POSIX open function.
2+
3+
This query implements the CERT-C rule EXP37-C:
4+
5+
> Call functions with the correct number and type of arguments
6+
## CERT
7+
8+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
10+
## Implementation notes
11+
12+
None
13+
14+
## References
15+
16+
* CERT-C: [EXP37-C: Call functions with the correct number and type of arguments](https://wiki.sei.cmu.edu/confluence/display/c)
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* @id c/cert/call-posix-open-with-correct-argument-count
3+
* @name EXP37-C: Pass the correct number of arguments to the POSIX open function.
4+
* @description A third argument should be passed to the POSIX function open() when and only when
5+
* creating a new file.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/exp37-c
10+
* correctness
11+
* security
12+
* external/cert/obligation/rule
13+
*/
14+
15+
import cpp
16+
import codingstandards.c.cert
17+
import semmle.code.cpp.commons.unix.Constants
18+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
19+
20+
int o_creat_val() {
21+
result = any(MacroInvocation ma | ma.getMacroName() = "O_CREAT" | ma.getExpr().getValue().toInt())
22+
or
23+
result = o_creat()
24+
}
25+
26+
/**
27+
* A function call to POSIX open()
28+
*/
29+
class POSIXOpenFunctionCall extends FunctionCall {
30+
POSIXOpenFunctionCall() { this.getTarget().getQualifiedName() = "open" }
31+
32+
/**
33+
* Holds if reasonable bounds exist for the value of the 'flags' argument of the call.
34+
* This predicate will never hold for cases such as wrapper functions
35+
* which pass a parameter to the open() 'flags' argument.
36+
*/
37+
predicate hasFlagsArgBounds() { lowerBound(this.getArgument(1)) >= 0 }
38+
39+
/**
40+
* Holds if the 'flags' argument contains the O_CREAT flag.
41+
* Because this predicate uses the SimpleRangeAnalysis library, it only
42+
* analyzes the bounds of 'flag' arguments which can be deduced locally.
43+
*/
44+
predicate isOpenCreateCall() {
45+
hasFlagsArgBounds() and
46+
upperBound(this.getArgument(1)).toString().toInt().bitAnd(o_creat_val()) != 0
47+
}
48+
}
49+
50+
from POSIXOpenFunctionCall call, string message
51+
where
52+
not isExcluded(call, ExpressionsPackage::callPOSIXOpenWithCorrectArgumentCountQuery()) and
53+
// include only analyzable flag arguments which have values that can be determined locally
54+
call.hasFlagsArgBounds() and
55+
// differentiate between two variants:
56+
// 1) a call to open() with the O_CREAT flag set, which should pass three arguments
57+
// 2) a call to open without the O_CREAT flag set, which should pass two arguments
58+
if call.isOpenCreateCall()
59+
then (
60+
call.getNumberOfArguments() != 3 and
61+
message =
62+
"Call to " + call.getTarget().getName() +
63+
" with O_CREAT flag does not pass exactly three arguments."
64+
) else (
65+
call.getNumberOfArguments() != 2 and
66+
message =
67+
"Call to " + call.getTarget().getName() +
68+
" without O_CREAT flag does not pass exactly two arguments."
69+
)
70+
select call, message
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# EXP37-C: Do not call a function pointer which points to a function of an incompatible type
2+
3+
This query implements the CERT-C rule EXP37-C:
4+
5+
> Call functions with the correct number and type of arguments
6+
## CERT
7+
8+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
10+
## Implementation notes
11+
12+
None
13+
14+
## References
15+
16+
* CERT-C: [EXP37-C: Call functions with the correct number and type of arguments](https://wiki.sei.cmu.edu/confluence/display/c)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* @id c/cert/do-not-call-function-pointer-with-incompatible-type
3+
* @name EXP37-C: Do not call a function pointer which points to a function of an incompatible type
4+
* @description Calling a function pointer with a type incompatible with the function it points to
5+
* is undefined.
6+
* @kind path-problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/exp37-c
10+
* correctness
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
import semmle.code.cpp.dataflow.DataFlow
17+
import DataFlow::PathGraph
18+
19+
class SuspectFunctionPointerCastExpr extends Expr {
20+
SuspectFunctionPointerCastExpr() {
21+
exists(CStyleCast cast, Type old, Type new |
22+
this = cast.getUnconverted() and
23+
old = cast.getUnconverted().getUnderlyingType() and
24+
new = cast.getFullyConverted().getUnderlyingType() and
25+
old != new and
26+
old instanceof FunctionPointerType and
27+
new instanceof FunctionPointerType
28+
)
29+
}
30+
}
31+
32+
class SuspectFunctionPointerToCallConfig extends DataFlow::Configuration {
33+
SuspectFunctionPointerToCallConfig() { this = "SuspectFunctionPointerToCallConfig" }
34+
35+
override predicate isSource(DataFlow::Node src) {
36+
src.asExpr() instanceof SuspectFunctionPointerCastExpr
37+
}
38+
39+
override predicate isSink(DataFlow::Node sink) {
40+
exists(VariableCall call | sink.asExpr() = call.getExpr().(VariableAccess))
41+
}
42+
}
43+
44+
from
45+
SuspectFunctionPointerToCallConfig config, DataFlow::PathNode src, DataFlow::PathNode sink,
46+
Access access
47+
where
48+
not isExcluded(src.getNode().asExpr(),
49+
ExpressionsPackage::doNotCallFunctionPointerWithIncompatibleTypeQuery()) and
50+
access = src.getNode().asExpr() and
51+
config.hasFlowPath(src, sink)
52+
select src, src, sink,
53+
"Incompatible function $@ assigned to function pointer is eventually called through the pointer.",
54+
access.getTarget(), access.getTarget().getName()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# EXP37-C: Do not pass arguments with an incompatible count or type to a function.
2+
3+
This query implements the CERT-C rule EXP37-C:
4+
5+
> Call functions with the correct number and type of arguments
6+
## CERT
7+
8+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
10+
## Implementation notes
11+
12+
None
13+
14+
## References
15+
16+
* CERT-C: [EXP37-C: Call functions with the correct number and type of arguments](https://wiki.sei.cmu.edu/confluence/display/c)
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/**
2+
* @id c/cert/do-not-call-functions-with-incompatible-arguments
3+
* @name EXP37-C: Do not pass arguments with an incompatible count or type to a function.
4+
* @description The arguments passed to a function must be compatible with the function's
5+
* parameters.
6+
* @kind problem
7+
* @precision high
8+
* @problem.severity error
9+
* @tags external/cert/id/exp37-c
10+
* correctness
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
17+
pragma[inline]
18+
private predicate arithTypesMatch(Type arg, Type parm) {
19+
arg = parm
20+
or
21+
arg.getSize() = parm.getSize() and
22+
(
23+
arg instanceof IntegralOrEnumType and
24+
parm instanceof IntegralOrEnumType
25+
or
26+
arg instanceof FloatingPointType and
27+
parm instanceof FloatingPointType
28+
)
29+
}
30+
31+
pragma[inline]
32+
private predicate nestedPointerArgTypeMayBeUsed(Type arg, Type parm) {
33+
// arithmetic types
34+
arithTypesMatch(arg, parm)
35+
or
36+
// conversion to/from pointers to void is allowed
37+
arg instanceof VoidType
38+
or
39+
parm instanceof VoidType
40+
}
41+
42+
pragma[inline]
43+
private predicate pointerArgTypeMayBeUsed(Type arg, Type parm) {
44+
nestedPointerArgTypeMayBeUsed(arg, parm)
45+
or
46+
// nested pointers
47+
nestedPointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
48+
parm.(PointerType).getBaseType().getUnspecifiedType())
49+
or
50+
nestedPointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
51+
parm.(PointerType).getBaseType().getUnspecifiedType())
52+
}
53+
54+
pragma[inline]
55+
private predicate argTypeMayBeUsed(Type arg, Type parm) {
56+
// arithmetic types
57+
arithTypesMatch(arg, parm)
58+
or
59+
// pointers to compatible types
60+
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
61+
parm.(PointerType).getBaseType().getUnspecifiedType())
62+
or
63+
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
64+
parm.(PointerType).getBaseType().getUnspecifiedType())
65+
or
66+
// C11 arrays
67+
pointerArgTypeMayBeUsed(arg.(PointerType).getBaseType().getUnspecifiedType(),
68+
parm.(ArrayType).getBaseType().getUnspecifiedType())
69+
or
70+
pointerArgTypeMayBeUsed(arg.(ArrayType).getBaseType().getUnspecifiedType(),
71+
parm.(ArrayType).getBaseType().getUnspecifiedType())
72+
}
73+
74+
// This predicate holds whenever expression `arg` may be used to initialize
75+
// function parameter `parm` without need for run-time conversion.
76+
pragma[inline]
77+
private predicate argMayBeUsed(Expr arg, Parameter parm) {
78+
argTypeMayBeUsed(arg.getFullyConverted().getUnspecifiedType(), parm.getUnspecifiedType())
79+
}
80+
81+
// True if function was ()-declared, but not (void)-declared or K&R-defined
82+
private predicate hasZeroParamDecl(Function f) {
83+
exists(FunctionDeclarationEntry fde | fde = f.getADeclarationEntry() |
84+
not fde.hasVoidParamList() and fde.getNumberOfParameters() = 0 and not fde.isDefinition()
85+
)
86+
}
87+
88+
// True if this file (or header) was compiled as a C file
89+
private predicate isCompiledAsC(File f) {
90+
f.compiledAsC()
91+
or
92+
exists(File src | isCompiledAsC(src) | src.getAnIncludedFile() = f)
93+
}
94+
95+
predicate mistypedFunctionArguments(FunctionCall fc, Function f, Parameter p) {
96+
f = fc.getTarget() and
97+
p = f.getAParameter() and
98+
hasZeroParamDecl(f) and
99+
isCompiledAsC(f.getFile()) and
100+
not f.isVarargs() and
101+
not f instanceof BuiltInFunction and
102+
p.getIndex() < fc.getNumberOfArguments() and
103+
// Parameter p and its corresponding call argument must have mismatched types
104+
not argMayBeUsed(fc.getArgument(p.getIndex()), p)
105+
}
106+
107+
// The implementation of this query was taken from the following standard library query:
108+
// codeql/cpp/ql/src/Likely Bugs/Underspecified Functions/MistypedFunctionArguments.ql
109+
from FunctionCall fc, Function f, Parameter p
110+
where
111+
not isExcluded(fc, ExpressionsPackage::doNotCallFunctionsWithIncompatibleArgumentsQuery()) and
112+
mistypedFunctionArguments(fc, f, p)
113+
select fc, "Argument $@ in call to $@ is incompatible with parameter $@.",
114+
fc.getArgument(p.getIndex()) as arg, arg.toString(), f, f.toString(), p, p.getTypedName()
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# EXP46-C: Do not use a bitwise operator with a Boolean-like operand
2+
3+
This query implements the CERT-C rule EXP46-C:
4+
5+
> Do not use a bitwise operator with a Boolean-like operand
6+
## CERT
7+
8+
** REPLACE THIS BY RUNNING THE SCRIPT `scripts/help/cert-help-extraction.py` **
9+
10+
## Implementation notes
11+
12+
None
13+
14+
## References
15+
16+
* CERT-C: [EXP46-C: Do not use a bitwise operator with a Boolean-like operand](https://wiki.sei.cmu.edu/confluence/display/c)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/**
2+
* @id c/cert/do-not-use-a-bitwise-operator-with-a-boolean-like-operand
3+
* @name EXP46-C: Do not use a bitwise operator with a Boolean-like operand
4+
* @description
5+
* @kind problem
6+
* @precision very-high
7+
* @problem.severity error
8+
* @tags external/cert/id/exp46-c
9+
* maintainability
10+
* readability
11+
* external/cert/obligation/rule
12+
*/
13+
14+
import cpp
15+
import codingstandards.c.cert
16+
17+
predicate isBitwiseOperationPotentiallyAmbiguous(BinaryBitwiseOperation op) {
18+
op instanceof BitwiseAndExpr or
19+
op instanceof BitwiseOrExpr or
20+
op instanceof BitwiseXorExpr
21+
}
22+
23+
predicate isDisallowedBitwiseOperationOperand(Expr e) {
24+
not e.isParenthesised() and
25+
(
26+
e.getFullyConverted().getUnderlyingType() instanceof BoolType or
27+
e instanceof RelationalOperation or
28+
e instanceof EqualityOperation
29+
)
30+
}
31+
32+
from Expr operand, Operation operation
33+
where
34+
not isExcluded(operation,
35+
ExpressionsPackage::doNotUseABitwiseOperatorWithABooleanLikeOperandQuery()) and
36+
isBitwiseOperationPotentiallyAmbiguous(operation) and
37+
operand = operation.getAnOperand() and
38+
isDisallowedBitwiseOperationOperand(operand)
39+
select operation,
40+
"Bitwise operator " + operation.getOperator() +
41+
" performs potentially unintended operation on $@.", operand, "boolean operand"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| test.c:18:3:18:6 | call to open | Call to open without O_CREAT flag does not pass exactly two arguments. |
2+
| test.c:19:3:19:6 | call to open | Call to open with O_CREAT flag does not pass exactly three arguments. |
3+
| test.c:23:3:23:6 | call to open | Call to open without O_CREAT flag does not pass exactly two arguments. |
4+
| test.c:26:3:26:6 | call to open | Call to open with O_CREAT flag does not pass exactly three arguments. |
5+
| test.c:34:3:34:6 | call to open | Call to open without O_CREAT flag does not pass exactly two arguments. |
6+
| test.c:35:3:35:6 | call to open | Call to open with O_CREAT flag does not pass exactly three arguments. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rules/EXP37-C/CallPOSIXOpenWithCorrectArgumentCount.ql

0 commit comments

Comments
 (0)