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

Skip to content

Commit 27b2556

Browse files
committed
Python: Implement field-stores, -reads, and -content
1 parent a2d006f commit 27b2556

11 files changed

Lines changed: 427 additions & 9 deletions

File tree

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

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ class DataFlowType extends TDataFlowType {
361361
}
362362

363363
/** A node that performs a type cast. */
364-
class CastNode extends Node {
364+
class CastNode extends CfgNode {
365365
CastNode() { none() }
366366
}
367367

@@ -423,6 +423,8 @@ predicate storeStep(Node nodeFrom, Content c, Node nodeTo) {
423423
dictStoreStep(nodeFrom, c, nodeTo)
424424
or
425425
comprehensionStoreStep(nodeFrom, c, nodeTo)
426+
or
427+
attributeStoreStep(nodeFrom, c, nodeTo)
426428
}
427429

428430
/** Data flows from an element of a list to the list. */
@@ -497,6 +499,30 @@ predicate comprehensionStoreStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
497499
c instanceof ListElementContent
498500
}
499501

502+
/**
503+
* In
504+
* ```python
505+
* obj.foo = x
506+
* ```
507+
* data flows from `x` to (the post-update node for) `obj` via assignment to `foo`.
508+
*/
509+
predicate attributeStoreStep(CfgNode nodeFrom, Content c, PostUpdateNode nodeTo) {
510+
exists(AssignStmt a, Attribute attr |
511+
a.getValue().getAFlowNode() = nodeFrom.getNode() and
512+
a.getATarget().(Attribute) = attr and
513+
attr.getName() = c.(AttributeContent).getAttribute() and
514+
attr.getObject().getAFlowNode() = nodeTo.getPreUpdateNode().(CfgNode).getNode() and
515+
attr.getCtx() instanceof Store
516+
)
517+
or
518+
exists(AssignExpr ae |
519+
ae.getValue().getAFlowNode() = nodeFrom.getNode() and
520+
ae.getTarget().(Attribute).getName() = c.(AttributeContent).getAttribute() and
521+
ae.getTarget().(Attribute).getObject().getAFlowNode() =
522+
nodeTo.getPreUpdateNode().(CfgNode).getNode()
523+
)
524+
}
525+
500526
/**
501527
* Holds if data can flow from `nodeFrom` to `nodeTo` via a read of content `c`.
502528
*/
@@ -506,6 +532,8 @@ predicate readStep(Node nodeFrom, Content c, Node nodeTo) {
506532
popReadStep(nodeFrom, c, nodeTo)
507533
or
508534
comprehensionReadStep(nodeFrom, c, nodeTo)
535+
or
536+
attributeReadStep(nodeFrom, c, nodeTo)
509537
}
510538

511539
/** Data flows from a sequence to a subscript of the sequence. */
@@ -592,6 +620,22 @@ predicate comprehensionReadStep(CfgNode nodeFrom, Content c, EssaNode nodeTo) {
592620
)
593621
}
594622

623+
/**
624+
* In
625+
* ```python
626+
* obj.foo
627+
* ```
628+
* data flows from `obj` to `obj.foo` via a read from `foo`.
629+
*/
630+
predicate attributeReadStep(CfgNode nodeFrom, Content c, CfgNode nodeTo) {
631+
exists(Attribute attr |
632+
nodeTo.asCfgNode().(AttrNode).getNode() = attr and
633+
nodeFrom.asCfgNode() = attr.getObject().getAFlowNode() and
634+
attr.getName() = c.(AttributeContent).getAttribute() and
635+
attr.getCtx() instanceof Load
636+
)
637+
}
638+
595639
/**
596640
* Holds if values stored inside content `c` are cleared at node `n`. For example,
597641
* any value stored inside `f` is cleared at the pre-update node associated with `x`

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

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -202,20 +202,20 @@ newtype TContent =
202202
key = any(Keyword kw).getArg()
203203
} or
204204
/** An element of a dictionary at any key. */
205-
TDictionaryElementAnyContent()
205+
TDictionaryElementAnyContent() or
206+
/** An object attribute. */
207+
TAttributeContent(string attr) { attr = any(Attribute a).getName() }
206208

207209
class Content extends TContent {
208210
/** Gets a textual representation of this element. */
209211
string toString() { result = "Content" }
210212
}
211213

212214
class ListElementContent extends TListElementContent, Content {
213-
/** Gets a textual representation of this element. */
214215
override string toString() { result = "List element" }
215216
}
216217

217218
class SetElementContent extends TSetElementContent, Content {
218-
/** Gets a textual representation of this element. */
219219
override string toString() { result = "Set element" }
220220
}
221221

@@ -224,10 +224,9 @@ class TupleElementContent extends TTupleElementContent, Content {
224224

225225
TupleElementContent() { this = TTupleElementContent(index) }
226226

227-
/** Gets the index for this tuple element */
227+
/** Gets the index for this tuple element. */
228228
int getIndex() { result = index }
229229

230-
/** Gets a textual representation of this element. */
231230
override string toString() { result = "Tuple element at index " + index.toString() }
232231
}
233232

