Merge branch 'main' into port-url-redirect-query

This commit is contained in:
Rasmus Wriedt Larsen
2021-01-29 16:22:50 +01:00
469 changed files with 78092 additions and 11197 deletions

View File

@@ -39,6 +39,16 @@ class Function extends Function_, Scope, AstNode {
exists(YieldFrom y | y.getScope() = this)
}
/**
* Holds if this function represents a lambda.
*
* The extractor reifies each lambda expression as a (local) function with the name
* "lambda". As `lambda` is a keyword in Python, it's impossible to create a function with this
* name otherwise, and so it's impossible to get a non-lambda function accidentally
* classified as a lambda.
*/
predicate isLambda() { this.getName() = "lambda" }
/** Whether this function is declared in a class and is named `__init__` */
predicate isInitMethod() { this.isMethod() and this.getName() = "__init__" }

View File

@@ -11,103 +11,138 @@ private import semmle.python.essa.SsaCompute
//--------
predicate isExpressionNode(ControlFlowNode node) { node.getNode() instanceof Expr }
/** A data flow node for which we should synthesise an associated pre-update node. */
abstract class NeedsSyntheticPreUpdateNode extends Node {
/** A label for this kind of node. This will figure in the textual representation of the synthesized pre-update node. */
abstract string label();
}
/** A module collecting the different reasons for synthesising a pre-update node. */
module syntheticPreUpdateNode {
class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
NeedsSyntheticPreUpdateNode post;
class SyntheticPreUpdateNode extends Node, TSyntheticPreUpdateNode {
NeedsSyntheticPreUpdateNode post;
SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(post) }
SyntheticPreUpdateNode() { this = TSyntheticPreUpdateNode(post) }
/** Gets the node for which this is a synthetic pre-update node. */
Node getPostUpdateNode() { result = post }
/** Gets the node for which this is a synthetic pre-update node. */
Node getPostUpdateNode() { result = post }
override string toString() { result = "[pre " + post.label() + "] " + post.toString() }
override string toString() { result = "[pre " + post.label() + "] " + post.toString() }
override Scope getScope() { result = post.getScope() }
override Scope getScope() { result = post.getScope() }
override Location getLocation() { result = post.getLocation() }
}
/** A data flow node for which we should synthesise an associated post-update node. */
abstract class NeedsSyntheticPostUpdateNode extends Node {
/** A label for this kind of node. This will figure in the textual representation of the synthesized post-update node. */
abstract string label();
}
/** An argument might have its value changed as a result of a call. */
class ArgumentPreUpdateNode extends NeedsSyntheticPostUpdateNode, ArgumentNode {
// Certain arguments, such as implicit self arguments are already post-update nodes
// and should not have an extra node synthesised.
ArgumentPreUpdateNode() {
this = any(FunctionCall c).getArg(_)
or
// Avoid argument 0 of method calls as those have read post-update nodes.
exists(MethodCall c, int n | n > 0 | this = c.getArg(n))
or
this = any(SpecialCall c).getArg(_)
or
// Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
exists(ClassCall c, int n | n > 0 | this = c.getArg(n))
override Location getLocation() { result = post.getLocation() }
}
override string label() { result = "arg" }
/** A data flow node for which we should synthesise an associated pre-update node. */
class NeedsSyntheticPreUpdateNode extends PostUpdateNode {
NeedsSyntheticPreUpdateNode() { this = objectCreationNode() }
override Node getPreUpdateNode() { result.(SyntheticPreUpdateNode).getPostUpdateNode() = this }
/**
* A label for this kind of node. This will figure in the textual representation of the synthesized pre-update node.
*
* There is currently only one reason for needing a pre-update node, so we always use that as the label.
*/
string label() { result = "objCreate" }
}
/**
* Calls to constructors are treated as post-update nodes for the synthesized argument
* that is mapped to the `self` parameter. That way, constructor calls represent the value of the
* object after the constructor (currently only `__init__`) has run.
*/
CfgNode objectCreationNode() { result.getNode().(CallNode) = any(ClassCall c).getNode() }
}
/** An object might have its value changed after a store. */
class StorePreUpdateNode extends NeedsSyntheticPostUpdateNode, CfgNode {
StorePreUpdateNode() {
import syntheticPreUpdateNode
/** A module collecting the different reasons for synthesising a post-update node. */
module syntheticPostUpdateNode {
/** A post-update node is synthesized for all nodes which satisfy `NeedsSyntheticPostUpdateNode`. */
class SyntheticPostUpdateNode extends PostUpdateNode, TSyntheticPostUpdateNode {
NeedsSyntheticPostUpdateNode pre;
SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(pre) }
override Node getPreUpdateNode() { result = pre }
override string toString() { result = "[post " + pre.label() + "] " + pre.toString() }
override Scope getScope() { result = pre.getScope() }
override Location getLocation() { result = pre.getLocation() }
}
/** A data flow node for which we should synthesise an associated post-update node. */
class NeedsSyntheticPostUpdateNode extends Node {
NeedsSyntheticPostUpdateNode() {
this = argumentPreUpdateNode()
or
this = storePreUpdateNode()
or
this = readPreUpdateNode()
}
/**
* A label for this kind of node. This will figure in the textual representation of the synthesized post-update node.
* We favour being an arguments as the reason for the post-update node in case multiple reasons apply.
*/
string label() {
if this = argumentPreUpdateNode()
then result = "arg"
else
if this = storePreUpdateNode()
then result = "store"
else result = "read"
}
}
/**
* An argument might have its value changed as a result of a call.
* Certain arguments, such as implicit self arguments are already post-update nodes
* and should not have an extra node synthesised.
*/
ArgumentNode argumentPreUpdateNode() {
result = any(FunctionCall c).getArg(_)
or
// Avoid argument 0 of method calls as those have read post-update nodes.
exists(MethodCall c, int n | n > 0 | result = c.getArg(n))
or
result = any(SpecialCall c).getArg(_)
or
// Avoid argument 0 of class calls as those have non-synthetic post-update nodes.
exists(ClassCall c, int n | n > 0 | result = c.getArg(n))
}
/** An object might have its value changed after a store. */
CfgNode storePreUpdateNode() {
exists(Attribute a |
node = a.getObject().getAFlowNode() and
result.getNode() = a.getObject().getAFlowNode() and
a.getCtx() instanceof Store
)
}
override string label() { result = "store" }
}
/** A node marking the state change of an object after a read. */
class ReadPreUpdateNode extends NeedsSyntheticPostUpdateNode, CfgNode {
ReadPreUpdateNode() {
/**
* A node marking the state change of an object after a read.
*
* A reverse read happens when the result of a read is modified, e.g. in
* ```python
* l = [ mutable ]
* l[0].mutate()
* ```
* we may now have changed the content of `l`. To track this, there must be
* a postupdate node for `l`.
*/
CfgNode readPreUpdateNode() {
exists(Attribute a |
node = a.getObject().getAFlowNode() and
result.getNode() = a.getObject().getAFlowNode() and
a.getCtx() instanceof Load
)
or
result.getNode() = any(SubscriptNode s).getObject()
or
// The dictionary argument is read from if the callable has parameters matching the keys.
result.getNode().getNode() = any(Call call).getKwargs()
}
override string label() { result = "read" }
}
/** A post-update node is synthesized for all nodes which satisfy `NeedsSyntheticPostUpdateNode`. */
class SyntheticPostUpdateNode extends PostUpdateNode, TSyntheticPostUpdateNode {
NeedsSyntheticPostUpdateNode pre;
SyntheticPostUpdateNode() { this = TSyntheticPostUpdateNode(pre) }
override Node getPreUpdateNode() { result = pre }
override string toString() { result = "[post " + pre.label() + "] " + pre.toString() }
override Scope getScope() { result = pre.getScope() }
override Location getLocation() { result = pre.getLocation() }
}
/**
* Calls to constructors are treated as post-update nodes for the synthesized argument
* that is mapped to the `self` parameter. That way, constructor calls represent the value of the
* object after the constructor (currently only `__init__`) has run.
*/
class ObjectCreationNode extends PostUpdateNode, NeedsSyntheticPreUpdateNode, CfgNode {
ObjectCreationNode() { node.(CallNode) = any(ClassCall c).getNode() }
override Node getPreUpdateNode() { result.(SyntheticPreUpdateNode).getPostUpdateNode() = this }
override string label() { result = "objCreate" }
}
import syntheticPostUpdateNode
class DataFlowExpr = Expr;
@@ -126,6 +161,15 @@ module EssaFlow {
nodeFrom.(CfgNode).getNode() =
nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getValue()
or
// Definition
// `[a, b] = iterable`
// nodeFrom = `iterable`, cfg node
// nodeTo = `TIterableSequence([a, b])`
exists(UnpackingAssignmentDirectTarget target |
nodeFrom.asExpr() = target.getValue() and
nodeTo = TIterableSequenceNode(target)
)
or
// With definition
// `with f(42) as x:`
// nodeFrom is `f(42)`, cfg node
@@ -139,6 +183,10 @@ module EssaFlow {
contextManager.strictlyDominates(var)
)
or
// Parameter definition
// `def foo(x):`
// nodeFrom is `x`, cfgNode
// nodeTo is `x`, essa var
exists(ParameterDefinition pd |
nodeFrom.asCfgNode() = pd.getDefiningNode() and
nodeTo.asVar() = pd.getVariable()
@@ -161,6 +209,9 @@ module EssaFlow {
// If expressions
nodeFrom.asCfgNode() = nodeTo.asCfgNode().(IfExprNode).getAnOperand()
or
// Flow inside an unpacking assignment
unpackingAssignmentFlowStep(nodeFrom, nodeTo)
or
// Overflow keyword argument
exists(CallNode call, CallableValue callable |
call = callable.getACall() and
@@ -419,7 +470,7 @@ module ArgumentPassing {
// argument unpacked from dict
exists(string name |
call_unpacks(call, mapping, callable, name, paramN) and
result = TKwUnpacked(call, callable, name)
result = TKwUnpackedNode(call, callable, name)
)
)
}
@@ -484,10 +535,12 @@ import ArgumentPassing
*/
newtype TDataFlowCallable =
TCallableValue(CallableValue callable) {
callable instanceof FunctionValue
callable instanceof FunctionValue and
not callable.(FunctionValue).isLambda()
or
callable instanceof ClassValue
} or
TLambda(Function lambda) { lambda.isLambda() } or
TModule(Module m)
/** Represents a callable. */
@@ -530,6 +583,27 @@ class DataFlowCallableValue extends DataFlowCallable, TCallableValue {
override CallableValue getCallableValue() { result = callable }
}
/** A class representing a callable lambda. */
class DataFlowLambda extends DataFlowCallable, TLambda {
Function lambda;
DataFlowLambda() { this = TLambda(lambda) }
override string toString() { result = lambda.toString() }
override CallNode getACall() { result = getCallableValue().getACall() }
override Scope getScope() { result = lambda.getEvaluatingScope() }
override NameNode getParameter(int n) { result = getParameter(getCallableValue(), n) }
override string getName() { result = "Lambda callable" }
override FunctionValue getCallableValue() {
result.getOrigin().getNode() = lambda.getDefinition()
}
}
/** A class representing the scope in which a `ModuleVariableNode` appears. */
class DataFlowModuleScope extends DataFlowCallable, TModule {
Module mod;
@@ -703,17 +777,6 @@ class SpecialCall extends DataFlowCall, TSpecialCall {
}
}
/** A data flow node that represents a call argument. */
class ArgumentNode extends Node {
ArgumentNode() { this = any(DataFlowCall c).getArg(_) }
/** Holds if this argument occurs at the given position in the given call. */
predicate argumentOf(DataFlowCall call, int pos) { this = call.getArg(pos) }
/** Gets the call in which this node is an argument. */
final DataFlowCall getCall() { this.argumentOf(result, _) }
}
/** Gets a viable run-time target for the call `call`. */
DataFlowCallable viableCallable(DataFlowCall call) { result = call.getCallable() }
@@ -844,6 +907,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
or
comprehensionStoreStep(nodeFrom, c, nodeTo)
or
unpackingAssignmentStoreStep(nodeFrom, c, nodeTo)
or
attributeStoreStep(nodeFrom, c, nodeTo)
or
posOverflowStoreStep(nodeFrom, c, nodeTo)
@@ -859,6 +924,7 @@ predicate listStoreStep(CfgNode nodeFrom, ListElementContent c, CfgNode nodeTo)
// nodeTo is the list, `[..., 42, ...]`, cfg node
// c denotes element of list
nodeTo.getNode().(ListNode).getAnElement() = nodeFrom.getNode() and
not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and
// Suppress unused variable warning
c = c
}
@@ -884,6 +950,7 @@ predicate tupleStoreStep(CfgNode nodeFrom, TupleElementContent c, CfgNode nodeTo
// c denotes element of tuple and index of nodeFrom
exists(int n |
nodeTo.getNode().(TupleNode).getElement(n) = nodeFrom.getNode() and
not nodeTo.getNode() instanceof UnpackingAssignmentSequenceTarget and
c.getIndex() = n
)
}
@@ -974,6 +1041,8 @@ predicate kwOverflowStoreStep(CfgNode nodeFrom, DictionaryElementContent c, Node
predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
subscriptReadStep(nodeFrom, c, nodeTo)
or
unpackingAssignmentReadStep(nodeFrom, c, nodeTo)
or
popReadStep(nodeFrom, c, nodeTo)
or
comprehensionReadStep(nodeFrom, c, nodeTo)
@@ -1006,6 +1075,322 @@ predicate subscriptReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
)
}
/**
* The unpacking assignment takes the general form
* ```python
* sequence = iterable
* ```
* where `sequence` is either a tuple or a list and it can contain wildcards.
* The iterable can be any iterable, which means that (CodeQL modeling of) content
* will need to change type if it should be transferred from the LHS to the RHS.
*
* Note that (CodeQL modeling of) content does not have to change type on data-flow
* paths _inside_ the LHS, as the different allowed syntaxes here are merely a convenience.
* Consequently, we model all LHS sequences as tuples, which have the more precise content
* model, making flow to the elements more precise. If an element is a starred variable,
* we will have to mutate the content type to be list content.
*
* We may for instance have
* ```python
* (a, b) = ["a", SOURCE] # RHS has content `ListElementContent`
* ```
* Due to the abstraction for list content, we do not know whether `SOURCE`
* ends up in `a` or in `b`, so we want to overapproximate and see it in both.
*
* Using wildcards we may have
* ```python
* (a, *b) = ("a", "b", SOURCE) # RHS has content `TupleElementContent(2)`
* ```
* Since the starred variables are always assigned (Python-)type list, `*b` will be
* `["b", SOURCE]`, and we will again overapproximate and assign it
* content corresponding to anything found in the RHS.
*
* For a precise transfer
* ```python
* (a, b) = ("a", SOURCE) # RHS has content `TupleElementContent(1)`
* ```
* we wish to keep the precision, so only `b` receives the tuple content at index 1.
*
* Finally, `sequence` is actually a pattern and can have a more complicated structure,
* such as
* ```python
* (a, [b, *c]) = ("a", ["b", SOURCE]) # RHS has content `TupleElementContent(1); ListElementContent`
* ```
* where `a` should not receive content, but `b` and `c` should. `c` will be `[SOURCE]` so
* should have the content transferred, while `b` should read it.
*
* To transfer content from RHS to the elements of the LHS in the expression `sequence = iterable`,
* we use two synthetic nodes:
*
* - `TIterableSequence(sequence)` which captures the content-modeling the entire `sequence` will have
* (essentially just a copy of the content-modeling the RHS has)
*
* - `TIterableElement(sequence)` which captures the content-modeling that will be assigned to an element.
* Note that an empty access path means that the value we are tracking flows directly to the element.
*
*
* The `TIterableSequence(sequence)` is at this point superflous but becomes useful when handling recursive
* structures in the LHS, where `sequence` is some internal sequence node. We can have a uniform treatment
* by always having these two synthetic nodes. So we transfer to (or, in the recursive case, read into)
* `TIterableSequence(sequence)`, from which we take a read step to `TIterableElement(sequence)` and then a
* store step to `sequence`.
*
* This allows the unknown content from the RHS to be read into `TIterableElement(sequence)` and tuple content
* to then be stored into `sequence`. If the content is already tuple content, this inderection creates crosstalk
* between indices. Therefore, tuple content is never read into `TIterableElement(sequence)`; it is instead
* transferred directly from `TIterableSequence(sequence)` to `sequence` via a flow step. Such a flow step will
* also transfer other content, but only tuple content is further read from `sequence` into its elements.
*
* The strategy is then via several read-, store-, and flow steps:
* 1. [Flow] Content is transferred from `iterable` to `TIterableSequence(sequence)` via a
* flow step. From here, everything happens on the LHS.
*
* 2. [Flow] Content is transferred from `TIterableSequence(sequence)` to `sequence` via a
* flow step. (Here only tuple content is relevant.)
*
* 3. [Read] Content is read from `TIterableSequence(sequence)` into `TIterableElement(sequence)`.
* As `sequence` is modeled as a tuple, we will not read tuple content as that would allow
* crosstalk.
*
* 4. [Store] Content is stored from `TIterableElement(sequence)` to `sequence`.
* Content type is `TupleElementContent` with indices taken from the syntax.
* For instance, if `sequence` is `(a, *b, c)`, content is written to index 0, 1, and 2.
* This is adequate as the route through `TIterableElement(sequence)` does not transfer precise content.
*
* 5. [Read] Content is read from `sequence` to its elements.
* a) If the element is a plain variable, the target is the corresponding essa node.
*
* b) If the element is itself a sequence, with control-flow node `seq`, the target is `TIterableSequence(seq)`.
*
* c) If the element is a starred variable, with control-flow node `v`, the target is `TIterableElement(v)`.
*
* 6. [Store] Content is stored from `TIterableElement(v)` to the essa variable for `v`, with
* content type `ListElementContent`.
*
* 7. [Flow, Read, Store] Steps 2 through 7 are repeated for all recursive elements which are sequences.
*
*
* We illustrate the above steps on the assignment
*
* ```python
* (a, b) = ["a", SOURCE]
* ```
*
* Looking at the content propagation to `a`:
* `["a", SOURCE]`: [ListElementContent]
*
* --Step 1-->
*
* `TIterableSequence((a, b))`: [ListElementContent]
*
* --Step 3-->
*
* `TIterableElement((a, b))`: []
*
* --Step 4-->
*
* `(a, b)`: [TupleElementContent(0)]
*
* --Step 5a-->
*
* `a`: []
*
* Meaning there is data-flow from the RHS to `a` (an over approximation). The same logic would be applied to show there is data-flow to `b`. Note that _Step 3_ and _Step 4_ would not have been needed if the RHS had been a tuple (since that would have been able to use _Step 2_ instead).
*
* Another, more complicated example:
* ```python
* (a, [b, *c]) = ["a", [SOURCE]]
* ```
* where the path to `c` is
*
* `["a", [SOURCE]]`: [ListElementContent; ListElementContent]
*
* --Step 1-->
*
* `TIterableSequence((a, [b, *c]))`: [ListElementContent; ListElementContent]
*
* --Step 3-->
*
* `TIterableElement((a, [b, *c]))`: [ListElementContent]
*
* --Step 4-->
*
* `(a, [b, *c])`: [TupleElementContent(1); ListElementContent]
*
* --Step 5b-->
*
* `TIterableSequence([b, *c])`: [ListElementContent]
*
* --Step 3-->
*
* `TIterableElement([b, *c])`: []
*
* --Step 4-->
*
* `[b, *c]`: [TupleElementContent(1)]
*
* --Step 5c-->
*
* `TIterableElement(c)`: []
*
* --Step 6-->
*
* `c`: [ListElementContent]
*/
module UnpackingAssignment {
/** A direct (or top-level) target of an unpacking assignment. */
class UnpackingAssignmentDirectTarget extends ControlFlowNode {
Expr value;
UnpackingAssignmentDirectTarget() {
this instanceof SequenceNode and
exists(Assign assign | this.getNode() = assign.getATarget() | value = assign.getValue())
}
Expr getValue() { result = value }
}
/** A (possibly recursive) target of an unpacking assignment. */
class UnpackingAssignmentTarget extends ControlFlowNode {
UnpackingAssignmentTarget() {
this instanceof UnpackingAssignmentDirectTarget
or
this = any(UnpackingAssignmentSequenceTarget parent).getAnElement()
}
}
/** A (possibly recursive) target of an unpacking assignment which is also a sequence. */
class UnpackingAssignmentSequenceTarget extends UnpackingAssignmentTarget {
UnpackingAssignmentSequenceTarget() { this instanceof SequenceNode }
ControlFlowNode getElement(int i) { result = this.(SequenceNode).getElement(i) }
ControlFlowNode getAnElement() { result = this.getElement(_) }
}
/**
* Step 2
* Data flows from `TIterableSequence(sequence)` to `sequence`
*/
predicate unpackingAssignmentFlowStep(Node nodeFrom, Node nodeTo) {
exists(UnpackingAssignmentSequenceTarget target |
nodeFrom = TIterableSequenceNode(target) and
nodeTo.asCfgNode() = target
)
}
/**
* Step 3
* Data flows from `TIterableSequence(sequence)` into `TIterableElement(sequence)`.
* As `sequence` is modeled as a tuple, we will not read tuple content as that would allow
* crosstalk.
*/
predicate unpackingAssignmentConvertingReadStep(Node nodeFrom, Content c, Node nodeTo) {
exists(UnpackingAssignmentSequenceTarget target |
nodeFrom = TIterableSequenceNode(target) and
nodeTo = TIterableElementNode(target) and
(
c instanceof ListElementContent
or
c instanceof SetElementContent
// TODO: dict content in iterable unpacking not handled
)
)
}
/**
* Step 4
* Data flows from `TIterableElement(sequence)` to `sequence`.
* Content type is `TupleElementContent` with indices taken from the syntax.
* For instance, if `sequence` is `(a, *b, c)`, content is written to index 0, 1, and 2.
*/
predicate unpackingAssignmentConvertingStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(UnpackingAssignmentSequenceTarget target |
nodeFrom = TIterableElementNode(target) and
nodeTo.asCfgNode() = target and
exists(int index | exists(target.getElement(index)) |
c.(TupleElementContent).getIndex() = index
)
)
}
/**
* Step 5
* For a sequence node inside an iterable unpacking, data flows from the sequence to its elements. There are
* three cases for what `toNode` should be:
* a) If the element is a plain variable, `toNode` is the corresponding essa node.
*
* b) If the element is itself a sequence, with control-flow node `seq`, `toNode` is `TIterableSequence(seq)`.
*
* c) If the element is a starred variable, with control-flow node `v`, `toNode` is `TIterableElement(v)`.
*/
predicate unpackingAssignmentElementReadStep(Node nodeFrom, Content c, Node nodeTo) {
exists(
UnpackingAssignmentSequenceTarget target, int index, ControlFlowNode element, int starIndex
|
target.getElement(starIndex) instanceof StarredNode
or
not exists(target.getAnElement().(StarredNode)) and
starIndex = -1
|
nodeFrom.asCfgNode() = target and
element = target.getElement(index) and
(
if starIndex = -1 or index < starIndex
then c.(TupleElementContent).getIndex() = index
else
// This could get big if big tuples exist
if index = starIndex
then c.(TupleElementContent).getIndex() >= index
else c.(TupleElementContent).getIndex() >= index - 1
) and
(
if element instanceof SequenceNode
then
// Step 5b
nodeTo = TIterableSequenceNode(element)
else
if element instanceof StarredNode
then
// Step 5c
nodeTo = TIterableElementNode(element)
else
// Step 5a
nodeTo.asVar().getDefinition().(MultiAssignmentDefinition).getDefiningNode() = element
)
)
}
/**
* Step 6
* Data flows from `TIterableElement(v)` to the essa variable for `v`, with
* content type `ListElementContent`.
*/
predicate unpackingAssignmentStarredElementStoreStep(Node nodeFrom, Content c, Node nodeTo) {
exists(ControlFlowNode starred | starred.getNode() instanceof Starred |
nodeFrom = TIterableElementNode(starred) and
nodeTo.asVar().getDefinition().(MultiAssignmentDefinition).getDefiningNode() = starred and
c instanceof ListElementContent
)
}
/** All read steps associated with unpacking assignment. */
predicate unpackingAssignmentReadStep(Node nodeFrom, Content c, Node nodeTo) {
unpackingAssignmentElementReadStep(nodeFrom, c, nodeTo)
or
unpackingAssignmentConvertingReadStep(nodeFrom, c, nodeTo)
}
/** All store steps associated with unpacking assignment. */
predicate unpackingAssignmentStoreStep(Node nodeFrom, Content c, Node nodeTo) {
unpackingAssignmentStarredElementStoreStep(nodeFrom, c, nodeTo)
or
unpackingAssignmentConvertingStoreStep(nodeFrom, c, nodeTo)
}
}
import UnpackingAssignment
/** Data flows from a sequence to a call to `pop` on the sequence. */
predicate popReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
// set.pop or list.pop
@@ -1092,7 +1477,7 @@ predicate attributeReadStep(CfgNode nodeFrom, AttributeContent c, CfgNode nodeTo
predicate kwUnpackReadStep(CfgNode nodeFrom, DictionaryElementContent c, Node nodeTo) {
exists(CallNode call, CallableValue callable, string name |
nodeFrom.asCfgNode() = call.getNode().getKwargs().getAFlowNode() and
nodeTo = TKwUnpacked(call, callable, name) and
nodeTo = TKwUnpackedNode(call, callable, name) and
name = c.getKey()
)
}

View File

@@ -58,9 +58,18 @@ newtype TNode =
* That is, `call` contains argument `**{"foo": bar}` which is passed
* to parameter `foo` of `callable`.
*/
TKwUnpacked(CallNode call, CallableValue callable, string name) {
TKwUnpackedNode(CallNode call, CallableValue callable, string name) {
call_unpacks(call, _, callable, name, _)
}
} or
/**
* A synthetic node representing that an iterable sequence flows to consumer.
*/
TIterableSequenceNode(UnpackingAssignmentSequenceTarget consumer) or
/**
* A synthetic node representing that there may be an iterable element
* for `consumer` to consume.
*/
TIterableElementNode(UnpackingAssignmentTarget consumer)
/** Helper for `Node::getEnclosingCallable`. */
private DataFlowCallable getCallableScope(Scope s) {
@@ -179,7 +188,12 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e }
class ParameterNode extends CfgNode {
ParameterDefinition def;
ParameterNode() { node = def.getDefiningNode() }
ParameterNode() {
node = def.getDefiningNode() and
// Disregard parameters that we cannot resolve
// TODO: Make this unnecessary
exists(DataFlowCallable c | node = c.getParameter(_))
}
/**
* Holds if this node is the parameter of callable `c` at the
@@ -193,6 +207,17 @@ class ParameterNode extends CfgNode {
Parameter getParameter() { result = def.getParameter() }
}
/** A data flow node that represents a call argument. */
class ArgumentNode extends Node {
ArgumentNode() { this = any(DataFlowCall c).getArg(_) }
/** Holds if this argument occurs at the given position in the given call. */
predicate argumentOf(DataFlowCall call, int pos) { this = call.getArg(pos) }
/** Gets the call in which this node is an argument. */
final DataFlowCall getCall() { this.argumentOf(result, _) }
}
/**
* A node associated with an object after an operation that might have
* changed its state.
@@ -322,11 +347,11 @@ class KwOverflowNode extends Node, TKwOverflowNode {
* The node representing the synthetic argument of a call that is unpacked from a dictionary
* argument.
*/
class KwUnpacked extends Node, TKwUnpacked {
class KwUnpackedNode extends Node, TKwUnpackedNode {
CallNode call;
string name;
KwUnpacked() { this = TKwUnpacked(call, _, name) }
KwUnpackedNode() { this = TKwUnpackedNode(call, _, name) }
override string toString() { result = "KwUnpacked " + name }
@@ -340,6 +365,42 @@ class KwUnpacked extends Node, TKwUnpacked {
override Location getLocation() { result = call.getLocation() }
}
/**
* A synthetic node representing an iterable sequence. Used for changing content type
* for instance from a `ListElement` to a `TupleElement`, especially if the content is
* transferred via a read step which cannot be broken up into a read and a store. The
* read step then targets TIterableSequence, and the conversion can happen via a read
* step to TIterableElement followed by a store step to the target.
*/
class IterableSequenceNode extends Node, TIterableSequenceNode {
CfgNode consumer;
IterableSequenceNode() { this = TIterableSequenceNode(consumer.getNode()) }
override string toString() { result = "IterableSequence" }
override DataFlowCallable getEnclosingCallable() { result = consumer.getEnclosingCallable() }
override Location getLocation() { result = consumer.getLocation() }
}
/**
* A synthetic node representing an iterable element. Used for changing content type
* for instance from a `ListElement` to a `TupleElement`. This would happen via a
* read step from the list to IterableElement followed by a store step to the tuple.
*/
class IterableElementNode extends Node, TIterableElementNode {
CfgNode consumer;
IterableElementNode() { this = TIterableElementNode(consumer.getNode()) }
override string toString() { result = "IterableElement" }
override DataFlowCallable getEnclosingCallable() { result = consumer.getEnclosingCallable() }
override Location getLocation() { result = consumer.getLocation() }
}
/**
* A node that controls whether other nodes are evaluated.
*/

View File

@@ -68,5 +68,11 @@ Node importNode(string name) {
// Because named imports are modelled as `AttrRead`s, the statement `from foo import bar as baz`
// is interpreted as if it was an assignment `baz = foo.bar`, which means `baz` gets tracked as a
// reference to `foo.bar`, as desired.
result.asCfgNode().getNode() = any(ImportExpr i | i.getName() = name)
exists(ImportExpr imp_expr |
imp_expr.getName() = name and
result.asCfgNode().getNode() = imp_expr and
// in `import foo.bar` we DON'T want to give a result for `importNode("foo.bar")`,
// only for `importNode("foo")`. We exclude those cases with the following clause.
not exists(Import imp | imp.getAName().getValue() = imp_expr)
)
}

View File

@@ -1938,7 +1938,23 @@ private module Django {
private class DjangoUrlsRePathCall extends DjangoRegexRouteSetup {
override CallNode node;
DjangoUrlsRePathCall() { node.getFunction() = django::urls::re_path().asCfgNode() }
DjangoUrlsRePathCall() {
node.getFunction() = django::urls::re_path().asCfgNode() and
// `django.conf.urls.url` (which we support directly with
// `DjangoConfUrlsUrlCall`), is implemented in Django 2+ as backward compatibility
// using `django.urls.re_path`. See
// https://github.com/django/django/blob/stable/3.2.x/django/conf/urls/__init__.py#L22
// Since we're still installing dependencies and analyzing their source code,
// without explicitly filtering out this call, we would be double-counting such
// route-setups :( One practical negative side effect of double-counting it, is
// that since we can't figure out the URL in the library code calling `django.urls.re_path`
// (because we only consider local flow), we will for all those cases mark ANY parameter
// as being a routed-parameter, which can lead to FPs.
not exists(Module mod |
mod.getName() = "django.conf.urls.__init__" and
node.getEnclosingModule() = mod
)
}
override DataFlow::Node getUrlPatternArg() {
result.asCfgNode() = [node.getArg(0), node.getArgByName("route")]

View File

@@ -227,6 +227,17 @@ private module Tornado {
/** Gets a reference the `redirect` method. */
DataFlow::Node redirectMethod() { result = redirectMethod(DataFlow::TypeTracker::end()) }
/** Gets a reference to the `write` method. */
private DataFlow::Node writeMethod(DataFlow::TypeTracker t) {
t.startInAttr("write") and
result = instance()
or
exists(DataFlow::TypeTracker t2 | result = writeMethod(t2).track(t2, t))
}
/** Gets a reference to the `write` method. */
DataFlow::Node writeMethod() { result = writeMethod(DataFlow::TypeTracker::end()) }
private class AdditionalTaintStep extends TaintTracking::AdditionalTaintStep {
override predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
// Method access
@@ -575,6 +586,26 @@ private module Tornado {
override DataFlow::Node getBody() { none() }
override string getMimetypeDefault() { none() }
}
/**
* A call to `tornado.web.RequestHandler.write` method.
*
* See https://www.tornadoweb.org/en/stable/web.html?highlight=write#tornado.web.RequestHandler.write
*/
private class TornadoRequestHandlerWriteCall extends HTTP::Server::HttpResponse::Range,
DataFlow::CfgNode {
override CallNode node;
TornadoRequestHandlerWriteCall() {
node.getFunction() = tornado::web::RequestHandler::writeMethod().asCfgNode()
}
override DataFlow::Node getBody() {
result.asCfgNode() in [node.getArg(0), node.getArgByName("chunk")]
}
override string getMimetypeDefault() { result = "text/html" }
override DataFlow::Node getMimetypeOrContentTypeArg() { none() }
}

View File

@@ -720,6 +720,9 @@ abstract class FunctionValue extends CallableValue {
/** Gets a class that this function may return */
abstract ClassValue getAnInferredReturnType();
/** Holds if this function represents a lambda. */
predicate isLambda() { this.getOrigin().getNode() instanceof Lambda }
}
/** Class representing Python functions */

View File

@@ -0,0 +1,40 @@
import python
import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.TestUtil.PrintNode
abstract class FlowTest extends InlineExpectationsTest {
bindingset[this]
FlowTest() { any() }
abstract string flowTag();
abstract predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode);
override string getARelevantTag() { result = this.flowTag() }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node fromNode, DataFlow::Node toNode | this.relevantFlow(fromNode, toNode) |
location = toNode.getLocation() and
tag = this.flowTag() and
value =
"\"" + prettyNode(fromNode).replaceAll("\"", "'") + lineStr(fromNode, toNode) + " -> " +
prettyNode(toNode).replaceAll("\"", "'") + "\"" and
element = toNode.toString()
)
}
pragma[inline]
private string lineStr(DataFlow::Node fromNode, DataFlow::Node toNode) {
exists(int delta |
delta = fromNode.getLocation().getStartLine() - toNode.getLocation().getStartLine()
|
if delta = 0
then result = ""
else
if delta > 0
then result = ", l:+" + delta.toString()
else result = ", l:" + delta.toString()
)
}
}

View File

@@ -0,0 +1,13 @@
import python
import semmle.python.dataflow.new.DataFlow
import FlowTest
class LocalFlowStepTest extends FlowTest {
LocalFlowStepTest() { this = "LocalFlowStepTest" }
override string flowTag() { result = "step" }
override predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode) {
DataFlow::localFlowStep(fromNode, toNode)
}
}

View File

@@ -0,0 +1,42 @@
import python
import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.DataFlowPrivate
import FlowTest
class MaximalFlowTest extends FlowTest {
MaximalFlowTest() { this = "MaximalFlowTest" }
override string flowTag() { result = "flow" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
source != sink and
exists(MaximalFlowsConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to find all "maximal" flows.
* To be used on small programs.
*/
class MaximalFlowsConfig extends DataFlow::Configuration {
MaximalFlowsConfig() { this = "MaximalFlowsConfig" }
override predicate isSource(DataFlow::Node node) {
exists(node.getLocation().getFile().getRelativePath()) and
not node.asCfgNode() instanceof CallNode and
not node.asCfgNode().getNode() instanceof Return and
not node instanceof DataFlow::ParameterNode and
not node instanceof DataFlow::PostUpdateNode and
// not node.asExpr() instanceof FunctionExpr and
// not node.asExpr() instanceof ClassExpr and
not exists(DataFlow::Node pred | DataFlow::localFlowStep(pred, node))
}
override predicate isSink(DataFlow::Node node) {
exists(node.getLocation().getFile().getRelativePath()) and
not any(CallNode c).getArg(_) = node.asCfgNode() and
not node instanceof DataFlow::ArgumentNode and
not node.asCfgNode().(NameNode).getId().matches("SINK%") and
not exists(DataFlow::Node succ | DataFlow::localFlowStep(node, succ))
}
}

View File

@@ -0,0 +1,31 @@
import python
import semmle.python.dataflow.new.DataFlow
string prettyExp(Expr e) {
not e instanceof Num and
not e instanceof StrConst and
not e instanceof Subscript and
not e instanceof Call and
not e instanceof Attribute and
result = e.toString()
or
result = e.(Num).getN()
or
result =
e.(StrConst).getPrefix() + e.(StrConst).getText() +
e.(StrConst).getPrefix().regexpReplaceAll("[a-zA-Z]+", "")
or
result = prettyExp(e.(Subscript).getObject()) + "[" + prettyExp(e.(Subscript).getIndex()) + "]"
or
(
if exists(e.(Call).getAnArg()) or exists(e.(Call).getANamedArg())
then result = prettyExp(e.(Call).getFunc()) + "(..)"
else result = prettyExp(e.(Call).getFunc()) + "()"
)
or
result = prettyExp(e.(Attribute).getObject()) + "." + e.(Attribute).getName()
}
string prettyNode(DataFlow::Node node) {
if exists(node.asExpr()) then result = prettyExp(node.asExpr()) else result = node.toString()
}

View File

@@ -0,0 +1,51 @@
import python
import semmle.python.dataflow.new.DataFlow
import TestUtilities.InlineExpectationsTest
import experimental.dataflow.TestUtil.PrintNode
/**
* A routing test is designed to test that values are routed to the
* correct arguments of the correct functions. It is assumed that
* the functions tested sink their arguments sequentially, that is
* `SINK1(arg1)`, etc.
*/
abstract class RoutingTest extends InlineExpectationsTest {
bindingset[this]
RoutingTest() { any() }
abstract string flowTag();
abstract predicate relevantFlow(DataFlow::Node fromNode, DataFlow::Node toNode);
override string getARelevantTag() { result in ["func", this.flowTag()] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node fromNode, DataFlow::Node toNode | this.relevantFlow(fromNode, toNode) |
location = fromNode.getLocation() and
element = fromNode.toString() and
(
tag = this.flowTag() and
if "\"" + tag + "\"" = fromValue(fromNode) then value = "" else value = fromValue(fromNode)
or
tag = "func" and
value = toFunc(toNode) and
not value = fromFunc(fromNode)
)
)
}
pragma[inline]
private string fromValue(DataFlow::Node fromNode) {
result = "\"" + prettyNode(fromNode).replaceAll("\"", "'") + "\""
}
pragma[inline]
private string fromFunc(DataFlow::ArgumentNode fromNode) {
result = fromNode.getCall().getNode().(CallNode).getFunction().getNode().(Name).getId()
}
pragma[inline]
private string toFunc(DataFlow::Node toNode) {
result = toNode.getEnclosingCallable().getCallableValue().getScope().getQualifiedName() // TODO: More robust pretty printing?
}
}

View File

@@ -0,0 +1 @@
import experimental.dataflow.TestUtil.LocalFlowStepTest

View File

@@ -0,0 +1 @@
import experimental.dataflow.TestUtil.MaximalFlowTest

View File

@@ -1,7 +1,7 @@
def obfuscated_id(x):
y = x
z = y
return z
def obfuscated_id(x): #$ step="FunctionExpr -> GSSA Variable obfuscated_id" step="x -> SSA variable x"
y = x #$ step="x -> SSA variable y" step="SSA variable x, l:-1 -> x"
z = y #$ step="y -> SSA variable z" step="SSA variable y, l:-1 -> y"
return z #$ flow="42, l:+2 -> z" step="SSA variable z, l:-1 -> z"
a = 42
b = obfuscated_id(a)
a = 42 #$ step="42 -> GSSA Variable a"
b = obfuscated_id(a) #$ flow="42, l:-1 -> GSSA Variable b" flow="FunctionExpr, l:-6 -> obfuscated_id" step="obfuscated_id(..) -> GSSA Variable b" step="GSSA Variable obfuscated_id, l:-6 -> obfuscated_id" step="GSSA Variable a, l:-1 -> a"

View File

@@ -11,7 +11,7 @@ class CallGraphConfig extends DataFlow::Configuration {
override predicate isSource(DataFlow::Node node) {
node instanceof DataFlowPrivate::ReturnNode
or
node instanceof DataFlowPrivate::ArgumentNode
node instanceof DataFlow::ArgumentNode
}
override predicate isSink(DataFlow::Node node) {

View File

@@ -1,5 +1,4 @@
uniqueEnclosingCallable
| test.py:239:27:239:27 | ControlFlowNode for p | Node should have one enclosing callable but has 0. |
uniqueType
uniqueNodeLocation
missingLocation

View File

@@ -0,0 +1 @@
| test.py:239:27:239:27 | Parameter | There is no `ParameterNode` associated with this parameter. |

View File

@@ -0,0 +1,7 @@
import python
import semmle.python.dataflow.new.DataFlow
query predicate parameterWithoutNode(Parameter p, string msg) {
not exists(DataFlow::ParameterNode node | p = node.getParameter()) and
msg = "There is no `ParameterNode` associated with this parameter."
}

View File

@@ -249,3 +249,10 @@ def synth_arg_kwOverflow():
def synth_arg_kwUnpacked():
overflowCallee(**{"p": "42"})
def split_lambda(cond):
if cond:
pass
foo = lambda x: False
if cond:
pass

View File

@@ -86,12 +86,12 @@ def argument_passing(
@expects(7)
def test_argument_passing1():
argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7})
argument_passing(arg1, *(arg2, arg3, arg4), e=arg5, **{"f": arg6, "g": arg7}) #$ arg1 arg7 func=argument_passing MISSING: arg2 arg3="arg3 arg4 arg5 arg6
@expects(7)
def test_argument_passing2():
argument_passing(arg1, arg2, arg3, f=arg6)
argument_passing(arg1, arg2, arg3, f=arg6) #$ arg1 arg2 arg3
def with_pos_only(a, /, b):
@@ -101,9 +101,9 @@ def with_pos_only(a, /, b):
@expects(6)
def test_pos_only():
with_pos_only(arg1, arg2)
with_pos_only(arg1, b=arg2)
with_pos_only(arg1, *(arg2,))
with_pos_only(arg1, arg2) #$ arg1 arg2
with_pos_only(arg1, b=arg2) #$ arg1 arg2
with_pos_only(arg1, *(arg2,)) #$ arg1 MISSING: arg2
def with_multiple_kw_args(a, b, c):
@@ -114,13 +114,13 @@ def with_multiple_kw_args(a, b, c):
@expects(12)
def test_multiple_kw_args():
with_multiple_kw_args(b=arg2, c=arg3, a=arg1)
with_multiple_kw_args(arg1, *(arg2,), arg3)
with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2)
with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1})
with_multiple_kw_args(b=arg2, c=arg3, a=arg1) #$ arg1 arg2 arg3
with_multiple_kw_args(arg1, *(arg2,), arg3) #$ arg1 MISSING: arg2 arg3
with_multiple_kw_args(arg1, **{"c": arg3}, b=arg2) #$ arg1 arg3 func=with_multiple_kw_args MISSING: arg2
with_multiple_kw_args(**{"b": arg2}, **{"c": arg3}, **{"a": arg1}) #$ arg1 arg2 arg3 func=with_multiple_kw_args
def with_default_arguments(a=arg1, b=arg2, c=arg3):
def with_default_arguments(a=arg1, b=arg2, c=arg3): # Need a mechanism to test default arguments
SINK1(a)
SINK2(b)
SINK3(c)
@@ -129,9 +129,9 @@ def with_default_arguments(a=arg1, b=arg2, c=arg3):
@expects(12)
def test_default_arguments():
with_default_arguments()
with_default_arguments(arg1)
with_default_arguments(b=arg2)
with_default_arguments(**{"c": arg3})
with_default_arguments(arg1) #$ arg1
with_default_arguments(b=arg2) #$ arg2
with_default_arguments(**{"c": arg3}) #$ arg3 func=with_default_arguments
# Nested constructor pattern
@@ -157,7 +157,7 @@ def grab_baz(baz):
@expects(4)
def test_grab():
grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1)
grab_foo_bar_baz(baz=arg3, bar=arg2, foo=arg1) #$ arg1 arg2 arg3 func=grab_bar_baz func=grab_baz
# All combinations
@@ -165,14 +165,14 @@ def test_pos_pos():
def with_pos(a):
SINK1(a)
with_pos(arg1)
with_pos(arg1) #$ arg1 func=test_pos_pos.with_pos
def test_pos_pos_only():
def with_pos_only(a, /):
SINK1(a)
with_pos_only(arg1)
with_pos_only(arg1) #$ arg1 func=test_pos_pos_only.with_pos_only
def test_pos_star():
@@ -180,32 +180,32 @@ def test_pos_star():
if len(a) > 0:
SINK1(a[0])
with_star(arg1)
with_star(arg1) #$ arg1 func=test_pos_star.with_star
def test_pos_kw():
def with_kw(a=""):
SINK1(a)
with_kw(arg1)
with_kw(arg1) #$ arg1 func=test_pos_kw.with_kw
def test_kw_pos():
def with_pos(a):
SINK1(a)
with_pos(a=arg1)
with_pos(a=arg1) #$ arg1 func=test_kw_pos.with_pos
def test_kw_kw():
def with_kw(a=""):
SINK1(a)
with_kw(a=arg1)
with_kw(a=arg1) #$ arg1 func=test_kw_kw.with_kw
def test_kw_doublestar():
def with_doublestar(**a):
SINK1(a["a"])
with_doublestar(a=arg1)
with_doublestar(a=arg1) #$ arg1 func=test_kw_doublestar.with_doublestar

View File

@@ -0,0 +1,263 @@
import python
import semmle.python.dataflow.new.DataFlow
private import semmle.python.dataflow.new.internal.DataFlowPrivate as DataFlowPrivate
import experimental.dataflow.TestUtil.RoutingTest
class Argument1RoutingTest extends RoutingTest {
Argument1RoutingTest() { this = "Argument1RoutingTest" }
override string flowTag() { result = "arg1" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(Argument1RoutingConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to check routing of arguments through magic methods.
*/
class Argument1RoutingConfig extends DataFlow::Configuration {
Argument1RoutingConfig() { this = "Argument1RoutingConfig" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg1"
or
exists(AssignmentDefinition def, DataFlowPrivate::DataFlowCall call |
def.getVariable() = node.(DataFlow::EssaNode).getVar() and
def.getValue() = call.getNode() and
call.getNode().(CallNode).getFunction().(NameNode).getId().matches("With\\_%")
) and
node.(DataFlow::EssaNode).getVar().getName().matches("with\\_%")
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK1" and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
/**
* We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`.
* Use-use flow lets the argument to the first call reach the sink inside the second call,
* making it seem like we handle all cases even if we only handle the last one.
* We make the test honest by preventing flow into source nodes.
*/
override predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}
class Argument2RoutingTest extends RoutingTest {
Argument2RoutingTest() { this = "Argument2RoutingTest" }
override string flowTag() { result = "arg2" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(Argument2RoutingConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to check routing of arguments through magic methods.
*/
class Argument2RoutingConfig extends DataFlow::Configuration {
Argument2RoutingConfig() { this = "Argument2RoutingConfig" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg2"
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK2" and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
/**
* We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`.
* Use-use flow lets the argument to the first call reach the sink inside the second call,
* making it seem like we handle all cases even if we only handle the last one.
* We make the test honest by preventing flow into source nodes.
*/
override predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}
class Argument3RoutingTest extends RoutingTest {
Argument3RoutingTest() { this = "Argument3RoutingTest" }
override string flowTag() { result = "arg3" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(Argument3RoutingConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to check routing of arguments through magic methods.
*/
class Argument3RoutingConfig extends DataFlow::Configuration {
Argument3RoutingConfig() { this = "Argument3RoutingConfig" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg3"
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK3" and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
/**
* We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`.
* Use-use flow lets the argument to the first call reach the sink inside the second call,
* making it seem like we handle all cases even if we only handle the last one.
* We make the test honest by preventing flow into source nodes.
*/
override predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}
class Argument4RoutingTest extends RoutingTest {
Argument4RoutingTest() { this = "Argument4RoutingTest" }
override string flowTag() { result = "arg4" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(Argument4RoutingConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to check routing of arguments through magic methods.
*/
class Argument4RoutingConfig extends DataFlow::Configuration {
Argument4RoutingConfig() { this = "Argument4RoutingConfig" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg4"
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK4" and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
/**
* We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`.
* Use-use flow lets the argument to the first call reach the sink inside the second call,
* making it seem like we handle all cases even if we only handle the last one.
* We make the test honest by preventing flow into source nodes.
*/
override predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}
class Argument5RoutingTest extends RoutingTest {
Argument5RoutingTest() { this = "Argument5RoutingTest" }
override string flowTag() { result = "arg5" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(Argument5RoutingConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to check routing of arguments through magic methods.
*/
class Argument5RoutingConfig extends DataFlow::Configuration {
Argument5RoutingConfig() { this = "Argument5RoutingConfig" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg5"
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK5" and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
/**
* We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`.
* Use-use flow lets the argument to the first call reach the sink inside the second call,
* making it seem like we handle all cases even if we only handle the last one.
* We make the test honest by preventing flow into source nodes.
*/
override predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}
class Argument6RoutingTest extends RoutingTest {
Argument6RoutingTest() { this = "Argument6RoutingTest" }
override string flowTag() { result = "arg6" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(Argument6RoutingConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to check routing of arguments through magic methods.
*/
class Argument6RoutingConfig extends DataFlow::Configuration {
Argument6RoutingConfig() { this = "Argument6RoutingConfig" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg6"
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK6" and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
/**
* We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`.
* Use-use flow lets the argument to the first call reach the sink inside the second call,
* making it seem like we handle all cases even if we only handle the last one.
* We make the test honest by preventing flow into source nodes.
*/
override predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}
class Argument7RoutingTest extends RoutingTest {
Argument7RoutingTest() { this = "Argument7RoutingTest" }
override string flowTag() { result = "arg7" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(Argument7RoutingConfig cfg | cfg.hasFlow(source, sink))
}
}
/**
* A configuration to check routing of arguments through magic methods.
*/
class Argument7RoutingConfig extends DataFlow::Configuration {
Argument7RoutingConfig() { this = "Argument7RoutingConfig" }
override predicate isSource(DataFlow::Node node) {
node.(DataFlow::CfgNode).getNode().(NameNode).getId() = "arg7"
}
override predicate isSink(DataFlow::Node node) {
exists(CallNode call |
call.getFunction().(NameNode).getId() = "SINK7" and
node.(DataFlow::CfgNode).getNode() = call.getAnArg()
)
}
/**
* We want to be able to use `arg` in a sequence of calls such as `func(kw=arg); ... ; func(arg)`.
* Use-use flow lets the argument to the first call reach the sink inside the second call,
* making it seem like we handle all cases even if we only handle the last one.
* We make the test honest by preventing flow into source nodes.
*/
override predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,7 @@ class CallGraphConfig extends DataFlow::Configuration {
node instanceof DataFlowPrivate::ReturnNode
or
// These sources should allow for the non-standard call syntax
node instanceof DataFlowPrivate::ArgumentNode
node instanceof DataFlow::ArgumentNode
}
override predicate isSink(DataFlow::Node node) {

View File

@@ -1,69 +1,13 @@
edges
| datamodel.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module datamodel | datamodel.py:152:14:152:19 | ControlFlowNode for SOURCE |
| datamodel.py:13:1:13:6 | GSSA Variable SOURCE | datamodel.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module datamodel |
| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:13:1:13:6 | GSSA Variable SOURCE |
| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE |
| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE |
| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE |
| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE |
| datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE |
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() |
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE |
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE |
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE |
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE |
| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() |
| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE |
| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE |
| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE |
| datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() |
| datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE |
| datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE |
| datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE |
| datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE |
| datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() |
| datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE |
| datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() |
| datamodel.py:152:5:152:8 | [post store] ControlFlowNode for self [Attribute b] | datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] |
| datamodel.py:152:14:152:19 | ControlFlowNode for SOURCE | datamodel.py:152:5:152:8 | [post store] ControlFlowNode for self [Attribute b] |
| datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] | datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] |
| datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:42:21:42:26 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:55:9:55:14 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:87:10:87:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:93:10:93:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:103:10:103:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:108:22:108:27 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:113:10:113:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:125:10:125:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:130:10:130:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:135:22:135:27 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:140:10:140:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:152:15:152:20 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:157:15:157:20 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:183:23:183:28 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:188:25:188:30 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:199:34:199:39 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:336:11:336:16 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:340:11:340:16 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:344:16:344:21 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:367:28:367:33 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:375:30:375:35 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:383:36:383:41 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:391:33:391:38 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:399:39:399:44 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:420:10:420:15 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:428:34:428:39 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:452:12:452:17 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:459:28:459:33 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:473:30:473:35 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:487:36:487:41 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:492:33:492:38 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:497:39:497:44 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:509:9:509:14 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:588:16:588:21 | ControlFlowNode for SOURCE |
| test.py:20:1:20:6 | GSSA Variable SOURCE | test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test |
| test.py:20:10:20:17 | ControlFlowNode for Str | test.py:20:1:20:6 | GSSA Variable SOURCE |
| test.py:42:10:42:26 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:43:9:43:9 | ControlFlowNode for x [Tuple element at index 1] |
| test.py:42:21:42:26 | ControlFlowNode for SOURCE | test.py:42:10:42:26 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:43:9:43:9 | ControlFlowNode for x [Tuple element at index 1] | test.py:43:9:43:12 | ControlFlowNode for Subscript |
@@ -151,47 +95,204 @@ edges
| test.py:199:33:199:40 | ControlFlowNode for List [List element] | test.py:199:28:199:28 | SSA variable z |
| test.py:199:34:199:39 | ControlFlowNode for SOURCE | test.py:199:33:199:40 | ControlFlowNode for List [List element] |
| test.py:200:10:200:10 | ControlFlowNode for x [List element] | test.py:200:10:200:13 | ControlFlowNode for Subscript |
| test.py:336:11:336:16 | ControlFlowNode for SOURCE | test.py:336:11:336:17 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:336:11:336:17 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:336:10:336:21 | ControlFlowNode for Subscript |
| test.py:340:10:340:17 | ControlFlowNode for List [List element] | test.py:340:10:340:20 | ControlFlowNode for Subscript |
| test.py:340:11:340:16 | ControlFlowNode for SOURCE | test.py:340:10:340:17 | ControlFlowNode for List [List element] |
| test.py:344:10:344:22 | ControlFlowNode for Dict [Dictionary element at key s] | test.py:344:10:344:27 | ControlFlowNode for Subscript |
| test.py:344:16:344:21 | ControlFlowNode for SOURCE | test.py:344:10:344:22 | ControlFlowNode for Dict [Dictionary element at key s] |
| test.py:367:28:367:33 | ControlFlowNode for SOURCE | test.py:367:10:367:34 | ControlFlowNode for second() |
| test.py:375:30:375:35 | ControlFlowNode for SOURCE | test.py:375:10:375:36 | ControlFlowNode for second() |
| test.py:383:10:383:43 | KwUnpacked b | test.py:383:10:383:43 | ControlFlowNode for second() |
| test.py:383:30:383:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:383:10:383:43 | KwUnpacked b |
| test.py:383:36:383:41 | ControlFlowNode for SOURCE | test.py:383:30:383:42 | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:391:10:391:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() |
| test.py:391:33:391:38 | ControlFlowNode for SOURCE | test.py:391:10:391:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:399:10:399:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() |
| test.py:399:39:399:44 | ControlFlowNode for SOURCE | test.py:399:10:399:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:420:10:420:15 | ControlFlowNode for SOURCE | test.py:420:10:420:38 | ControlFlowNode for IfExp |
| test.py:428:34:428:39 | ControlFlowNode for SOURCE | test.py:428:10:428:39 | ControlFlowNode for IfExp |
| test.py:452:12:452:17 | ControlFlowNode for SOURCE | test.py:452:10:452:18 | ControlFlowNode for f() |
| test.py:459:28:459:33 | ControlFlowNode for SOURCE | test.py:459:10:459:34 | ControlFlowNode for second() |
| test.py:473:30:473:35 | ControlFlowNode for SOURCE | test.py:473:10:473:36 | ControlFlowNode for second() |
| test.py:487:10:487:43 | KwUnpacked b | test.py:487:10:487:43 | ControlFlowNode for second() |
| test.py:487:30:487:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:487:10:487:43 | KwUnpacked b |
| test.py:487:36:487:41 | ControlFlowNode for SOURCE | test.py:487:30:487:42 | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:492:10:492:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() |
| test.py:492:33:492:38 | ControlFlowNode for SOURCE | test.py:492:10:492:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:497:10:497:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() |
| test.py:497:39:497:44 | ControlFlowNode for SOURCE | test.py:497:10:497:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:511:10:511:10 | ControlFlowNode for a |
| test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:516:10:516:10 | ControlFlowNode for b |
| test.py:588:16:588:21 | ControlFlowNode for SOURCE | test.py:591:10:591:36 | ControlFlowNode for return_from_inner_scope() |
| test.py:349:11:349:16 | ControlFlowNode for SOURCE | test.py:349:11:349:17 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:349:11:349:17 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:349:10:349:21 | ControlFlowNode for Subscript |
| test.py:353:10:353:17 | ControlFlowNode for List [List element] | test.py:353:10:353:20 | ControlFlowNode for Subscript |
| test.py:353:11:353:16 | ControlFlowNode for SOURCE | test.py:353:10:353:17 | ControlFlowNode for List [List element] |
| test.py:357:10:357:22 | ControlFlowNode for Dict [Dictionary element at key s] | test.py:357:10:357:27 | ControlFlowNode for Subscript |
| test.py:357:16:357:21 | ControlFlowNode for SOURCE | test.py:357:10:357:22 | ControlFlowNode for Dict [Dictionary element at key s] |
| test.py:380:28:380:33 | ControlFlowNode for SOURCE | test.py:380:10:380:34 | ControlFlowNode for second() |
| test.py:388:30:388:35 | ControlFlowNode for SOURCE | test.py:388:10:388:36 | ControlFlowNode for second() |
| test.py:396:10:396:43 | KwUnpacked b | test.py:396:10:396:43 | ControlFlowNode for second() |
| test.py:396:30:396:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:396:10:396:43 | KwUnpacked b |
| test.py:396:36:396:41 | ControlFlowNode for SOURCE | test.py:396:30:396:42 | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:404:10:404:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:404:10:404:39 | ControlFlowNode for f_extra_pos() |
| test.py:404:33:404:38 | ControlFlowNode for SOURCE | test.py:404:10:404:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:412:10:412:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:412:10:412:45 | ControlFlowNode for f_extra_keyword() |
| test.py:412:39:412:44 | ControlFlowNode for SOURCE | test.py:412:10:412:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:433:10:433:15 | ControlFlowNode for SOURCE | test.py:433:10:433:38 | ControlFlowNode for IfExp |
| test.py:441:34:441:39 | ControlFlowNode for SOURCE | test.py:441:10:441:39 | ControlFlowNode for IfExp |
| test.py:465:12:465:17 | ControlFlowNode for SOURCE | test.py:465:10:465:18 | ControlFlowNode for f() |
| test.py:472:28:472:33 | ControlFlowNode for SOURCE | test.py:472:10:472:34 | ControlFlowNode for second() |
| test.py:486:30:486:35 | ControlFlowNode for SOURCE | test.py:486:10:486:36 | ControlFlowNode for second() |
| test.py:500:10:500:43 | KwUnpacked b | test.py:500:10:500:43 | ControlFlowNode for second() |
| test.py:500:30:500:42 | ControlFlowNode for Dict [Dictionary element at key b] | test.py:500:10:500:43 | KwUnpacked b |
| test.py:500:36:500:41 | ControlFlowNode for SOURCE | test.py:500:30:500:42 | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:505:10:505:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | test.py:505:10:505:39 | ControlFlowNode for f_extra_pos() |
| test.py:505:33:505:38 | ControlFlowNode for SOURCE | test.py:505:10:505:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:510:10:510:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | test.py:510:10:510:45 | ControlFlowNode for f_extra_keyword() |
| test.py:510:39:510:44 | ControlFlowNode for SOURCE | test.py:510:10:510:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:522:9:522:14 | ControlFlowNode for SOURCE | test.py:524:10:524:10 | ControlFlowNode for a |
| test.py:522:9:522:14 | ControlFlowNode for SOURCE | test.py:529:10:529:10 | ControlFlowNode for b |
| test.py:534:10:534:15 | ControlFlowNode for SOURCE | test.py:534:10:534:26 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:534:10:534:26 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:535:5:535:8 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:535:5:535:5 | SSA variable a | test.py:536:10:536:10 | ControlFlowNode for a |
| test.py:535:5:535:8 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:535:5:535:5 | SSA variable a |
| test.py:542:10:542:15 | ControlFlowNode for SOURCE | test.py:542:10:542:36 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:542:10:542:36 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:543:5:543:13 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:542:10:542:36 | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] | test.py:543:5:543:13 | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] |
| test.py:542:19:542:35 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:542:10:542:36 | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] |
| test.py:542:30:542:35 | ControlFlowNode for SOURCE | test.py:542:19:542:35 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:543:5:543:5 | SSA variable a | test.py:544:10:544:10 | ControlFlowNode for a |
| test.py:543:5:543:13 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:543:5:543:5 | SSA variable a |
| test.py:543:5:543:13 | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] | test.py:543:9:543:12 | IterableSequence [Tuple element at index 1] |
| test.py:543:9:543:12 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:543:12:543:12 | SSA variable c |
| test.py:543:9:543:12 | IterableSequence [Tuple element at index 1] | test.py:543:9:543:12 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:543:12:543:12 | SSA variable c | test.py:546:10:546:10 | ControlFlowNode for c |
| test.py:551:9:551:33 | ControlFlowNode for List [List element, List element, List element, List element] | test.py:552:5:552:14 | IterableSequence [List element, List element, List element, List element] |
| test.py:551:10:551:21 | ControlFlowNode for List [List element, List element, List element] | test.py:551:9:551:33 | ControlFlowNode for List [List element, List element, List element, List element] |
| test.py:551:11:551:20 | ControlFlowNode for List [List element, List element] | test.py:551:10:551:21 | ControlFlowNode for List [List element, List element, List element] |
| test.py:551:12:551:19 | ControlFlowNode for List [List element] | test.py:551:11:551:20 | ControlFlowNode for List [List element, List element] |
| test.py:551:13:551:18 | ControlFlowNode for SOURCE | test.py:551:12:551:19 | ControlFlowNode for List [List element] |
| test.py:552:5:552:11 | ControlFlowNode for List [Tuple element at index 0, List element, List element] | test.py:552:6:552:10 | IterableSequence [List element, List element] |
| test.py:552:5:552:11 | IterableElement [List element, List element] | test.py:552:5:552:11 | ControlFlowNode for List [Tuple element at index 0, List element, List element] |
| test.py:552:5:552:11 | IterableSequence [List element, List element, List element] | test.py:552:5:552:11 | IterableElement [List element, List element] |
| test.py:552:5:552:14 | ControlFlowNode for Tuple [Tuple element at index 0, List element, List element, List element] | test.py:552:5:552:11 | IterableSequence [List element, List element, List element] |
| test.py:552:5:552:14 | IterableElement [List element, List element, List element] | test.py:552:5:552:14 | ControlFlowNode for Tuple [Tuple element at index 0, List element, List element, List element] |
| test.py:552:5:552:14 | IterableSequence [List element, List element, List element, List element] | test.py:552:5:552:14 | IterableElement [List element, List element, List element] |
| test.py:552:6:552:10 | ControlFlowNode for List [Tuple element at index 0, List element] | test.py:552:7:552:9 | IterableSequence [List element] |
| test.py:552:6:552:10 | IterableElement [List element] | test.py:552:6:552:10 | ControlFlowNode for List [Tuple element at index 0, List element] |
| test.py:552:6:552:10 | IterableSequence [List element, List element] | test.py:552:6:552:10 | IterableElement [List element] |
| test.py:552:7:552:9 | ControlFlowNode for List [Tuple element at index 0] | test.py:552:8:552:8 | SSA variable a |
| test.py:552:7:552:9 | IterableElement | test.py:552:7:552:9 | ControlFlowNode for List [Tuple element at index 0] |
| test.py:552:7:552:9 | IterableSequence [List element] | test.py:552:7:552:9 | IterableElement |
| test.py:552:8:552:8 | SSA variable a | test.py:553:10:553:10 | ControlFlowNode for a |
| test.py:559:10:559:15 | ControlFlowNode for SOURCE | test.py:559:10:559:34 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:559:10:559:34 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:560:5:560:12 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:559:10:559:34 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:560:5:560:12 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:559:18:559:23 | ControlFlowNode for SOURCE | test.py:559:10:559:34 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:560:5:560:5 | SSA variable a | test.py:561:10:561:10 | ControlFlowNode for a |
| test.py:560:5:560:12 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:560:5:560:5 | SSA variable a |
| test.py:560:5:560:12 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:560:8:560:9 | IterableElement |
| test.py:560:5:560:12 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:560:12:560:12 | SSA variable c |
| test.py:560:8:560:9 | IterableElement | test.py:560:8:560:9 | SSA variable b [List element] |
| test.py:560:8:560:9 | SSA variable b [List element] | test.py:563:10:563:10 | ControlFlowNode for b [List element] |
| test.py:560:12:560:12 | SSA variable c | test.py:564:12:564:12 | ControlFlowNode for c |
| test.py:563:10:563:10 | ControlFlowNode for b [List element] | test.py:563:10:563:13 | ControlFlowNode for Subscript |
| test.py:569:10:569:15 | ControlFlowNode for SOURCE | test.py:569:10:569:23 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:569:10:569:23 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:570:5:570:12 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:569:10:569:23 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:570:5:570:12 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:569:18:569:23 | ControlFlowNode for SOURCE | test.py:569:10:569:23 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:570:5:570:5 | SSA variable a | test.py:571:10:571:10 | ControlFlowNode for a |
| test.py:570:5:570:12 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:570:5:570:5 | SSA variable a |
| test.py:570:5:570:12 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:570:12:570:12 | SSA variable c |
| test.py:570:12:570:12 | SSA variable c | test.py:573:10:573:10 | ControlFlowNode for c |
| test.py:578:10:578:61 | ControlFlowNode for List [List element, List element] | test.py:581:6:581:23 | IterableSequence [List element, List element] |
| test.py:578:10:578:61 | ControlFlowNode for List [List element, List element] | test.py:589:5:589:24 | IterableSequence [List element, List element] |
| test.py:578:10:578:61 | ControlFlowNode for List [List element, List element] | test.py:597:6:597:23 | IterableSequence [List element, List element] |
| test.py:578:11:578:37 | ControlFlowNode for List [List element] | test.py:578:10:578:61 | ControlFlowNode for List [List element, List element] |
| test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:578:11:578:37 | ControlFlowNode for List [List element] |
| test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:578:11:578:37 | ControlFlowNode for List [List element] |
| test.py:578:40:578:47 | ControlFlowNode for List [List element] | test.py:578:10:578:61 | ControlFlowNode for List [List element, List element] |
| test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:578:40:578:47 | ControlFlowNode for List [List element] |
| test.py:581:6:581:23 | ControlFlowNode for Tuple [Tuple element at index 0, List element] | test.py:581:7:581:16 | IterableSequence [List element] |
| test.py:581:6:581:23 | IterableElement [List element] | test.py:581:6:581:23 | ControlFlowNode for Tuple [Tuple element at index 0, List element] |
| test.py:581:6:581:23 | IterableSequence [List element, List element] | test.py:581:6:581:23 | IterableElement [List element] |
| test.py:581:7:581:8 | SSA variable a1 | test.py:582:10:582:11 | ControlFlowNode for a1 |
| test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:581:7:581:8 | SSA variable a1 |
| test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:581:11:581:12 | SSA variable a2 |
| test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 2] | test.py:581:15:581:16 | SSA variable a3 |
| test.py:581:7:581:16 | IterableElement | test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:581:7:581:16 | IterableElement | test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:581:7:581:16 | IterableElement | test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:581:7:581:16 | IterableSequence [List element] | test.py:581:7:581:16 | IterableElement |
| test.py:581:11:581:12 | SSA variable a2 | test.py:583:12:583:13 | ControlFlowNode for a2 |
| test.py:581:15:581:16 | SSA variable a3 | test.py:584:10:584:11 | ControlFlowNode for a3 |
| test.py:589:5:589:24 | ControlFlowNode for List [Tuple element at index 0, List element] | test.py:589:7:589:16 | IterableSequence [List element] |
| test.py:589:5:589:24 | IterableElement [List element] | test.py:589:5:589:24 | ControlFlowNode for List [Tuple element at index 0, List element] |
| test.py:589:5:589:24 | IterableSequence [List element, List element] | test.py:589:5:589:24 | IterableElement [List element] |
| test.py:589:7:589:8 | SSA variable a1 | test.py:590:10:590:11 | ControlFlowNode for a1 |
| test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:589:7:589:8 | SSA variable a1 |
| test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 1] | test.py:589:11:589:12 | SSA variable a2 |
| test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 2] | test.py:589:15:589:16 | SSA variable a3 |
| test.py:589:7:589:16 | IterableElement | test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:589:7:589:16 | IterableElement | test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:589:7:589:16 | IterableElement | test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:589:7:589:16 | IterableSequence [List element] | test.py:589:7:589:16 | IterableElement |
| test.py:589:11:589:12 | SSA variable a2 | test.py:591:12:591:13 | ControlFlowNode for a2 |
| test.py:589:15:589:16 | SSA variable a3 | test.py:592:10:592:11 | ControlFlowNode for a3 |
| test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 0] | test.py:597:7:597:8 | SSA variable a1 |
| test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 1] | test.py:597:11:597:12 | SSA variable a2 |
| test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 2] | test.py:597:15:597:16 | SSA variable a3 |
| test.py:597:6:597:17 | IterableElement | test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 0] |
| test.py:597:6:597:17 | IterableElement | test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 1] |
| test.py:597:6:597:17 | IterableElement | test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 2] |
| test.py:597:6:597:17 | IterableSequence [List element] | test.py:597:6:597:17 | IterableElement |
| test.py:597:6:597:23 | ControlFlowNode for Tuple [Tuple element at index 0, List element] | test.py:597:6:597:17 | IterableSequence [List element] |
| test.py:597:6:597:23 | IterableElement [List element] | test.py:597:6:597:23 | ControlFlowNode for Tuple [Tuple element at index 0, List element] |
| test.py:597:6:597:23 | IterableSequence [List element, List element] | test.py:597:6:597:23 | IterableElement [List element] |
| test.py:597:7:597:8 | SSA variable a1 | test.py:598:10:598:11 | ControlFlowNode for a1 |
| test.py:597:11:597:12 | SSA variable a2 | test.py:599:12:599:13 | ControlFlowNode for a2 |
| test.py:597:15:597:16 | SSA variable a3 | test.py:600:10:600:11 | ControlFlowNode for a3 |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | test.py:609:5:609:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | test.py:618:6:618:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | test.py:627:5:627:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | test.py:636:6:636:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | test.py:609:5:609:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | test.py:618:6:618:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | test.py:627:5:627:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | test.py:636:6:636:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] |
| test.py:606:12:606:17 | ControlFlowNode for SOURCE | test.py:606:12:606:36 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:606:12:606:36 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] |
| test.py:606:12:606:36 | ControlFlowNode for Tuple [Tuple element at index 2] | test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] |
| test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:606:12:606:36 | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:609:5:609:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] | test.py:609:6:609:14 | IterableSequence [Tuple element at index 0] |
| test.py:609:5:609:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] | test.py:609:6:609:14 | IterableSequence [Tuple element at index 2] |
| test.py:609:6:609:14 | ControlFlowNode for List [Tuple element at index 0] | test.py:609:7:609:8 | SSA variable a1 |
| test.py:609:6:609:14 | ControlFlowNode for List [Tuple element at index 2] | test.py:609:11:609:13 | IterableElement |
| test.py:609:6:609:14 | IterableSequence [Tuple element at index 0] | test.py:609:6:609:14 | ControlFlowNode for List [Tuple element at index 0] |
| test.py:609:6:609:14 | IterableSequence [Tuple element at index 2] | test.py:609:6:609:14 | ControlFlowNode for List [Tuple element at index 2] |
| test.py:609:7:609:8 | SSA variable a1 | test.py:610:10:610:11 | ControlFlowNode for a1 |
| test.py:609:11:609:13 | IterableElement | test.py:609:11:609:13 | SSA variable a2 [List element] |
| test.py:609:11:609:13 | SSA variable a2 [List element] | test.py:612:12:612:13 | ControlFlowNode for a2 [List element] |
| test.py:609:11:609:13 | SSA variable a2 [List element] | test.py:613:10:613:11 | ControlFlowNode for a2 [List element] |
| test.py:612:12:612:13 | ControlFlowNode for a2 [List element] | test.py:612:12:612:16 | ControlFlowNode for Subscript |
| test.py:613:10:613:11 | ControlFlowNode for a2 [List element] | test.py:613:10:613:14 | ControlFlowNode for Subscript |
| test.py:618:6:618:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | test.py:618:7:618:13 | IterableSequence [Tuple element at index 0] |
| test.py:618:6:618:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | test.py:618:7:618:13 | IterableSequence [Tuple element at index 2] |
| test.py:618:7:618:8 | SSA variable a1 | test.py:619:10:619:11 | ControlFlowNode for a1 |
| test.py:618:7:618:13 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:618:7:618:8 | SSA variable a1 |
| test.py:618:7:618:13 | ControlFlowNode for Tuple [Tuple element at index 2] | test.py:618:11:618:13 | IterableElement |
| test.py:618:7:618:13 | IterableSequence [Tuple element at index 0] | test.py:618:7:618:13 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:618:7:618:13 | IterableSequence [Tuple element at index 2] | test.py:618:7:618:13 | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:618:11:618:13 | IterableElement | test.py:618:11:618:13 | SSA variable a2 [List element] |
| test.py:618:11:618:13 | SSA variable a2 [List element] | test.py:621:12:621:13 | ControlFlowNode for a2 [List element] |
| test.py:618:11:618:13 | SSA variable a2 [List element] | test.py:622:10:622:11 | ControlFlowNode for a2 [List element] |
| test.py:621:12:621:13 | ControlFlowNode for a2 [List element] | test.py:621:12:621:16 | ControlFlowNode for Subscript |
| test.py:622:10:622:11 | ControlFlowNode for a2 [List element] | test.py:622:10:622:14 | ControlFlowNode for Subscript |
| test.py:627:5:627:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] | test.py:627:7:627:13 | IterableSequence [Tuple element at index 0] |
| test.py:627:5:627:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] | test.py:627:7:627:13 | IterableSequence [Tuple element at index 2] |
| test.py:627:7:627:8 | SSA variable a1 | test.py:628:10:628:11 | ControlFlowNode for a1 |
| test.py:627:7:627:13 | ControlFlowNode for Tuple [Tuple element at index 0] | test.py:627:7:627:8 | SSA variable a1 |
| test.py:627:7:627:13 | ControlFlowNode for Tuple [Tuple element at index 2] | test.py:627:11:627:13 | IterableElement |
| test.py:627:7:627:13 | IterableSequence [Tuple element at index 0] | test.py:627:7:627:13 | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:627:7:627:13 | IterableSequence [Tuple element at index 2] | test.py:627:7:627:13 | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:627:11:627:13 | IterableElement | test.py:627:11:627:13 | SSA variable a2 [List element] |
| test.py:627:11:627:13 | SSA variable a2 [List element] | test.py:630:12:630:13 | ControlFlowNode for a2 [List element] |
| test.py:627:11:627:13 | SSA variable a2 [List element] | test.py:631:10:631:11 | ControlFlowNode for a2 [List element] |
| test.py:630:12:630:13 | ControlFlowNode for a2 [List element] | test.py:630:12:630:16 | ControlFlowNode for Subscript |
| test.py:631:10:631:11 | ControlFlowNode for a2 [List element] | test.py:631:10:631:14 | ControlFlowNode for Subscript |
| test.py:636:6:636:14 | ControlFlowNode for List [Tuple element at index 0] | test.py:636:7:636:8 | SSA variable a1 |
| test.py:636:6:636:14 | ControlFlowNode for List [Tuple element at index 2] | test.py:636:11:636:13 | IterableElement |
| test.py:636:6:636:14 | IterableSequence [Tuple element at index 0] | test.py:636:6:636:14 | ControlFlowNode for List [Tuple element at index 0] |
| test.py:636:6:636:14 | IterableSequence [Tuple element at index 2] | test.py:636:6:636:14 | ControlFlowNode for List [Tuple element at index 2] |
| test.py:636:6:636:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | test.py:636:6:636:14 | IterableSequence [Tuple element at index 0] |
| test.py:636:6:636:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | test.py:636:6:636:14 | IterableSequence [Tuple element at index 2] |
| test.py:636:7:636:8 | SSA variable a1 | test.py:637:10:637:11 | ControlFlowNode for a1 |
| test.py:636:11:636:13 | IterableElement | test.py:636:11:636:13 | SSA variable a2 [List element] |
| test.py:636:11:636:13 | SSA variable a2 [List element] | test.py:639:12:639:13 | ControlFlowNode for a2 [List element] |
| test.py:636:11:636:13 | SSA variable a2 [List element] | test.py:640:10:640:11 | ControlFlowNode for a2 [List element] |
| test.py:639:12:639:13 | ControlFlowNode for a2 [List element] | test.py:639:12:639:16 | ControlFlowNode for Subscript |
| test.py:640:10:640:11 | ControlFlowNode for a2 [List element] | test.py:640:10:640:14 | ControlFlowNode for Subscript |
| test.py:647:19:647:24 | ControlFlowNode for SOURCE | test.py:648:10:648:10 | ControlFlowNode for a |
| test.py:739:16:739:21 | ControlFlowNode for SOURCE | test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() |
nodes
| datamodel.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module datamodel | semmle.label | ModuleVariableNode for Global Variable SOURCE in Module datamodel |
| datamodel.py:13:1:13:6 | GSSA Variable SOURCE | semmle.label | GSSA Variable SOURCE |
| datamodel.py:13:10:13:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str |
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
| datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
| datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
@@ -201,9 +302,6 @@ nodes
| datamodel.py:155:14:155:25 | ControlFlowNode for Customized() [Attribute b] | semmle.label | ControlFlowNode for Customized() [Attribute b] |
| datamodel.py:159:6:159:15 | ControlFlowNode for customized [Attribute b] | semmle.label | ControlFlowNode for customized [Attribute b] |
| datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | semmle.label | ModuleVariableNode for Global Variable SOURCE in Module test |
| test.py:20:1:20:6 | GSSA Variable SOURCE | semmle.label | GSSA Variable SOURCE |
| test.py:20:10:20:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str |
| test.py:42:10:42:26 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:42:21:42:26 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:43:9:43:9 | ControlFlowNode for x [Tuple element at index 1] | semmle.label | ControlFlowNode for x [Tuple element at index 1] |
@@ -311,150 +409,319 @@ nodes
| test.py:199:34:199:39 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:200:10:200:10 | ControlFlowNode for x [List element] | semmle.label | ControlFlowNode for x [List element] |
| test.py:200:10:200:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:336:10:336:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:336:11:336:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:336:11:336:17 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:340:10:340:17 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| test.py:340:10:340:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:340:11:340:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:344:10:344:22 | ControlFlowNode for Dict [Dictionary element at key s] | semmle.label | ControlFlowNode for Dict [Dictionary element at key s] |
| test.py:344:10:344:27 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:344:16:344:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:367:10:367:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:367:28:367:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:375:10:375:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:375:30:375:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:383:10:383:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:383:10:383:43 | KwUnpacked b | semmle.label | KwUnpacked b |
| test.py:383:30:383:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:383:36:383:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() |
| test.py:391:10:391:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:391:33:391:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() |
| test.py:399:10:399:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:399:39:399:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:420:10:420:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:420:10:420:38 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp |
| test.py:428:10:428:39 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp |
| test.py:428:34:428:39 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:452:10:452:18 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
| test.py:452:12:452:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:459:10:459:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:459:28:459:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:473:10:473:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:473:30:473:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:487:10:487:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:487:10:487:43 | KwUnpacked b | semmle.label | KwUnpacked b |
| test.py:487:30:487:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:487:36:487:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() |
| test.py:492:10:492:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:492:33:492:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() |
| test.py:497:10:497:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:497:39:497:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:509:9:509:14 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:511:10:511:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:516:10:516:10 | ControlFlowNode for b | semmle.label | ControlFlowNode for b |
| test.py:588:16:588:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:591:10:591:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
| test.py:349:10:349:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:349:11:349:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:349:11:349:17 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:353:10:353:17 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| test.py:353:10:353:20 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:353:11:353:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:357:10:357:22 | ControlFlowNode for Dict [Dictionary element at key s] | semmle.label | ControlFlowNode for Dict [Dictionary element at key s] |
| test.py:357:10:357:27 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:357:16:357:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:380:10:380:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:380:28:380:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:388:10:388:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:388:30:388:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:396:10:396:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:396:10:396:43 | KwUnpacked b | semmle.label | KwUnpacked b |
| test.py:396:30:396:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:396:36:396:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:404:10:404:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() |
| test.py:404:10:404:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:404:33:404:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:412:10:412:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() |
| test.py:412:10:412:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:412:39:412:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:433:10:433:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:433:10:433:38 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp |
| test.py:441:10:441:39 | ControlFlowNode for IfExp | semmle.label | ControlFlowNode for IfExp |
| test.py:441:34:441:39 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:465:10:465:18 | ControlFlowNode for f() | semmle.label | ControlFlowNode for f() |
| test.py:465:12:465:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:472:10:472:34 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:472:28:472:33 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:486:10:486:36 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:486:30:486:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:500:10:500:43 | ControlFlowNode for second() | semmle.label | ControlFlowNode for second() |
| test.py:500:10:500:43 | KwUnpacked b | semmle.label | KwUnpacked b |
| test.py:500:30:500:42 | ControlFlowNode for Dict [Dictionary element at key b] | semmle.label | ControlFlowNode for Dict [Dictionary element at key b] |
| test.py:500:36:500:41 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:505:10:505:39 | ControlFlowNode for f_extra_pos() | semmle.label | ControlFlowNode for f_extra_pos() |
| test.py:505:10:505:39 | PosOverflowNode for f_extra_pos() [Tuple element at index 0] | semmle.label | PosOverflowNode for f_extra_pos() [Tuple element at index 0] |
| test.py:505:33:505:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:510:10:510:45 | ControlFlowNode for f_extra_keyword() | semmle.label | ControlFlowNode for f_extra_keyword() |
| test.py:510:10:510:45 | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] | semmle.label | KwOverflowNode for f_extra_keyword() [Dictionary element at key b] |
| test.py:510:39:510:44 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:522:9:522:14 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:524:10:524:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:529:10:529:10 | ControlFlowNode for b | semmle.label | ControlFlowNode for b |
| test.py:534:10:534:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:534:10:534:26 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:535:5:535:5 | SSA variable a | semmle.label | SSA variable a |
| test.py:535:5:535:8 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:536:10:536:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:542:10:542:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:542:10:542:36 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:542:10:542:36 | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] |
| test.py:542:19:542:35 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:542:30:542:35 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:543:5:543:5 | SSA variable a | semmle.label | SSA variable a |
| test.py:543:5:543:13 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:543:5:543:13 | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1, Tuple element at index 1] |
| test.py:543:9:543:12 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:543:9:543:12 | IterableSequence [Tuple element at index 1] | semmle.label | IterableSequence [Tuple element at index 1] |
| test.py:543:12:543:12 | SSA variable c | semmle.label | SSA variable c |
| test.py:544:10:544:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:546:10:546:10 | ControlFlowNode for c | semmle.label | ControlFlowNode for c |
| test.py:551:9:551:33 | ControlFlowNode for List [List element, List element, List element, List element] | semmle.label | ControlFlowNode for List [List element, List element, List element, List element] |
| test.py:551:10:551:21 | ControlFlowNode for List [List element, List element, List element] | semmle.label | ControlFlowNode for List [List element, List element, List element] |
| test.py:551:11:551:20 | ControlFlowNode for List [List element, List element] | semmle.label | ControlFlowNode for List [List element, List element] |
| test.py:551:12:551:19 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| test.py:551:13:551:18 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:552:5:552:11 | ControlFlowNode for List [Tuple element at index 0, List element, List element] | semmle.label | ControlFlowNode for List [Tuple element at index 0, List element, List element] |
| test.py:552:5:552:11 | IterableElement [List element, List element] | semmle.label | IterableElement [List element, List element] |
| test.py:552:5:552:11 | IterableSequence [List element, List element, List element] | semmle.label | IterableSequence [List element, List element, List element] |
| test.py:552:5:552:14 | ControlFlowNode for Tuple [Tuple element at index 0, List element, List element, List element] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, List element, List element, List element] |
| test.py:552:5:552:14 | IterableElement [List element, List element, List element] | semmle.label | IterableElement [List element, List element, List element] |
| test.py:552:5:552:14 | IterableSequence [List element, List element, List element, List element] | semmle.label | IterableSequence [List element, List element, List element, List element] |
| test.py:552:6:552:10 | ControlFlowNode for List [Tuple element at index 0, List element] | semmle.label | ControlFlowNode for List [Tuple element at index 0, List element] |
| test.py:552:6:552:10 | IterableElement [List element] | semmle.label | IterableElement [List element] |
| test.py:552:6:552:10 | IterableSequence [List element, List element] | semmle.label | IterableSequence [List element, List element] |
| test.py:552:7:552:9 | ControlFlowNode for List [Tuple element at index 0] | semmle.label | ControlFlowNode for List [Tuple element at index 0] |
| test.py:552:7:552:9 | IterableElement | semmle.label | IterableElement |
| test.py:552:7:552:9 | IterableSequence [List element] | semmle.label | IterableSequence [List element] |
| test.py:552:8:552:8 | SSA variable a | semmle.label | SSA variable a |
| test.py:553:10:553:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:559:10:559:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:559:10:559:34 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:559:10:559:34 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:559:18:559:23 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:560:5:560:5 | SSA variable a | semmle.label | SSA variable a |
| test.py:560:5:560:12 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:560:5:560:12 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:560:8:560:9 | IterableElement | semmle.label | IterableElement |
| test.py:560:8:560:9 | SSA variable b [List element] | semmle.label | SSA variable b [List element] |
| test.py:560:12:560:12 | SSA variable c | semmle.label | SSA variable c |
| test.py:561:10:561:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:563:10:563:10 | ControlFlowNode for b [List element] | semmle.label | ControlFlowNode for b [List element] |
| test.py:563:10:563:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:564:12:564:12 | ControlFlowNode for c | semmle.label | ControlFlowNode for c |
| test.py:569:10:569:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:569:10:569:23 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:569:10:569:23 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:569:18:569:23 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:570:5:570:5 | SSA variable a | semmle.label | SSA variable a |
| test.py:570:5:570:12 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:570:5:570:12 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:570:12:570:12 | SSA variable c | semmle.label | SSA variable c |
| test.py:571:10:571:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:573:10:573:10 | ControlFlowNode for c | semmle.label | ControlFlowNode for c |
| test.py:578:10:578:61 | ControlFlowNode for List [List element, List element] | semmle.label | ControlFlowNode for List [List element, List element] |
| test.py:578:11:578:37 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| test.py:578:12:578:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:578:31:578:36 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:578:40:578:47 | ControlFlowNode for List [List element] | semmle.label | ControlFlowNode for List [List element] |
| test.py:578:41:578:46 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:581:6:581:23 | ControlFlowNode for Tuple [Tuple element at index 0, List element] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, List element] |
| test.py:581:6:581:23 | IterableElement [List element] | semmle.label | IterableElement [List element] |
| test.py:581:6:581:23 | IterableSequence [List element, List element] | semmle.label | IterableSequence [List element, List element] |
| test.py:581:7:581:8 | SSA variable a1 | semmle.label | SSA variable a1 |
| test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:581:7:581:16 | ControlFlowNode for Tuple [Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:581:7:581:16 | IterableElement | semmle.label | IterableElement |
| test.py:581:7:581:16 | IterableSequence [List element] | semmle.label | IterableSequence [List element] |
| test.py:581:11:581:12 | SSA variable a2 | semmle.label | SSA variable a2 |
| test.py:581:15:581:16 | SSA variable a3 | semmle.label | SSA variable a3 |
| test.py:582:10:582:11 | ControlFlowNode for a1 | semmle.label | ControlFlowNode for a1 |
| test.py:583:12:583:13 | ControlFlowNode for a2 | semmle.label | ControlFlowNode for a2 |
| test.py:584:10:584:11 | ControlFlowNode for a3 | semmle.label | ControlFlowNode for a3 |
| test.py:589:5:589:24 | ControlFlowNode for List [Tuple element at index 0, List element] | semmle.label | ControlFlowNode for List [Tuple element at index 0, List element] |
| test.py:589:5:589:24 | IterableElement [List element] | semmle.label | IterableElement [List element] |
| test.py:589:5:589:24 | IterableSequence [List element, List element] | semmle.label | IterableSequence [List element, List element] |
| test.py:589:7:589:8 | SSA variable a1 | semmle.label | SSA variable a1 |
| test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 1] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 1] |
| test.py:589:7:589:16 | ControlFlowNode for Tuple [Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:589:7:589:16 | IterableElement | semmle.label | IterableElement |
| test.py:589:7:589:16 | IterableSequence [List element] | semmle.label | IterableSequence [List element] |
| test.py:589:11:589:12 | SSA variable a2 | semmle.label | SSA variable a2 |
| test.py:589:15:589:16 | SSA variable a3 | semmle.label | SSA variable a3 |
| test.py:590:10:590:11 | ControlFlowNode for a1 | semmle.label | ControlFlowNode for a1 |
| test.py:591:12:591:13 | ControlFlowNode for a2 | semmle.label | ControlFlowNode for a2 |
| test.py:592:10:592:11 | ControlFlowNode for a3 | semmle.label | ControlFlowNode for a3 |
| test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 0] | semmle.label | ControlFlowNode for List [Tuple element at index 0] |
| test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 1] | semmle.label | ControlFlowNode for List [Tuple element at index 1] |
| test.py:597:6:597:17 | ControlFlowNode for List [Tuple element at index 2] | semmle.label | ControlFlowNode for List [Tuple element at index 2] |
| test.py:597:6:597:17 | IterableElement | semmle.label | IterableElement |
| test.py:597:6:597:17 | IterableSequence [List element] | semmle.label | IterableSequence [List element] |
| test.py:597:6:597:23 | ControlFlowNode for Tuple [Tuple element at index 0, List element] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, List element] |
| test.py:597:6:597:23 | IterableElement [List element] | semmle.label | IterableElement [List element] |
| test.py:597:6:597:23 | IterableSequence [List element, List element] | semmle.label | IterableSequence [List element, List element] |
| test.py:597:7:597:8 | SSA variable a1 | semmle.label | SSA variable a1 |
| test.py:597:11:597:12 | SSA variable a2 | semmle.label | SSA variable a2 |
| test.py:597:15:597:16 | SSA variable a3 | semmle.label | SSA variable a3 |
| test.py:598:10:598:11 | ControlFlowNode for a1 | semmle.label | ControlFlowNode for a1 |
| test.py:599:12:599:13 | ControlFlowNode for a2 | semmle.label | ControlFlowNode for a2 |
| test.py:600:10:600:11 | ControlFlowNode for a3 | semmle.label | ControlFlowNode for a3 |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] |
| test.py:606:11:606:47 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] |
| test.py:606:12:606:17 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:606:12:606:36 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:606:12:606:36 | ControlFlowNode for Tuple [Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:606:31:606:36 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:609:5:609:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] | semmle.label | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] |
| test.py:609:5:609:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] | semmle.label | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] |
| test.py:609:6:609:14 | ControlFlowNode for List [Tuple element at index 0] | semmle.label | ControlFlowNode for List [Tuple element at index 0] |
| test.py:609:6:609:14 | ControlFlowNode for List [Tuple element at index 2] | semmle.label | ControlFlowNode for List [Tuple element at index 2] |
| test.py:609:6:609:14 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] |
| test.py:609:6:609:14 | IterableSequence [Tuple element at index 2] | semmle.label | IterableSequence [Tuple element at index 2] |
| test.py:609:7:609:8 | SSA variable a1 | semmle.label | SSA variable a1 |
| test.py:609:11:609:13 | IterableElement | semmle.label | IterableElement |
| test.py:609:11:609:13 | SSA variable a2 [List element] | semmle.label | SSA variable a2 [List element] |
| test.py:610:10:610:11 | ControlFlowNode for a1 | semmle.label | ControlFlowNode for a1 |
| test.py:612:12:612:13 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:612:12:612:16 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:613:10:613:11 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:613:10:613:14 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:618:6:618:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] |
| test.py:618:6:618:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] |
| test.py:618:7:618:8 | SSA variable a1 | semmle.label | SSA variable a1 |
| test.py:618:7:618:13 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:618:7:618:13 | ControlFlowNode for Tuple [Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:618:7:618:13 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] |
| test.py:618:7:618:13 | IterableSequence [Tuple element at index 2] | semmle.label | IterableSequence [Tuple element at index 2] |
| test.py:618:11:618:13 | IterableElement | semmle.label | IterableElement |
| test.py:618:11:618:13 | SSA variable a2 [List element] | semmle.label | SSA variable a2 [List element] |
| test.py:619:10:619:11 | ControlFlowNode for a1 | semmle.label | ControlFlowNode for a1 |
| test.py:621:12:621:13 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:621:12:621:16 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:622:10:622:11 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:622:10:622:14 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:627:5:627:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] | semmle.label | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 0] |
| test.py:627:5:627:19 | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] | semmle.label | ControlFlowNode for List [Tuple element at index 0, Tuple element at index 2] |
| test.py:627:7:627:8 | SSA variable a1 | semmle.label | SSA variable a1 |
| test.py:627:7:627:13 | ControlFlowNode for Tuple [Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0] |
| test.py:627:7:627:13 | ControlFlowNode for Tuple [Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 2] |
| test.py:627:7:627:13 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] |
| test.py:627:7:627:13 | IterableSequence [Tuple element at index 2] | semmle.label | IterableSequence [Tuple element at index 2] |
| test.py:627:11:627:13 | IterableElement | semmle.label | IterableElement |
| test.py:627:11:627:13 | SSA variable a2 [List element] | semmle.label | SSA variable a2 [List element] |
| test.py:628:10:628:11 | ControlFlowNode for a1 | semmle.label | ControlFlowNode for a1 |
| test.py:630:12:630:13 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:630:12:630:16 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:631:10:631:11 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:631:10:631:14 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:636:6:636:14 | ControlFlowNode for List [Tuple element at index 0] | semmle.label | ControlFlowNode for List [Tuple element at index 0] |
| test.py:636:6:636:14 | ControlFlowNode for List [Tuple element at index 2] | semmle.label | ControlFlowNode for List [Tuple element at index 2] |
| test.py:636:6:636:14 | IterableSequence [Tuple element at index 0] | semmle.label | IterableSequence [Tuple element at index 0] |
| test.py:636:6:636:14 | IterableSequence [Tuple element at index 2] | semmle.label | IterableSequence [Tuple element at index 2] |
| test.py:636:6:636:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 0] |
| test.py:636:6:636:18 | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] | semmle.label | ControlFlowNode for Tuple [Tuple element at index 0, Tuple element at index 2] |
| test.py:636:7:636:8 | SSA variable a1 | semmle.label | SSA variable a1 |
| test.py:636:11:636:13 | IterableElement | semmle.label | IterableElement |
| test.py:636:11:636:13 | SSA variable a2 [List element] | semmle.label | SSA variable a2 [List element] |
| test.py:637:10:637:11 | ControlFlowNode for a1 | semmle.label | ControlFlowNode for a1 |
| test.py:639:12:639:13 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:639:12:639:16 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:640:10:640:11 | ControlFlowNode for a2 [List element] | semmle.label | ControlFlowNode for a2 [List element] |
| test.py:640:10:640:14 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
| test.py:647:19:647:24 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:648:10:648:10 | ControlFlowNode for a | semmle.label | ControlFlowNode for a |
| test.py:739:16:739:21 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() | semmle.label | ControlFlowNode for return_from_inner_scope() |
#select
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found |
| datamodel.py:38:6:38:17 | ControlFlowNode for f() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:38:6:38:17 | ControlFlowNode for f() | Flow found |
| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:71:6:71:24 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:72:6:72:27 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:80:6:80:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:38:8:38:13 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:71:15:71:20 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:72:18:72:23 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:73:18:73:23 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:80:20:80:25 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | datamodel.py:81:20:81:25 | ControlFlowNode for SOURCE | datamodel.py:81:6:81:26 | ControlFlowNode for Attribute() | Flow found |
| datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | datamodel.py:13:10:13:17 | ControlFlowNode for Str | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | Flow found |
| datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | datamodel.py:152:14:152:19 | ControlFlowNode for SOURCE | datamodel.py:159:6:159:17 | ControlFlowNode for Attribute | Flow found |
| test.py:44:10:44:10 | ControlFlowNode for y | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:44:10:44:10 | ControlFlowNode for y | Flow found |
| test.py:44:10:44:10 | ControlFlowNode for y | test.py:42:21:42:26 | ControlFlowNode for SOURCE | test.py:44:10:44:10 | ControlFlowNode for y | Flow found |
| test.py:56:10:56:10 | ControlFlowNode for x | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:56:10:56:10 | ControlFlowNode for x | Flow found |
| test.py:56:10:56:10 | ControlFlowNode for x | test.py:55:9:55:14 | ControlFlowNode for SOURCE | test.py:56:10:56:10 | ControlFlowNode for x | Flow found |
| test.py:62:10:62:10 | ControlFlowNode for x | test.py:61:9:61:16 | ControlFlowNode for Str | test.py:62:10:62:10 | ControlFlowNode for x | Flow found |
| test.py:67:10:67:10 | ControlFlowNode for x | test.py:66:9:66:17 | ControlFlowNode for Str | test.py:67:10:67:10 | ControlFlowNode for x | Flow found |
| test.py:72:10:72:10 | ControlFlowNode for x | test.py:71:9:71:10 | ControlFlowNode for IntegerLiteral | test.py:72:10:72:10 | ControlFlowNode for x | Flow found |
| test.py:77:10:77:10 | ControlFlowNode for x | test.py:76:9:76:12 | ControlFlowNode for FloatLiteral | test.py:77:10:77:10 | ControlFlowNode for x | Flow found |
| test.py:88:10:88:10 | ControlFlowNode for x | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:88:10:88:10 | ControlFlowNode for x | Flow found |
| test.py:88:10:88:10 | ControlFlowNode for x | test.py:87:10:87:15 | ControlFlowNode for SOURCE | test.py:88:10:88:10 | ControlFlowNode for x | Flow found |
| test.py:94:10:94:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:94:10:94:13 | ControlFlowNode for Subscript | Flow found |
| test.py:94:10:94:13 | ControlFlowNode for Subscript | test.py:93:10:93:15 | ControlFlowNode for SOURCE | test.py:94:10:94:13 | ControlFlowNode for Subscript | Flow found |
| test.py:104:10:104:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:104:10:104:13 | ControlFlowNode for Subscript | Flow found |
| test.py:104:10:104:13 | ControlFlowNode for Subscript | test.py:103:10:103:15 | ControlFlowNode for SOURCE | test.py:104:10:104:13 | ControlFlowNode for Subscript | Flow found |
| test.py:109:10:109:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:109:10:109:13 | ControlFlowNode for Subscript | Flow found |
| test.py:109:10:109:13 | ControlFlowNode for Subscript | test.py:108:22:108:27 | ControlFlowNode for SOURCE | test.py:109:10:109:13 | ControlFlowNode for Subscript | Flow found |
| test.py:115:10:115:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:115:10:115:13 | ControlFlowNode for Subscript | Flow found |
| test.py:115:10:115:13 | ControlFlowNode for Subscript | test.py:113:10:113:15 | ControlFlowNode for SOURCE | test.py:115:10:115:13 | ControlFlowNode for Subscript | Flow found |
| test.py:126:10:126:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:126:10:126:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:126:10:126:16 | ControlFlowNode for Attribute() | test.py:125:10:125:15 | ControlFlowNode for SOURCE | test.py:126:10:126:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:131:10:131:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:131:10:131:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:131:10:131:16 | ControlFlowNode for Attribute() | test.py:130:10:130:15 | ControlFlowNode for SOURCE | test.py:131:10:131:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:136:10:136:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:136:10:136:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:136:10:136:16 | ControlFlowNode for Attribute() | test.py:135:22:135:27 | ControlFlowNode for SOURCE | test.py:136:10:136:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:142:10:142:16 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:142:10:142:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:142:10:142:16 | ControlFlowNode for Attribute() | test.py:140:10:140:15 | ControlFlowNode for SOURCE | test.py:142:10:142:16 | ControlFlowNode for Attribute() | Flow found |
| test.py:153:10:153:15 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:153:10:153:15 | ControlFlowNode for Subscript | Flow found |
| test.py:153:10:153:15 | ControlFlowNode for Subscript | test.py:152:15:152:20 | ControlFlowNode for SOURCE | test.py:153:10:153:15 | ControlFlowNode for Subscript | Flow found |
| test.py:158:10:158:19 | ControlFlowNode for Attribute() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:158:10:158:19 | ControlFlowNode for Attribute() | Flow found |
| test.py:158:10:158:19 | ControlFlowNode for Attribute() | test.py:157:15:157:20 | ControlFlowNode for SOURCE | test.py:158:10:158:19 | ControlFlowNode for Attribute() | Flow found |
| test.py:184:10:184:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:184:10:184:13 | ControlFlowNode for Subscript | Flow found |
| test.py:184:10:184:13 | ControlFlowNode for Subscript | test.py:183:23:183:28 | ControlFlowNode for SOURCE | test.py:184:10:184:13 | ControlFlowNode for Subscript | Flow found |
| test.py:189:10:189:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:189:10:189:13 | ControlFlowNode for Subscript | Flow found |
| test.py:189:10:189:13 | ControlFlowNode for Subscript | test.py:188:25:188:30 | ControlFlowNode for SOURCE | test.py:189:10:189:13 | ControlFlowNode for Subscript | Flow found |
| test.py:200:10:200:13 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:200:10:200:13 | ControlFlowNode for Subscript | Flow found |
| test.py:200:10:200:13 | ControlFlowNode for Subscript | test.py:199:34:199:39 | ControlFlowNode for SOURCE | test.py:200:10:200:13 | ControlFlowNode for Subscript | Flow found |
| test.py:336:10:336:21 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:336:10:336:21 | ControlFlowNode for Subscript | Flow found |
| test.py:336:10:336:21 | ControlFlowNode for Subscript | test.py:336:11:336:16 | ControlFlowNode for SOURCE | test.py:336:10:336:21 | ControlFlowNode for Subscript | Flow found |
| test.py:340:10:340:20 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:340:10:340:20 | ControlFlowNode for Subscript | Flow found |
| test.py:340:10:340:20 | ControlFlowNode for Subscript | test.py:340:11:340:16 | ControlFlowNode for SOURCE | test.py:340:10:340:20 | ControlFlowNode for Subscript | Flow found |
| test.py:344:10:344:27 | ControlFlowNode for Subscript | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:344:10:344:27 | ControlFlowNode for Subscript | Flow found |
| test.py:344:10:344:27 | ControlFlowNode for Subscript | test.py:344:16:344:21 | ControlFlowNode for SOURCE | test.py:344:10:344:27 | ControlFlowNode for Subscript | Flow found |
| test.py:367:10:367:34 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:367:10:367:34 | ControlFlowNode for second() | Flow found |
| test.py:367:10:367:34 | ControlFlowNode for second() | test.py:367:28:367:33 | ControlFlowNode for SOURCE | test.py:367:10:367:34 | ControlFlowNode for second() | Flow found |
| test.py:375:10:375:36 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:375:10:375:36 | ControlFlowNode for second() | Flow found |
| test.py:375:10:375:36 | ControlFlowNode for second() | test.py:375:30:375:35 | ControlFlowNode for SOURCE | test.py:375:10:375:36 | ControlFlowNode for second() | Flow found |
| test.py:383:10:383:43 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:383:10:383:43 | ControlFlowNode for second() | Flow found |
| test.py:383:10:383:43 | ControlFlowNode for second() | test.py:383:36:383:41 | ControlFlowNode for SOURCE | test.py:383:10:383:43 | ControlFlowNode for second() | Flow found |
| test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | Flow found |
| test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | test.py:391:33:391:38 | ControlFlowNode for SOURCE | test.py:391:10:391:39 | ControlFlowNode for f_extra_pos() | Flow found |
| test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | Flow found |
| test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | test.py:399:39:399:44 | ControlFlowNode for SOURCE | test.py:399:10:399:45 | ControlFlowNode for f_extra_keyword() | Flow found |
| test.py:420:10:420:38 | ControlFlowNode for IfExp | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:420:10:420:38 | ControlFlowNode for IfExp | Flow found |
| test.py:420:10:420:38 | ControlFlowNode for IfExp | test.py:420:10:420:15 | ControlFlowNode for SOURCE | test.py:420:10:420:38 | ControlFlowNode for IfExp | Flow found |
| test.py:428:10:428:39 | ControlFlowNode for IfExp | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:428:10:428:39 | ControlFlowNode for IfExp | Flow found |
| test.py:428:10:428:39 | ControlFlowNode for IfExp | test.py:428:34:428:39 | ControlFlowNode for SOURCE | test.py:428:10:428:39 | ControlFlowNode for IfExp | Flow found |
| test.py:452:10:452:18 | ControlFlowNode for f() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:452:10:452:18 | ControlFlowNode for f() | Flow found |
| test.py:452:10:452:18 | ControlFlowNode for f() | test.py:452:12:452:17 | ControlFlowNode for SOURCE | test.py:452:10:452:18 | ControlFlowNode for f() | Flow found |
| test.py:459:10:459:34 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:459:10:459:34 | ControlFlowNode for second() | Flow found |
| test.py:459:10:459:34 | ControlFlowNode for second() | test.py:459:28:459:33 | ControlFlowNode for SOURCE | test.py:459:10:459:34 | ControlFlowNode for second() | Flow found |
| test.py:473:10:473:36 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:473:10:473:36 | ControlFlowNode for second() | Flow found |
| test.py:473:10:473:36 | ControlFlowNode for second() | test.py:473:30:473:35 | ControlFlowNode for SOURCE | test.py:473:10:473:36 | ControlFlowNode for second() | Flow found |
| test.py:487:10:487:43 | ControlFlowNode for second() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:487:10:487:43 | ControlFlowNode for second() | Flow found |
| test.py:487:10:487:43 | ControlFlowNode for second() | test.py:487:36:487:41 | ControlFlowNode for SOURCE | test.py:487:10:487:43 | ControlFlowNode for second() | Flow found |
| test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | Flow found |
| test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | test.py:492:33:492:38 | ControlFlowNode for SOURCE | test.py:492:10:492:39 | ControlFlowNode for f_extra_pos() | Flow found |
| test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | Flow found |
| test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | test.py:497:39:497:44 | ControlFlowNode for SOURCE | test.py:497:10:497:45 | ControlFlowNode for f_extra_keyword() | Flow found |
| test.py:511:10:511:10 | ControlFlowNode for a | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:511:10:511:10 | ControlFlowNode for a | Flow found |
| test.py:511:10:511:10 | ControlFlowNode for a | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:511:10:511:10 | ControlFlowNode for a | Flow found |
| test.py:516:10:516:10 | ControlFlowNode for b | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:516:10:516:10 | ControlFlowNode for b | Flow found |
| test.py:516:10:516:10 | ControlFlowNode for b | test.py:509:9:509:14 | ControlFlowNode for SOURCE | test.py:516:10:516:10 | ControlFlowNode for b | Flow found |
| test.py:591:10:591:36 | ControlFlowNode for return_from_inner_scope() | test.py:20:10:20:17 | ControlFlowNode for Str | test.py:591:10:591:36 | ControlFlowNode for return_from_inner_scope() | Flow found |
| test.py:591:10:591:36 | ControlFlowNode for return_from_inner_scope() | test.py:588:16:588:21 | ControlFlowNode for SOURCE | test.py:591:10:591:36 | ControlFlowNode for return_from_inner_scope() | Flow found |
| test.py:349:10:349:21 | ControlFlowNode for Subscript | test.py:349:11:349:16 | ControlFlowNode for SOURCE | test.py:349:10:349:21 | ControlFlowNode for Subscript | Flow found |
| test.py:353:10:353:20 | ControlFlowNode for Subscript | test.py:353:11:353:16 | ControlFlowNode for SOURCE | test.py:353:10:353:20 | ControlFlowNode for Subscript | Flow found |
| test.py:357:10:357:27 | ControlFlowNode for Subscript | test.py:357:16:357:21 | ControlFlowNode for SOURCE | test.py:357:10:357:27 | ControlFlowNode for Subscript | Flow found |
| test.py:380:10:380:34 | ControlFlowNode for second() | test.py:380:28:380:33 | ControlFlowNode for SOURCE | test.py:380:10:380:34 | ControlFlowNode for second() | Flow found |
| test.py:388:10:388:36 | ControlFlowNode for second() | test.py:388:30:388:35 | ControlFlowNode for SOURCE | test.py:388:10:388:36 | ControlFlowNode for second() | Flow found |
| test.py:396:10:396:43 | ControlFlowNode for second() | test.py:396:36:396:41 | ControlFlowNode for SOURCE | test.py:396:10:396:43 | ControlFlowNode for second() | Flow found |
| test.py:404:10:404:39 | ControlFlowNode for f_extra_pos() | test.py:404:33:404:38 | ControlFlowNode for SOURCE | test.py:404:10:404:39 | ControlFlowNode for f_extra_pos() | Flow found |
| test.py:412:10:412:45 | ControlFlowNode for f_extra_keyword() | test.py:412:39:412:44 | ControlFlowNode for SOURCE | test.py:412:10:412:45 | ControlFlowNode for f_extra_keyword() | Flow found |
| test.py:433:10:433:38 | ControlFlowNode for IfExp | test.py:433:10:433:15 | ControlFlowNode for SOURCE | test.py:433:10:433:38 | ControlFlowNode for IfExp | Flow found |
| test.py:441:10:441:39 | ControlFlowNode for IfExp | test.py:441:34:441:39 | ControlFlowNode for SOURCE | test.py:441:10:441:39 | ControlFlowNode for IfExp | Flow found |
| test.py:465:10:465:18 | ControlFlowNode for f() | test.py:465:12:465:17 | ControlFlowNode for SOURCE | test.py:465:10:465:18 | ControlFlowNode for f() | Flow found |
| test.py:472:10:472:34 | ControlFlowNode for second() | test.py:472:28:472:33 | ControlFlowNode for SOURCE | test.py:472:10:472:34 | ControlFlowNode for second() | Flow found |
| test.py:486:10:486:36 | ControlFlowNode for second() | test.py:486:30:486:35 | ControlFlowNode for SOURCE | test.py:486:10:486:36 | ControlFlowNode for second() | Flow found |
| test.py:500:10:500:43 | ControlFlowNode for second() | test.py:500:36:500:41 | ControlFlowNode for SOURCE | test.py:500:10:500:43 | ControlFlowNode for second() | Flow found |
| test.py:505:10:505:39 | ControlFlowNode for f_extra_pos() | test.py:505:33:505:38 | ControlFlowNode for SOURCE | test.py:505:10:505:39 | ControlFlowNode for f_extra_pos() | Flow found |
| test.py:510:10:510:45 | ControlFlowNode for f_extra_keyword() | test.py:510:39:510:44 | ControlFlowNode for SOURCE | test.py:510:10:510:45 | ControlFlowNode for f_extra_keyword() | Flow found |
| test.py:524:10:524:10 | ControlFlowNode for a | test.py:522:9:522:14 | ControlFlowNode for SOURCE | test.py:524:10:524:10 | ControlFlowNode for a | Flow found |
| test.py:529:10:529:10 | ControlFlowNode for b | test.py:522:9:522:14 | ControlFlowNode for SOURCE | test.py:529:10:529:10 | ControlFlowNode for b | Flow found |
| test.py:536:10:536:10 | ControlFlowNode for a | test.py:534:10:534:15 | ControlFlowNode for SOURCE | test.py:536:10:536:10 | ControlFlowNode for a | Flow found |
| test.py:544:10:544:10 | ControlFlowNode for a | test.py:542:10:542:15 | ControlFlowNode for SOURCE | test.py:544:10:544:10 | ControlFlowNode for a | Flow found |
| test.py:546:10:546:10 | ControlFlowNode for c | test.py:542:30:542:35 | ControlFlowNode for SOURCE | test.py:546:10:546:10 | ControlFlowNode for c | Flow found |
| test.py:553:10:553:10 | ControlFlowNode for a | test.py:551:13:551:18 | ControlFlowNode for SOURCE | test.py:553:10:553:10 | ControlFlowNode for a | Flow found |
| test.py:561:10:561:10 | ControlFlowNode for a | test.py:559:10:559:15 | ControlFlowNode for SOURCE | test.py:561:10:561:10 | ControlFlowNode for a | Flow found |
| test.py:563:10:563:13 | ControlFlowNode for Subscript | test.py:559:18:559:23 | ControlFlowNode for SOURCE | test.py:563:10:563:13 | ControlFlowNode for Subscript | Flow found |
| test.py:564:12:564:12 | ControlFlowNode for c | test.py:559:18:559:23 | ControlFlowNode for SOURCE | test.py:564:12:564:12 | ControlFlowNode for c | Flow found |
| test.py:571:10:571:10 | ControlFlowNode for a | test.py:569:10:569:15 | ControlFlowNode for SOURCE | test.py:571:10:571:10 | ControlFlowNode for a | Flow found |
| test.py:573:10:573:10 | ControlFlowNode for c | test.py:569:18:569:23 | ControlFlowNode for SOURCE | test.py:573:10:573:10 | ControlFlowNode for c | Flow found |
| test.py:582:10:582:11 | ControlFlowNode for a1 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:582:10:582:11 | ControlFlowNode for a1 | Flow found |
| test.py:582:10:582:11 | ControlFlowNode for a1 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:582:10:582:11 | ControlFlowNode for a1 | Flow found |
| test.py:582:10:582:11 | ControlFlowNode for a1 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:582:10:582:11 | ControlFlowNode for a1 | Flow found |
| test.py:583:12:583:13 | ControlFlowNode for a2 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:583:12:583:13 | ControlFlowNode for a2 | Flow found |
| test.py:583:12:583:13 | ControlFlowNode for a2 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:583:12:583:13 | ControlFlowNode for a2 | Flow found |
| test.py:583:12:583:13 | ControlFlowNode for a2 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:583:12:583:13 | ControlFlowNode for a2 | Flow found |
| test.py:584:10:584:11 | ControlFlowNode for a3 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:584:10:584:11 | ControlFlowNode for a3 | Flow found |
| test.py:584:10:584:11 | ControlFlowNode for a3 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:584:10:584:11 | ControlFlowNode for a3 | Flow found |
| test.py:584:10:584:11 | ControlFlowNode for a3 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:584:10:584:11 | ControlFlowNode for a3 | Flow found |
| test.py:590:10:590:11 | ControlFlowNode for a1 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:590:10:590:11 | ControlFlowNode for a1 | Flow found |
| test.py:590:10:590:11 | ControlFlowNode for a1 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:590:10:590:11 | ControlFlowNode for a1 | Flow found |
| test.py:590:10:590:11 | ControlFlowNode for a1 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:590:10:590:11 | ControlFlowNode for a1 | Flow found |
| test.py:591:12:591:13 | ControlFlowNode for a2 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:591:12:591:13 | ControlFlowNode for a2 | Flow found |
| test.py:591:12:591:13 | ControlFlowNode for a2 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:591:12:591:13 | ControlFlowNode for a2 | Flow found |
| test.py:591:12:591:13 | ControlFlowNode for a2 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:591:12:591:13 | ControlFlowNode for a2 | Flow found |
| test.py:592:10:592:11 | ControlFlowNode for a3 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:592:10:592:11 | ControlFlowNode for a3 | Flow found |
| test.py:592:10:592:11 | ControlFlowNode for a3 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:592:10:592:11 | ControlFlowNode for a3 | Flow found |
| test.py:592:10:592:11 | ControlFlowNode for a3 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:592:10:592:11 | ControlFlowNode for a3 | Flow found |
| test.py:598:10:598:11 | ControlFlowNode for a1 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:598:10:598:11 | ControlFlowNode for a1 | Flow found |
| test.py:598:10:598:11 | ControlFlowNode for a1 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:598:10:598:11 | ControlFlowNode for a1 | Flow found |
| test.py:598:10:598:11 | ControlFlowNode for a1 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:598:10:598:11 | ControlFlowNode for a1 | Flow found |
| test.py:599:12:599:13 | ControlFlowNode for a2 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:599:12:599:13 | ControlFlowNode for a2 | Flow found |
| test.py:599:12:599:13 | ControlFlowNode for a2 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:599:12:599:13 | ControlFlowNode for a2 | Flow found |
| test.py:599:12:599:13 | ControlFlowNode for a2 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:599:12:599:13 | ControlFlowNode for a2 | Flow found |
| test.py:600:10:600:11 | ControlFlowNode for a3 | test.py:578:12:578:17 | ControlFlowNode for SOURCE | test.py:600:10:600:11 | ControlFlowNode for a3 | Flow found |
| test.py:600:10:600:11 | ControlFlowNode for a3 | test.py:578:31:578:36 | ControlFlowNode for SOURCE | test.py:600:10:600:11 | ControlFlowNode for a3 | Flow found |
| test.py:600:10:600:11 | ControlFlowNode for a3 | test.py:578:41:578:46 | ControlFlowNode for SOURCE | test.py:600:10:600:11 | ControlFlowNode for a3 | Flow found |
| test.py:610:10:610:11 | ControlFlowNode for a1 | test.py:606:12:606:17 | ControlFlowNode for SOURCE | test.py:610:10:610:11 | ControlFlowNode for a1 | Flow found |
| test.py:612:12:612:16 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:612:12:612:16 | ControlFlowNode for Subscript | Flow found |
| test.py:613:10:613:14 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:613:10:613:14 | ControlFlowNode for Subscript | Flow found |
| test.py:619:10:619:11 | ControlFlowNode for a1 | test.py:606:12:606:17 | ControlFlowNode for SOURCE | test.py:619:10:619:11 | ControlFlowNode for a1 | Flow found |
| test.py:621:12:621:16 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:621:12:621:16 | ControlFlowNode for Subscript | Flow found |
| test.py:622:10:622:14 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:622:10:622:14 | ControlFlowNode for Subscript | Flow found |
| test.py:628:10:628:11 | ControlFlowNode for a1 | test.py:606:12:606:17 | ControlFlowNode for SOURCE | test.py:628:10:628:11 | ControlFlowNode for a1 | Flow found |
| test.py:630:12:630:16 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:630:12:630:16 | ControlFlowNode for Subscript | Flow found |
| test.py:631:10:631:14 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:631:10:631:14 | ControlFlowNode for Subscript | Flow found |
| test.py:637:10:637:11 | ControlFlowNode for a1 | test.py:606:12:606:17 | ControlFlowNode for SOURCE | test.py:637:10:637:11 | ControlFlowNode for a1 | Flow found |
| test.py:639:12:639:16 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:639:12:639:16 | ControlFlowNode for Subscript | Flow found |
| test.py:640:10:640:14 | ControlFlowNode for Subscript | test.py:606:31:606:36 | ControlFlowNode for SOURCE | test.py:640:10:640:14 | ControlFlowNode for Subscript | Flow found |
| test.py:648:10:648:10 | ControlFlowNode for a | test.py:647:19:647:24 | ControlFlowNode for SOURCE | test.py:648:10:648:10 | ControlFlowNode for a | Flow found |
| test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() | test.py:739:16:739:21 | ControlFlowNode for SOURCE | test.py:742:10:742:36 | ControlFlowNode for return_from_inner_scope() | Flow found |

