Skip to content

Commit 0580587

Browse files
authored
Merge pull request #22679 from owen-mc/go/fix/unreachable-statement-allowlist
Go: fix some duplicate results in go/unreachable-statement
2 parents 1dc8dbc + e5fc419 commit 0580587

4 files changed

Lines changed: 57 additions & 8 deletions

File tree

‎go/ql/src/RedundantCode/UnreachableStatement.ql‎

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ Stmt getPreviousStmt(Stmt s) {
3737
*/
3838
predicate firstUnreachableStmt(Stmt s) {
3939
not isReachable(s) and
40-
not s instanceof EmptyStmt and
4140
(
4241
// a statement whose preceding statement in the same list is reachable
4342
isReachable(getPreviousStmt(s))
@@ -47,6 +46,16 @@ predicate firstUnreachableStmt(Stmt s) {
4746
)
4847
}
4948

49+
/** Holds if `s` is in a run of unreachable statements following a constant condition. */
50+
predicate isInUnreachableRunAfterConstantCondition(Stmt s) {
51+
not isReachable(s) and
52+
(
53+
exists(getPreviousStmt(s).(IfStmt).getCondition().getBoolValue())
54+
or
55+
isInUnreachableRunAfterConstantCondition(getPreviousStmt(s))
56+
)
57+
}
58+
5059
/**
5160
* Matches if `retval` is a constant or a struct composed wholly of constants.
5261
*/
@@ -78,6 +87,8 @@ predicate isAllowedReturnValue(Expr retval) {
7887
* Matches if `s` is an allowed unreachable statement.
7988
*/
8089
predicate allowlist(Stmt s) {
90+
s instanceof EmptyStmt
91+
or
8192
// `panic("unreachable")` and similar
8293
exists(CallExpr ce | ce = s.(ExprStmt).getExpr() or ce = s.(ReturnStmt).getExpr() |
8394
ce.getTarget().mustPanic() or ce.getCalleeName().toLowerCase() = "error"
@@ -87,14 +98,28 @@ predicate allowlist(Stmt s) {
8798
exists(ReturnStmt ret | ret = s |
8899
forall(Expr retval | retval = ret.getAnExpr() | isAllowedReturnValue(retval))
89100
)
90-
or
91-
// statements deliberately made unreachable by a constant condition, such as the code
92-
// following `if true { return }`
93-
exists(getPreviousStmt(s).(IfStmt).getCondition().getBoolValue())
101+
}
102+
103+
Stmt firstNonAllowlisted(Stmt s) {
104+
not isReachable(s) and
105+
(
106+
not allowlist(s) and result = s
107+
or
108+
allowlist(s) and
109+
exists(Stmt next | getPreviousStmt(next) = s | result = firstNonAllowlisted(next))
110+
)
111+
}
112+
113+
/** Holds if `s` is the first non-allowlisted statement in a run of unreachable statements. */
114+
predicate firstNonAllowlistedUnreachableStmt(Stmt s) {
115+
exists(Stmt unreachable |
116+
firstUnreachableStmt(unreachable) and
117+
s = firstNonAllowlisted(unreachable)
118+
)
94119
}
95120

96121
from Stmt s
97122
where
98-
firstUnreachableStmt(s) and
99-
not allowlist(s)
123+
firstNonAllowlistedUnreachableStmt(s) and
124+
not isInUnreachableRunAfterConstantCondition(s)
100125
select s, "This statement is unreachable."

‎go/ql/test/query-tests/RedundantCode/UnreachableStatement/CONSISTENCY/CfgConsistency.expected‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
consistencyOverview
2-
| deadEnd | 10 |
2+
| deadEnd | 11 |
33
deadEnd
44
| main.go:17:2:17:10 | select statement |
55
| main.go:109:2:109:10 | select statement |
@@ -11,3 +11,4 @@ deadEnd
1111
| main.go:151:2:151:10 | select statement |
1212
| main.go:157:2:157:10 | select statement |
1313
| main.go:164:2:164:10 | select statement |
14+
| main.go:168:2:168:10 | select statement |

‎go/ql/test/query-tests/RedundantCode/UnreachableStatement/UnreachableStatement.expected‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@
1010
| main.go:147:2:147:17 | return statement | This statement is unreachable. |
1111
| main.go:153:2:153:22 | return statement | This statement is unreachable. |
1212
| main.go:159:2:159:43 | return statement | This statement is unreachable. |
13+
| main.go:171:2:171:14 | expression statement | This statement is unreachable. |

‎go/ql/test/query-tests/RedundantCode/UnreachableStatement/main.go‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,26 @@ func test20() {
164164
select {} // OK: reachable after starting the goroutine
165165
}
166166

167+
func test21() {
168+
select {}
169+
panic("unreachable") // OK: allowlisted statement
170+
// OK: empty statement
171+
unreachable() // $ Alert
172+
}
173+
174+
func test22() {
175+
goto reachableLabel
176+
panic("unreachable") // OK: allowlisted statement
177+
reachableLabel:
178+
reachable() // OK: reachable through the goto
179+
}
180+
181+
func test23() {
182+
if true {
183+
return
184+
}
185+
unreachable() // OK: deliberately unreachable
186+
unreachable() // OK: deliberately unreachable
187+
}
188+
167189
func main() {}

0 commit comments

Comments
 (0)