Skip to content

Commit 584d94c

Browse files
committed
Rule 14.2: Recognise loop counters
* Identify loop counters that are not initialized in the loop * Identify loop counters that are increment/decremented by += or -=
1 parent 23b36b4 commit 584d94c

File tree

2 files changed

+89
-1
lines changed
  • cpp/common/src/codingstandards/cpp
  • c/misra/test/rules/RULE-14-2

2 files changed

+89
-1
lines changed

c/misra/test/rules/RULE-14-2/test.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,8 @@ void f13() {
6666
g1--;
6767
}
6868
}
69+
70+
void f14() {
71+
for (int i = 0; i < 10; i += 3) { // COMPLIANT
72+
}
73+
}

cpp/common/src/codingstandards/cpp/Loops.qll

Lines changed: 84 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,88 @@
55
import cpp
66
import Operator
77

8+
// ******* COPIED FROM semmle.code.cpp.Iteration ******* //
9+
/**
10+
* Holds if `child` is in the condition `forCondition` of a 'for'
11+
* statement.
12+
*
13+
* For example, if a program includes
14+
* ```
15+
* for (i = 0; i < 10; i++) { j++; }
16+
* ```
17+
* then this predicate will hold with `forCondition` as `i < 10`,
18+
* and `child` as any of `i`, `10` and `i < 10`.
19+
*/
20+
pragma[noopt]
21+
private predicate inForCondition(Expr forCondition, Expr child) {
22+
exists(ForStmt for |
23+
forCondition = for.getCondition() and
24+
child = forCondition and
25+
for instanceof ForStmt
26+
)
27+
or
28+
exists(Expr mid |
29+
inForCondition(forCondition, mid) and
30+
child.getParent() = mid
31+
)
32+
}
33+
34+
// ******* COPIED FROM semmle.code.cpp.Iteration ******* //
35+
/**
36+
* Holds if `child` is in the update `forUpdate` of a 'for' statement.
37+
*
38+
* For example, if a program includes
39+
* ```
40+
* for (i = 0; i < 10; i += 1) { j++; }
41+
* ```
42+
* then this predicate will hold with `forUpdate` as `i += 1`,
43+
* and `child` as any of `i`, `1` and `i += 1`.
44+
*/
45+
pragma[noopt]
46+
private predicate inForUpdate(Expr forUpdate, Expr child) {
47+
exists(ForStmt for | forUpdate = for.getUpdate() and child = forUpdate)
48+
or
49+
exists(Expr mid | inForUpdate(forUpdate, mid) and child.getParent() = mid)
50+
}
51+
52+
/**
53+
* Gets a LoopCounter for the given `ForStmt`.
54+
*
55+
* Equivalent to ForStmt.getAnIterationVariable(), but handles += and -= as well.
56+
*/
57+
pragma[noopt]
58+
Variable getALoopCounter(ForStmt fs) {
59+
// check that it is assigned to, incremented or decremented in the update
60+
exists(Expr updateOpRoot, Expr updateOp |
61+
updateOpRoot = fs.getUpdate() and
62+
inForUpdate(updateOpRoot, updateOp)
63+
|
64+
exists(CrementOperation op, VariableAccess va |
65+
op = updateOp and
66+
op instanceof CrementOperation and
67+
op.getOperand() = va and
68+
va = result.getAnAccess()
69+
)
70+
or
71+
exists(AssignArithmeticOperation op, VariableAccess va |
72+
op = updateOp and
73+
op instanceof AssignArithmeticOperation and
74+
op.getOperator() = ["+=", "-="] and
75+
op.getLValue() = va and
76+
va = result.getAnAccess()
77+
)
78+
or
79+
updateOp = result.getAnAssignedValue()
80+
) and
81+
result instanceof Variable and
82+
// checked or used in the condition
83+
exists(Expr e, VariableAccess va |
84+
va = result.getAnAccess() and
85+
inForCondition(e, va) and
86+
e = fs.getCondition()
87+
)
88+
}
89+
890
/**
991
* Gets an iteration variable as identified by the initialization statement for the loop.
1092
*/
@@ -148,7 +230,8 @@ predicate isLoopControlVarModifiedInLoopExpr(
148230
ForStmt forLoop, LoopControlVariable loopControlVariable, VariableAccess loopControlVariableAccess
149231
) {
150232
loopControlVariableAccess = loopControlVariable.getVariableAccessInLoop(forLoop) and
151-
not loopControlVariable = getAnIterationVariable(forLoop) and
233+
// Not a standard loop counter for this loop
234+
not loopControlVariable = getALoopCounter(forLoop) and
152235
loopControlVariableAccess = forLoop.getUpdate().getAChild() and
153236
(
154237
loopControlVariableAccess.isModified() or

0 commit comments

Comments
 (0)