View File

@@ -0,0 +1,13 @@
import python
import experimental.dataflow.TestUtil.FlowTest
import experimental.dataflow.testConfig
class DataFlowTest extends FlowTest {
DataFlowTest() { this = "DataFlowTest" }
override string flowTag() { result = "flow" }
override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
exists(TestConfiguration cfg | cfg.hasFlow(source, sink))
}
}

View File

@@ -35,7 +35,7 @@ def SINK_F(x):
def f(a, b):
return a
SINK(f(SOURCE, 3))
SINK(f(SOURCE, 3)) #$ flow="SOURCE -> f(..)"
# Instance methods
# An instance method object combines a class, a class instance and any callable object (normally a user-defined function).
@@ -68,18 +68,18 @@ c = C()
func_obj = c.method.__func__
# When an instance method object is called, the underlying function (__func__) is called, inserting the class instance (__self__) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1).
SINK(c.method(SOURCE, C))
SINK(C.method(c, SOURCE, C))
SINK(func_obj(c, SOURCE, C))
SINK(c.method(SOURCE, C)) #$ flow="SOURCE -> c.method(..)"
SINK(C.method(c, SOURCE, C)) #$ flow="SOURCE -> C.method(..)"
SINK(func_obj(c, SOURCE, C)) #$ MISSING: flow="SOURCE -> func_obj(..)"
# When an instance method object is created by retrieving a class method object from a class or instance, its __self__ attribute is the class itself, and its __func__ attribute is the function object underlying the class method.
c_func_obj = C.classmethod.__func__
# When an instance method object is derived from a class method object, the “class instance” stored in __self__ will actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function.
SINK(c.classmethod(SOURCE))
SINK(C.classmethod(SOURCE))
SINK(c_func_obj(C, SOURCE))
SINK(c.classmethod(SOURCE)) #$ flow="SOURCE -> c.classmethod(..)"
SINK(C.classmethod(SOURCE)) #$ flow="SOURCE -> C.classmethod(..)"
SINK(c_func_obj(C, SOURCE)) #$ MISSING: flow="SOURCE -> c_func_obj(..)"
# Generator functions
# A function or method which uses the yield statement (see section The yield statement) is called a generator function. Such a function, when called, always returns an iterator object which can be used to execute the body of the function: calling the iterators iterator.__next__() method will cause the function to execute until it provides a value using the yield statement. When the function executes a return statement or falls off the end, a StopIteration exception is raised and the iterator will have reached the end of the set of values to be returned.
@@ -153,7 +153,7 @@ class Customized:
# testing __new__ and __init__
customized = Customized()
SINK(Customized.a)
SINK(Customized.a) #$ MISSING:flow="SOURCE, l:-8 -> customized.a"
SINK_F(Customized.b)
SINK(customized.a)
SINK(customized.b) # Flow found
SINK(customized.a) #$ MISSING:flow="SOURCE, l:-10 -> customized.a"
SINK(customized.b) #$ flow="SOURCE, l:-7 -> customized.b"

