Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 9312b42

Browse files
committed
Python: More easy-to-get content flow
There are some things that should be rewritten, though, but it may involve the extractor
1 parent 9d09b4c commit 9312b42

5 files changed

Lines changed: 85 additions & 9 deletions

File tree

python/ql/src/experimental/dataflow/internal/DataFlowPrivate.qll

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
234234
or
235235
// Comprehension
236236
// `[x+1 for x in l]`
237-
// nodeFrom is `x+1`
238-
// nodeTo is `[x+1 for x in l]`
237+
// nodeFrom is `x+1`, cfg node
238+
// nodeTo is `[x+1 for x in l]`, cfg node
239239
nodeTo.(CfgNode).getNode().getNode().(Comp).getElt() = nodeFrom.(CfgNode).getNode().getNode()
240240
}
241241

@@ -245,9 +245,42 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
245245
predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
246246
// Subscription
247247
// `l[3]`
248-
// nodeFrom is `l`
249-
// nodeTo is `l[3]`
248+
// nodeFrom is `l`, cfg node
249+
// nodeTo is `l[3]`, cfg node
250250
nodeFrom.(CfgNode).getNode() = nodeTo.(CfgNode).getNode().(SubscriptNode).getObject()
251+
or
252+
// set.pop
253+
// `s.pop()`
254+
// nodeFrom is `s`, cfg node
255+
// nodeTo is `s.pop()`, cfg node
256+
exists(CallNode call, AttrNode a |
257+
call.getFunction() = a and
258+
a.getName() = "pop" and // TODO: Should be made more robust, like Value::named("set.pop").getACall()
259+
nodeFrom.(CfgNode).getNode() = a.getObject() and
260+
nodeTo.(CfgNode).getNode() = call
261+
)
262+
or
263+
// Comprehension
264+
// `[x+1 for x in l]`
265+
// nodeFrom is `l`, cfg node
266+
// nodeTo is `x`, essa var
267+
exists(For f, Comp comp |
268+
// Seems to need extractor changes to write this part properly
269+
nodeFrom.(CfgNode).getNode().(SequenceNode).getNode().getParentNode() = comp and
270+
colocated(f.getIter(), comp) and
271+
nodeTo.(EssaNode).getVar().getDefinition().(AssignmentDefinition).getDefiningNode().getNode() = f.getTarget()
272+
)
273+
}
274+
275+
276+
277+
/** This should not be necessary */
278+
predicate colocated(AstNode n1, AstNode n2) {
279+
n1.getLocation().getFile() = n2.getLocation().getFile() and
280+
n1.getLocation().getStartLine() = n2.getLocation().getStartLine() and
281+
n1.getLocation().getEndLine() = n2.getLocation().getEndLine() and
282+
n1.getLocation().getStartColumn() = n2.getLocation().getStartColumn() and
283+
n1.getLocation().getEndColumn() = n2.getLocation().getEndColumn()
251284
}
252285

253286
/**

python/ql/src/experimental/dataflow/internal/DataFlowPublic.qll

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,15 @@ class Node extends TNode {
3333
/** Gets the scope of this node. */
3434
Scope getScope() { none() }
3535

36+
private DataFlowCallable getCallableScope(Scope s) {
37+
result.getScope() = s
38+
or
39+
not exists(DataFlowCallable c | c.getScope() = s) and
40+
result = getCallableScope(s.getEnclosingScope())
41+
}
42+
3643
/** Gets the enclosing callable of this node. */
37-
DataFlowCallable getEnclosingCallable() { result.getScope() = this.getScope() }
44+
DataFlowCallable getEnclosingCallable() { result = getCallableScope(this.getScope()) }
3845

3946
/** Gets the location of this node */
4047
Location getLocation() { none() }

python/ql/test/experimental/dataflow/consistency/dataflow-consistency.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ uniquePostUpdate
8888
postIsInSameCallable
8989
reverseRead
9090
storeIsPostUpdate
91-
| test.py:152:5:152:5 | SSA variable l | Store targets should be PostUpdateNodes. |
91+
| test.py:152:9:152:16 | ControlFlowNode for List | Store targets should be PostUpdateNodes. |
9292
argHasPostUpdate
9393
| test.py:25:10:25:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |
9494
| test.py:29:10:29:10 | ControlFlowNode for t | ArgumentNode is missing PostUpdateNode. |

