Skip to content

Commit 01e3276

Browse files
committed
Finish first draft
1 parent 49bdc07 commit 01e3276

File tree

1 file changed

+165
-41
lines changed

1 file changed

+165
-41
lines changed

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

Lines changed: 165 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import codingstandards.cpp.misra
2424
* compared to a value, which is supposed to be the loop bound.
2525
*/
2626
class LegacyForLoopCondition extends RelationalOperation {
27+
/**
28+
* The legacy for-loop this relational operation is a condition of.
29+
*/
2730
ForStmt forLoop;
2831
VariableAccess loopCounter;
2932
Expr loopBound;
@@ -35,8 +38,14 @@ class LegacyForLoopCondition extends RelationalOperation {
3538
loopBound != loopCounter
3639
}
3740

41+
/**
42+
* Gets the variable access to the loop counter variable, embedded in this loop condition.
43+
*/
3844
VariableAccess getLoopCounter() { result = loopCounter }
3945

46+
/**
47+
* Gets the variable access to the loop bound variable, embedded in this loop condition.
48+
*/
4049
Expr getLoopBound() { result = loopBound }
4150
}
4251

@@ -69,17 +78,16 @@ Expr getLoopStepOfForStmt(ForStmt forLoop) {
6978
}
7079

7180
/**
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.
81+
* Holds if the given function has as parameter a pointer to a constant
82+
* value, at a given index.
7483
*/
75-
private predicate functionHasConstPointerOrReferenceParameter(Function function, int index) {
76-
function.getParameter(index).getType().(PointerType).getBaseType().isConst() or
77-
function.getParameter(index).getType().(ReferenceType).getBaseType().isConst()
84+
private predicate functionHasConstPointerParameter(Function function, int index) {
85+
function.getParameter(index).getType().(PointerType).getBaseType().isConst()
7886
}
7987

8088
/**
81-
* Holds if the the variable behind a given variable access is taken its address
82-
* in a non-const variable declaration, in the body of the for-loop.
89+
* Holds if the variable behind a given variable access is taken its address in
90+
* a non-const variable declaration, in the body of the for-loop.
8391
*
8492
* e.g.1. The loop counter variable `i` in the body is taken its address in the
8593
* declaration of a pointer variable `m`.
@@ -115,22 +123,26 @@ predicate variableAddressTakenInNonConstDeclaration(
115123
}
116124

117125
/**
118-
* Holds if the the variable behind a given variable access is taken its address
126+
* Holds if the variable behind a given variable access is taken its address
119127
* as an argument of a call in either the body of the for-loop or in its update
120128
* expression.
121129
*
122-
* e.g.1. The loop counter variable `i` in the body is taken its address in the
123-
* declaration of a pointer variable `m`.
130+
* e.g.1. The address of the loop counter variable `i` is passed as argument
131+
* to the call to `g`.
124132
* ``` C++
133+
* void g1(int *x);
134+
*
125135
* for (int i = 0; i < k; i += l) {
126-
* g(&i);
136+
* g1(&i);
127137
* }
128138
* ```
129-
* e.g.2. The loop bound variable `k` in the body is taken its address in the
130-
* declaration of a pointer variable `m`.
139+
* e.g.2. The address of the loop counter variable `k` is passed as argument
140+
* to the call to `g`.
131141
* ``` C++
142+
* void g1(int *x);
143+
*
132144
* for (int i = j; i < k; i += l) {
133-
* g(&k);
145+
* g1(&k);
134146
* }
135147
* ```
136148
*/
@@ -140,32 +152,119 @@ private predicate variableAddressTakenAsConstArgument(
140152
exists(AddressOfExpr addressOfExpr, int index |
141153
call.getParent+() = forLoop.getAChild+() and // TODO: Bad
142154
call.getArgument(index).getAChild*() = addressOfExpr and
143-
functionHasConstPointerOrReferenceParameter(call.getTarget(), index) and
155+
exists(PointerType parameterType |
156+
parameterType = call.getTarget().getParameter(index).getType() and
157+
not parameterType.getBaseType().isConst()
158+
) and
144159
addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess() and
145160
baseVariableAccess.getParent+() = forLoop
146161
)
147162
}
148163

149164
/**
150-
* Holds if the the variable behind a given variable access is taken its address
165+
* Holds if the variable behind a given variable access is taken its address
151166
* as an argument of a complex expression in either the body of the for-loop or
152167
* in its update expression.
153168
*
154-
* e.g. The loop counter variable `i` in the body and the loop bound variable `k`
169+
* e.g.1. The loop counter variable `i` in the body and the loop bound variable `k`
170+
* is taken its address in a call.
171+
* ``` C++
172+
* void g1(int *x);
173+
*
174+
* for (int i = j; i < k; i += l) {
175+
* g1(&i);
176+
* }
177+
* ```
178+
* e.g.2. The loop counter variable `i` in the body and the loop bound variable `k`
155179
* is taken its address in a compound expression.
156180
* ``` C++
157181
* for (int i = 0; i < k; i += l) {
158182
* *(cond ? &i : &k) += 1;
159183
* }
160184
* ```
161185
*/
186+
/* TODO: Do we need to use Expr.getUnderlyingType() to ensure that the expression is non-const? */
162187
predicate variableAddressTakenInExpression(ForStmt forLoop, VariableAccess baseVariableAccess) {
163188
exists(AddressOfExpr addressOfExpr |
164189
baseVariableAccess.getParent+() = forLoop.getAChild+() and // TODO: Bad
165190
addressOfExpr.getParent+() = forLoop.getAChild+() and
166191
addressOfExpr.getOperand() = baseVariableAccess.getTarget().getAnAccess()
167-
) and
168-
not variableAddressTakenAsConstArgument(forLoop, baseVariableAccess.getTarget().getAnAccess(), _)
192+
)
193+
}
194+
195+
/**
196+
* Holds if the variable behind a given variable access is taken its reference
197+
* in a non-const variable declaration, in the body of the for-loop.
198+
*
199+
* e.g.1. The loop counter variable `i` in the body is taken its reference in
200+
* the declaration of a variable `m`.
201+
* ``` C++
202+
* for (int i = j; i < k; i += l) {
203+
* int &m = i;
204+
* }
205+
* ```
206+
* e.g.2. The loop bound variable `k` in the body is taken its reference in the
207+
* declaration of a variable `m`.
208+
* ``` C++
209+
* for (int i = j; i < k; i += l) {
210+
* int &m = k;
211+
* }
212+
* ```
213+
*/
214+
predicate variableReferenceTakenInNonConstDeclaration(
215+
ForStmt forLoop, VariableAccess baseVariableAccess
216+
) {
217+
exists(DeclStmt decl, Variable definedVariable, ReferenceType definedVariableType |
218+
decl.getParentStmt+() = forLoop and
219+
not decl = forLoop.getInitialization() and // Exclude the for-loop counter initialization.
220+
definedVariable = decl.getADeclarationEntry().(VariableDeclarationEntry).getVariable() and
221+
definedVariable.getInitializer().getExpr() = baseVariableAccess and
222+
definedVariableType = definedVariable.getType() and
223+
not definedVariableType.getBaseType().isConst()
224+
)
225+
}
226+
227+
/**
228+
* Holds if the variable behind a given variable access is taken its reference
229+
* as an argument of a call in either the body of the for-loop or in its update
230+
* expression.
231+
*
232+
* e.g.1. The loop counter variable `i` in the body is passed by reference to the
233+
* call to `f1`.
234+
* ``` C++
235+
* void f1(int &x);
236+
*
237+
* for (int i = j; i < k; i += l) {
238+
* f1(i);
239+
* }
240+
* ```
241+
* e.g.2. The loop bound variable `k` in the body is passed by reference to the
242+
* call to `f1`.
243+
* ``` C++
244+
* void f1(int &x);
245+
*
246+
* for (int i = j; i < k; i += l) {
247+
* f1(k);
248+
* }
249+
* ```
250+
*/
251+
private predicate variableReferenceTakenAsNonConstArgument(
252+
ForStmt forLoop, VariableAccess baseVariableAccess, Call call
253+
) {
254+
exists(int index |
255+
call.getParent+() = forLoop.getAChild+() and
256+
call.getArgument(index).getAChild*() = baseVariableAccess.getTarget().getAnAccess() and
257+
/*
258+
* The given function has as parameter a reference of a constant
259+
* value, at a given index.
260+
*/
261+
262+
exists(ReferenceType parameterType |
263+
parameterType = call.getTarget().getParameter(index).getType() and
264+
not parameterType.getBaseType().isConst()
265+
) and
266+
baseVariableAccess.getParent+() = forLoop
267+
)
169268
}
170269