View File

@@ -8,6 +8,7 @@
| test.py:187:1:187:53 | GSSA Variable SINK | test.py:189:5:189:8 | ControlFlowNode for SINK |
| test.py:187:1:187:53 | GSSA Variable SOURCE | test.py:188:25:188:30 | ControlFlowNode for SOURCE |
| test.py:188:5:188:5 | SSA variable x | test.py:189:10:189:10 | ControlFlowNode for x |
| test.py:188:9:188:68 | ControlFlowNode for .0 | test.py:188:9:188:68 | SSA variable .0 |
| test.py:188:9:188:68 | ControlFlowNode for ListComp | test.py:188:5:188:5 | SSA variable x |
| test.py:188:9:188:68 | SSA variable .0 | test.py:188:9:188:68 | ControlFlowNode for .0 |
| test.py:188:16:188:16 | SSA variable v | test.py:188:45:188:45 | ControlFlowNode for v |

View File

@@ -41,7 +41,7 @@ def SINK_F(x):
def test_tuple_with_local_flow():
x = (NONSOURCE, SOURCE)
y = x[1]
SINK(y)
SINK(y) #$ flow="SOURCE, l:-2 -> y"
def test_tuple_negative():
@@ -53,45 +53,45 @@ def test_tuple_negative():
# 6.2.1. Identifiers (Names)
def test_names():
x = SOURCE
SINK(x)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
# 6.2.2. Literals
def test_string_literal():
x = "source"
SINK(x)
SINK(x) #$ flow="'source', l:-1 -> x"
def test_bytes_literal():
x = b"source"
SINK(x)
SINK(x) #$ flow="b'source', l:-1 -> x"
def test_integer_literal():
x = 42
SINK(x)
SINK(x) #$ flow="42, l:-1 -> x"
def test_floatnumber_literal():
x = 42.0
SINK(x)
SINK(x) #$ flow="42.0, l:-1 -> x"
def test_imagnumber_literal():
x = 42j
SINK(x) # Flow missing
SINK(x) #$ MISSING:flow="42j, l:-1 -> x"
# 6.2.3. Parenthesized forms
def test_parenthesized_form():
x = (SOURCE)
SINK(x)
SINK(x) #$ flow="SOURCE, l:-1 -> x"
# 6.2.5. List displays
def test_list_display():
x = [SOURCE]
SINK(x[0])
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
def test_list_display_negative():
@@ -101,109 +101,120 @@ def test_list_display_negative():
def test_list_comprehension():
x = [SOURCE for y in [NONSOURCE]]
SINK(x[0])
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
def test_list_comprehension_flow():
x = [y for y in [SOURCE]]
SINK(x[0])
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
def test_list_comprehension_inflow():
l = [SOURCE]
x = [y for y in l]
SINK(x[0])
SINK(x[0]) #$ flow="SOURCE, l:-2 -> x[0]"
def test_nested_list_display():
x = [*[SOURCE]]
SINK(x[0]) # Flow missing
SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]"
# 6.2.6. Set displays
def test_set_display():
x = {SOURCE}
SINK(x.pop())
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension():
x = {SOURCE for y in [NONSOURCE]}
SINK(x.pop())
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension_flow():
x = {y for y in [SOURCE]}
SINK(x.pop())
SINK(x.pop()) #$ flow="SOURCE, l:-1 -> x.pop()"
def test_set_comprehension_inflow():
l = {SOURCE}
x = {y for y in l}
SINK(x.pop())
SINK(x.pop()) #$ flow="SOURCE, l:-2 -> x.pop()"
def test_nested_set_display():
x = {*{SOURCE}}
SINK(x.pop()) # Flow missing
SINK(x.pop()) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
# 6.2.7. Dictionary displays
def test_dict_display():
x = {"s": SOURCE}
SINK(x["s"])
SINK(x["s"]) #$ flow="SOURCE, l:-1 -> x['s']"
def test_dict_display_pop():
x = {"s": SOURCE}
SINK(x.pop("s"))
SINK(x.pop("s")) #$ flow="SOURCE, l:-1 -> x.pop(..)"
def test_dict_comprehension():
x = {y: SOURCE for y in ["s"]}
SINK(x["s"]) # Flow missing
SINK(x["s"]) #$ MISSING:flow="SOURCE, l:-1 -> x['s']"
def test_dict_comprehension_pop():
x = {y: SOURCE for y in ["s"]}
SINK(x.pop("s")) # Flow missing
SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
def test_nested_dict_display():
x = {**{"s": SOURCE}}
SINK(x["s"]) # Flow missing
SINK(x["s"]) #$ MISSING:flow="SOURCE, l:-1 -> x['s']"
def test_nested_dict_display_pop():
x = {**{"s": SOURCE}}
SINK(x.pop("s")) # Flow missing
SINK(x.pop("s")) #$ MISSING:flow="SOURCE, l:-1 -> x.pop()"
# Nested comprehensions
def test_nested_comprehension():
x = [y for z in [[SOURCE]] for y in z]
SINK(x[0])
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
def test_nested_comprehension_deep_with_local_flow():
x = [y for v in [[[[SOURCE]]]] for u in v for z in u for y in z]
SINK(x[0])
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
def test_nested_comprehension_dict():
d = {"s": [SOURCE]}
x = [y for k, v in d.items() for y in v]
SINK(x[0]) # Flow missing
SINK(x[0]) #$ MISSING:flow="SOURCE, l:-1 -> x[0]"
def test_nested_comprehension_paren():
x = [y for y in (z for z in [SOURCE])]
SINK(x[0])
SINK(x[0]) #$ flow="SOURCE, l:-1 -> x[0]"
# Iterable unpacking in comprehensions
def test_unpacking_comprehension():
x = [a for (a, b) in [(SOURCE, NONSOURCE)]]
SINK(x[0]) # Flow missing
def test_star_unpacking_comprehension():
x = [a[0] for (*a, b) in [(SOURCE, NONSOURCE)]]
SINK(x[0]) # Flow missing
# 6.2.8. Generator expressions
def test_generator():
x = (SOURCE for y in [NONSOURCE])
SINK([*x][0]) # Flow missing
SINK([*x][0]) #$ MISSING:flow="SOURCE, l:-1 -> List[0]"
# 6.2.9. Yield expressions
@@ -213,7 +224,7 @@ def gen(x):
def test_yield():
g = gen(SOURCE)
SINK(next(g)) # Flow missing
SINK(next(g)) #$ MISSING:flow="SOURCE, l:-1 -> next()"
def gen_from(x):
@@ -222,19 +233,19 @@ def gen_from(x):
def test_yield_from():
g = gen_from(SOURCE)
SINK(next(g)) # Flow missing
SINK(next(g)) #$ MISSING:flow="SOURCE, l:-1 -> next()"
# a statement rather than an expression, but related to generators
def test_for():
for x in gen(SOURCE):
SINK(x) # Flow missing
SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x"
# 6.2.9.1. Generator-iterator methods
def test___next__():
g = gen(SOURCE)
SINK(g.__next__()) # Flow missing
SINK(g.__next__()) #$ MISSING:flow="SOURCE, l:-1 -> g.__next__()"
def gen2(x):
@@ -246,7 +257,7 @@ def gen2(x):
def test_send():
g = gen2(NONSOURCE)
n = next(g)
SINK(g.send(SOURCE)) # Flow missing
SINK(g.send(SOURCE)) #$ MISSING:flow="SOURCE -> g.send()"
def gen_ex(x):
@@ -259,7 +270,7 @@ def gen_ex(x):
def test_throw():
g = gen_ex(SOURCE)
n = next(g)
SINK(g.throw(TypeError)) # Flow missing
SINK(g.throw(TypeError)) #$ MISSING:flow="SOURCE, l:-2 -> g.throw()"
# no `test_close` as `close` involves no data flow
@@ -280,7 +291,7 @@ def runa(a):
async def atest___anext__():
g = agen(SOURCE)
SINK(await g.__anext__()) # Flow missing
SINK(await g.__anext__()) #$ MISSING:flow="SOURCE, l:-1 -> g.__anext__()"
def test___anext__():
@@ -296,7 +307,7 @@ async def agen2(x):
async def atest_asend():
g = agen2(NONSOURCE)
n = await g.__anext__()
SINK(await g.asend(SOURCE)) # Flow missing
SINK(await g.asend(SOURCE)) #$ MISSING:flow="SOURCE -> g.asend()"
def test_asend():
@@ -313,7 +324,7 @@ async def agen_ex(x):
async def atest_athrow():
g = agen_ex(SOURCE)
n = await g.__anext__()
SINK(await g.athrow(TypeError)) # Flow missing
SINK(await g.athrow(TypeError)) #$ MISSING:flow="SOURCE, l:-2 -> g.athrow()"
def test_athrow():
@@ -325,23 +336,25 @@ class C:
a = SOURCE
@expects(2)
def test_attribute_reference():
SINK(C.a) # Flow missing
SINK(C.a) #$ MISSING:flow="SOURCE, l:-4 -> C.a"
c = C()
SINK(c.a) #$ MISSING:flow="SOURCE, l:-6 -> c.a"
# overriding __getattr__ should be tested by the class coverage tests
# 6.3.2. Subscriptions
def test_subscription_tuple():
SINK((SOURCE,)[0])
SINK((SOURCE,)[0]) #$ flow="SOURCE -> Tuple[0]"
def test_subscription_list():
SINK([SOURCE][0])
SINK([SOURCE][0]) #$ flow="SOURCE -> List[0]"
def test_subscription_mapping():
SINK({"s": SOURCE}["s"])
SINK({"s": SOURCE}["s"]) #$ flow="SOURCE -> Dict['s']"
# overriding __getitem__ should be tested by the class coverage tests
@@ -353,7 +366,7 @@ l = [SOURCE]
def test_slicing():
s = l[0:1:1]
SINK(s[0]) # Flow missing
SINK(s[0]) #$ MISSING:flow="SOURCE -> s[0]"
# The grammar seems to allow `l[0:1:1, 0:1]`, but the interpreter does not like it
@@ -364,7 +377,7 @@ def second(a, b):
def test_call_positional():
SINK(second(NONSOURCE, SOURCE))
SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)"
def test_call_positional_negative():
@@ -372,15 +385,15 @@ def test_call_positional_negative():
def test_call_keyword():
SINK(second(NONSOURCE, b=SOURCE))
SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)"
def test_call_unpack_iterable():
SINK(second(NONSOURCE, *[SOURCE])) # Flow missing
SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)"
def test_call_unpack_mapping():
SINK(second(NONSOURCE, **{"b": SOURCE}))
SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)"
def f_extra_pos(a, *b):
@@ -388,7 +401,7 @@ def f_extra_pos(a, *b):
def test_call_extra_pos():
SINK(f_extra_pos(NONSOURCE, SOURCE))
SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)"
def f_extra_keyword(a, **b):
@@ -396,7 +409,7 @@ def f_extra_keyword(a, **b):
def test_call_extra_keyword():
SINK(f_extra_keyword(NONSOURCE, b=SOURCE))
SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)"
# return the name of the first extra keyword argument
@@ -406,18 +419,18 @@ def f_extra_keyword_flow(**a):
# call the function with our source as the name of the keyword arguemnt
def test_call_extra_keyword_flow():
SINK(f_extra_keyword_flow(**{SOURCE: None})) # Flow missing
SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)"
# 6.12. Assignment expressions
def test_assignment_expression():
x = NONSOURCE
SINK(x := SOURCE) # Flow missing
SINK(x := SOURCE) #$ MISSING:flow="SOURCE -> x"
# 6.13. Conditional expressions
def test_conditional_true():
SINK(SOURCE if True else NONSOURCE)
SINK(SOURCE if True else NONSOURCE) #$ flow="SOURCE -> IfExp"
def test_conditional_true_guards():
@@ -425,7 +438,7 @@ def test_conditional_true_guards():
def test_conditional_false():
SINK(NONSOURCE if False else SOURCE)
SINK(NONSOURCE if False else SOURCE) #$ flow="SOURCE -> IfExp"
def test_conditional_false_guards():
@@ -435,13 +448,13 @@ def test_conditional_false_guards():
# Condition is evaluated first, so x is SOURCE once chosen
def test_conditional_evaluation_true():
x = NONSOURCE
SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) # Flow missing
SINK(x if (SOURCE == (x := SOURCE)) else NONSOURCE) #$ MISSING:flow="SOURCE -> IfExp"
# Condition is evaluated first, so x is SOURCE once chosen
def test_conditional_evaluation_false():
x = NONSOURCE
SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) # Flow missing
SINK(NONSOURCE if (NONSOURCE == (x := SOURCE)) else x) #$ MISSING:flow="SOURCE -> IfExp"
# 6.14. Lambdas
@@ -449,14 +462,14 @@ def test_lambda():
def f(x):
return x
SINK(f(SOURCE))
SINK(f(SOURCE)) #$ flow="SOURCE -> f(..)"
def test_lambda_positional():
def second(a, b):
return b
SINK(second(NONSOURCE, SOURCE))
SINK(second(NONSOURCE, SOURCE)) #$ flow="SOURCE -> second(..)"
def test_lambda_positional_negative():
@@ -470,50 +483,188 @@ def test_lambda_keyword():
def second(a, b):
return b
SINK(second(NONSOURCE, b=SOURCE))
SINK(second(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> second(..)"
def test_lambda_unpack_iterable():
def second(a, b):
return b
SINK(second(NONSOURCE, *[SOURCE])) # Flow missing
SINK(second(NONSOURCE, *[SOURCE])) #$ MISSING:flow="SOURCE -> second(..)" # Flow missing
def test_lambda_unpack_mapping():
def second(a, b):
return b
SINK(second(NONSOURCE, **{"b": SOURCE}))
SINK(second(NONSOURCE, **{"b": SOURCE})) #$ flow="SOURCE -> second(..)"
def test_lambda_extra_pos():
f_extra_pos = lambda a, *b: b[0]
SINK(f_extra_pos(NONSOURCE, SOURCE))
SINK(f_extra_pos(NONSOURCE, SOURCE)) #$ flow="SOURCE -> f_extra_pos(..)"
def test_lambda_extra_keyword():
f_extra_keyword = lambda a, **b: b["b"]
SINK(f_extra_keyword(NONSOURCE, b=SOURCE))
SINK(f_extra_keyword(NONSOURCE, b=SOURCE)) #$ flow="SOURCE -> f_extra_keyword(..)"
# call the function with our source as the name of the keyword argument
def test_lambda_extra_keyword_flow():
# return the name of the first extra keyword argument
f_extra_keyword_flow = lambda **a: [*a][0]
SINK(f_extra_keyword_flow(**{SOURCE: None})) # Flow missing
SINK(f_extra_keyword_flow(**{SOURCE: None})) #$ MISSING:flow="SOURCE -> f_extra_keyword(..)"
@expects(4)
def test_swap():
a = SOURCE
b = NONSOURCE
SINK(a)
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK_F(b)
a, b = b, a
SINK_F(a)
SINK(b)
SINK(b) #$ flow="SOURCE, l:-7 -> b"
@expects(2)
def test_unpacking_assignment():
t = (SOURCE, NONSOURCE)
a, b = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK_F(b)
@expects(3)
def test_nested_unpacking_assignment():
t = (SOURCE, (NONSOURCE, SOURCE))
a, (b, c) = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK_F(b)
SINK(c) #$ flow="SOURCE, l:-4 -> c"
@expects(2)
def test_deeply_nested_unpacking_assignment():
t = [[[[SOURCE]]], NONSOURCE]
[[[a]]], b = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK_F(b)
@expects(4)
def test_iterated_unpacking_assignment():
t = (SOURCE, SOURCE, NONSOURCE)
a, *b, c = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK_F(b)
SINK(b[0]) #$ flow="SOURCE, l:-4 -> b[0]"
SINK_F(c) #$ SPURIOUS: flow="SOURCE, l:-5 -> c" # We do not track tuple sizes
@expects(3)
def test_iterated_unpacking_assignment_shrink():
t = (SOURCE, SOURCE)
a, *b, c = t
SINK(a) #$ flow="SOURCE, l:-2 -> a"
SINK_F(b)
SINK(c) #$ flow="SOURCE, l:-4 -> c"
@expects(15)
def test_unpacking_assignment_conversion():
ll = [[SOURCE, NONSOURCE, SOURCE], [SOURCE], [NONSOURCE]]
# tuple
((a1, a2, a3), b, c) = ll
SINK(a1) #$ flow="SOURCE, l:-4 -> a1"
SINK_F(a2) #$ SPURIOUS: flow="SOURCE, l:-5 -> a2" # We expect an FP as all elements are tainted
SINK(a3) #$ flow="SOURCE, l:-6 -> a3"
SINK_F(b) # The list itself is not tainted
SINK_F(c)
# mixed
[(a1, a2, a3), b, c] = ll
SINK(a1) #$ flow="SOURCE, l:-12 -> a1"
SINK_F(a2) #$ SPURIOUS: flow="SOURCE, l:-13 -> a2" # We expect an FP as all elements are tainted
SINK(a3) #$ flow="SOURCE, l:-14 -> a3"
SINK_F(b) # The list itself is not tainted
SINK_F(c)
# mixed differently
([a1, a2, a3], b, c) = ll
SINK(a1) #$ flow="SOURCE, l:-20 -> a1"
SINK_F(a2) #$ SPURIOUS: flow="SOURCE, l:-21 -> a2" # We expect an FP as all elements are tainted
SINK(a3) #$ flow="SOURCE, l:-22 -> a3"
SINK_F(b) # The list itself is not tainted
SINK_F(c)
@expects(24)
def test_iterated_unpacking_assignment_conversion():
tt = ((SOURCE, NONSOURCE, SOURCE),NONSOURCE)
# list
[[a1, *a2], *b] = tt
SINK(a1) #$ flow="SOURCE, l:-4 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-6 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-7 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
# tuple
((a1, *a2), *b) = tt
SINK(a1) #$ flow="SOURCE, l:-13 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-15 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-16 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
# mixed
[(a1, *a2), *b] = tt
SINK(a1) #$ flow="SOURCE, l:-22 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-24 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-25 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
# mixed differently
([a1, *a2], *b) = tt
SINK(a1) #$ flow="SOURCE, l:-31 -> a1"
SINK_F(a2) # The list itself is not tainted
SINK_F(a2[0]) #$ SPURIOUS: flow="SOURCE, l:-33 -> a2[0]" # FP here due to list abstraction
SINK(a2[1]) #$ flow="SOURCE, l:-34 -> a2[1]"
SINK_F(b) # The list itself is not tainted
SINK_F(b[0])
@expects(3)
def test_iterable_repacking():
a, *(b, c) = (SOURCE, NONSOURCE, SOURCE)
SINK(a) #$ flow="SOURCE, l:-1 -> a"
SINK_F(b)
SINK(c) #$ MISSING: flow="SOURCE, l:-3 -> c"
@expects(4)
def test_iterable_unpacking_in_for():
tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)]
for x,y in tl:
SINK(x) #$ MISSING: flow="SOURCE, l:-2 -> x"
SINK_F(y)
@expects(6)
def test_iterable_star_unpacking_in_for():
tl = [(SOURCE, NONSOURCE), (SOURCE, NONSOURCE)]
for *x,y in tl:
SINK_F(x)
SINK(x[0]) #$ MISSING: flow="SOURCE, l:-3 -> x[0]"
SINK_F(y)
def test_deep_callgraph():
@@ -538,7 +689,7 @@ def test_deep_callgraph():
return f5(arg)
x = f6(SOURCE)
SINK(x) # Flow missing
SINK(x) #$ MISSING:flow="SOURCE, l:-1 -> x"
@expects(2)
@@ -547,7 +698,7 @@ def test_dynamic_tuple_creation_1():
tup += (SOURCE,)
tup += (NONSOURCE,)
SINK(tup[0]) # Flow missing
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK_F(tup[1])
@@ -557,7 +708,7 @@ def test_dynamic_tuple_creation_2():
tup += (SOURCE,)
tup += (NONSOURCE,)
SINK(tup[0]) # Flow missing
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK_F(tup[1])
@@ -567,7 +718,7 @@ def test_dynamic_tuple_creation_3():
tup2 = (NONSOURCE,)
tup = tup1 + tup2
SINK(tup[0]) # Flow missing
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-4 -> tup[0]"
SINK_F(tup[1])
@@ -578,7 +729,7 @@ def test_dynamic_tuple_creation_4():
for item in [SOURCE, NONSOURCE]:
tup += (item,)
SINK(tup[0]) # Flow missing
SINK(tup[0]) #$ MISSING:flow="SOURCE, l:-3 -> tup[0]"
SINK_F(tup[1])
def return_from_inner_scope(x):
@@ -588,4 +739,36 @@ def return_from_inner_scope(x):
return SOURCE
def test_return_from_inner_scope():
SINK(return_from_inner_scope([]))
SINK(return_from_inner_scope([])) #$ flow="SOURCE, l:-3 -> return_from_inner_scope(..)"
# Inspired by reverse read inconsistency check
def insertAtA(d):
d["a"] = SOURCE
def test_reverse_read_subscript():
d = {"a": NONSOURCE}
l = [d]
insertAtA(l[0])
SINK(d["a"]) #$ MISSING:flow="SOURCE, l-6 -> d['a']""
def test_reverse_read_dict_arg():
d = {"a": NONSOURCE}
dd = {"d": d}
insertAtA(**dd)
SINK(d["a"]) #$ MISSING:flow="SOURCE, l-12 -> d['a']""
class WithA:
def setA(self, v):
self.a = v
def __init__(self):
self.a = ""
def test_reverse_read_subscript_cls():
withA = WithA()
l = [withA]
l[0].setA(SOURCE)
SINK(withA.a) #$ MISSING:flow="SOURCE, l:-1 -> self.a"

