Skip to content

Commit b7ae38e

Browse files
committed
Add more cases and more vocabularies to reason about them
1 parent c2cbed3 commit b7ae38e

File tree

2 files changed

+337
-37
lines changed

2 files changed

+337
-37
lines changed

cpp/misra/src/rules/RULE-9-5-1/LegacyForStatementsShouldBeSimple.ql

Lines changed: 231 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,235 @@
1818
import cpp
1919
import codingstandards.cpp.misra
2020

21-
from
21+
/**
22+
* A comparison expression that has the minimum qualification as being a valid termination
23+
* condition of a legacy for-loop. It is characterized by a value read from a variable being
24+
* compared to a value, which is supposed to be the loop bound.
25+
*/
26+
class LegacyForLoopCondition extends RelationalOperation {
27+
ForStmt forLoop;
28+
VariableAccess loopCounter;
29+
Expr loopBound;
30+
31+
LegacyForLoopCondition() {
32+
loopCounter = this.getAnOperand() and
33+
loopBound = this.getAnOperand() and
34+
loopCounter.getTarget() = forLoop.getInitialization().(DeclStmt).getADeclaration() and
35+
loopBound != loopCounter
36+
}
37+
38+
VariableAccess getLoopCounter() { result = loopCounter }
39+
40+
Expr getLoopBound() { result = loopBound }
41+
}
42+
43+
/**
44+
* Holds if the given expression is impure and contains an access to the variable, and
45+
* thus may mutate the variable.
46+
*
47+
* Note that this relation over-approximates and might include impure expressions that
48+
* in fact do not mutate the variable.
49+
*/
50+
predicate exprWithVarAccessMaybeImpure(Expr expr, Variable variable) {
51+
exists(VariableAccess varAccess |
52+
expr.mayBeImpure() and
53+
expr.getAChild*() = varAccess and
54+
variable = varAccess.getTarget()
55+
)
56+
}
57+
58+
/**
59+
* Gets the loop step of a legacy for loop.
60+
*
61+
* This predicate assumes the update expression of the given for loop is an add-and-assign
62+
* (`+=`) or sub-and-assign (`-=`) expression, so the update expression that is an increment
63+
* (`++`) or a decrement (`--`) operation should be handled using different means than this
64+
* predicate.
65+
*/
66+
Expr getLoopStepOfForStmt(ForStmt forLoop) {
67+
result = forLoop.getUpdate().(AssignAddExpr).getRValue() or
68+
result = forLoop.getUpdate().(AssignSubExpr).getRValue()
69+
}
70+
71+
/**
72+
* Holds if the given function has as parameter at a given index a pointer to a
73+
* constant value or a reference of a constant value.
74+
*/
75+
predicate functionHasConstPointerOrReferenceParameter(Function function, int index) {
76+
function.getParameter(index).getType().(PointerType).getBaseType().isConst() or
77+
function.getParameter(index).getType().(ReferenceType).getBaseType().isConst()
78+
}
79+
80+
/**
81+
* Holds if the the variable behind a given variable access is taken its address
82+
* in a declaration in either the body of the for-loop or in its update expression.
83+
*
84+
* e.g.1. The loop counter variable `i` in the body is taken its address in the
85+
* declaration of a pointer variable `m`.
86+
* ``` C++
87+
* for (int i = 0; i < k; i += l) {
88+
* int *m = &i;
89+
* }
90+
* ```
91+
* e.g.2. The loop bound variable `k` in the body is taken its address in the
92+
* declaration of a pointer variable `m`.
93+
* ``` C++
94+
* for (int i = j; i < k; i += l) {
95+
* int *m = &k;
96+
* }
97+
* ```
98+
*/
99+
predicate variableAddressTakenInDeclaration(ForStmt forLoop, VariableAccess baseVariableAccess) {
100+
exists(AddressOfExpr addressOfExpr, DeclStmt decl |
101+
decl.getParentStmt+() = forLoop and
102+
decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable().getInitializer().getExpr() =
103+
addressOfExpr and
104+
baseVariableAccess.getTarget() =
105+
forLoop.getCondition().(LegacyForLoopCondition).getLoopBound().(VariableAccess).getTarget()
106+
)
107+
}
108+
109+
/**
110+
* Holds if the the variable behind a given variable access is taken its address
111+
* as an argument of a call in either the body of the for-loop or in its update
112+
* expression.
113+
*
114+
* e.g.1. The loop counter variable `i` in the body is taken its address in the
115+
* declaration of a pointer variable `m`.
116+
* ``` C++
117+
* for (int i = 0; i < k; i += l) {
118+
* g(&i);
119+
* }
120+
* ```
121+
* e.g.2. The loop bound variable `k` in the body is taken its address in the
122+
* declaration of a pointer variable `m`.
123+
* ``` C++
124+
* for (int i = j; i < k; i += l) {
125+
* g(&k);
126+
* }
127+
* ```
128+
*/
129+
predicate variableAddressTakenAsConstArgument(
130+
ForStmt forLoop, VariableAccess baseVariableAccess, Call call
131+
) {
132+
exists(AddressOfExpr addressOfExpr, int index |
133+
call.getParent+() = forLoop.getAChild+() and
134+
call.getArgument(index).getAChild*() = addressOfExpr and
135+
functionHasConstPointerOrReferenceParameter(call.getTarget(), index) and
136+
addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess()
137+
)
138+
}
139+
140+
/**
141+
* Holds if the the variable behind a given variable access is taken its address
142+
* as an argument of a complex expression in either the body of the for-loop or
143+
* in its update expression.
144+
*
145+
* e.g. The loop counter variable `i` in the body and the loop bound variable `k`
146+
* is taken its address in a compound expression.
147+
* ``` C++
148+
* for (int i = 0; i < k; i += l) {
149+
* *(cond ? &i : &k) += 1;
150+
* }
151+
* ```
152+
*/
153+
predicate variableAddressTakenInExpression(ForStmt forLoop, VariableAccess baseVariableAccess) {
154+
exists(AddressOfExpr addressOfExpr |
155+
baseVariableAccess.getParent+() = forLoop.getAChild+() and
156+
addressOfExpr.getParent+() = forLoop.getAChild+() and
157+
addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess()
158+
) and
159+
not exists(Call call | variableAddressTakenAsConstArgument(forLoop, baseVariableAccess, call))
160+
}
161+
162+
from ForStmt forLoop
22163
where
23-
not isExcluded(x, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and
24-
select
164+
not isExcluded(forLoop, StatementsPackage::legacyForStatementsShouldBeSimpleQuery()) and
165+
/* 1. There is a counter variable that is not of an integer type. */
166+
exists(Type type | type = forLoop.getAnIterationVariable().getType() |
167+
not (
168+
type instanceof IntegralType or
169+
type instanceof FixedWidthIntegralType
170+
)
171+
)
172+
or
173+
/*
174+
* 2. The loop condition checks termination without comparing the counter variable and the
175+
* loop bound using a relational operator.
176+
*/
177+
178+
not forLoop.getCondition() instanceof LegacyForLoopCondition
179+
or
180+
/* 3. The loop counter is mutated somewhere other than its update expression. */
181+
exists(Expr mutatingExpr, Variable loopCounter |
182+
mutatingExpr = forLoop.getStmt().getChildStmt().getAChild() and
183+
loopCounter = forLoop.getAnIterationVariable()
184+
|
185+
exprWithVarAccessMaybeImpure(mutatingExpr, loopCounter)
186+
)
187+
or
188+
/* 4. The type size of the loop counter is not greater or equal to that of the loop counter. */
189+
exists(LegacyForLoopCondition forLoopCondition | forLoopCondition = forLoop.getCondition() |
190+
exists(Type loopCounterType, Type loopBoundType |
191+
loopCounterType = forLoopCondition.getLoopCounter().getType() and
192+
loopBoundType = forLoopCondition.getLoopBound().getType()
193+
|
194+
loopCounterType.getSize() < loopBoundType.getSize()
195+
)
196+
)
197+
or
198+
/* 5. The loop bound and the loop step is a variable that is mutated in the for loop. */
199+
exists(Expr mutatingExpr |
200+
(
201+
/* 1. The mutating expression may be in the loop body. */
202+
mutatingExpr = forLoop.getStmt().getChildStmt().getAChild*()
203+
or
204+
/* 2. The mutating expression may be in the loop updating expression. */
205+
mutatingExpr = forLoop.getUpdate().getAChild*()
206+
)
207+
|
208+
/* 5-1. The mutating expression mutates the loop bound. */
209+
exists(LegacyForLoopCondition forLoopCondition, Variable loopBoundVariable |
210+
forLoopCondition = forLoop.getCondition() and
211+
loopBoundVariable = forLoopCondition.getLoopBound().(VariableAccess).getTarget()
212+
|
213+
exprWithVarAccessMaybeImpure(mutatingExpr, loopBoundVariable)
214+
)
215+
or
216+
/* 5-2. The mutating expression mutates the loop step. */
217+
exists(VariableAccess loopStep | loopStep = getLoopStepOfForStmt(forLoop) |
218+
exprWithVarAccessMaybeImpure(mutatingExpr, loopStep.getTarget())
219+
)
220+
)
221+
or
222+
/*
223+
* 6. Any of the loop counter, loop bound, or a loop step is taken as a mutable reference
224+
* or its address to a mutable pointer.
225+
*/
226+
227+
/* 6-1. The loop counter is taken a mutable reference or its address to a mutable pointer. */
228+
variableAddressTakenInDeclaration(forLoop,
229+
forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter())
230+
or
231+
/* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */
232+
none()
233+
or
234+
/* 6-3. The loop step is taken a mutable reference or its address to a mutable pointer. */
235+
none()
236+
select forLoop, "TODO"
237+
238+
private module Notebook {
239+
private predicate test(Function function) {
240+
function.getParameter(_).getType().(PointerType).getBaseType().isConst() or
241+
function.getParameter(_).getType().(ReferenceType).getBaseType().isConst()
242+
}
243+
244+
private predicate test2(Expr expr, string qlClasses) {
245+
expr.getType().isConst() and
246+
qlClasses = expr.getPrimaryQlClasses()
247+
}
248+
249+
private predicate test3(Function function, string qlClasses) {
250+
qlClasses = function.getParameter(_).getType().getAQlClass()
251+
}
252+
}

0 commit comments

Comments
 (0)