Skip to content

Commit ebb7d39

Browse files
committed
M0-2-1: missed more renaming
1 parent 43e6d67 commit ebb7d39

File tree

3 files changed

+185
-203
lines changed

3 files changed

+185
-203
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
/**
2-
* @id cpp/autosar/do-not-pass-aliased-pointer-to-restrict-qualified-param
2+
* @id cpp/autosar/do-not-pass-aliased-pointer-to-param
33
* @name M0-2-1: Do not pass aliased pointers as parameters of functions where it is undefined behaviour for those pointers to overlap
4-
* @description Passing an aliased pointer to a conceptually restrict-qualified parameter is
5-
* undefined behavior.
4+
* @description Passing a aliased pointers as parameters of certain functions is undefined behavior.
65
* @kind problem
76
* @precision medium
87
* @problem.severity error
@@ -15,11 +14,11 @@
1514

1615
import cpp
1716
import codingstandards.cpp.autosar
18-
import codingstandards.cpp.rules.donotpassaliasedpointertorestrictqualifiedparam_shared.DoNotPassAliasedPointerToRestrictQualifiedParam_Shared
17+
import codingstandards.cpp.rules.donotpassaliasedpointertorestrictqualifiedparamshared.DoNotPassAliasedPointerToRestrictQualifiedParamShared
1918

20-
class DoNotPassAliasedPointerToRestrictQualifiedParamQuery extends DoNotPassAliasedPointerToRestrictQualifiedParam_SharedSharedQuery
19+
class DoNotPassAliasedPointerToRestrictQualifiedParamQuery extends DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery
2120
{
2221
DoNotPassAliasedPointerToRestrictQualifiedParamQuery() {
23-
this = RepresentationPackage::doNotPassAliasedPointerToRestrictQualifiedParamQuery()
22+
this = RepresentationPackage::doNotPassAliasedPointerToParamQuery()
2423
}
2524
}

cpp/common/src/codingstandards/cpp/rules/donotpassaliasedpointertorestrictqualifiedparamshared/DoNotPassAliasedPointerToRestrictQualifiedParamShared.qll

+180-4
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,189 @@
55
import cpp
66
import codingstandards.cpp.Customizations
77
import codingstandards.cpp.Exclusions
8+
import codingstandards.cpp.Pointers
9+
import codingstandards.cpp.Variable
10+
import codingstandards.cpp.dataflow.DataFlow
11+
import semmle.code.cpp.pointsto.PointsTo
12+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
813

9-
abstract class DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery extends Query { }
14+
/**
15+
* A function that has a parameter with a restrict-qualified pointer type.
16+
*/
17+
class FunctionWithRestrictParameters extends Function {
18+
Parameter restrictPtrParam;
19+
20+
FunctionWithRestrictParameters() {
21+
restrictPtrParam.getUnspecifiedType() instanceof PointerOrArrayType and
22+
(
23+
restrictPtrParam.getType().hasSpecifier(["restrict"]) and
24+
restrictPtrParam = this.getAParameter()
25+
or
26+
this.hasGlobalName(["strcpy", "strncpy", "strcat", "strncat", "memcpy"]) and
27+
restrictPtrParam = this.getParameter([0, 1])
28+
or
29+
this.hasGlobalName(["strcpy_s", "strncpy_s", "strcat_s", "strncat_s", "memcpy_s"]) and
30+
restrictPtrParam = this.getParameter([0, 2])
31+
or
32+
this.hasGlobalName(["strtok_s"]) and
33+
restrictPtrParam = this.getAParameter()
34+
or
35+
this.hasGlobalName(["printf", "printf_s", "scanf", "scanf_s"]) and
36+
restrictPtrParam = this.getParameter(0)
37+
or
38+
this.hasGlobalName(["sprintf", "sprintf_s", "snprintf", "snprintf_s"]) and
39+
restrictPtrParam = this.getParameter(3)
40+
)
41+
}
42+
43+
Parameter getARestrictPtrParam() { result = restrictPtrParam }
44+
}
45+
46+
/**
47+
* A call to a function that has a parameter with a restrict-qualified pointer type.
48+
*/
49+
class CallToFunctionWithRestrictParameters extends FunctionCall {
50+
CallToFunctionWithRestrictParameters() {
51+
this.getTarget() instanceof FunctionWithRestrictParameters
52+
}
53+
54+
Expr getARestrictPtrArg() {
55+
result =
56+
this.getArgument(this.getTarget()
57+
.(FunctionWithRestrictParameters)
58+
.getARestrictPtrParam()
59+
.getIndex())
60+
}
61+
62+
Expr getAPtrArg(int index) {
63+
result = this.getArgument(index) and
64+
pointerValue(result)
65+
}
66+
67+
Expr getAPossibleSizeArg() {
68+
exists(Parameter param |
69+
param = this.getTarget().(FunctionWithRestrictParameters).getAParameter() and
70+
param.getUnderlyingType() instanceof IntegralType and
71+
// exclude __builtin_object_size
72+
not result.(FunctionCall).getTarget() instanceof BuiltInFunction and
73+
result = this.getArgument(param.getIndex())
74+
)
75+
}
76+
}
77+
78+
/**
79+
* A `PointsToExpr` that is an argument of a pointer-type in a `CallToFunctionWithRestrictParameters`
80+
*/
81+
class CallToFunctionWithRestrictParametersArgExpr extends Expr {
82+
int paramIndex;
83+
84+
CallToFunctionWithRestrictParametersArgExpr() {
85+
this = any(CallToFunctionWithRestrictParameters call).getAPtrArg(paramIndex)
86+
}
87+
88+
int getParamIndex() { result = paramIndex }
89+
}
90+
91+
int getStatedValue(Expr e) {
92+
// `upperBound(e)` defaults to `exprMaxVal(e)` when `e` isn't analyzable. So to get a meaningful
93+
// result in this case we pick the minimum value obtainable from dataflow and range analysis.
94+
result =
95+
upperBound(e)
96+
.minimum(min(Expr source | DataFlow::localExprFlow(source, e) | source.getValue().toInt()))
97+
}
98+
99+
int getPointerArithmeticOperandStatedValue(CallToFunctionWithRestrictParametersArgExpr expr) {
100+
result = getStatedValue(expr.(PointerArithmeticExpr).getOperand())
101+
or
102+
// edge-case: &(array[index]) expressions
103+
result = getStatedValue(expr.(AddressOfExpr).getOperand().(PointerArithmeticExpr).getOperand())
104+
or
105+
// fall-back if `expr` is not a pointer arithmetic expression
106+
not expr instanceof PointerArithmeticExpr and
107+
not expr.(AddressOfExpr).getOperand() instanceof PointerArithmeticExpr and
108+
result = 0
109+
}
110+
111+
module PointerValueToRestrictArgConfig implements DataFlow::ConfigSig {
112+
predicate isSource(DataFlow::Node source) { pointerValue(source.asExpr()) }
113+
114+
predicate isSink(DataFlow::Node sink) {
115+
exists(CallToFunctionWithRestrictParameters call |
116+
sink.asExpr() = call.getAPtrArg(_).getAChild*()
117+
)
118+
}
119+
120+
predicate isBarrierIn(DataFlow::Node node) {
121+
exists(AddressOfExpr a | node.asExpr() = a.getOperand().getAChild*())
122+
}
123+
}
124+
125+
module PointerValueToRestrictArgFlow = DataFlow::Global<PointerValueToRestrictArgConfig>;
126+
127+
abstract class DoNotPassAliasedPointerToRestrictQualifiedParam_SharedSharedQuery extends Query { }
10128