View File

@@ -1,34 +1,17 @@
edges
| examples.py:27:8:27:12 | [post arg] ControlFlowNode for myobj [Attribute foo] | examples.py:28:6:28:10 | ControlFlowNode for myobj [Attribute foo] |
| examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:27:8:27:12 | [post arg] ControlFlowNode for myobj [Attribute foo] |
| examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:35:13:35:13 | ControlFlowNode for x |
| examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:49:13:49:18 | ControlFlowNode for SOURCE |
| examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE |
| examples.py:28:6:28:10 | ControlFlowNode for myobj [Attribute foo] | examples.py:28:6:28:14 | ControlFlowNode for Attribute |
| examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:35:13:35:13 | ControlFlowNode for x |
| examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:49:13:49:18 | ControlFlowNode for SOURCE |
| examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE |
| examples.py:35:1:35:1 | [post read] ControlFlowNode for a [Attribute obj, Attribute foo] | examples.py:37:6:37:6 | ControlFlowNode for a [Attribute obj, Attribute foo] |
| examples.py:35:1:35:5 | [post store] ControlFlowNode for Attribute [Attribute foo] | examples.py:35:1:35:1 | [post read] ControlFlowNode for a [Attribute obj, Attribute foo] |
| examples.py:35:13:35:13 | ControlFlowNode for x | examples.py:35:1:35:5 | [post store] ControlFlowNode for Attribute [Attribute foo] |
| examples.py:37:6:37:6 | ControlFlowNode for a [Attribute obj, Attribute foo] | examples.py:37:6:37:10 | ControlFlowNode for Attribute [Attribute foo] |
| examples.py:37:6:37:10 | ControlFlowNode for Attribute [Attribute foo] | examples.py:37:6:37:14 | ControlFlowNode for Attribute |
| examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:49:13:49:18 | ControlFlowNode for SOURCE |
| examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE |
| examples.py:49:7:49:19 | ControlFlowNode for MyObj() [Attribute foo] | examples.py:50:6:50:8 | ControlFlowNode for obj [Attribute foo] |
| examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:49:7:49:19 | ControlFlowNode for MyObj() [Attribute foo] |
| examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:59:29:59:34 | ControlFlowNode for SOURCE |
| examples.py:50:6:50:8 | ControlFlowNode for obj [Attribute foo] | examples.py:50:6:50:12 | ControlFlowNode for Attribute |
| examples.py:59:29:59:34 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:49:19:49:24 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:56:18:56:23 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:61:9:61:14 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:71:9:71:14 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:81:17:81:22 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:86:21:86:26 | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | test.py:97:33:97:38 | ControlFlowNode for SOURCE |
| test.py:3:1:3:6 | GSSA Variable SOURCE | test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test |
| test.py:3:10:3:17 | ControlFlowNode for Str | test.py:3:1:3:6 | GSSA Variable SOURCE |
| test.py:49:12:49:16 | [post arg] ControlFlowNode for myobj [Attribute foo] | test.py:50:10:50:14 | ControlFlowNode for myobj [Attribute foo] |
| test.py:49:19:49:24 | ControlFlowNode for SOURCE | test.py:49:12:49:16 | [post arg] ControlFlowNode for myobj [Attribute foo] |
| test.py:50:10:50:14 | ControlFlowNode for myobj [Attribute foo] | test.py:50:10:50:18 | ControlFlowNode for Attribute |
@@ -66,16 +49,12 @@ nodes
| examples.py:37:6:37:6 | ControlFlowNode for a [Attribute obj, Attribute foo] | semmle.label | ControlFlowNode for a [Attribute obj, Attribute foo] |
| examples.py:37:6:37:10 | ControlFlowNode for Attribute [Attribute foo] | semmle.label | ControlFlowNode for Attribute [Attribute foo] |
| examples.py:37:6:37:14 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| examples.py:40:5:40:10 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| examples.py:49:7:49:19 | ControlFlowNode for MyObj() [Attribute foo] | semmle.label | ControlFlowNode for MyObj() [Attribute foo] |
| examples.py:49:13:49:18 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| examples.py:50:6:50:8 | ControlFlowNode for obj [Attribute foo] | semmle.label | ControlFlowNode for obj [Attribute foo] |
| examples.py:50:6:50:12 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | semmle.label | ControlFlowNode for fields_with_local_flow() |
| examples.py:59:29:59:34 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:0:0:0:0 | ModuleVariableNode for Global Variable SOURCE in Module test | semmle.label | ModuleVariableNode for Global Variable SOURCE in Module test |
| test.py:3:1:3:6 | GSSA Variable SOURCE | semmle.label | GSSA Variable SOURCE |
| test.py:3:10:3:17 | ControlFlowNode for Str | semmle.label | ControlFlowNode for Str |
| test.py:49:12:49:16 | [post arg] ControlFlowNode for myobj [Attribute foo] | semmle.label | [post arg] ControlFlowNode for myobj [Attribute foo] |
| test.py:49:19:49:24 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
| test.py:50:10:50:14 | ControlFlowNode for myobj [Attribute foo] | semmle.label | ControlFlowNode for myobj [Attribute foo] |
@@ -110,28 +89,13 @@ nodes
| test.py:97:33:97:38 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
#select
| examples.py:28:6:28:14 | ControlFlowNode for Attribute | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:28:6:28:14 | ControlFlowNode for Attribute | Flow found |
| examples.py:37:6:37:14 | ControlFlowNode for Attribute | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:37:6:37:14 | ControlFlowNode for Attribute | Flow found |
| examples.py:37:6:37:14 | ControlFlowNode for Attribute | examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:37:6:37:14 | ControlFlowNode for Attribute | Flow found |
| examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found |
| examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found |
| examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found |
| examples.py:50:6:50:12 | ControlFlowNode for Attribute | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:50:6:50:12 | ControlFlowNode for Attribute | Flow found |
| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:27:15:27:20 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found |
| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:31:5:31:10 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found |
| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:40:5:40:10 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found |
| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:49:13:49:18 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found |
| examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | examples.py:59:29:59:34 | ControlFlowNode for SOURCE | examples.py:59:6:59:35 | ControlFlowNode for fields_with_local_flow() | Flow found |
| test.py:50:10:50:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:50:10:50:18 | ControlFlowNode for Attribute | Flow found |
| test.py:50:10:50:18 | ControlFlowNode for Attribute | test.py:49:19:49:24 | ControlFlowNode for SOURCE | test.py:50:10:50:18 | ControlFlowNode for Attribute | Flow found |
| test.py:57:10:57:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:57:10:57:18 | ControlFlowNode for Attribute | Flow found |
| test.py:57:10:57:18 | ControlFlowNode for Attribute | test.py:56:18:56:23 | ControlFlowNode for SOURCE | test.py:57:10:57:18 | ControlFlowNode for Attribute | Flow found |
| test.py:67:10:67:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:67:10:67:18 | ControlFlowNode for Attribute | Flow found |
| test.py:67:10:67:18 | ControlFlowNode for Attribute | test.py:61:9:61:14 | ControlFlowNode for SOURCE | test.py:67:10:67:18 | ControlFlowNode for Attribute | Flow found |
| test.py:77:10:77:18 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:77:10:77:18 | ControlFlowNode for Attribute | Flow found |
| test.py:77:10:77:18 | ControlFlowNode for Attribute | test.py:71:9:71:14 | ControlFlowNode for SOURCE | test.py:77:10:77:18 | ControlFlowNode for Attribute | Flow found |
| test.py:82:10:82:16 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:82:10:82:16 | ControlFlowNode for Attribute | Flow found |
| test.py:82:10:82:16 | ControlFlowNode for Attribute | test.py:81:17:81:22 | ControlFlowNode for SOURCE | test.py:82:10:82:16 | ControlFlowNode for Attribute | Flow found |
| test.py:87:10:87:16 | ControlFlowNode for Attribute | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:87:10:87:16 | ControlFlowNode for Attribute | Flow found |
| test.py:87:10:87:16 | ControlFlowNode for Attribute | test.py:86:21:86:26 | ControlFlowNode for SOURCE | test.py:87:10:87:16 | ControlFlowNode for Attribute | Flow found |
| test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | test.py:3:10:3:17 | ControlFlowNode for Str | test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | Flow found |
| test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | test.py:97:33:97:38 | ControlFlowNode for SOURCE | test.py:97:10:97:39 | ControlFlowNode for fields_with_local_flow() | Flow found |