@@ -236,14 +235,23 @@ class DictionaryElementContent extends TDictionaryElementContent, Content {
236235

237236
DictionaryElementContent() { this = TDictionaryElementContent(key) }
238237

239-
/** Gets the index for this tuple element */
238+
/** Gets the key for this dictionary element. */
240239
string getKey() { result = key }
241240

242-
/** Gets a textual representation of this element. */
243241
override string toString() { result = "Dictionary element at key " + key }
244242
}
245243

246244
class DictionaryElementAnyContent extends TDictionaryElementAnyContent, Content {
247-
/** Gets a textual representation of this element. */
248245
override string toString() { result = "Any dictionary element" }
249246
}
247+
248+
class AttributeContent extends TAttributeContent, Content {
249+
private string attr;
250+
251+
AttributeContent() { this = TAttributeContent(attr) }
252+
253+
/** Gets the name of the attribute under which this content is stored. */
254+
string getAttribute() { result = attr }
255+
256+
override string toString() { result = "Attribute " + attr }
257+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
| test.py:0:0:0:0 | SSA variable $ | test.py:1:1:1:66 | SSA variable $ |
2+
| test.py:0:0:0:0 | SSA variable * | test.py:1:1:1:66 | SSA variable * |
3+
| test.py:6:13:6:18 | ControlFlowNode for object | test.py:12:17:12:22 | ControlFlowNode for object |
4+
| test.py:8:5:8:28 | ControlFlowNode for FunctionExpr | test.py:8:9:8:16 | SSA variable __init__ |
5+
| test.py:8:18:8:21 | SSA variable self | test.py:9:9:9:12 | ControlFlowNode for self |
6+
| test.py:8:18:8:21 | SSA variable self | test.py:9:9:9:16 | SSA variable self |
7+
| test.py:8:24:8:26 | SSA variable foo | test.py:9:20:9:22 | ControlFlowNode for foo |
8+
| test.py:14:5:14:23 | ControlFlowNode for FunctionExpr | test.py:14:9:14:16 | SSA variable __init__ |
9+
| test.py:14:18:14:21 | SSA variable self | test.py:15:9:15:12 | ControlFlowNode for self |
10+
| test.py:14:18:14:21 | SSA variable self | test.py:15:9:15:16 | SSA variable self |
11+
| test.py:17:5:17:21 | ControlFlowNode for FunctionExpr | test.py:17:9:17:14 | SSA variable getObj |
12+
| test.py:17:16:17:19 | SSA variable self | test.py:18:16:18:19 | ControlFlowNode for self |
13+
| test.py:21:12:21:14 | SSA variable obj | test.py:22:12:22:14 | ControlFlowNode for obj |
14+
| test.py:21:12:21:14 | SSA variable obj | test.py:23:5:23:11 | SSA variable obj |
15+
| test.py:21:17:21:17 | SSA variable x | test.py:23:15:23:15 | ControlFlowNode for x |
16+
| test.py:22:12:22:14 | ControlFlowNode for obj | test.py:23:5:23:7 | ControlFlowNode for obj |
17+
| test.py:22:12:22:14 | [post] ControlFlowNode for obj | test.py:23:5:23:7 | ControlFlowNode for obj |
18+
| test.py:27:5:27:9 | SSA variable myobj | test.py:29:5:29:25 | SSA variable myobj |
19+
| test.py:27:5:27:9 | SSA variable myobj | test.py:29:12:29:16 | ControlFlowNode for myobj |
20+
| test.py:27:13:27:23 | ControlFlowNode for MyObj() | test.py:27:5:27:9 | SSA variable myobj |
21+
| test.py:29:12:29:16 | ControlFlowNode for myobj | test.py:30:10:30:14 | ControlFlowNode for myobj |
22+
| test.py:29:12:29:16 | [post] ControlFlowNode for myobj | test.py:30:10:30:14 | ControlFlowNode for myobj |
23+
| test.py:34:5:34:5 | SSA variable x | test.py:38:17:38:17 | ControlFlowNode for x |
24+
| test.py:34:9:34:14 | ControlFlowNode for SOURCE | test.py:34:5:34:5 | SSA variable x |
25+
| test.py:36:5:36:5 | SSA variable a | test.py:38:5:38:5 | ControlFlowNode for a |
26+
| test.py:36:5:36:5 | SSA variable a | test.py:39:5:39:14 | SSA variable a |
27+
| test.py:36:9:36:19 | ControlFlowNode for NestedObj() | test.py:36:5:36:5 | SSA variable a |
28+
| test.py:38:5:38:5 | ControlFlowNode for a | test.py:39:5:39:5 | ControlFlowNode for a |
29+
| test.py:38:5:38:5 | [post] ControlFlowNode for a | test.py:39:5:39:5 | ControlFlowNode for a |
30+
| test.py:38:17:38:17 | ControlFlowNode for x | test.py:39:22:39:22 | ControlFlowNode for x |
31+
| test.py:39:5:39:5 | ControlFlowNode for a | test.py:41:10:41:10 | ControlFlowNode for a |
32+
| test.py:39:5:39:5 | [post] ControlFlowNode for a | test.py:41:10:41:10 | ControlFlowNode for a |
33+
| test.py:45:5:45:7 | SSA variable obj | test.py:46:10:46:12 | ControlFlowNode for obj |
34+
| test.py:45:11:45:23 | ControlFlowNode for MyObj() | test.py:45:5:45:7 | SSA variable obj |
35+
| test.py:49:28:49:28 | SSA variable x | test.py:50:11:50:18 | SSA variable x |
36+
| test.py:49:28:49:28 | SSA variable x | test.py:50:17:50:17 | ControlFlowNode for x |
37+
| test.py:50:5:50:7 | SSA variable obj | test.py:51:9:51:11 | ControlFlowNode for obj |
38+
| test.py:50:11:50:18 | ControlFlowNode for MyObj() | test.py:50:5:50:7 | SSA variable obj |
39+
| test.py:51:5:51:5 | SSA variable a | test.py:52:12:52:12 | ControlFlowNode for a |
40+
| test.py:51:9:51:15 | ControlFlowNode for Attribute | test.py:51:5:51:5 | SSA variable a |
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import python
2+
import experimental.dataflow.DataFlow
3+
4+
from DataFlow::Node nodeFrom, DataFlow::Node nodeTo
5+
where
6+
DataFlow::localFlowStep(nodeFrom, nodeTo) and
7+
nodeFrom.getLocation().getFile().getBaseName() = "test.py"
8+
select nodeFrom, nodeTo
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
11
edges
2+
| test.py:29:12:29:16 | [post] ControlFlowNode for myobj [Attribute foo] | test.py:30:10:30:14 | ControlFlowNode for myobj [Attribute foo] |
3+
| test.py:29:19:29:24 | ControlFlowNode for SOURCE | test.py:29:12:29:16 | [post] ControlFlowNode for myobj [Attribute foo] |
4+
| test.py:30:10:30:14 | ControlFlowNode for myobj [Attribute foo] | test.py:30:10:30:18 | ControlFlowNode for Attribute |
5+
| test.py:34:9:34:14 | ControlFlowNode for SOURCE | test.py:38:17:38:17 | ControlFlowNode for x |
6+
| test.py:38:5:38:5 | [post] ControlFlowNode for a [Attribute obj, Attribute foo] | test.py:41:10:41:10 | ControlFlowNode for a [Attribute obj, Attribute foo] |
7+
| test.py:38:5:38:9 | [post] ControlFlowNode for Attribute [Attribute foo] | test.py:38:5:38:5 | [post] ControlFlowNode for a [Attribute obj, Attribute foo] |
8+
| test.py:38:17:38:17 | ControlFlowNode for x | test.py:38:5:38:9 | [post] ControlFlowNode for Attribute [Attribute foo] |
9+
| test.py:41:10:41:10 | ControlFlowNode for a [Attribute obj, Attribute foo] | test.py:41:10:41:14 | ControlFlowNode for Attribute [Attribute foo] |
10+
| test.py:41:10:41:14 | ControlFlowNode for Attribute [Attribute foo] | test.py:41:10:41:18 | ControlFlowNode for Attribute |
211
nodes
12+
| test.py:29:12:29:16 | [post] ControlFlowNode for myobj [Attribute foo] | semmle.label | [post] ControlFlowNode for myobj [Attribute foo] |
13+
| test.py:29:19:29:24 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
14+
| test.py:30:10:30:14 | ControlFlowNode for myobj [Attribute foo] | semmle.label | ControlFlowNode for myobj [Attribute foo] |
15+
| test.py:30:10:30:18 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
16+
| test.py:34:9:34:14 | ControlFlowNode for SOURCE | semmle.label | ControlFlowNode for SOURCE |
17+
| test.py:38:5:38:5 | [post] ControlFlowNode for a [Attribute obj, Attribute foo] | semmle.label | [post] ControlFlowNode for a [Attribute obj, Attribute foo] |
18+
| test.py:38:5:38:9 | [post] ControlFlowNode for Attribute [Attribute foo] | semmle.label | [post] ControlFlowNode for Attribute [Attribute foo] |
19+
| test.py:38:17:38:17 | ControlFlowNode for x | semmle.label | ControlFlowNode for x |
20+
| test.py:41:10:41:10 | ControlFlowNode for a [Attribute obj, Attribute foo] | semmle.label | ControlFlowNode for a [Attribute obj, Attribute foo] |
21+
| test.py:41:10:41:14 | ControlFlowNode for Attribute [Attribute foo] | semmle.label | ControlFlowNode for Attribute [Attribute foo] |
22+
| test.py:41:10:41:18 | ControlFlowNode for Attribute | semmle.label | ControlFlowNode for Attribute |
323
#select
24+
| test.py:30:10:30:18 | ControlFlowNode for Attribute | test.py:29:19:29:24 | ControlFlowNode for SOURCE | test.py:30:10:30:18 | ControlFlowNode for Attribute | <message> |
25+
| test.py:41:10:41:18 | ControlFlowNode for Attribute | test.py:34:9:34:14 | ControlFlowNode for SOURCE | test.py:41:10:41:18 | ControlFlowNode for Attribute | <message> |

0 commit comments

Comments
 (0)