Skip to content

Commit 016c95a

Browse files
authored
Merge pull request #2078 from taus-semmle/python-unreachable-suppressed
Python: Teach `py/unreachable-statement` about `contextlib.suppress`.
2 parents 82ca45f + b2f7b09 commit 016c95a

File tree

5 files changed

+57
-0
lines changed

5 files changed

+57
-0
lines changed

change-notes/1.23/analysis-python.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,11 @@
1212
| Clear-text logging of sensitive information (`py/clear-text-logging-sensitive-data`) | security, external/cwe/cwe-312 | Finds instances where sensitive information is logged without encryption or hashing. Results are shown on LGTM by default. |
1313
| Clear-text storage of sensitive information (`py/clear-text-storage-sensitive-data`) | security, external/cwe/cwe-312 | Finds instances where sensitive information is stored without encryption or hashing. Results are shown on LGTM by default. |
1414
| Binding a socket to all network interfaces (`py/bind-socket-all-network-interfaces`) | security | Finds instances where a socket is bound to all network interfaces. Results are shown on LGTM by default. |
15+
16+
17+
## Changes to existing queries
18+
19+
| **Query** | **Expected impact** | **Change** |
20+
|----------------------------|------------------------|------------|
21+
| Unreachable code | Fewer false positives | Analysis now accounts for uses of `contextlib.suppress` to suppress exceptions. |
22+

python/ql/src/Statements/UnreachableCode.ql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,18 @@ predicate unique_yield(Stmt s) {
3131
)
3232
}
3333

34+
/** Holds if `contextlib.suppress` may be used in the same scope as `s` */
35+
predicate suppression_in_scope(Stmt s) {
36+
exists(With w |
37+
w.getContextExpr().(Call).getFunc().pointsTo(Value::named("contextlib.suppress")) and
38+
w.getScope() = s.getScope()
39+
)
40+
}
41+
3442
predicate reportable_unreachable(Stmt s) {
3543
s.isUnreachable() and
3644
not typing_import(s) and
45+
not suppression_in_scope(s) and
3746
not exists(Stmt other | other.isUnreachable() |
3847
other.contains(s)
3948
or

python/ql/test/3/query-tests/Statements/unreachable_suppressed/UnreachableCode.expected

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Statements/UnreachableCode.ql
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from contextlib import suppress
2+
3+
def raises_exception():
4+
raise Exception("This will be suppressed")
5+
6+
def foo():
7+
test = False
8+
with suppress(Exception):
9+
raises_exception()
10+
test = True
11+
if test:
12+
return
13+
print("An exception was raised") # FP: not reached
14+
15+
foo()
16+
17+
def bar(x):
18+
test = False
19+
try:
20+
if x:
21+
raise Exception("Bar")
22+
test = True
23+
except Exception:
24+
pass
25+
if test:
26+
print("Test was set")
27+
return
28+
print("Test was not set")
29+
30+
bar(True)
31+
bar(False)
32+
33+
# False negative
34+
35+
def fn_suppression():
36+
with suppress(Exception):
37+
raise Exception()
38+
return False
39+
return True

0 commit comments

Comments
 (0)