View File

@@ -4,9 +4,7 @@
| test2.py:1:19:1:21 | ControlFlowNode for ImportMember | mypkg.foo |
| test2.py:1:24:1:26 | ControlFlowNode for ImportMember | mypkg.bar |
| test3.py:1:8:1:16 | ControlFlowNode for ImportExpr | mypkg |
| test3.py:1:8:1:16 | ControlFlowNode for ImportExpr | mypkg.foo |
| test3.py:2:8:2:16 | ControlFlowNode for ImportExpr | mypkg |
| test3.py:2:8:2:16 | ControlFlowNode for ImportExpr | mypkg.bar |
| test4.py:1:8:1:16 | ControlFlowNode for ImportExpr | mypkg.foo |
| test4.py:2:8:2:16 | ControlFlowNode for ImportExpr | mypkg.bar |
| test5.py:1:8:1:12 | ControlFlowNode for ImportExpr | mypkg |
@@ -14,10 +12,12 @@
| test5.py:9:19:9:29 | ControlFlowNode for ImportMember | mypkg.bar |
| test6.py:1:8:1:12 | ControlFlowNode for ImportExpr | mypkg |
| test6.py:5:8:5:16 | ControlFlowNode for ImportExpr | mypkg |
| test6.py:5:8:5:16 | ControlFlowNode for ImportExpr | mypkg.foo |
| test7.py:1:6:1:10 | ControlFlowNode for ImportExpr | mypkg |
| test7.py:1:19:1:21 | ControlFlowNode for ImportMember | mypkg.foo |
| test7.py:5:8:5:16 | ControlFlowNode for ImportExpr | mypkg |
| test7.py:5:8:5:16 | ControlFlowNode for ImportExpr | mypkg.foo |
| test7.py:9:6:9:10 | ControlFlowNode for ImportExpr | mypkg |
| test7.py:9:19:9:21 | ControlFlowNode for ImportMember | mypkg.foo |
| test_deep.py:1:6:1:21 | ControlFlowNode for ImportExpr | start.middle.end |
| test_deep.py:1:6:1:21 | ControlFlowNode for ImportExpr | start.middle.end |
| test_deep.py:1:30:1:32 | ControlFlowNode for ImportMember | start.middle.end.foo |
| test_deep.py:1:35:1:37 | ControlFlowNode for ImportMember | start.middle.end.bar |

