Skip to content

Commit 1f390f2

Browse files
Merge pull request #326 from rdmarsh2/rdmarsh/cpp/dead-code-goto
C++: new query for dead code after goto or break
2 parents b1a463b + 7bcc437 commit 1f390f2

File tree

7 files changed

+158
-2
lines changed

7 files changed

+158
-2
lines changed

change-notes/1.19/analysis-cpp.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
| **Query** | **Tags** | **Purpose** |
88
|-----------------------------|-----------|--------------------------------------------------------------------|
9-
| Cast between HRESULT and a Boolean type (`cpp/hresult-boolean-conversion`) | external/cwe/cwe-253 | Finds logic errors caused by mistakenly treating the Windows `HRESULT` type as a Boolean instead of testing it with the appropriate macros. Enabled by default. |
9+
| Cast between `HRESULT` and a Boolean type (`cpp/hresult-boolean-conversion`) | external/cwe/cwe-253 | Finds logic errors caused by mistakenly treating the Windows `HRESULT` type as a Boolean instead of testing it with the appropriate macros. Enabled by default. |
1010
| Setting a DACL to `NULL` in a `SECURITY_DESCRIPTOR` (`cpp/unsafe-dacl-security-descriptor`) | external/cwe/cwe-732 | This query finds code that creates world-writable objects on Windows by setting their DACL to `NULL`. Enabled by default. |
11-
| Cast from char* to wchar_t* | security, external/cwe/cwe-704 | Detects potentially dangerous casts from char* to wchar_t*. Enabled by default on LGTM. |
11+
| Cast from `char*` to `wchar_t*` | security, external/cwe/cwe-704 | Detects potentially dangerous casts from `char*` to `wchar_t*`. Enabled by default on LGTM. |
12+
| Dead code due to `goto` or `break` statement (`cpp/dead-code-goto`) | maintainability, external/cwe/cwe-561 | Detects dead code following a goto or break statement. Enabled by default on LGTM. |
1213

1314
## Changes to existing queries
1415

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
goto err1;
2+
free(pointer); // BAD: this line is unreachable
3+
err1: return -1;
4+
5+
free(pointer); // GOOD: this line is reachable
6+
goto err2;
7+
err2: return -1;
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
7+
<overview>
8+
<p>
9+
Code immediately following a <code>goto</code> or <code>break</code> statement will not be executed,
10+
unless there is a label or switch case. When the code is necessary, this leads to logical errors or
11+
resource leaks. If the code is unnecessary, it may confuse readers.
12+
</p>
13+
</overview>
14+
<recommendation>
15+
<p>
16+
If the unreachable code is necessary, move the <code>goto</code> or <code>break</code> statement to
17+
after the code. Otherwise, delete the unreachable code.
18+
</p>
19+
20+
</recommendation>
21+
<example><sample src="DeadCodeGoto.cpp" />
22+
</example>
23+
<references>
24+
<li>
25+
The CERT C Secure Coding Standard: <a href="https://wiki.sei.cmu.edu/confluence/display/c/MSC12-C.+Detect+and+remove+code+that+has+no+effect+or+is+never+executed">MSC12-C. Detect and remove code that has no effect or is never executed</a>.
26+
</li>
27+
</references>
28+
</qhelp>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/**
2+
* @name Dead code due to goto or break statement
3+
* @description A goto or break statement is followed by unreachable code.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @precision high
7+
* @id cpp/dead-code-goto
8+
* @tags maintainability
9+
* external/cwe/cwe-561
10+
*/
11+
12+
import cpp
13+
14+
Stmt getNextRealStmt(Block b, int i) {
15+
result = b.getStmt(i + 1) and
16+
not result instanceof EmptyStmt
17+
or
18+
b.getStmt(i + 1) instanceof EmptyStmt and
19+
result = getNextRealStmt(b, i + 1)
20+
}
21+
22+
from JumpStmt js, Block b, int i, Stmt s
23+
where b.getStmt(i) = js
24+
and s = getNextRealStmt(b, i)
25+
// the next statement isn't jumped to
26+
and not s instanceof LabelStmt
27+
and not s instanceof SwitchCase
28+
// the next statement isn't breaking out of a switch
29+
and not s.(BreakStmt).getBreakable() instanceof SwitchStmt
30+
// the next statement isn't a loop that can be jumped into
31+
and not exists (LabelStmt ls | s.(Loop).getStmt().getAChild*() = ls)
32+
and not exists (SwitchCase sc | s.(Loop).getStmt().getAChild*() = sc)
33+
select js, "This statement makes $@ unreachable.", s, s.toString()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| test.cpp:2:2:2:12 | goto ... | This statement makes $@ unreachable. | test.cpp:3:2:3:5 | ExprStmt | ExprStmt |
2+
| test.cpp:9:3:9:8 | break; | This statement makes $@ unreachable. | test.cpp:10:3:10:6 | ExprStmt | ExprStmt |
3+
| test.cpp:37:3:37:8 | break; | This statement makes $@ unreachable. | test.cpp:38:3:38:11 | return ... | return ... |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Critical/DeadCodeGoto.ql
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
int test1(int x) {
2+
goto label; // BAD
3+
x++;
4+
label: return x;
5+
}
6+
7+
int test2(int x) {
8+
do {
9+
break; // BAD
10+
x++;
11+
} while(false);
12+
return x;
13+
}
14+
15+
int test3(int x) {
16+
goto label; // GOOD
17+
label: x++;
18+
return x;
19+
}
20+
21+
int test4(int x) {
22+
goto label; // GOOD
23+
do {
24+
label: x++;
25+
} while(false);
26+
return x;
27+
}
28+
29+
int test5(int x, int y) {
30+
switch(y) {
31+
case 0:
32+
break; // GOOD
33+
case 1:
34+
goto label; // GOOD
35+
break;
36+
case 2:
37+
break; // BAD
38+
return x;
39+
case 3:
40+
return x;
41+
break; // GOOD
42+
case 4:
43+
goto label; // GOOD
44+
case 5:
45+
goto label;; // GOOD
46+
default:
47+
x++;
48+
}
49+
label:
50+
return x;
51+
}
52+
53+
void test6(int x, int cond) {
54+
if (cond) {
55+
x++;
56+
} else goto end; // GOOD
57+
x++;
58+
end:
59+
}
60+
61+
void test7(int x, int cond) {
62+
if (cond)
63+
{
64+
goto target;
65+
}
66+
goto somewhere_else; // GOOD
67+
while (x < 10) // not dead code
68+
{
69+
target:
70+
x++;
71+
}
72+
somewhere_else:
73+
switch (1)
74+
{
75+
goto end;
76+
while (x < 10) // not dead code
77+
{
78+
case 1:
79+
x++;
80+
} break;
81+
}
82+
end:
83+
}

0 commit comments

Comments
 (0)