Skip to content

Commit 501e8da

Browse files
committed
Rule 15.4: Improve query
* Accurately determine which loops each `break` and `goto` statement breaks out of. - `break` breaks out of the nearest enclosing breakable, which could be a switch. - `goto` depends on the target, and which breakables are shared between both the goto and target. * Add a placeholder location for the break or goto (so that it can be more easily verified). * Include more tests.
1 parent aaa1044 commit 501e8da

File tree

3 files changed

+88
-12
lines changed

3 files changed

+88
-12
lines changed

c/misra/src/rules/RULE-15-4/LoopIterationCondition.ql

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,41 @@
1515
import cpp
1616
import codingstandards.c.misra
1717

18-
from Loop loop
18+
/**
19+
* A breaking statement.
20+
*/
21+
class BreakOrGotoStmt extends JumpStmt {
22+
BreakOrGotoStmt() {
23+
this instanceof BreakStmt or
24+
this instanceof GotoStmt
25+
}
26+
27+
/**
28+
* Gets a loop this breaks out of, if any.
29+
*
30+
* - This can produce no results if this is a `break` and the enclosing breakable is a switch statement.
31+
* - This can produce no result if this is a `goto`, and the target is within the same nearest enclosing loop.
32+
* - This can produce multiple results if this is a `goto`, and the target is outside multiple enclosing loops.
33+
*/
34+
Loop getABrokenLoop() {
35+
result = this.(BreakStmt).getBreakable()
36+
or
37+
exists(GotoStmt goto |
38+
goto = this and
39+
// Find any loop that encloses this goto
40+
result.getChildStmt*() = goto and
41+
// But does not enclose the target of the goto i.e. the goto breaks out of it
42+
not result.getChildStmt*() = goto.getTarget()
43+
)
44+
}
45+
}
46+
47+
from Loop loop, BreakOrGotoStmt breakOrGoto
1948
where
2049
not isExcluded(loop, Statements2Package::loopIterationConditionQuery()) and
21-
count(Stmt terminationStmt |
22-
loop.getChildStmt*() = terminationStmt and
23-
(
24-
terminationStmt instanceof BreakStmt
25-
or
26-
terminationStmt instanceof GotoStmt
27-
)
28-
) > 1
29-
select loop, "$@ statement contains more than one break or goto statement", loop, "Iteration"
50+
// More than one break or goto statement in the loop
51+
count(BreakOrGotoStmt terminationStmt | terminationStmt.getABrokenLoop() = loop) > 1 and
52+
// Report a break or goto statement
53+
breakOrGoto.getABrokenLoop() = loop
54+
select loop, "Iteration statement contains more than one $@.", breakOrGoto,
55+
"break or goto statement"
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
1-
| test.c:24:3:32:3 | for(...;...;...) ... | $@ statement contains more than one break or goto statement | test.c:24:3:32:3 | for(...;...;...) ... | Iteration |
2-
| test.c:38:3:45:3 | while (...) ... | $@ statement contains more than one break or goto statement | test.c:38:3:45:3 | while (...) ... | Iteration |
1+
| test.c:24:3:32:3 | for(...;...;...) ... | Iteration statement contains more than one $@. | test.c:26:7:26:12 | break; | break or goto statement |
2+
| test.c:24:3:32:3 | for(...;...;...) ... | Iteration statement contains more than one $@. | test.c:29:7:29:12 | break; | break or goto statement |
3+
| test.c:24:3:32:3 | for(...;...;...) ... | Iteration statement contains more than one $@. | test.c:31:5:31:12 | goto ... | break or goto statement |
4+
| test.c:38:3:45:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:40:7:40:12 | break; | break or goto statement |
5+
| test.c:38:3:45:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:43:7:43:14 | goto ... | break or goto statement |
6+
| test.c:61:3:72:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:64:7:64:12 | break; | break or goto statement |
7+
| test.c:61:3:72:3 | while (...) ... | Iteration statement contains more than one $@. | test.c:68:7:68:14 | goto ... | break or goto statement |

c/misra/test/rules/RULE-15-4/test.c

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,49 @@ L1:;
4343
goto L1;
4444
}
4545
}
46+
47+
while (k < 10) { // COMPLIANT - the nested goto
48+
// only applies to the nested loop
49+
if (k > 5) {
50+
break;
51+
}
52+
while (k < 3) { // COMPLIANT
53+
break;
54+
}
55+
}
56+
}
57+
58+
void f3(int k) {
59+
L3:
60+
k++;
61+
while (k < 10) { // NON_COMPLIANT - the nested goto
62+
// only applies to the switch
63+
if (k > 5) {
64+
break;
65+
}
66+
switch (k) {
67+
case 1:
68+
goto L3;
69+
case 2:
70+
break;
71+
}
72+
}
73+
}
74+
75+
void f4(int k) {
76+
k++;
77+
while (k < 10) { // COMPLIANT
78+
if (k > 5) {
79+
break;
80+
}
81+
switch (k) {
82+
case 1:
83+
goto L4;
84+
case 2:
85+
k += 1;
86+
L4:
87+
k += 2;
88+
break;
89+
}
90+
}
4691
}

0 commit comments

Comments
 (0)