View File

@@ -0,0 +1,3 @@
from start.middle.end import foo, bar
print(foo)
print(bar)

View File

@@ -1,6 +1,7 @@
import python
import semmle.python.dataflow.new.TaintTracking
import semmle.python.dataflow.new.DataFlow
import experimental.dataflow.TestUtil.PrintNode
class TestTaintTrackingConfiguration extends TaintTracking::Configuration {
TestTaintTrackingConfiguration() { this = "TestTaintTrackingConfiguration" }
@@ -19,31 +20,6 @@ class TestTaintTrackingConfiguration extends TaintTracking::Configuration {
}
}
private string repr(Expr e) {
not e instanceof Num and
not e instanceof StrConst and
not e instanceof Subscript and
not e instanceof Call and
not e instanceof Attribute and
result = e.toString()
or
result = e.(Num).getN()
or
result =
e.(StrConst).getPrefix() + e.(StrConst).getText() +
e.(StrConst).getPrefix().regexpReplaceAll("[a-zA-Z]+", "")
or
result = repr(e.(Subscript).getObject()) + "[" + repr(e.(Subscript).getIndex()) + "]"
or
(
if exists(e.(Call).getAnArg()) or exists(e.(Call).getANamedArg())
then result = repr(e.(Call).getFunc()) + "(..)"
else result = repr(e.(Call).getFunc()) + "()"
)
or
result = repr(e.(Attribute).getObject()) + "." + e.(Attribute).getName()
}
query predicate test_taint(string arg_location, string test_res, string scope_name, string repr) {
exists(Call call, Expr arg, boolean expected_taint, boolean has_taint |
// only consider files that are extracted as part of the test
@@ -70,6 +46,6 @@ query predicate test_taint(string arg_location, string test_res, string scope_na
arg_location = arg.getLocation().toString() and
test_res = test_res and
scope_name = call.getScope().getName() and
repr = repr(arg)
repr = prettyExp(arg)
)
}

View File

@@ -44,5 +44,7 @@ class TestConfiguration extends DataFlow::Configuration {
)
}
override int explorationLimit() { result = 4 }
override predicate isBarrierIn(DataFlow::Node node) { this.isSource(node) }
override int explorationLimit() { result = 5 }
}