11129
Query getQuery() {
12-
result instanceof DoNotPassAliasedPointerToRestrictQualifiedParamSharedSharedQuery
130+
result instanceof DoNotPassAliasedPointerToRestrictQualifiedParam_SharedSharedQuery
13131
}
14132

15-
query predicate problems(Element e, string message) {
16-
not isExcluded(e, getQuery()) and message = "<replace with problem alert message for >"
133+
query predicate problems(
134+
CallToFunctionWithRestrictParameters call, string message,
135+
CallToFunctionWithRestrictParametersArgExpr arg2, string arg2message,
136+
CallToFunctionWithRestrictParametersArgExpr arg1, string arg1message, Expr source1,
137+
string sourceMessage2, Expr source2, string lastMessage2
138+
) {
139+
not isExcluded(call, getQuery()) and
140+
exists(int argOffset1, int argOffset2, string sourceMessage1 |
141+
arg1 = call.getARestrictPtrArg() and
142+
arg2 = call.getAPtrArg(_) and
143+
// enforce ordering to remove permutations if multiple restrict-qualified args exist
144+
(not arg2 = call.getARestrictPtrArg() or arg2.getParamIndex() > arg1.getParamIndex()) and
145+
(
146+
// check if two pointers address the same object
147+
PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1),
148+
DataFlow::exprNode(arg1.getAChild*())) and
149+
(
150+
// one pointer value flows to both args
151+
PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source1),
152+
DataFlow::exprNode(arg2.getAChild*())) and
153+
sourceMessage1 = "$@" and
154+
sourceMessage2 = "source" and
155+
source1 = source2
156+
or
157+
// there are two separate values that flow from an AddressOfExpr of the same target
158+
getAddressOfExprTargetBase(source1) = getAddressOfExprTargetBase(source2) and
159+
PointerValueToRestrictArgFlow::flow(DataFlow::exprNode(source2),
160+
DataFlow::exprNode(arg2.getAChild*())) and
161+
sourceMessage1 = "a pair of address-of expressions ($@, $@)" and
162+
sourceMessage2 = "addressof1" and
163+
not source1 = source2
164+
)
165+
) and
166+
// get the offset of the pointer arithmetic operand (or '0' if there is none)
167+
argOffset1 = getPointerArithmeticOperandStatedValue(arg1) and
168+
argOffset2 = getPointerArithmeticOperandStatedValue(arg2) and
169+
(
170+
// case 1: the pointer args are the same.
171+
// (definite aliasing)
172+
argOffset1 = argOffset2
173+
or
174+
// case 2: the pointer args are different, a size arg exists,
175+
// and the size arg is greater than the difference between the offsets.
176+
// (potential aliasing)
177+
exists(Expr sizeArg |
178+
sizeArg = call.getAPossibleSizeArg() and
179+
getStatedValue(sizeArg) > (argOffset1 - argOffset2).abs()
180+
)
181+
or
182+
// case 3: the pointer args are different, and a size arg does not exist
183+
// (potential aliasing)
184+
not exists(call.getAPossibleSizeArg())
185+
) and
186+
lastMessage2 = "addressof2" and
187+
arg2message = "aliased pointer" and
188+
arg1message = "restrict-qualified parameter" and
189+
message =
190+
"Call to '" + call.getTarget().getName() +
191+
"' passes an $@ to a $@ (pointer value derived from " + sourceMessage1 + "."
192+
)
17193
}

0 commit comments

Comments
 (0)