Skip to content

Commit d90b7e8

Browse files
committed
Python: Add scope entry definition nodes
otherwise we confuse captured variables in the single scope entry cfg node. Now we have one for each defined variable. TODO: Add test to demonstrate gain.
1 parent 1417c2c commit d90b7e8

File tree

5 files changed

+28
-6
lines changed

5 files changed

+28
-6
lines changed

Diff for: python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPrivate.qll

+4-1
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,10 @@ module LocalFlow {
361361
// nodeFrom is `y` on first line
362362
// nodeTo is `y` on second line
363363
exists(EssaDefinition def |
364-
nodeFrom.(CfgNode).getNode() = def.(EssaNodeDefinition).getDefiningNode() and
364+
nodeFrom.(CfgNode).getNode() = def.(EssaNodeDefinition).getDefiningNode()
365+
or
366+
nodeFrom.(ScopeEntryDefinitionNode).getDefinition() = def
367+
|
365368
AdjacentUses::firstUse(def, nodeTo.(CfgNode).getNode())
366369
)
367370
or

Diff for: python/ql/lib/semmle/python/dataflow/new/internal/DataFlowPublic.qll

+21-2
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,12 @@ newtype TNode =
2727
isExpressionNode(node)
2828
or
2929
node.getNode() instanceof Pattern
30-
or
31-
node = any(ScopeEntryDefinition def | not def.getScope() instanceof Module).getDefiningNode()
3230
} or
31+
/**
32+
* A node corresponding to a scope entry definition. That is, the value of a variable
33+
* as it enters a scope.
34+
*/
35+
TScopeEntryDefinitionNode(ScopeEntryDefinition def) { not def.getScope() instanceof Module } or
3336
/**
3437
* A synthetic node representing the value of an object before a state change.
3538
*
@@ -265,6 +268,22 @@ class ExprNode extends CfgNode {
265268
/** Gets a node corresponding to expression `e`. */
266269
ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e }
267270

271+
class ScopeEntryDefinitionNode extends Node, TScopeEntryDefinitionNode {
272+
ScopeEntryDefinition def;
273+
274+
ScopeEntryDefinitionNode() { this = TScopeEntryDefinitionNode(def) }
275+
276+
ScopeEntryDefinition getDefinition() { result = def }
277+
278+
SsaSourceVariable getVariable() { result = def.getSourceVariable() }
279+
280+
override Location getLocation() { result = def.getLocation() }
281+
282+
override Scope getScope() { result = def.getScope() }
283+
284+
override string toString() { result = "Entry definition for " + this.getVariable().toString() }
285+
}
286+
268287
/**
269288
* The value of a parameter at function entry, viewed as a node in a data
270289
* flow graph.

Diff for: python/ql/lib/semmle/python/dataflow/new/internal/LocalSources.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class LocalSourceNode extends Node {
7171
or
7272
// We include all scope entry definitions, as these act as the local source within the scope they
7373
// enter.
74-
this.asCfgNode() = any(ScopeEntryDefinition def).getDefiningNode()
74+
this instanceof ScopeEntryDefinitionNode
7575
or
7676
this instanceof ParameterNode
7777
}

Diff for: python/ql/lib/semmle/python/dataflow/new/internal/TypeTrackingImpl.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ module TypeTrackingInput implements Shared::TypeTrackingInput {
251251
e.getSourceVariable() = var and
252252
var.hasDefiningNode(def)
253253
|
254-
nodeTo.asCfgNode() = e.getDefiningNode() and
254+
nodeTo.(DataFlowPublic::ScopeEntryDefinitionNode).getDefinition() = e and
255255
nodeFrom.asCfgNode() = def.getValue() and
256256
var.getScope().getScope*() = nodeFrom.getScope()
257257
)

Diff for: python/ql/test/experimental/dataflow/typetracking/tracked.ql

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ module TrackedTest implements TestSig {
2626
not e.getLocation().getStartLine() = 0 and
2727
// We do not wish to annotate scope entry definitions,
2828
// as they do not appear in the source code.
29-
not e.asCfgNode() = any(ScopeEntryDefinition def).getDefiningNode() and
29+
not e instanceof DataFlow::ScopeEntryDefinitionNode and
3030
// ...same for `SynthCaptureNode`s
3131
not e instanceof DataFlow::SynthCaptureNode and
3232
tag = "tracked" and

0 commit comments

Comments
 (0)