Skip to content

Commit e53f35d

Browse files
committed
Python: Port UnusedExceptionObject.ql
Depending on whether other queries depend on this, we may end up moving the exception utility functions to a more central location.
1 parent d8d26d1 commit e53f35d

File tree

1 file changed

+42
-4
lines changed

1 file changed

+42
-4
lines changed

python/ql/src/Statements/UnusedExceptionObject.ql

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,49 @@
1212
*/
1313

1414
import python
15-
private import LegacyPointsTo
15+
private import semmle.python.dataflow.new.internal.DataFlowDispatch
16+
private import semmle.python.dataflow.new.internal.Builtins
17+
private import semmle.python.ApiGraphs
1618

17-
from Call call, ClassValue ex
19+
/**
20+
* Holds if `cls` is a user-defined exception class, i.e. it transitively
21+
* extends one of the builtin exception base classes.
22+
*/
23+
predicate isUserDefinedExceptionClass(Class cls) {
24+
cls.getABase() =
25+
API::builtin(["BaseException", "Exception"]).getAValueReachableFromSource().asExpr()
26+
or
27+
isUserDefinedExceptionClass(getADirectSuperclass(cls))
28+
}
29+
30+
/**
31+
* Gets the name of a builtin exception class.
32+
*/
33+
string getBuiltinExceptionName() {
34+
result = Builtins::getBuiltinName() and
35+
(
36+
result.matches("%Error") or
37+
result.matches("%Exception") or
38+
result.matches("%Warning") or
39+
result =
40+
["GeneratorExit", "KeyboardInterrupt", "StopIteration", "StopAsyncIteration", "SystemExit"]
41+
)
42+
}
43+
44+
/**
45+
* Holds if `call` is an instantiation of an exception class.
46+
*/
47+
predicate isExceptionInstantiation(Call call) {
48+
exists(Class cls |
49+
classTracker(cls).asExpr() = call.getFunc() and
50+
isUserDefinedExceptionClass(cls)
51+
)
52+
or
53+
call.getFunc() = API::builtin(getBuiltinExceptionName()).getAValueReachableFromSource().asExpr()
54+
}
55+
56+
from Call call
1857
where
19-
call.getFunc().(ExprWithPointsTo).pointsTo(ex) and
20-
ex.getASuperType() = ClassValue::exception() and
58+
isExceptionInstantiation(call) and
2159
exists(ExprStmt s | s.getValue() = call)
2260
select call, "Instantiating an exception, but not raising it, has no effect."

0 commit comments

Comments
 (0)