Skip to content

Commit e14d493

Browse files
committed
Python: Move exception modelling to DataFlowDispatch.qll
1 parent 16683ae commit e14d493

File tree

2 files changed

+111
-68
lines changed

2 files changed

+111
-68
lines changed

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

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2159,3 +2159,113 @@ module DuckTyping {
21592159
f.getADecorator().(Name).getId() = "property"
21602160
}
21612161
}
2162+
2163+
/**
2164+
* Provides a class hierarchy for exception types, covering both builtin
2165+
* exceptions (from typeshed models) and user-defined exception classes.
2166+
*/
2167+
module ExceptionTypes {
2168+
private import semmle.python.ApiGraphs
2169+
private import semmle.python.frameworks.data.internal.ApiGraphModels
2170+
2171+
/** Holds if `name` is a builtin exception class name. */
2172+
predicate builtinException(string name) {
2173+
typeModel("builtins.BaseException~Subclass", "builtins." + name, "")
2174+
}
2175+
2176+
/** Holds if builtin exception `sub` is a direct subclass of builtin exception `base`. */
2177+
private predicate builtinExceptionSubclass(string base, string sub) {
2178+
typeModel("builtins." + base + "~Subclass", "builtins." + sub, "")
2179+
}
2180+
2181+
/** An exception type, either a builtin exception or a user-defined exception class. */
2182+
newtype TExceptType =
2183+
/** A user-defined exception class. */
2184+
TUserExceptType(Class c) or
2185+
/** A builtin exception class, identified by name. */
2186+
TBuiltinExceptType(string name) { builtinException(name) }
2187+
2188+
/** An exception type, either a builtin exception or a user-defined exception class. */
2189+
class ExceptType extends TExceptType {
2190+
/** Gets the name of this exception type. */
2191+
string getName() { none() }
2192+
2193+
/** Gets a data-flow node that refers to this exception type. */
2194+
DataFlow::Node getAUse() { none() }
2195+
2196+
/** Gets a direct superclass of this exception type. */
2197+
ExceptType getADirectSuperclass() { none() }
2198+
2199+
/** Gets a string representation of this exception type. */
2200+
string toString() { result = this.getName() }
2201+
2202+
/**
2203+
* Holds if this element is at the specified location.
2204+
* The location spans column `startColumn` of line `startLine` to
2205+
* column `endColumn` of line `endLine` in file `filepath`.
2206+
* For more information, see
2207+
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
2208+
*/
2209+
predicate hasLocationInfo(
2210+
string filePath, int startLine, int startColumn, int endLine, int endColumn
2211+
) {
2212+
none()
2213+
}
2214+
}
2215+
2216+
/** A user-defined exception class. */
2217+
class UserExceptType extends ExceptType, TUserExceptType {
2218+
Class cls;
2219+
2220+
UserExceptType() { this = TUserExceptType(cls) }
2221+
2222+
/** Gets the underlying class. */
2223+
Class asClass() { result = cls }
2224+
2225+
override string getName() { result = cls.getName() }
2226+
2227+
override DataFlow::Node getAUse() { result = classTracker(cls) }
2228+
2229+
override ExceptType getADirectSuperclass() {
2230+
result.(UserExceptType).asClass() = getADirectSuperclass(cls)
2231+
or
2232+
result.(BuiltinExceptType).getAUse().asExpr() = cls.getABase()
2233+
}
2234+
2235+
override predicate hasLocationInfo(
2236+
string filePath, int startLine, int startColumn, int endLine, int endColumn
2237+
) {
2238+
cls.getLocation().hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
2239+
}
2240+
}
2241+
2242+
/** A builtin exception class, identified by name. */
2243+
class BuiltinExceptType extends ExceptType, TBuiltinExceptType {
2244+
string name;
2245+
2246+
BuiltinExceptType() { this = TBuiltinExceptType(name) }
2247+
2248+
/** Gets the builtin name. */
2249+
string asBuiltinName() { result = name }
2250+
2251+
override string getName() { result = name }
2252+
2253+
override DataFlow::Node getAUse() { API::builtin(name).asSource().flowsTo(result) }
2254+
2255+
override ExceptType getADirectSuperclass() {
2256+
builtinExceptionSubclass(result.(BuiltinExceptType).asBuiltinName(), name) and
2257+
result != this
2258+
}
2259+
2260+
override predicate hasLocationInfo(
2261+
string filePath, int startLine, int startColumn, int endLine, int endColumn
2262+
) {
2263+
filePath = "" and
2264+
startLine = 0 and
2265+
startColumn = 0 and
2266+
endLine = 0 and
2267+
endColumn = 0
2268+
}
2269+
}
2270+
}
2271+

python/ql/src/Exceptions/IncorrectExceptOrder.ql

Lines changed: 1 addition & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -15,74 +15,7 @@
1515

1616
import python
1717
import semmle.python.dataflow.new.internal.DataFlowDispatch
18-
import semmle.python.ApiGraphs
19-
import semmle.python.frameworks.data.internal.ApiGraphModels
20-
21-
predicate builtinException(string name) {
22-
typeModel("builtins.BaseException~Subclass", "builtins." + name, "")
23-
}
24-
25-
predicate builtinExceptionSubclass(string base, string sub) {
26-
typeModel("builtins." + base + "~Subclass", "builtins." + sub, "")
27-
}
28-
29-
newtype TExceptType =
30-
TClass(Class c) or
31-
TBuiltin(string name) { builtinException(name) }
32-
33-
class ExceptType extends TExceptType {
34-
Class asClass() { this = TClass(result) }
35-
36-
string asBuiltinName() { this = TBuiltin(result) }
37-
38-
predicate isBuiltin() { this = TBuiltin(_) }
39-
40-
string getName() {
41-
result = this.asClass().getName()
42-
or
43-
result = this.asBuiltinName()
44-
}
45-
46-
string toString() { result = this.getName() }
47-
48-
DataFlow::Node getAUse() {
49-
result = classTracker(this.asClass())
50-
or
51-
API::builtin(this.asBuiltinName()).asSource().flowsTo(result)
52-
}
53-
54-
ExceptType getADirectSuperclass() {
55-
result.asClass() = getADirectSuperclass(this.asClass())
56-
or
57-
result.isBuiltin() and
58-
result.getAUse().asExpr() = this.asClass().getABase()
59-
or
60-
builtinExceptionSubclass(result.asBuiltinName(), this.asBuiltinName()) and
61-
this != result
62-
}
63-
64-
/**
65-
* Holds if this element is at the specified location.
66-
* The location spans column `startColumn` of line `startLine` to
67-
* column `endColumn` of line `endLine` in file `filepath`.
68-
* For more information, see
69-
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
70-
*/
71-
predicate hasLocationInfo(
72-
string filePath, int startLine, int startColumn, int endLine, int endColumn
73-
) {
74-
this.asClass()
75-
.getLocation()
76-
.hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
77-
or
78-
this.isBuiltin() and
79-
filePath = "" and
80-
startLine = 0 and
81-
startColumn = 0 and
82-
endLine = 0 and
83-
endColumn = 0
84-
}
85-
}
18+
private import ExceptionTypes
8619

8720
predicate incorrectExceptOrder(ExceptStmt ex1, ExceptType cls1, ExceptStmt ex2, ExceptType cls2) {
8821
exists(int i, int j, Try t |

0 commit comments

Comments
 (0)