python/ql/test/experimental/dataflow/coverage/dataflow.expected

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ edges
1919
| test.py:74:9:74:37 | ControlFlowNode for ListComp [Content] | test.py:75:10:75:10 | ControlFlowNode for x [Content] |
2020
| test.py:74:10:74:15 | ControlFlowNode for SOURCE | test.py:74:9:74:37 | ControlFlowNode for ListComp [Content] |
2121
| test.py:75:10:75:10 | ControlFlowNode for x [Content] | test.py:75:10:75:13 | ControlFlowNode for Subscript |
22+
| test.py:78:9:78:29 | ControlFlowNode for ListComp [Content] | test.py:79:10:79:10 | ControlFlowNode for x [Content] |
23+
| test.py:78:10:78:10 | ControlFlowNode for y | test.py:78:9:78:29 | ControlFlowNode for ListComp [Content] |
24+
| test.py:78:16:78:16 | SSA variable y | test.py:78:10:78:10 | ControlFlowNode for y |
25+
| test.py:78:21:78:28 | ControlFlowNode for List [Content] | test.py:78:16:78:16 | SSA variable y |
26+
| test.py:78:22:78:27 | ControlFlowNode for SOURCE | test.py:78:21:78:28 | ControlFlowNode for List [Content] |
27+
| test.py:79:10:79:10 | ControlFlowNode for x [Content] | test.py:79:10:79:13 | ControlFlowNode for Subscript |
28+
| test.py:91:9:91:37 | ControlFlowNode for SetComp [Content] | test.py:92:10:92:10 | ControlFlowNode for x [Content] |
29+
| test.py:91:10:91:15 | ControlFlowNode for SOURCE | test.py:91:9:91:37 | ControlFlowNode for SetComp [Content] |
30+
| test.py:92:10:92:10 | ControlFlowNode for x [Content] | test.py:92:10:92:16 | ControlFlowNode for Attribute() |
31+
| test.py:95:9:95:29 | ControlFlowNode for SetComp [Content] | test.py:96:10:96:10 | ControlFlowNode for x [Content] |
32+
| test.py:95:10:95:10 | ControlFlowNode for y | test.py:95:9:95:29 | ControlFlowNode for SetComp [Content] |
33+
| test.py:95:16:95:16 | SSA variable y | test.py:95:10:95:10 | ControlFlowNode for y |
34+
| test.py:95:21:95:28 | ControlFlowNode for List [Content] | test.py:95:16:95:16 | SSA variable y |
35+
| test.py:95:22:95:27 | ControlFlowNode for SOURCE | test.py:95:21:95:28 | ControlFlowNode for List [Content] |
36+
| test.py:96:10:96:10 | ControlFlowNode for x [Content] | test.py:96:10:96:16 | ControlFlowNode for Attribute() |
2237
| test.py:222:11:222:16 | ControlFlowNode for SOURCE | test.py:222:11:222:17 | ControlFlowNode for Tuple [Content] |
2338
| test.py:222:11:222:17 | ControlFlowNode for Tuple [Content] | test.py:222:10:222:21 | ControlFlowNode for Subscript |
2439
| test.py:225:10:225:17 | ControlFlowNode for List [Content] | test.py:225:10:225:20 | ControlFlowNode for Subscript |
@@ -57,6 +72,24 @@ nodes
5772
| test.py:74:10:74:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
5873
| test.py:75:10:75:10 | ControlFlowNode for x [Content] | semmle.label | ControlFlowNode for x [Content] |
5974
| test.py:75:10:75:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
75+
| test.py:78:9:78:29 | ControlFlowNode for ListComp [Content] | semmle.label | ControlFlowNode for ListComp [Content] |
76+
| test.py:78:10:78:10 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
77+
| test.py:78:16:78:16 | SSA variable y | semmle.label | SSA variable y |
78+
| test.py:78:21:78:28 | ControlFlowNode for List [Content] | semmle.label | ControlFlowNode for List [Content] |
79+
| test.py:78:22:78:27 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
80+
| test.py:79:10:79:10 | ControlFlowNode for x [Content] | semmle.label | ControlFlowNode for x [Content] |
81+
| test.py:79:10:79:13 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
82+
| test.py:91:9:91:37 | ControlFlowNode for SetComp [Content] | semmle.label | ControlFlowNode for SetComp [Content] |
83+
| test.py:91:10:91:15 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
84+
| test.py:92:10:92:10 | ControlFlowNode for x [Content] | semmle.label | ControlFlowNode for x [Content] |
85+
| test.py:92:10:92:16 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
86+
| test.py:95:9:95:29 | ControlFlowNode for SetComp [Content] | semmle.label | ControlFlowNode for SetComp [Content] |
87+
| test.py:95:10:95:10 | ControlFlowNode for y | semmle.label | ControlFlowNode for y |
88+
| test.py:95:16:95:16 | SSA variable y | semmle.label | SSA variable y |
89+
| test.py:95:21:95:28 | ControlFlowNode for List [Content] | semmle.label | ControlFlowNode for List [Content] |
90+
| test.py:95:22:95:27 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
91+
| test.py:96:10:96:10 | ControlFlowNode for x [Content] | semmle.label | ControlFlowNode for x [Content] |
92+
| test.py:96:10:96:16 | ControlFlowNode for Attribute() | semmle.label | ControlFlowNode for Attribute() |
6093
| test.py:222:10:222:21 | ControlFlowNode for Subscript | semmle.label | ControlFlowNode for Subscript |
6194
| test.py:222:11:222:16 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
6295
| test.py:222:11:222:17 | ControlFlowNode for Tuple [Content] | semmle.label | ControlFlowNode for Tuple [Content] |
@@ -80,6 +113,9 @@ nodes
80113
| test.py:62:10:62:10 | ControlFlowNode for x | test.py:61:10:61:15 | ControlFlowNode for SOURCE | test.py:62:10:62:10 | ControlFlowNode for x | <message> |
81114
| test.py:67:10:67:13 | ControlFlowNode for Subscript | test.py:66:10:66:15 | ControlFlowNode for SOURCE | test.py:67:10:67:13 | ControlFlowNode for Subscript | <message> |
82115
| test.py:75:10:75:13 | ControlFlowNode for Subscript | test.py:74:10:74:15 | ControlFlowNode for SOURCE | test.py:75:10:75:13 | ControlFlowNode for Subscript | <message> |
116+
| test.py:79:10:79:13 | ControlFlowNode for Subscript | test.py:78:22:78:27 | ControlFlowNode for SOURCE | test.py:79:10:79:13 | ControlFlowNode for Subscript | <message> |
117+
| test.py:92:10:92:16 | ControlFlowNode for Attribute() | test.py:91:10:91:15 | ControlFlowNode for SOURCE | test.py:92:10:92:16 | ControlFlowNode for Attribute() | <message> |
118+
| test.py:96:10:96:16 | ControlFlowNode for Attribute() | test.py:95:22:95:27 | ControlFlowNode for SOURCE | test.py:96:10:96:16 | ControlFlowNode for Attribute() | <message> |
83119
| test.py:222:10:222:21 | ControlFlowNode for Subscript | test.py:222:11:222:16 | ControlFlowNode for SOURCE | test.py:222:10:222:21 | ControlFlowNode for Subscript | <message> |
84120
| test.py:225:10:225:20 | ControlFlowNode for Subscript | test.py:225:11:225:16 | ControlFlowNode for SOURCE | test.py:225:10:225:20 | ControlFlowNode for Subscript | <message> |
85121
| test.py:246:10:246:34 | ControlFlowNode for second() | test.py:246:28:246:33 | ControlFlowNode for SOURCE | test.py:246:10:246:34 | ControlFlowNode for second() | <message> |

python/ql/test/experimental/dataflow/coverage/test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def test_list_comprehension():
7676

7777
def test_list_comprehension_flow():
7878
x = [y for y in [SOURCE]]
79-
SINK(x[0]) # Flow missing
79+
SINK(x[0])
8080

8181
def test_nested_list_display():
8282
x = [* [SOURCE]]
@@ -89,11 +89,11 @@ def test_set_display():
8989

9090
def test_set_comprehension():
9191
x = {SOURCE for y in [NONSOURCE]}
92-
SINK(x.pop()) # Flow missing
92+
SINK(x.pop())
9393

9494
def test_set_comprehension_flow():
9595
x = {y for y in [SOURCE]}
96-
SINK(x.pop()) # Flow missing
96+
SINK(x.pop())
9797

9898
def test_nested_set_display():
9999
x = {* {SOURCE}}

0 commit comments

Comments
 (0)