Skip to content

Commit 1593cbf

Browse files
committed
Python: Extend ExceptionTypes API
Adds support for finding instances, and adds a `BaseException` convenience class.
1 parent c5f29c6 commit 1593cbf

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
@@ -2154,12 +2154,27 @@ module ExceptionTypes {
21542154
/** Gets a string representation of this exception type. */
21552155
string toString() { result = this.getName() }
21562156

2157-
/** Holds if this exception type may be raised at control flow node `r`. */
2158-
predicate isRaisedAt(ControlFlowNode r) {
2159-
exists(Expr raised |
2160-
raised = r.getNode().(Raise).getRaised() and
2157+
/** Gets a data-flow node that refers to an instance of this exception type. */
2158+
DataFlow::Node getAnInstance() { none() }
2159+
2160+
/** Holds if this is a legal exception type (a subclass of `BaseException`). */
2161+
predicate isLegalExceptionType() { this.getADirectSuperclass*() instanceof BaseException }
2162+
2163+
/**
2164+
* Holds if this exception type is raised by `r`, either as a class reference
2165+
* (e.g. `raise ValueError`) or as an instantiation (e.g. `raise ValueError("msg")`).
2166+
*/
2167+
predicate isRaisedBy(Raise r) {
2168+
exists(Expr raised | raised = r.getRaised() |
21612169
this.getAUse().asExpr() in [raised, raised.(Call).getFunc()]
2170+
or
2171+
this.getAnInstance().asExpr() = raised
21622172
)
2173+
}
2174+
2175+
/** Holds if this exception type may be raised at control flow node `r`. */
2176+
predicate isRaisedAt(ControlFlowNode r) {
2177+
this.isRaisedBy(r.getNode())
21632178
or
21642179
exists(Function callee |
21652180
resolveCall(r, callee, _) and
@@ -2186,7 +2201,7 @@ module ExceptionTypes {
21862201
or
21872202
// A bare `except:` handles everything
21882203
not exists(handler.getNode().(ExceptStmt).getType()) and
2189-
this.(BuiltinExceptType).getName() = "BaseException"
2204+
this instanceof BaseException
21902205
}
21912206

21922207
/**
@@ -2216,6 +2231,8 @@ module ExceptionTypes {
22162231

22172232
override DataFlow::Node getAUse() { result = classTracker(cls) }
22182233

2234+
override DataFlow::Node getAnInstance() { result = classInstanceTracker(cls) }
2235+
22192236
override ExceptType getADirectSuperclass() {
22202237
result.(UserExceptType).asClass() = getADirectSuperclass(cls)
22212238
or
@@ -2240,7 +2257,11 @@ module ExceptionTypes {
22402257

22412258
override string getName() { result = name }
22422259

2243-
override DataFlow::Node getAUse() { API::builtin(name).asSource().flowsTo(result) }
2260+
override DataFlow::Node getAUse() { result = API::builtin(name).getAValueReachableFromSource() }
2261+
2262+
override DataFlow::Node getAnInstance() {
2263+
result = API::builtin(name).getAnInstance().getAValueReachableFromSource()
2264+
}
22442265

22452266
override ExceptType getADirectSuperclass() {
22462267
builtinExceptionSubclass(result.(BuiltinExceptType).asBuiltinName(), name) and
@@ -2258,6 +2279,11 @@ module ExceptionTypes {
22582279
}
22592280
}
22602281

2282+
/** The builtin `BaseException` type. */
2283+
class BaseException extends BuiltinExceptType {
2284+
BaseException() { name = "BaseException" }
2285+
}
2286+
22612287
/**
22622288
* Holds if the exception edge from `r` to `handler` is unlikely because
22632289
* none of the exception types that `r` may raise are handled by `handler`.

0 commit comments

Comments
 (0)