171270
from ForStmt forLoop
@@ -237,34 +336,59 @@ where
237336
exists(VariableAccess loopCounterAccessInCondition |
238337
loopCounterAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopCounter()
239338
|
240-
exists(VariableAccess loopCounterAccessTakenAddress |
241-
loopCounterAccessInCondition.getTarget() = loopCounterAccessTakenAddress.getTarget()
339+
exists(VariableAccess loopCounterAccessTakenAddressOrReference |
340+
loopCounterAccessInCondition.getTarget() =
341+
loopCounterAccessTakenAddressOrReference.getTarget()
242342
|
243-
variableAddressTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddress)
343+
variableAddressTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference)
344+
or
345+
variableAddressTakenInExpression(forLoop, loopCounterAccessTakenAddressOrReference) and
346+
not variableAddressTakenAsConstArgument(forLoop,
347+
loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _)
348+
or
349+
variableReferenceTakenInNonConstDeclaration(forLoop, loopCounterAccessTakenAddressOrReference)
244350
or
245-
variableAddressTakenInExpression(forLoop, loopCounterAccessTakenAddress)
351+
variableReferenceTakenAsNonConstArgument(forLoop,
352+
loopCounterAccessTakenAddressOrReference.getTarget().getAnAccess(), _)
246353
)
247354
)
248355
or
249356
/* 6-2. The loop bound is taken a mutable reference or its address to a mutable pointer. */
250-
none()
357+
exists(VariableAccess loopBoundAccessInCondition |
358+
loopBoundAccessInCondition = forLoop.getCondition().(LegacyForLoopCondition).getLoopBound()
359+
|
360+
exists(VariableAccess loopBoundAccessTakenAddressOrReference |
361+
loopBoundAccessInCondition.getTarget() = loopBoundAccessTakenAddressOrReference.getTarget()
362+
|
363+
variableAddressTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference)
364+
or
365+
variableAddressTakenInExpression(forLoop, loopBoundAccessTakenAddressOrReference) and
366+
not variableAddressTakenAsConstArgument(forLoop,
367+
loopBoundAccessTakenAddressOrReference.getTarget().getAnAccess(), _)
368+
or
369+
variableReferenceTakenInNonConstDeclaration(forLoop, loopBoundAccessTakenAddressOrReference)
370+
or
371+
variableReferenceTakenAsNonConstArgument(forLoop, loopBoundAccessTakenAddressOrReference, _)
372+
)
373+
)
251374
or
252375
/* 6-3. The loop step is taken a mutable reference or its address to a mutable pointer. */
253-
none()
376+
exists(VariableAccess loopStepAccessInCondition |
377+
loopStepAccessInCondition = getLoopStepOfForStmt(forLoop)
378+
|
379+
exists(VariableAccess loopStepAccessTakenAddressOrReference |
380+
loopStepAccessInCondition.getTarget() = loopStepAccessTakenAddressOrReference.getTarget()
381+
|
382+
variableAddressTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference)
383+
or
384+
variableAddressTakenInExpression(forLoop, loopStepAccessTakenAddressOrReference) and
385+
not variableAddressTakenAsConstArgument(forLoop,
386+
loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _)
387+
or
388+
variableReferenceTakenInNonConstDeclaration(forLoop, loopStepAccessTakenAddressOrReference)
389+
or
390+
variableReferenceTakenAsNonConstArgument(forLoop,
391+
loopStepAccessTakenAddressOrReference.getTarget().getAnAccess(), _)
392+
)
393+
)
254394
select forLoop, "TODO"
255-
256-
private module Notebook {
257-
private predicate test(Function function) {
258-
function.getParameter(_).getType().(PointerType).getBaseType().isConst() or
259-
function.getParameter(_).getType().(ReferenceType).getBaseType().isConst()
260-
}
261-
262-
private predicate test2(Expr expr, string qlClasses) {
263-
expr.getType().isConst() and
264-
qlClasses = expr.getPrimaryQlClasses()
265-
}
266-
267-
private predicate test3(Function function, string qlClasses) {
268-
qlClasses = function.getParameter(_).getType().getAQlClass()
269-
}
270-
}

0 commit comments

Comments
 (0)