Skip to content

Commit 0ebb24e

Browse files
authored
Merge pull request github#5398 from yoff/python-api-enhancements
Python: Add small api enhancements determined useful during documentation work
2 parents 667b26b + c777f1d commit 0ebb24e

File tree

3 files changed

+122
-104
lines changed

3 files changed

+122
-104
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
lgtm,codescanning
2+
* The class ParameterNode now extends LocalSourceNode, thus making methods like flowsTo available.
3+
* The new predicate `parameterNode` can now be used to map from a `Parameter` to a data-flow node.

python/ql/src/semmle/python/dataflow/new/internal/DataFlowPublic.qll

Lines changed: 6 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ private import python
66
private import DataFlowPrivate
77
import semmle.python.dataflow.new.TypeTracker
88
import Attributes
9+
import LocalSources
910
private import semmle.python.essa.SsaCompute
1011

1112
/**
@@ -135,7 +136,7 @@ class Node extends TNode {
135136
LocalSourceNode backtrack(TypeBackTracker t2, TypeBackTracker t) { t2 = t.step(result, this) }
136137

137138
/**
138-
* Gets a local source node from which data may flow to this node in zero or more local steps.
139+
* Gets a local source node from which data may flow to this node in zero or more local data-flow steps.
139140
*/
140141
LocalSourceNode getALocalSource() { result.flowsTo(this) }
141142
}
@@ -215,7 +216,7 @@ ExprNode exprNode(DataFlowExpr e) { result.getNode().getNode() = e }
215216
* The value of a parameter at function entry, viewed as a node in a data
216217
* flow graph.
217218
*/
218-
class ParameterNode extends CfgNode {
219+
class ParameterNode extends CfgNode, LocalSourceNode {
219220
ParameterDefinition def;
220221

221222
ParameterNode() {
@@ -237,6 +238,9 @@ class ParameterNode extends CfgNode {
237238
Parameter getParameter() { result = def.getParameter() }
238239
}
239240

241+
/** Gets a node corresponding to parameter `p`. */
242+
ParameterNode parameterNode(Parameter p) { result.getParameter() = p }
243+
240244
/** A data flow node that represents a call argument. */
241245
class ArgumentNode extends Node {
242246
ArgumentNode() { this = any(DataFlowCall c).getArg(_) }
@@ -467,108 +471,6 @@ class BarrierGuard extends GuardNode {
467471
}
468472
}
469473

470-
private predicate comes_from_cfgnode(Node node) {
471-
exists(CfgNode first, Node second |
472-
simpleLocalFlowStep(first, second) and
473-
simpleLocalFlowStep*(second, node)
474-
)
475-
}
476-
477-
/**
478-
* A data flow node that is a source of local flow. This includes things like
479-
* - Expressions
480-
* - Function parameters
481-
*/
482-
class LocalSourceNode extends Node {
483-
cached
484-
LocalSourceNode() {
485-
not comes_from_cfgnode(this) and
486-
not this instanceof ModuleVariableNode
487-
or
488-
this = any(ModuleVariableNode mvn).getARead()
489-
}
490-
491-
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
492-
pragma[inline]
493-
predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) }
494-
495-
/**
496-
* Gets a reference (read or write) of attribute `attrName` on this node.
497-
*/
498-
AttrRef getAnAttributeReference(string attrName) { Cached::namedAttrRef(this, attrName, result) }
499-
500-
/**
501-
* Gets a read of attribute `attrName` on this node.
502-
*/
503-
AttrRead getAnAttributeRead(string attrName) { result = getAnAttributeReference(attrName) }
504-
505-
/**
506-
* Gets a reference (read or write) of any attribute on this node.
507-
*/
508-
AttrRef getAnAttributeReference() {
509-
Cached::namedAttrRef(this, _, result)
510-
or
511-
Cached::dynamicAttrRef(this, result)
512-
}
513-
514-
/**
515-
* Gets a read of any attribute on this node.
516-
*/
517-
AttrRead getAnAttributeRead() { result = getAnAttributeReference() }
518-
519-
/**
520-
* Gets a call to this node.
521-
*/
522-
CallCfgNode getACall() { Cached::call(this, result) }
523-
}
524-
525-
cached
526-
private module Cached {
527-
/**
528-
* Holds if `source` is a `LocalSourceNode` that can reach `sink` via local flow steps.
529-
*
530-
* The slightly backwards parametering ordering is to force correct indexing.
531-
*/
532-
cached
533-
predicate hasLocalSource(Node sink, LocalSourceNode source) {
534-
source = sink
535-
or
536-
exists(Node second |
537-
simpleLocalFlowStep(source, second) and
538-
simpleLocalFlowStep*(second, sink)
539-
)
540-
}
541-
542-
/**
543-
* Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`.
544-
*/
545-
cached
546-
predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) {
547-
base.flowsTo(ref.getObject()) and
548-
ref.getAttributeName() = attr
549-
}
550-
551-
/**
552-
* Holds if `base` flows to the base of `ref` and `ref` has no known attribute name.
553-
*/
554-
cached
555-
predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) {
556-
base.flowsTo(ref.getObject()) and
557-
not exists(ref.getAttributeName())
558-
}
559-
560-
/**
561-
* Holds if `func` flows to the callee of `call`.
562-
*/
563-
cached
564-
predicate call(LocalSourceNode func, CallCfgNode call) {
565-
exists(CfgNode n |
566-
func.flowsTo(n) and
567-
n = call.getFunction()
568-
)
569-
}
570-
}
571-
572474
/**
573475
* Algebraic datatype for tracking data content associated with values.
574476
* Content can be collection elements or object attributes.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/**
2+
* Provides support for intra-procedural tracking of a customizable
3+
* set of data flow nodes.
4+
*
5+
* Note that unlike `TypeTracker.qll`, this library only performs
6+
* local tracking within a function.
7+
*/
8+
9+
import python
10+
import DataFlowPublic
11+
private import DataFlowPrivate
12+
13+
private predicate comes_from_cfgnode(Node node) {
14+
exists(CfgNode first, Node second |
15+
simpleLocalFlowStep(first, second) and
16+
simpleLocalFlowStep*(second, node)
17+
)
18+
}
19+
20+
/**
21+
* A data flow node that is a source of local flow. This includes things like
22+
* - Expressions
23+
* - Function parameters
24+
*/
25+
class LocalSourceNode extends Node {
26+
cached
27+
LocalSourceNode() {
28+
not comes_from_cfgnode(this) and
29+
not this instanceof ModuleVariableNode
30+
or
31+
this = any(ModuleVariableNode mvn).getARead()
32+
}
33+
34+
/** Holds if this `LocalSourceNode` can flow to `nodeTo` in one or more local flow steps. */
35+
pragma[inline]
36+
predicate flowsTo(Node nodeTo) { Cached::hasLocalSource(nodeTo, this) }
37+
38+
/**
39+
* Gets a reference (read or write) of attribute `attrName` on this node.
40+
*/
41+
AttrRef getAnAttributeReference(string attrName) { Cached::namedAttrRef(this, attrName, result) }
42+
43+
/**
44+
* Gets a read of attribute `attrName` on this node.
45+
*/
46+
AttrRead getAnAttributeRead(string attrName) { result = getAnAttributeReference(attrName) }
47+
48+
/**
49+
* Gets a reference (read or write) of any attribute on this node.
50+
*/
51+
AttrRef getAnAttributeReference() {
52+
Cached::namedAttrRef(this, _, result)
53+
or
54+
Cached::dynamicAttrRef(this, result)
55+
}
56+
57+
/**
58+
* Gets a read of any attribute on this node.
59+
*/
60+
AttrRead getAnAttributeRead() { result = getAnAttributeReference() }
61+
62+
/**
63+
* Gets a call to this node.
64+
*/
65+
CallCfgNode getACall() { Cached::call(this, result) }
66+
}
67+
68+
cached
69+
private module Cached {
70+
/**
71+
* Holds if `source` is a `LocalSourceNode` that can reach `sink` via local flow steps.
72+
*
73+
* The slightly backwards parametering ordering is to force correct indexing.
74+
*/
75+
cached
76+
predicate hasLocalSource(Node sink, LocalSourceNode source) {
77+
source = sink
78+
or
79+
exists(Node second |
80+
simpleLocalFlowStep(source, second) and
81+
simpleLocalFlowStep*(second, sink)
82+
)
83+
}
84+
85+
/**
86+
* Holds if `base` flows to the base of `ref` and `ref` has attribute name `attr`.
87+
*/
88+
cached
89+
predicate namedAttrRef(LocalSourceNode base, string attr, AttrRef ref) {
90+
base.flowsTo(ref.getObject()) and
91+
ref.getAttributeName() = attr
92+
}
93+
94+
/**
95+
* Holds if `base` flows to the base of `ref` and `ref` has no known attribute name.
96+
*/
97+
cached
98+
predicate dynamicAttrRef(LocalSourceNode base, AttrRef ref) {
99+
base.flowsTo(ref.getObject()) and
100+
not exists(ref.getAttributeName())
101+
}
102+
103+
/**
104+
* Holds if `func` flows to the callee of `call`.
105+
*/
106+
cached
107+
predicate call(LocalSourceNode func, CallCfgNode call) {
108+
exists(CfgNode n |
109+
func.flowsTo(n) and
110+
n = call.getFunction()
111+
)
112+
}
113+
}

0 commit comments

Comments
 (0)