mirror of
https://github.com/github/codeql.git
synced 2026-02-15 06:23:42 +01:00
109 lines
3.2 KiB
Plaintext
109 lines
3.2 KiB
Plaintext
/**
|
|
* @name Unreachable `except` block
|
|
* @description Handling general exceptions before specific exceptions means that the specific
|
|
* handlers are never executed.
|
|
* @kind problem
|
|
* @tags quality
|
|
* reliability
|
|
* error-handling
|
|
* external/cwe/cwe-561
|
|
* @problem.severity error
|
|
* @sub-severity low
|
|
* @precision very-high
|
|
* @id py/unreachable-except
|
|
*/
|
|
|
|
import python
|
|
import semmle.python.dataflow.new.internal.DataFlowDispatch
|
|
import semmle.python.ApiGraphs
|
|
import semmle.python.frameworks.data.internal.ApiGraphModels
|
|
|
|
predicate builtinException(string name) {
|
|
typeModel("builtins.BaseException~Subclass", "builtins." + name, "")
|
|
}
|
|
|
|
predicate builtinExceptionSubclass(string base, string sub) {
|
|
typeModel("builtins." + base + "~Subclass", "builtins." + sub, "")
|
|
}
|
|
|
|
newtype TExceptType =
|
|
TClass(Class c) or
|
|
TBuiltin(string name) { builtinException(name) }
|
|
|
|
class ExceptType extends TExceptType {
|
|
Class asClass() { this = TClass(result) }
|
|
|
|
string asBuiltinName() { this = TBuiltin(result) }
|
|
|
|
predicate isBuiltin() { this = TBuiltin(_) }
|
|
|
|
string getName() {
|
|
result = this.asClass().getName()
|
|
or
|
|
result = this.asBuiltinName()
|
|
}
|
|
|
|
string toString() { result = this.getName() }
|
|
|
|
DataFlow::Node getAUse() {
|
|
result = classTracker(this.asClass())
|
|
or
|
|
API::builtin(this.asBuiltinName()).asSource().flowsTo(result)
|
|
}
|
|
|
|
ExceptType getADirectSuperclass() {
|
|
result.asClass() = getADirectSuperclass(this.asClass())
|
|
or
|
|
result.isBuiltin() and
|
|
result.getAUse().asExpr() = this.asClass().getABase()
|
|
or
|
|
builtinExceptionSubclass(result.asBuiltinName(), this.asBuiltinName()) and
|
|
this != result
|
|
}
|
|
|
|
/**
|
|
* Holds if this element is at the specified location.
|
|
* The location spans column `startColumn` of line `startLine` to
|
|
* column `endColumn` of line `endLine` in file `filepath`.
|
|
* For more information, see
|
|
* [Providing locations in CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
|
*/
|
|
predicate hasLocationInfo(
|
|
string filePath, int startLine, int startColumn, int endLine, int endColumn
|
|
) {
|
|
this.asClass()
|
|
.getLocation()
|
|
.hasLocationInfo(filePath, startLine, startColumn, endLine, endColumn)
|
|
or
|
|
this.isBuiltin() and
|
|
filePath = "" and
|
|
startLine = 0 and
|
|
startColumn = 0 and
|
|
endLine = 0 and
|
|
endColumn = 0
|
|
}
|
|
}
|
|
|
|
predicate incorrectExceptOrder(ExceptStmt ex1, ExceptType cls1, ExceptStmt ex2, ExceptType cls2) {
|
|
exists(int i, int j, Try t |
|
|
ex1 = t.getHandler(i) and
|
|
ex2 = t.getHandler(j) and
|
|
i < j and
|
|
cls1 = exceptClass(ex1) and
|
|
cls2 = exceptClass(ex2) and
|
|
cls1 = cls2.getADirectSuperclass*()
|
|
)
|
|
}
|
|
|
|
ExceptType exceptClass(ExceptStmt ex) { ex.getType() = result.getAUse().asExpr() }
|
|
|
|
from ExceptStmt ex1, ExceptType cls1, ExceptStmt ex2, ExceptType cls2, string msg
|
|
where
|
|
incorrectExceptOrder(ex1, cls1, ex2, cls2) and
|
|
if cls1 = cls2
|
|
then msg = "This except block handling $@ is unreachable; as $@ also handles $@."
|
|
else
|
|
msg =
|
|
"This except block handling $@ is unreachable; as $@ for the more general $@ always subsumes it."
|
|
select ex2, msg, cls2, cls2.getName(), ex1, "this except block", cls1, cls1.getName()
|