Skip to content

Commit 4606d90

Browse files
committed
Python: Extend ExceptionTypes API
Adds support for finding instances, and adds a `BaseException` convenience class.
1 parent 54af9dd commit 4606d90

File tree

1 file changed

+32
-6
lines changed

1 file changed

+32
-6
lines changed

python/ql/lib/semmle/python/dataflow/new/internal/DataFlowDispatch.qll

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2175,12 +2175,27 @@ module ExceptionTypes {
21752175
/** Gets a string representation of this exception type. */
21762176
string toString() { result = this.getName() }
21772177

2178-
/** Holds if this exception type may be raised at control flow node `r`. */
2179-
predicate isRaisedAt(ControlFlowNode r) {
2180-
exists(Expr raised |
2181-
raised = r.getNode().(Raise).getRaised() and
2178+
/** Gets a data-flow node that refers to an instance of this exception type. */
2179+
DataFlow::Node getAnInstance() { none() }
2180+
2181+
/** Holds if this is a legal exception type (a subclass of `BaseException`). */
2182+
predicate isLegalExceptionType() { this.getADirectSuperclass*() instanceof BaseException }
2183+
2184+
/**
2185+
* Holds if this exception type is raised by `r`, either as a class reference
2186+
* (e.g. `raise ValueError`) or as an instantiation (e.g. `raise ValueError("msg")`).
2187+
*/
2188+
predicate isRaisedBy(Raise r) {
2189+
exists(Expr raised | raised = r.getRaised() |
21822190
this.getAUse().asExpr() in [raised, raised.(Call).getFunc()]
2191+
or
2192+
this.getAnInstance().asExpr() = raised
21832193
)
2194+
}
2195+
2196+
/** Holds if this exception type may be raised at control flow node `r`. */
2197+
predicate isRaisedAt(ControlFlowNode r) {
2198+
this.isRaisedBy(r.getNode())
21842199
or
21852200
exists(Function callee |
21862201
resolveCall(r, callee, _) and
@@ -2207,7 +2222,7 @@ module ExceptionTypes {
22072222
or
22082223
// A bare `except:` handles everything
22092224
not exists(handler.getNode().(ExceptStmt).getType()) and
2210-
this.(BuiltinExceptType).getName() = "BaseException"
2225+
this instanceof BaseException
22112226
}
22122227

22132228
/**
@@ -2237,6 +2252,8 @@ module ExceptionTypes {
22372252

22382253
override DataFlow::Node getAUse() { result = classTracker(cls) }
22392254

2255+
override DataFlow::Node getAnInstance() { result = classInstanceTracker(cls) }
2256+
22402257
override ExceptType getADirectSuperclass() {
22412258
result.(UserExceptType).asClass() = getADirectSuperclass(cls)
22422259
or
@@ -2261,7 +2278,11 @@ module ExceptionTypes {
22612278

22622279
override string getName() { result = name }
22632280

2264-
override DataFlow::Node getAUse() { API::builtin(name).asSource().flowsTo(result) }
2281+
override DataFlow::Node getAUse() { result = API::builtin(name).getAValueReachableFromSource() }
2282+
2283+
override DataFlow::Node getAnInstance() {
2284+
result = API::builtin(name).getAnInstance().getAValueReachableFromSource()
2285+
}
22652286

22662287
override ExceptType getADirectSuperclass() {
22672288
builtinExceptionSubclass(result.(BuiltinExceptType).asBuiltinName(), name) and
@@ -2279,6 +2300,11 @@ module ExceptionTypes {
22792300
}
22802301
}
22812302

2303+
/** The builtin `BaseException` type. */
2304+
class BaseException extends BuiltinExceptType {
2305+
BaseException() { name = "BaseException" }
2306+
}
2307+
22822308
/**
22832309
* Holds if the exception edge from `r` to `handler` is unlikely because
22842310
* none of the exception types that `r` may raise are handled by `handler`.

0 commit comments

Comments
 (0)