View File

@@ -69,3 +69,54 @@ def redefine_test():
expects_int(x) # $int
x = str("Hello") # $str
expects_string(x) # $str
# ------------------------------------------------------------------------------
# Tracking of self in methods
# ------------------------------------------------------------------------------
class Foo(object):
def meth1(self):
do_stuff(self)
def meth2(self): # $ MISSING: tracked_self
do_stuff(self) # $ MISSING: tracked_self
def meth3(self): # $ MISSING: tracked_self
do_stuff(self) # $ MISSING: tracked_self
class Bar(Foo):
def meth1(self): # $ tracked_self
do_stuff(self) # $ tracked_self
def meth2(self):
do_stuff(self)
def meth3(self):
do_stuff(self)
def track_self(self): # $ tracked_self
self.meth1() # $ tracked_self
super().meth2()
super(Bar, self).foo3() # $ tracked_self
# ------------------------------------------------------------------------------
# Tracking of attribute lookup after "long" import chain
# ------------------------------------------------------------------------------
def test_long_import_chain():
import foo.bar
foo.baz
x = foo.bar.baz # $ tracked_foo_bar_baz
do_stuff(x) # $ tracked_foo_bar_baz
class Example(foo.bar.baz): # $ tracked_foo_bar_baz
pass
def test_long_import_chain_full_path():
from foo.bar import baz # $ tracked_foo_bar_baz
x = baz # $ tracked_foo_bar_baz
do_stuff(x) # $ tracked_foo_bar_baz

