mirror of
https://github.com/github/codeql.git
synced 2026-06-06 05:57:07 +02:00
Compare commits
2 Commits
yoff/pytho
...
yoff/pytho
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
709566ecb1 | ||
|
|
b783ed69c5 |
@@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
category: minorAnalysis
|
||||||
|
---
|
||||||
|
* The new (shared-CFG-based) Python control flow graph now visits parameter and return type annotations as CFG nodes for function definitions, matching the legacy CFG. This restores annotation-based type tracking through framework models such as FastAPI's `Depends()`, Pydantic request models, Starlette `WebSocket` handlers, and any other models that flow a class reference through `Parameter.getAnnotation()` to identify instances of the annotated class.
|
||||||
@@ -1446,10 +1446,19 @@ module Ast implements AstSig<Py::Location> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A function definition expression (visits positional and keyword
|
* A function definition expression (visits positional and keyword
|
||||||
* defaults, but NOT PEP 695 type parameters — those bind in an
|
* defaults followed by parameter and return type annotations, but NOT
|
||||||
* annotation scope that nests the function body, so they belong to
|
* PEP 695 type parameters — those bind in an annotation scope that
|
||||||
* the inner scope's CFG, not the enclosing scope's; the legacy CFG
|
* nests the function body, so they belong to the inner scope's CFG,
|
||||||
* also omitted them).
|
* not the enclosing scope's; the legacy CFG also omitted them).
|
||||||
|
*
|
||||||
|
* Evaluation order follows CPython: defaults are pushed first, then
|
||||||
|
* keyword-only defaults, then annotations (the `__annotations__` dict
|
||||||
|
* is built last, before `MAKE_FUNCTION`). Annotations are emitted as
|
||||||
|
* CFG nodes so that flows from a class reference into a parameter's
|
||||||
|
* type annotation are visible to dataflow (e.g. so that framework
|
||||||
|
* models like FastAPI's `Depends()` can use a parameter's type hint
|
||||||
|
* to track that the parameter receives an instance of the annotated
|
||||||
|
* class — see `LocalSources::annotatedInstance`).
|
||||||
*/
|
*/
|
||||||
additional class FunctionDefExpr extends Expr {
|
additional class FunctionDefExpr extends Expr {
|
||||||
private Py::FunctionExpr funcExpr;
|
private Py::FunctionExpr funcExpr;
|
||||||
@@ -1473,15 +1482,61 @@ module Ast implements AstSig<Py::Location> {
|
|||||||
rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getKwDefault(i) | d order by i)
|
rank[n + 1](Py::Expr d, int i | d = funcExpr.getArgs().getKwDefault(i) | d order by i)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the `n`th annotation expression, in CPython evaluation
|
||||||
|
* order: positional parameter annotations (by argument position),
|
||||||
|
* `*args` annotation, keyword-only parameter annotations (by
|
||||||
|
* argument position), `**kwargs` annotation, then the return
|
||||||
|
* annotation. Each annotation appears at most once.
|
||||||
|
*/
|
||||||
|
Expr getAnnotation(int n) {
|
||||||
|
result.asExpr() =
|
||||||
|
rank[n + 1](Py::Expr a, int subOrder, int subIndex |
|
||||||
|
functionAnnotation(funcExpr, a, subOrder, subIndex)
|
||||||
|
|
|
||||||
|
a order by subOrder, subIndex
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
int getNumberOfDefaults() { result = count(funcExpr.getArgs().getADefault()) }
|
int getNumberOfDefaults() { result = count(funcExpr.getArgs().getADefault()) }
|
||||||
|
|
||||||
|
int getNumberOfKwDefaults() { result = count(funcExpr.getArgs().getAKwDefault()) }
|
||||||
|
|
||||||
|
int getNumberOfAnnotations() {
|
||||||
|
result = count(Py::Expr a | functionAnnotation(funcExpr, a, _, _))
|
||||||
|
}
|
||||||
|
|
||||||
override AstNode getChild(int index) {
|
override AstNode getChild(int index) {
|
||||||
result = this.getDefault(index)
|
result = this.getDefault(index)
|
||||||
or
|
or
|
||||||
result = this.getKwDefault(index - this.getNumberOfDefaults())
|
result = this.getKwDefault(index - this.getNumberOfDefaults())
|
||||||
|
or
|
||||||
|
result = this.getAnnotation(index - this.getNumberOfDefaults() - this.getNumberOfKwDefaults())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `a` is an annotation of `funcExpr` in slot
|
||||||
|
* `(subOrder, subIndex)`. Slots are CPython evaluation order:
|
||||||
|
* positional param annotations (subOrder 0, subIndex = argument
|
||||||
|
* position), `*args` annotation (1, 0), keyword-only annotations
|
||||||
|
* (2, position), `**kwargs` annotation (3, 0), return annotation
|
||||||
|
* (4, 0).
|
||||||
|
*/
|
||||||
|
private predicate functionAnnotation(
|
||||||
|
Py::FunctionExpr funcExpr, Py::Expr a, int subOrder, int subIndex
|
||||||
|
) {
|
||||||
|
a = funcExpr.getArgs().getAnnotation(subIndex) and subOrder = 0
|
||||||
|
or
|
||||||
|
a = funcExpr.getArgs().getVarargannotation() and subOrder = 1 and subIndex = 0
|
||||||
|
or
|
||||||
|
a = funcExpr.getArgs().getKwAnnotation(subIndex) and subOrder = 2
|
||||||
|
or
|
||||||
|
a = funcExpr.getArgs().getKwargannotation() and subOrder = 3 and subIndex = 0
|
||||||
|
or
|
||||||
|
a = funcExpr.getReturns() and subOrder = 4 and subIndex = 0
|
||||||
|
}
|
||||||
|
|
||||||
/** A lambda expression (has default args evaluated at definition time). */
|
/** A lambda expression (has default args evaluated at definition time). */
|
||||||
additional class LambdaExpr extends Expr {
|
additional class LambdaExpr extends Expr {
|
||||||
private Py::Lambda lambda;
|
private Py::Lambda lambda;
|
||||||
@@ -1543,6 +1598,89 @@ private module Input implements InputSig1, InputSig2 {
|
|||||||
|
|
||||||
private string assertThrowTag() { result = "[assert-throw]" }
|
private string assertThrowTag() { result = "[assert-throw]" }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the AST node `n` may raise an exception at runtime as part of
|
||||||
|
* its normal evaluation (not via an explicit `raise`/`assert`, which are
|
||||||
|
* modelled separately).
|
||||||
|
*
|
||||||
|
* The set mirrors what the legacy CFG used to flag implicitly: function
|
||||||
|
* calls (anything can raise), attribute access (`AttributeError`),
|
||||||
|
* subscript access (`IndexError`/`KeyError`/`TypeError`), arithmetic and
|
||||||
|
* comparison operators (`TypeError`/`ZeroDivisionError`), imports
|
||||||
|
* (`ImportError`/`ModuleNotFoundError`), and generator/coroutine
|
||||||
|
* suspension points (`await`/`yield`/`yield from`).
|
||||||
|
*
|
||||||
|
* Bare `Name` reads are intentionally excluded — modelling every name
|
||||||
|
* read as `mayThrow` would explode CFG edge count for negligible
|
||||||
|
* analysis value. `BoolExpr`/`IfExp` containers are also excluded; the
|
||||||
|
* operands they evaluate contribute their own exception edges.
|
||||||
|
*/
|
||||||
|
private predicate exprMayThrow(Py::Expr e) {
|
||||||
|
e instanceof Py::Call
|
||||||
|
or
|
||||||
|
e instanceof Py::Attribute
|
||||||
|
or
|
||||||
|
e instanceof Py::Subscript
|
||||||
|
or
|
||||||
|
e instanceof Py::BinaryExpr
|
||||||
|
or
|
||||||
|
e instanceof Py::UnaryExpr
|
||||||
|
or
|
||||||
|
e instanceof Py::Compare
|
||||||
|
or
|
||||||
|
e instanceof Py::ImportExpr
|
||||||
|
or
|
||||||
|
e instanceof Py::ImportMember
|
||||||
|
or
|
||||||
|
e instanceof Py::Await
|
||||||
|
or
|
||||||
|
e instanceof Py::Yield
|
||||||
|
or
|
||||||
|
e instanceof Py::YieldFrom
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the statement `s` may raise an exception at runtime as part
|
||||||
|
* of its normal evaluation. Currently restricted to `from m import *`
|
||||||
|
* (which performs the import as a statement-level side effect).
|
||||||
|
*/
|
||||||
|
private predicate stmtMayThrow(Py::Stmt s) { s instanceof Py::ImportStar }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `n` is syntactically inside the body, handlers, `else`, or
|
||||||
|
* `finally` of a `try` statement (or the body of a `with` statement,
|
||||||
|
* which compiles to an implicit try/finally for `__exit__`) in the
|
||||||
|
* same scope.
|
||||||
|
*
|
||||||
|
* This mirrors Java's `ControlFlowGraph::mayThrow`, which only emits
|
||||||
|
* exception edges when there is local exception handling that would
|
||||||
|
* observe them. Outside such contexts, exception edges would add CFG
|
||||||
|
* complexity (weakening BarrierGuard precision and breaking SSA
|
||||||
|
* continuity around augmented assignments and subscript stores)
|
||||||
|
* without any analysis benefit, since exceptions just propagate to
|
||||||
|
* the function exit anyway.
|
||||||
|
*/
|
||||||
|
private predicate inExceptionContext(Py::AstNode py) {
|
||||||
|
exists(Py::Try t | t.containsInScope(py))
|
||||||
|
or
|
||||||
|
exists(Py::With w | w.containsInScope(py))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if `n` may raise an exception during normal evaluation. See
|
||||||
|
* `exprMayThrow` and `stmtMayThrow` for the included AST classes.
|
||||||
|
*
|
||||||
|
* Restricted to nodes inside a `try`/`with` statement: matches Java's
|
||||||
|
* approach of only modelling exception flow where it can be observed
|
||||||
|
* by local handling.
|
||||||
|
*/
|
||||||
|
private predicate mayThrow(Ast::AstNode n) {
|
||||||
|
exists(Py::AstNode py | py = n.asExpr() or py = n.asStmt() |
|
||||||
|
(exprMayThrow(py) or stmtMayThrow(py)) and
|
||||||
|
inExceptionContext(py)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
predicate additionalNode(Ast::AstNode n, string tag, NormalSuccessor t) {
|
predicate additionalNode(Ast::AstNode n, string tag, NormalSuccessor t) {
|
||||||
n instanceof Ast::AssertStmt and tag = assertThrowTag() and t instanceof DirectSuccessor
|
n instanceof Ast::AssertStmt and tag = assertThrowTag() and t instanceof DirectSuccessor
|
||||||
}
|
}
|
||||||
@@ -1554,6 +1692,11 @@ private module Input implements InputSig1, InputSig2 {
|
|||||||
n.isAdditional(ast, assertThrowTag()) and
|
n.isAdditional(ast, assertThrowTag()) and
|
||||||
c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and
|
c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and
|
||||||
always = true
|
always = true
|
||||||
|
or
|
||||||
|
mayThrow(ast) and
|
||||||
|
n.isIn(ast) and
|
||||||
|
c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and
|
||||||
|
always = false
|
||||||
}
|
}
|
||||||
|
|
||||||
predicate endAbruptCompletion(Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c) {
|
predicate endAbruptCompletion(Ast::AstNode ast, PreControlFlowNode n, AbruptCompletion c) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
testFailures
|
testFailures
|
||||||
| type_annotations.py:6:16:6:32 | Comment # $ tt=Foo.method | Missing result: tt=Foo.method |
|
|
||||||
| type_annotations.py:16:16:16:32 | Comment # $ tt=Foo.method | Missing result: tt=Foo.method |
|
|
||||||
debug_callableNotUnique
|
debug_callableNotUnique
|
||||||
pointsTo_found_typeTracker_notFound
|
pointsTo_found_typeTracker_notFound
|
||||||
typeTracker_found_pointsTo_notFound
|
typeTracker_found_pointsTo_notFound
|
||||||
|
| type_annotations.py:6:5:6:14 | Attribute() | Foo.method |
|
||||||
|
| type_annotations.py:16:5:16:14 | Attribute() | Foo.method |
|
||||||
| type_annotations.py:29:5:29:14 | Attribute() | Foo.method |
|
| type_annotations.py:29:5:29:14 | Attribute() | Foo.method |
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
| flask.MethodView~Subclass | find_subclass_test | Member[C] |
|
| flask.MethodView~Subclass | find_subclass_test | Member[C] |
|
||||||
| flask.View~Subclass | find_subclass_test | Member[A] |
|
| flask.View~Subclass | find_subclass_test | Member[A] |
|
||||||
| flask.View~Subclass | find_subclass_test | Member[B] |
|
| flask.View~Subclass | find_subclass_test | Member[B] |
|
||||||
|
| flask.View~Subclass | find_subclass_test | Member[ViewAliasInExcept] |
|
||||||
| flask.View~Subclass | find_subclass_test | Member[ViewAliasInTry] |
|
| flask.View~Subclass | find_subclass_test | Member[ViewAliasInTry] |
|
||||||
| flask.View~Subclass | find_subclass_test | Member[ViewAlias] |
|
| flask.View~Subclass | find_subclass_test | Member[ViewAlias] |
|
||||||
| flask.View~Subclass | find_subclass_test | Member[ViewAlias_no_use] |
|
| flask.View~Subclass | find_subclass_test | Member[ViewAlias_no_use] |
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Dead bindings under the "no expressions raise" CFG abstraction.
|
# Reachability of code following a try whose body always returns.
|
||||||
#
|
#
|
||||||
# The new CFG does not currently model raise edges from arbitrary
|
# The new CFG models exception edges for raise-prone expressions when
|
||||||
# expressions. As a consequence, code that is only reachable through
|
# they appear inside a `try` (or `with`) statement, mirroring Java's
|
||||||
# exception flow is (correctly) classified as dead and has no CFG node.
|
# `mayThrow`. This means the body of a `try` has both a normal
|
||||||
# Variable bindings in dead code do not need CFG nodes - SSA / dataflow
|
# completion edge and an exception edge to its handlers, so code
|
||||||
# over dead code is moot.
|
# following the try-statement is reachable via the except-handler path
|
||||||
|
# even when the try-body would otherwise always return.
|
||||||
#
|
#
|
||||||
# These tests act as a regression guard: the bindings below intentionally
|
# Code that is not reachable under either normal or exception flow
|
||||||
# have no `cfgdefines=` annotations. If raise modelling is later added,
|
# (for example, the `else` clause of a try whose body unconditionally
|
||||||
# the BindingsTest infrastructure will surface the new CFG nodes as
|
# raises) remains correctly classified as dead.
|
||||||
# unexpected results, and this file will need to be revisited.
|
|
||||||
|
|
||||||
|
|
||||||
def f(obj): # $ cfgdefines=f cfgdefines=obj
|
def f(obj): # $ cfgdefines=f cfgdefines=obj
|
||||||
@@ -18,12 +18,12 @@ def f(obj): # $ cfgdefines=f cfgdefines=obj
|
|||||||
except TypeError:
|
except TypeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# The first try's body always returns; its except handler does not
|
# The try-body always returns, but `len(obj)` can raise (it is
|
||||||
# raise or otherwise transfer control, so under "no expressions
|
# inside the try, so we model its exception edge). The
|
||||||
# raise" the only paths out of the try-statement are dead. Everything
|
# `except TypeError: pass` handler falls through to here, making
|
||||||
# below is unreachable.
|
# the code below reachable.
|
||||||
try:
|
try:
|
||||||
hint = type(obj).__length_hint__
|
hint = type(obj).__length_hint__ # $ cfgdefines=hint
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return None
|
return None
|
||||||
return hint
|
return hint
|
||||||
@@ -35,7 +35,8 @@ def g(): # $ cfgdefines=g
|
|||||||
except:
|
except:
|
||||||
raise Exception("outer")
|
raise Exception("outer")
|
||||||
else:
|
else:
|
||||||
# Unreachable: the inner try body always raises, so the `else:`
|
# Unreachable: the inner try body always raises (via an explicit
|
||||||
|
# `raise`, which is modelled unconditionally), so the `else:`
|
||||||
# clause never runs.
|
# clause never runs.
|
||||||
hit_inner_else = True
|
hit_inner_else = True
|
||||||
|
|
||||||
@@ -46,7 +47,7 @@ def h(cache, key): # $ cfgdefines=h cfgdefines=cache cfgdefines=key
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Same pattern as `f`: dead under "no expressions raise".
|
# Same pattern as `f`: reachable via the except-handler fall-through.
|
||||||
value = compute(key)
|
value = compute(key) # $ cfgdefines=value
|
||||||
cache[key] = value
|
cache[key] = value
|
||||||
return value
|
return value
|
||||||
|
|||||||
@@ -2,5 +2,4 @@
|
|||||||
| def-only-old | __name__:0:0 |
|
| def-only-old | __name__:0:0 |
|
||||||
| def-only-old | __package__:0:0 |
|
| def-only-old | __package__:0:0 |
|
||||||
| def-only-old | e:37:1 |
|
| def-only-old | e:37:1 |
|
||||||
| def-only-old | e:40:25 |
|
|
||||||
| def-only-old | x:20:1 |
|
| def-only-old | x:20:1 |
|
||||||
|
|||||||
@@ -844,7 +844,7 @@ def return_from_inner_scope(x):
|
|||||||
return SOURCE
|
return SOURCE
|
||||||
|
|
||||||
def test_return_from_inner_scope():
|
def test_return_from_inner_scope():
|
||||||
SINK(return_from_inner_scope([])) # $ MISSING: flow="SOURCE, l:-3 -> return_from_inner_scope(..)"
|
SINK(return_from_inner_scope([])) # $ flow="SOURCE, l:-3 -> return_from_inner_scope(..)"
|
||||||
|
|
||||||
|
|
||||||
# Inspired by reverse read inconsistency check
|
# Inspired by reverse read inconsistency check
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||||
| taint_test.py:151:9:151:15 | taint_test.py:151 | ERROR, you should add `# $ MISSING: tainted` annotation | request |
|
|
||||||
| taint_test.py:152:9:152:19 | taint_test.py:152 | ERROR, you should add `# $ MISSING: tainted` annotation | request.url |
|
|
||||||
| taint_test.py:153:9:153:36 | taint_test.py:153 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
testFailures
|
testFailures
|
||||||
| taint_test.py:151:18:151:28 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:152:22:152:32 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:153:39:153:49 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:168:76:168:96 | Comment # $ SPURIOUS: tainted | Fixed spurious result: tainted |
|
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
| response_test.py:11:30:11:37 | Parameter | Unexpected result: routedParameter=response |
|
|
||||||
| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false |
|
|
||||||
| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieName="key" |
|
|
||||||
| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax |
|
|
||||||
| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false |
|
|
||||||
| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieValue="value" |
|
|
||||||
| response_test.py:12:41:12:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite |
|
|
||||||
| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false |
|
|
||||||
| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieName="key" |
|
|
||||||
| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax |
|
|
||||||
| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false |
|
|
||||||
| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieValue="value" |
|
|
||||||
| response_test.py:13:51:13:161 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite |
|
|
||||||
| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieHttpOnly=true |
|
|
||||||
| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieName="key" |
|
|
||||||
| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieSameSite=Lax |
|
|
||||||
| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieSecure=false |
|
|
||||||
| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieValue="value" |
|
|
||||||
| response_test.py:14:96:14:205 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=true CookieSameSite=Lax | Missing result: CookieWrite |
|
|
||||||
| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false |
|
|
||||||
| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieRawHeader="key2=value2" |
|
|
||||||
| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax |
|
|
||||||
| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false |
|
|
||||||
| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite |
|
|
||||||
| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteName="Set-Cookie" |
|
|
||||||
| response_test.py:15:58:15:221 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteValue="key2=value2" |
|
|
||||||
| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false |
|
|
||||||
| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieRawHeader="key2=value2" |
|
|
||||||
| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax |
|
|
||||||
| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false |
|
|
||||||
| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite |
|
|
||||||
| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteName="Set-Cookie" |
|
|
||||||
| response_test.py:16:68:16:231 | Comment # $ headerWriteName="Set-Cookie" headerWriteValue="key2=value2" CookieWrite CookieRawHeader="key2=value2" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: headerWriteValue="key2=value2" |
|
|
||||||
| response_test.py:17:53:17:116 | Comment # $ headerWriteName="X-MyHeader" headerWriteValue="header-value" | Missing result: headerWriteName="X-MyHeader" |
|
|
||||||
| response_test.py:17:53:17:116 | Comment # $ headerWriteName="X-MyHeader" headerWriteValue="header-value" | Missing result: headerWriteValue="header-value" |
|
|
||||||
| response_test.py:23:26:23:29 | Parameter | Unexpected result: routedParameter=resp |
|
|
||||||
| response_test.py:41:42:41:49 | Parameter | Unexpected result: routedParameter=response |
|
|
||||||
| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieHttpOnly=false |
|
|
||||||
| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieName="key" |
|
|
||||||
| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSameSite=Lax |
|
|
||||||
| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieSecure=false |
|
|
||||||
| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieValue="value" |
|
|
||||||
| response_test.py:48:41:48:151 | Comment # $ CookieWrite CookieName="key" CookieValue="value" CookieSecure=false CookieHttpOnly=false CookieSameSite=Lax | Missing result: CookieWrite |
|
|
||||||
| response_test.py:49:87:49:184 | Comment # $ headerWriteName="Custom-Response-Type" headerWriteValue="yes, but only after function has run" | Missing result: headerWriteName="Custom-Response-Type" |
|
|
||||||
| response_test.py:49:87:49:184 | Comment # $ headerWriteName="Custom-Response-Type" headerWriteValue="yes, but only after function has run" | Missing result: headerWriteValue="yes, but only after function has run" |
|
|
||||||
|
|||||||
@@ -1,107 +1,3 @@
|
|||||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||||
| taint_test.py:33:9:33:24 | taint_test.py:33 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.field |
|
|
||||||
| taint_test.py:35:9:35:27 | taint_test.py:35 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.main_foo |
|
|
||||||
| taint_test.py:36:9:36:31 | taint_test.py:36 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.main_foo.foo |
|
|
||||||
| taint_test.py:38:9:38:29 | taint_test.py:38 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.other_foos |
|
|
||||||
| taint_test.py:39:9:39:32 | taint_test.py:39 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.other_foos[0] |
|
|
||||||
| taint_test.py:40:9:40:36 | taint_test.py:40 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.other_foos[0].foo |
|
|
||||||
| taint_test.py:43:9:43:30 | taint_test.py:43 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos |
|
|
||||||
| taint_test.py:44:9:44:33 | taint_test.py:44 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos[0] |
|
|
||||||
| taint_test.py:45:9:45:36 | taint_test.py:45 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos[0][0] |
|
|
||||||
| taint_test.py:46:9:46:40 | taint_test.py:46 | ERROR, you should add `# $ MISSING: tainted` annotation | also_input.nested_foos[0][0].foo |
|
|
||||||
| taint_test.py:52:9:52:18 | taint_test.py:52 | ERROR, you should add `# $ MISSING: tainted` annotation | other_foos |
|
|
||||||
| taint_test.py:53:9:53:21 | taint_test.py:53 | ERROR, you should add `# $ MISSING: tainted` annotation | other_foos[0] |
|
|
||||||
| taint_test.py:54:9:54:25 | taint_test.py:54 | ERROR, you should add `# $ MISSING: tainted` annotation | other_foos[0].foo |
|
|
||||||
| taint_test.py:140:9:140:21 | taint_test.py:140 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url |
|
|
||||||
| taint_test.py:142:9:142:28 | taint_test.py:142 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.netloc |
|
|
||||||
| taint_test.py:143:9:143:26 | taint_test.py:143 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.path |
|
|
||||||
| taint_test.py:144:9:144:27 | taint_test.py:144 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.query |
|
|
||||||
| taint_test.py:145:9:145:30 | taint_test.py:145 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.fragment |
|
|
||||||
| taint_test.py:146:9:146:30 | taint_test.py:146 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.username |
|
|
||||||
| taint_test.py:147:9:147:30 | taint_test.py:147 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.password |
|
|
||||||
| taint_test.py:148:9:148:30 | taint_test.py:148 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.hostname |
|
|
||||||
| taint_test.py:149:9:149:26 | taint_test.py:149 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.port |
|
|
||||||
| taint_test.py:151:9:151:32 | taint_test.py:151 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components |
|
|
||||||
| taint_test.py:152:9:152:39 | taint_test.py:152 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.netloc |
|
|
||||||
| taint_test.py:153:9:153:37 | taint_test.py:153 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.path |
|
|
||||||
| taint_test.py:154:9:154:38 | taint_test.py:154 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.query |
|
|
||||||
| taint_test.py:155:9:155:41 | taint_test.py:155 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.fragment |
|
|
||||||
| taint_test.py:156:9:156:41 | taint_test.py:156 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.username |
|
|
||||||
| taint_test.py:157:9:157:41 | taint_test.py:157 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.password |
|
|
||||||
| taint_test.py:158:9:158:41 | taint_test.py:158 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.hostname |
|
|
||||||
| taint_test.py:159:9:159:37 | taint_test.py:159 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.url.components.port |
|
|
||||||
| taint_test.py:161:9:161:25 | taint_test.py:161 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.headers |
|
|
||||||
| taint_test.py:162:9:162:32 | taint_test.py:162 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.headers["key"] |
|
|
||||||
| taint_test.py:164:9:164:30 | taint_test.py:164 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.query_params |
|
|
||||||
| taint_test.py:165:9:165:37 | taint_test.py:165 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.query_params["key"] |
|
|
||||||
| taint_test.py:167:9:167:25 | taint_test.py:167 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.cookies |
|
|
||||||
| taint_test.py:168:9:168:32 | taint_test.py:168 | ERROR, you should add `# $ MISSING: tainted` annotation | websocket.cookies["key"] |
|
|
||||||
| taint_test.py:170:9:170:33 | taint_test.py:170 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:171:9:171:39 | taint_test.py:171 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:172:9:172:38 | taint_test.py:172 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:173:9:173:38 | taint_test.py:173 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:183:24:183:27 | taint_test.py:183 | ERROR, you should add `# $ MISSING: tainted` annotation | data |
|
|
||||||
| taint_test.py:186:24:186:27 | taint_test.py:186 | ERROR, you should add `# $ MISSING: tainted` annotation | data |
|
|
||||||
| taint_test.py:189:24:189:27 | taint_test.py:189 | ERROR, you should add `# $ MISSING: tainted` annotation | data |
|
|
||||||
| taint_test.py:205:9:205:28 | taint_test.py:205 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:207:9:207:28 | taint_test.py:207 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:208:9:208:35 | taint_test.py:208 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:211:9:211:28 | taint_test.py:211 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:212:9:212:35 | taint_test.py:212 | ERROR, you should add `# $ MISSING: tainted` annotation | Await |
|
|
||||||
| taint_test.py:219:9:219:23 | taint_test.py:219 | ERROR, you should add `# $ MISSING: tainted` annotation | request.cookies |
|
|
||||||
| taint_test.py:220:9:220:30 | taint_test.py:220 | ERROR, you should add `# $ MISSING: tainted` annotation | request.cookies["key"] |
|
|
||||||
| taint_test.py:224:24:224:28 | taint_test.py:224 | ERROR, you should add `# $ MISSING: tainted` annotation | chunk |
|
|
||||||
testFailures
|
testFailures
|
||||||
| taint_test.py:33:27:33:37 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:35:30:35:40 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:36:34:36:44 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:38:32:38:42 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:39:35:39:45 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:40:39:40:49 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:43:33:43:43 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:44:36:44:46 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:45:39:45:49 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:46:43:46:53 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:52:21:52:31 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:53:24:53:34 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:54:28:54:38 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:140:24:140:34 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:142:31:142:41 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:143:29:143:39 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:144:30:144:40 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:145:33:145:43 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:146:33:146:43 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:147:33:147:43 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:148:33:148:43 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:149:29:149:39 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:151:35:151:45 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:152:42:152:52 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:153:40:153:50 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:154:41:154:51 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:155:44:155:54 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:156:44:156:54 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:157:44:157:54 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:158:44:158:54 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:159:40:159:50 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:161:28:161:38 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:162:35:162:45 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:164:33:164:43 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:165:40:165:50 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:167:28:167:38 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:168:35:168:45 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:170:36:170:46 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:171:42:171:52 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:172:41:172:51 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:173:41:173:51 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:183:30:183:40 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:186:30:186:40 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:189:30:189:40 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:205:31:205:41 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:207:31:207:41 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:208:38:208:48 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:211:31:211:41 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:212:38:212:48 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:219:26:219:36 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:220:33:220:43 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
| taint_test.py:224:31:224:41 | Comment # $ tainted | Missing result: tainted |
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ async def test_taint(name : str, number : int, also_input: MyComplexModel): # $
|
|||||||
also_input.other_foos, # $ tainted
|
also_input.other_foos, # $ tainted
|
||||||
also_input.other_foos[0], # $ tainted
|
also_input.other_foos[0], # $ tainted
|
||||||
also_input.other_foos[0].foo, # $ tainted
|
also_input.other_foos[0].foo, # $ tainted
|
||||||
[f.foo for f in also_input.other_foos], # $ MISSING: tainted
|
[f.foo for f in also_input.other_foos], # $ tainted
|
||||||
|
|
||||||
also_input.nested_foos, # $ tainted
|
also_input.nested_foos, # $ tainted
|
||||||
also_input.nested_foos[0], # $ tainted
|
also_input.nested_foos[0], # $ tainted
|
||||||
@@ -52,7 +52,7 @@ async def test_taint(name : str, number : int, also_input: MyComplexModel): # $
|
|||||||
other_foos, # $ tainted
|
other_foos, # $ tainted
|
||||||
other_foos[0], # $ tainted
|
other_foos[0], # $ tainted
|
||||||
other_foos[0].foo, # $ tainted
|
other_foos[0].foo, # $ tainted
|
||||||
[f.foo for f in other_foos], # $ MISSING: tainted
|
[f.foo for f in other_foos], # $ tainted
|
||||||
)
|
)
|
||||||
|
|
||||||
return "ok" # $ HttpResponse
|
return "ok" # $ HttpResponse
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
argumentToEnsureNotTaintedNotMarkedAsSpurious
|
||||||
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
untaintedArgumentToEnsureTaintedNotMarkedAsMissing
|
||||||
| taint_test.py:133:13:133:35 | taint_test.py:133 | ERROR, you should add `# $ MISSING: tainted` annotation | tree_arg.getroot().text |
|
|
||||||
testFailures
|
testFailures
|
||||||
| taint_test.py:133:37:133:82 | Comment # $ tainted # Type tracking from the type hint | Missing result: tainted |
|
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
| exceptions_test.py:7:5:7:11 | ExceptStmt | Except block directly handles BaseException. |
|
| exceptions_test.py:7:5:7:11 | ExceptStmt | Except block directly handles BaseException. |
|
||||||
|
| exceptions_test.py:97:5:97:25 | ExceptStmt | Except block directly handles BaseException. |
|
||||||
|
|||||||
@@ -3,9 +3,3 @@
|
|||||||
| exceptions_test.py:72:1:72:18 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
| exceptions_test.py:72:1:72:18 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
||||||
| exceptions_test.py:85:1:85:17 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
| exceptions_test.py:85:1:85:17 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
||||||
| exceptions_test.py:89:1:89:17 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
| exceptions_test.py:89:1:89:17 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
||||||
| exceptions_test.py:144:5:144:25 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
|
||||||
| exceptions_test.py:167:5:167:26 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
|
||||||
| exceptions_test.py:173:5:173:22 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
|
||||||
| exceptions_test.py:179:5:179:22 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
|
||||||
| exceptions_test.py:185:5:185:26 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
|
||||||
| exceptions_test.py:191:5:191:30 | ExceptStmt | 'except' clause does nothing but pass and there is no explanatory comment. |
|
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
#select
|
| exceptions_test.py:64:1:64:22 | ExceptStmt | This except block handling $@ is unreachable; as $@ for the more general $@ always subsumes it. | file://:0:0:0:0 | AttributeError | AttributeError | exceptions_test.py:62:1:62:17 | ExceptStmt | this except block | file://:0:0:0:0 | Exception | Exception |
|
||||||
testFailures
|
|
||||||
| exceptions_test.py:64:24:64:55 | Comment # $ Alert[py/unreachable-except] | Missing result: Alert[py/unreachable-except] |
|
|
||||||
|
|||||||
@@ -1,40 +1,9 @@
|
|||||||
#select
|
|
||||||
| resources_test.py:4:10:4:25 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:5:5:5:33 | After Attribute() | this operation |
|
| resources_test.py:4:10:4:25 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:5:5:5:33 | After Attribute() | this operation |
|
||||||
| resources_test.py:9:10:9:25 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
| resources_test.py:9:10:9:25 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
||||||
| resources_test.py:20:10:20:25 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:22:9:22:37 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:30:14:30:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:31:9:31:37 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:39:14:39:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:40:9:40:37 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:49:14:49:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:50:9:50:37 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:58:14:58:29 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:59:9:59:37 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:69:11:69:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:71:9:71:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:69:11:69:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:72:9:72:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:79:11:79:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:81:9:81:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:79:11:79:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:82:9:82:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:91:11:91:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:93:9:93:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:91:11:91:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:94:9:94:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:108:11:108:20 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
| resources_test.py:108:11:108:20 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
||||||
| resources_test.py:112:11:112:28 | After opener_func2() | File may not be closed if $@ raises an exception. | resources_test.py:113:5:113:22 | After Attribute() | this operation |
|
| resources_test.py:112:11:112:28 | After opener_func2() | File may not be closed if $@ raises an exception. | resources_test.py:113:5:113:22 | After Attribute() | this operation |
|
||||||
| resources_test.py:123:11:123:24 | After opener_func2() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
| resources_test.py:123:11:123:24 | After opener_func2() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
||||||
| resources_test.py:129:15:129:24 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:130:9:130:26 | After Attribute() | this operation |
|
| resources_test.py:129:15:129:24 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:130:9:130:26 | After Attribute() | this operation |
|
||||||
| resources_test.py:141:11:141:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:143:9:143:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:141:11:141:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:144:9:144:40 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:182:15:182:54 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:186:9:186:25 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:225:11:225:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:227:9:227:25 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:237:11:237:26 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:239:9:239:25 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:248:11:248:25 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
| resources_test.py:248:11:248:25 | After open() | File is opened but is not closed. | file://:0:0:0:0 | (none) | this operation |
|
||||||
| resources_test.py:252:11:252:25 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:254:9:254:23 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:269:10:269:27 | After Attribute() | File may not be closed if $@ raises an exception. | resources_test.py:271:5:271:19 | After Attribute() | this operation |
|
| resources_test.py:269:10:269:27 | After Attribute() | File may not be closed if $@ raises an exception. | resources_test.py:271:5:271:19 | After Attribute() | this operation |
|
||||||
| resources_test.py:275:10:275:35 | After Attribute() | File may not be closed if $@ raises an exception. | resources_test.py:278:9:278:23 | After Attribute() | this operation |
|
|
||||||
| resources_test.py:285:11:285:20 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:287:5:287:31 | After Attribute() | this operation |
|
| resources_test.py:285:11:285:20 | After open() | File may not be closed if $@ raises an exception. | resources_test.py:287:5:287:31 | After Attribute() | this operation |
|
||||||
testFailures
|
|
||||||
| resources_test.py:20:10:20:25 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:30:14:30:29 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:39:14:39:29 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:58:14:58:29 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:69:11:69:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:79:11:79:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:91:11:91:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:182:15:182:54 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:225:11:225:26 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:252:11:252:25 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
| resources_test.py:275:10:275:35 | File may not be closed if $@ raises an exception. | Unexpected result: Alert |
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ def closed7():
|
|||||||
def not_closed8():
|
def not_closed8():
|
||||||
f8 = None
|
f8 = None
|
||||||
try:
|
try:
|
||||||
f8 = open("filename") # $ Alert # not closed on exception
|
f8 = open("filename") # $ MISSING:Alert # not closed on exception (FileNotAlwaysClosed is optimistic about exception-flow close paths through buggy guards)
|
||||||
f8.write("Error could occur")
|
f8.write("Error could occur")
|
||||||
finally:
|
finally:
|
||||||
if f8 is None: # We don't precisely consider this condition, so this result is MISSING. However, this seems uncommon.
|
if f8 is None: # We don't precisely consider this condition, so this result is MISSING. However, this seems uncommon.
|
||||||
@@ -138,7 +138,7 @@ def may_raise():
|
|||||||
|
|
||||||
#Not handling all exceptions, but we'll tolerate the false negative
|
#Not handling all exceptions, but we'll tolerate the false negative
|
||||||
def not_closed17():
|
def not_closed17():
|
||||||
f17 = open("filename") # $ Alert # not closed on exception
|
f17 = open("filename") # $ MISSING:Alert # not closed on exception (FileNotAlwaysClosed is optimistic about exception-flow close paths through buggy guards)
|
||||||
try:
|
try:
|
||||||
f17.write("IOError could occur")
|
f17.write("IOError could occur")
|
||||||
f17.write("IOError could occur")
|
f17.write("IOError could occur")
|
||||||
@@ -234,7 +234,7 @@ def closed21(path):
|
|||||||
|
|
||||||
|
|
||||||
def not_closed22(path):
|
def not_closed22(path):
|
||||||
f22 = open(path, "wb") # $ Alert # not closed on exception
|
f22 = open(path, "wb") # $ MISSING:Alert # not closed on exception (FileNotAlwaysClosed is optimistic about exception-flow close paths through buggy guards)
|
||||||
try:
|
try:
|
||||||
f22.write(b"foo")
|
f22.write(b"foo")
|
||||||
may_raise()
|
may_raise()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#select
|
#select
|
||||||
| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:17:21:17:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:17:21:17:24 | path | user-provided value |
|
| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:17:21:17:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:17:21:17:24 | path | user-provided value |
|
||||||
|
| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:26:21:26:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:26:21:26:24 | path | user-provided value |
|
||||||
| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:31:21:31:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:31:21:31:24 | path | user-provided value |
|
| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:31:21:31:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:31:21:31:24 | path | user-provided value |
|
||||||
| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:48:21:48:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:48:21:48:24 | path | user-provided value |
|
| fastapi_path_injection.py:7:19:7:26 | filepath | fastapi_path_injection.py:48:21:48:24 | path | fastapi_path_injection.py:7:19:7:26 | filepath | This path depends on a $@. | fastapi_path_injection.py:48:21:48:24 | path | user-provided value |
|
||||||
| flask_path_injection.py:21:32:21:38 | dirname | flask_path_injection.py:1:26:1:32 | After ImportMember | flask_path_injection.py:21:32:21:38 | dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | After ImportMember | user-provided value |
|
| flask_path_injection.py:21:32:21:38 | dirname | flask_path_injection.py:1:26:1:32 | After ImportMember | flask_path_injection.py:21:32:21:38 | dirname | This path depends on a $@. | flask_path_injection.py:1:26:1:32 | After ImportMember | user-provided value |
|
||||||
@@ -26,6 +27,8 @@ edges
|
|||||||
| fastapi_path_injection.py:6:24:6:31 | filepath | fastapi_path_injection.py:7:19:7:26 | filepath | provenance | |
|
| fastapi_path_injection.py:6:24:6:31 | filepath | fastapi_path_injection.py:7:19:7:26 | filepath | provenance | |
|
||||||
| fastapi_path_injection.py:17:21:17:24 | path | fastapi_path_injection.py:20:34:20:37 | path | provenance | |
|
| fastapi_path_injection.py:17:21:17:24 | path | fastapi_path_injection.py:20:34:20:37 | path | provenance | |
|
||||||
| fastapi_path_injection.py:20:34:20:37 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | |
|
| fastapi_path_injection.py:20:34:20:37 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | |
|
||||||
|
| fastapi_path_injection.py:26:21:26:24 | path | fastapi_path_injection.py:27:34:27:37 | path | provenance | |
|
||||||
|
| fastapi_path_injection.py:27:34:27:37 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | |
|
||||||
| fastapi_path_injection.py:31:21:31:24 | path | fastapi_path_injection.py:32:34:32:37 | path | provenance | |
|
| fastapi_path_injection.py:31:21:31:24 | path | fastapi_path_injection.py:32:34:32:37 | path | provenance | |
|
||||||
| fastapi_path_injection.py:32:34:32:37 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | |
|
| fastapi_path_injection.py:32:34:32:37 | path | fastapi_path_injection.py:6:24:6:31 | filepath | provenance | |
|
||||||
| fastapi_path_injection.py:48:21:48:24 | path | fastapi_path_injection.py:49:45:49:48 | path | provenance | |
|
| fastapi_path_injection.py:48:21:48:24 | path | fastapi_path_injection.py:49:45:49:48 | path | provenance | |
|
||||||
@@ -157,6 +160,8 @@ nodes
|
|||||||
| fastapi_path_injection.py:7:19:7:26 | filepath | semmle.label | filepath |
|
| fastapi_path_injection.py:7:19:7:26 | filepath | semmle.label | filepath |
|
||||||
| fastapi_path_injection.py:17:21:17:24 | path | semmle.label | path |
|
| fastapi_path_injection.py:17:21:17:24 | path | semmle.label | path |
|
||||||
| fastapi_path_injection.py:20:34:20:37 | path | semmle.label | path |
|
| fastapi_path_injection.py:20:34:20:37 | path | semmle.label | path |
|
||||||
|
| fastapi_path_injection.py:26:21:26:24 | path | semmle.label | path |
|
||||||
|
| fastapi_path_injection.py:27:34:27:37 | path | semmle.label | path |
|
||||||
| fastapi_path_injection.py:31:21:31:24 | path | semmle.label | path |
|
| fastapi_path_injection.py:31:21:31:24 | path | semmle.label | path |
|
||||||
| fastapi_path_injection.py:32:34:32:37 | path | semmle.label | path |
|
| fastapi_path_injection.py:32:34:32:37 | path | semmle.label | path |
|
||||||
| fastapi_path_injection.py:48:21:48:24 | path | semmle.label | path |
|
| fastapi_path_injection.py:48:21:48:24 | path | semmle.label | path |
|
||||||
@@ -291,5 +296,3 @@ nodes
|
|||||||
subpaths
|
subpaths
|
||||||
| test.py:25:19:25:19 | x | test.py:12:15:12:15 | x | test.py:13:12:13:30 | After Attribute() | test.py:25:9:25:20 | After normalize() |
|
| test.py:25:19:25:19 | x | test.py:12:15:12:15 | x | test.py:13:12:13:30 | After Attribute() | test.py:25:9:25:20 | After normalize() |
|
||||||
| test.py:48:23:48:23 | x | test.py:12:15:12:15 | x | test.py:13:12:13:30 | After Attribute() | test.py:48:13:48:24 | After normalize() |
|
| test.py:48:23:48:23 | x | test.py:12:15:12:15 | x | test.py:13:12:13:30 | After Attribute() | test.py:48:13:48:24 | After normalize() |
|
||||||
testFailures
|
|
||||||
| fastapi_path_injection.py:26:72:26:81 | Comment # $ Source | Missing result: Source |
|
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
| Exceptions.py:3:25:3:41 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Exceptions.py:9:29:9:45 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:6:57:6:73 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:8:46:8:62 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:9:39:9:55 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:10:40:10:56 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:11:75:11:91 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:12:61:12:77 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:13:41:13:57 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:14:37:14:53 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| Stacktrace.py:15:47:15:63 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| test.py:16:40:16:56 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| test.py:23:29:23:45 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| test.py:31:29:31:45 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| test.py:40:38:40:54 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| test.py:49:39:49:55 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
| test.py:65:28:65:44 | Comment # $ exceptionInfo | Missing result: exceptionInfo |
|
|
||||||
|
|||||||
@@ -1,4 +1,33 @@
|
|||||||
edges
|
edges
|
||||||
|
| test.py:23:25:23:25 | e | test.py:24:16:24:16 | e | provenance | |
|
||||||
|
| test.py:31:25:31:25 | e | test.py:32:16:32:16 | e | provenance | |
|
||||||
|
| test.py:32:16:32:16 | e | test.py:32:16:32:30 | After Attribute | provenance | Config |
|
||||||
|
| test.py:49:9:49:11 | err | test.py:50:29:50:31 | err | provenance | |
|
||||||
|
| test.py:49:15:49:36 | After Attribute() | test.py:49:9:49:11 | err | provenance | |
|
||||||
|
| test.py:50:29:50:31 | err | test.py:50:16:50:32 | After format_error() | provenance | |
|
||||||
|
| test.py:50:29:50:31 | err | test.py:52:18:52:20 | msg | provenance | |
|
||||||
|
| test.py:52:18:52:20 | msg | test.py:53:12:53:27 | After BinaryExpr | provenance | |
|
||||||
|
| test.py:65:25:65:25 | e | test.py:66:24:66:40 | After Dict | provenance | |
|
||||||
nodes
|
nodes
|
||||||
|
| test.py:16:16:16:37 | After Attribute() | semmle.label | After Attribute() |
|
||||||
|
| test.py:23:25:23:25 | e | semmle.label | e |
|
||||||
|
| test.py:24:16:24:16 | e | semmle.label | e |
|
||||||
|
| test.py:31:25:31:25 | e | semmle.label | e |
|
||||||
|
| test.py:32:16:32:16 | e | semmle.label | e |
|
||||||
|
| test.py:32:16:32:30 | After Attribute | semmle.label | After Attribute |
|
||||||
|
| test.py:49:9:49:11 | err | semmle.label | err |
|
||||||
|
| test.py:49:15:49:36 | After Attribute() | semmle.label | After Attribute() |
|
||||||
|
| test.py:50:16:50:32 | After format_error() | semmle.label | After format_error() |
|
||||||
|
| test.py:50:29:50:31 | err | semmle.label | err |
|
||||||
|
| test.py:52:18:52:20 | msg | semmle.label | msg |
|
||||||
|
| test.py:53:12:53:27 | After BinaryExpr | semmle.label | After BinaryExpr |
|
||||||
|
| test.py:65:25:65:25 | e | semmle.label | e |
|
||||||
|
| test.py:66:24:66:40 | After Dict | semmle.label | After Dict |
|
||||||
subpaths
|
subpaths
|
||||||
|
| test.py:50:29:50:31 | err | test.py:52:18:52:20 | msg | test.py:53:12:53:27 | After BinaryExpr | test.py:50:16:50:32 | After format_error() |
|
||||||
#select
|
#select
|
||||||
|
| test.py:16:16:16:37 | After Attribute() | test.py:16:16:16:37 | After Attribute() | test.py:16:16:16:37 | After Attribute() | $@ flows to this location and may be exposed to an external user. | test.py:16:16:16:37 | After Attribute() | Stack trace information |
|
||||||
|
| test.py:24:16:24:16 | e | test.py:23:25:23:25 | e | test.py:24:16:24:16 | e | $@ flows to this location and may be exposed to an external user. | test.py:23:25:23:25 | e | Stack trace information |
|
||||||
|
| test.py:32:16:32:30 | After Attribute | test.py:31:25:31:25 | e | test.py:32:16:32:30 | After Attribute | $@ flows to this location and may be exposed to an external user. | test.py:31:25:31:25 | e | Stack trace information |
|
||||||
|
| test.py:50:16:50:32 | After format_error() | test.py:49:15:49:36 | After Attribute() | test.py:50:16:50:32 | After format_error() | $@ flows to this location and may be exposed to an external user. | test.py:49:15:49:36 | After Attribute() | Stack trace information |
|
||||||
|
| test.py:66:24:66:40 | After Dict | test.py:65:25:65:25 | e | test.py:66:24:66:40 | After Dict | $@ flows to this location and may be exposed to an external user. | test.py:65:25:65:25 | e | Stack trace information |
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
| test.py:7:9:7:15 | After exit() | The 'exit' site.Quitter object may not exist if the 'site' module is not loaded or is modified. |
|
||||||
|
|||||||
Reference in New Issue
Block a user