View File

@@ -3,6 +3,9 @@ import semmle.python.dataflow.new.DataFlow
import semmle.python.dataflow.new.TypeTracker
import TestUtilities.InlineExpectationsTest
// -----------------------------------------------------------------------------
// tracked
// -----------------------------------------------------------------------------
DataFlow::Node tracked(TypeTracker t) {
t.start() and
result.asCfgNode() = any(NameNode n | n.getId() = "tracked")
@@ -28,6 +31,9 @@ class TrackedTest extends InlineExpectationsTest {
}
}
// -----------------------------------------------------------------------------
// int + str
// -----------------------------------------------------------------------------
DataFlow::Node int_type(TypeTracker t) {
t.start() and
result.asCfgNode() = any(CallNode c | c.getFunction().(NameNode).getId() = "int")
@@ -73,3 +79,96 @@ class TrackedStringTest extends InlineExpectationsTest {
)
}
}
// -----------------------------------------------------------------------------
// tracked_self
// -----------------------------------------------------------------------------
DataFlow::Node tracked_self(TypeTracker t) {
t.start() and
exists(Function f |
f.isMethod() and
f.getName() = "track_self" and
result.(DataFlow::ParameterNode).getParameter() = f.getArg(0)
)
or
exists(TypeTracker t2 | result = tracked_self(t2).track(t2, t))
}
class TrackedSelfTest extends InlineExpectationsTest {
TrackedSelfTest() { this = "TrackedSelfTest" }
override string getARelevantTag() { result = "tracked_self" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node e, TypeTracker t |
e = tracked_self(t) and
// Module variables have no sensible location, and hence can't be annotated.
not e instanceof DataFlow::ModuleVariableNode and
tag = "tracked_self" and
location = e.getLocation() and
value = t.getAttr() and
element = e.toString()
)
}
}
// -----------------------------------------------------------------------------
// tracked_foo_bar_baz
// -----------------------------------------------------------------------------
// This modeling follows the same pattern that we currently use in our real library modeling.
/** Gets a reference to `foo` (fictive module). */
private DataFlow::Node foo(DataFlow::TypeTracker t) {
t.start() and
result = DataFlow::importNode("foo")
or
exists(DataFlow::TypeTracker t2 | result = foo(t2).track(t2, t))
}
/** Gets a reference to `foo` (fictive module). */
DataFlow::Node foo() { result = foo(DataFlow::TypeTracker::end()) }
/** Gets a reference to `foo.bar` (fictive module). */
private DataFlow::Node foo_bar(DataFlow::TypeTracker t) {
t.start() and
result = DataFlow::importNode("foo.bar")
or
t.startInAttr("bar") and
result = foo()
or
exists(DataFlow::TypeTracker t2 | result = foo_bar(t2).track(t2, t))
}
/** Gets a reference to `foo.bar` (fictive module). */
DataFlow::Node foo_bar() { result = foo_bar(DataFlow::TypeTracker::end()) }
/** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */
private DataFlow::Node foo_bar_baz(DataFlow::TypeTracker t) {
t.start() and
result = DataFlow::importNode("foo.bar.baz")
or
t.startInAttr("baz") and
result = foo_bar()
or
exists(DataFlow::TypeTracker t2 | result = foo_bar_baz(t2).track(t2, t))
}
/** Gets a reference to `foo.bar.baz` (fictive attribute on `foo.bar` module). */
DataFlow::Node foo_bar_baz() { result = foo_bar_baz(DataFlow::TypeTracker::end()) }
class TrackedFooBarBaz extends InlineExpectationsTest {
TrackedFooBarBaz() { this = "TrackedFooBarBaz" }
override string getARelevantTag() { result = "tracked_foo_bar_baz" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(DataFlow::Node e |
e = foo_bar_baz() and
// Module variables have no sensible location, and hence can't be annotated.
not e instanceof DataFlow::ModuleVariableNode and
tag = "tracked_foo_bar_baz" and
location = e.getLocation() and
value = "" and
element = e.toString()
)
}
}

View File

@@ -1,12 +1,12 @@
import python
import experimental.meta.ConceptsTest
//
// class DedicatedResponseTest extends HttpServerHttpResponseTest {
// DedicatedResponseTest() { file.getShortName() = "response_test.py" }
// }
//
// class OtherResponseTest extends HttpServerHttpResponseTest {
// OtherResponseTest() { not this instanceof DedicatedResponseTest }
//
// override string getARelevantTag() { result = "HttpResponse" }
// }
class DedicatedResponseTest extends HttpServerHttpResponseTest {
DedicatedResponseTest() { file.getShortName() = "response_test.py" }
}
class OtherResponseTest extends HttpServerHttpResponseTest {
OtherResponseTest() { not this instanceof DedicatedResponseTest }
override string getARelevantTag() { result = "HttpResponse" }
}

View File

@@ -3,21 +3,21 @@ import tornado.web
class BasicHandler(tornado.web.RequestHandler):
def get(self): # $ requestHandler
self.write("BasicHandler " + self.get_argument("xss"))
self.write("BasicHandler " + self.get_argument("xss")) # $ HttpResponse
def post(self): # $ requestHandler
self.write("BasicHandler (POST)")
self.write("BasicHandler (POST)") # $ HttpResponse
class DeepInheritance(BasicHandler):
def get(self): # $ requestHandler
self.write("DeepInheritance" + self.get_argument("also_xss"))
self.write("DeepInheritance" + self.get_argument("also_xss")) # $ HttpResponse
class FormHandler(tornado.web.RequestHandler):
def post(self): # $ requestHandler
name = self.get_body_argument("name")
self.write(name)
self.write(name) # $ HttpResponse
class RedirectHandler(tornado.web.RequestHandler):
@@ -30,7 +30,7 @@ class RedirectHandler(tornado.web.RequestHandler):
class BaseReverseInheritance(tornado.web.RequestHandler):
def get(self): # $ requestHandler
self.write("hello from BaseReverseInheritance")
self.write("hello from BaseReverseInheritance") # $ HttpResponse
class ReverseInheritance(BaseReverseInheritance):

View File

@@ -0,0 +1,85 @@
import tornado.web
import tornado.httputil
class ResponseWriting(tornado.web.RequestHandler):
def get(self, type_): # $ requestHandler routedParameter=type_
if type_ == "str":
self.write("foo") # $ HttpResponse mimetype=text/html responseBody="foo"
elif type_ == "bytes":
self.write(b"foo") # $ HttpResponse mimetype=text/html responseBody=b"foo"
elif type_ == "dict":
d = {"foo": 42}
# Content-type will be set to `application/json`
self.write(d) # $ HttpResponse responseBody=d MISSING: mimetype=application/json SPURIOUS: mimetype=text/html
else:
raise Exception("Bad type {} {}".format(type_, type(type_)))
class ExplicitContentType(tornado.web.RequestHandler):
def get(self): # $ requestHandler
# Note: Our current modeling makes it quite hard to give a good annotation here
# this write is technically while the HTTP response has mimetype text/html, but
# the returned HTTP response will have mimetype text/plain, which is _really_
# what matters.
self.write("foo") # $ HttpResponse mimetype=text/html responseBody="foo"
self.set_header("Content-Type", "text/plain; charset=utf-8")
def post(self): # $ requestHandler
self.set_header("Content-Type", "text/plain; charset=utf-8")
self.write("foo") # $ HttpResponse responseBody="foo" MISSING: mimetype=text/plain SPURIOUS: mimetype=text/html
class ExampleRedirect(tornado.web.RequestHandler):
def get(self): # $ requestHandler
self.redirect("http://example.com") # TODO: Model redirect
class ExampleConnectionWrite(tornado.web.RequestHandler):
def get(self, stream=False): # $ requestHandler routedParameter=stream
if not stream:
self.request.connection.write_headers(
tornado.httputil.ResponseStartLine('', 200, 'OK'),
tornado.httputil.HTTPHeaders(),
)
self.request.connection.write(b"foo") # $ MISSING: HttpResponse responseBody=b"foo"
self.request.connection.finish()
else:
# Note: The documentation says that connection.detach(): "May only be called
# during HTTPMessageDelegate.headers_received". Doing it here actually
# works, but does make tornado spit out some errors... good enough to
# illustrate the behavior.
#
# https://www.tornadoweb.org/en/stable/http1connection.html#tornado.http1connection.HTTP1Connection.detach
stream = self.request.connection.detach()
stream.write(b"foo stream") # $ MISSING: HttpResponse responseBody=b"foo stream"
stream.close()
def make_app():
return tornado.web.Application(
[
(r"/ResponseWriting/(str|bytes|dict)", ResponseWriting), # $ routeSetup="/ResponseWriting/(str|bytes|dict)"
(r"/ExplicitContentType", ExplicitContentType), # $ routeSetup="/ExplicitContentType"
(r"/ExampleRedirect", ExampleRedirect), # $ routeSetup="/ExampleRedirect"
(r"/ExampleConnectionWrite", ExampleConnectionWrite), # $ routeSetup="/ExampleConnectionWrite"
(r"/ExampleConnectionWrite/(stream)", ExampleConnectionWrite), # $ routeSetup="/ExampleConnectionWrite/(stream)"
],
debug=True,
)
if __name__ == "__main__":
import tornado.ioloop
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
# http://localhost:8888/ResponseWriting/str
# http://localhost:8888/ResponseWriting/bytes
# http://localhost:8888/ResponseWriting/dict
# http://localhost:8888/ExplicitContentType
# http://localhost:8888/ExampleRedirect
# http://localhost:8888/ExampleConnectionWrite

View File

@@ -1,35 +0,0 @@
import tornado.web
class ResponseWriting(tornado.web.RequestHandler):
def get(self, type_): # $ requestHandler routedParameter=type_
if type_ == "str":
self.write("foo")
elif type_ == "bytes":
self.write(b"foo")
elif type_ == "dict":
# Content-type will be set to `application/json`
self.write({"foo": 42})
else:
raise Exception("Bad type {} {}".format(type_, type(type_)))
def make_app():
return tornado.web.Application(
[
(r"/ResponseWriting/(str|bytes|dict)", ResponseWriting), # $ routeSetup="/ResponseWriting/(str|bytes|dict)"
],
debug=True,
)
if __name__ == "__main__":
import tornado.ioloop
app = make_app()
app.listen(8888)
tornado.ioloop.IOLoop.current().start()
# http://localhost:8888/ResponseWriting/str
# http://localhost:8888/ResponseWriting/bytes
# http://localhost:8888/ResponseWriting/dict

View File

@@ -4,47 +4,47 @@ import tornado.routing
class FooHandler(tornado.web.RequestHandler):
def get(self, x, y=None, not_used=None): # $ requestHandler routedParameter=x routedParameter=y
self.write("FooHandler {} {}".format(x, y))
self.write("FooHandler {} {}".format(x, y)) # $ HttpResponse
class BarHandler(tornado.web.RequestHandler):
def get(self, x, y=None, not_used=None): # $ requestHandler routedParameter=x routedParameter=y SPURIOUS: routedParameter=not_used
self.write("BarHandler {} {}".format(x, y))
self.write("BarHandler {} {}".format(x, y)) # $ HttpResponse
class BazHandler(tornado.web.RequestHandler):
def get(self, x, y=None, not_used=None): # $ requestHandler routedParameter=x routedParameter=y SPURIOUS: routedParameter=not_used
self.write("BazHandler {} {}".format(x, y))
self.write("BazHandler {} {}".format(x, y)) # $ HttpResponse
class KwArgs(tornado.web.RequestHandler):
def get(self, *, x, y=None, not_used=None): # $ requestHandler routedParameter=x routedParameter=y
self.write("KwArgs {} {}".format(x, y))
self.write("KwArgs {} {}".format(x, y)) # $ HttpResponse
class OnlyLocalhost(tornado.web.RequestHandler):
def get(self): # $ requestHandler
self.write("OnlyLocalhost")
self.write("OnlyLocalhost") # $ HttpResponse
class One(tornado.web.RequestHandler):
def get(self): # $ requestHandler
self.write("One")
self.write("One") # $ HttpResponse
class Two(tornado.web.RequestHandler):
def get(self): # $ requestHandler
self.write("Two")
self.write("Two") # $ HttpResponse
class Three(tornado.web.RequestHandler):
def get(self): # $ requestHandler
self.write("Three")
self.write("Three") # $ HttpResponse
class AddedLater(tornado.web.RequestHandler):
def get(self, x, y=None, not_used=None): # $ requestHandler routedParameter=x routedParameter=y
self.write("AddedLater {} {}".format(x, y))
self.write("AddedLater {} {}".format(x, y)) # $ HttpResponse
class PossiblyNotRouted(tornado.web.RequestHandler):
@@ -52,7 +52,7 @@ class PossiblyNotRouted(tornado.web.RequestHandler):
# consider it to be a handle incoming HTTP requests
def get(self): # $ requestHandler
self.write("NotRouted")
self.write("NotRouted") # $ HttpResponse
def make_app():

View File

@@ -2,3 +2,4 @@ name: codeql-python-tests
version: 0.0.0
libraryPathDependencies: codeql-python
extractor: python
tests: .