2
2
3
3
private import TypeTrackerPrivate
4
4
5
- /** Any string that may appear as the name of a piece of content. */
5
+ /**
6
+ * Any string that may appear as the name of a piece of content. This will usually include things like:
7
+ * - Attribute names (in Python)
8
+ * - Property names (in JavaScript)
9
+ *
10
+ * In general, this can also be used to model things like stores to specific list indices. To ensure
11
+ * correctness, it is important that
12
+ *
13
+ * - different types of content do not have overlapping names, and
14
+ * - the empty string `""` is not a valid piece of content, as it is used to indicate the absence of
15
+ * content instead.
16
+ */
6
17
class ContentName extends string {
7
18
ContentName ( ) { this = getPossibleContentName ( ) }
8
19
}
@@ -70,14 +81,41 @@ module StepSummary {
70
81
summary = ReturnStep ( )
71
82
or
72
83
exists ( string content |
73
- basicStoreStep ( nodeFrom , nodeTo , content ) and
84
+ localSourceStoreStep ( nodeFrom , nodeTo , content ) and
74
85
summary = StoreStep ( content )
75
86
or
76
87
basicLoadStep ( nodeFrom , nodeTo , content ) and summary = LoadStep ( content )
77
88
)
78
89
}
79
- }
80
90
91
+ /**
92
+ * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
93
+ *
94
+ * Note that `nodeTo` will always be a local source node that flows to the place where the content
95
+ * is written in `basicStoreStep`. This may lead to the flow of information going "back in time"
96
+ * from the point of view of the execution of the program.
97
+ *
98
+ * For instance, if we interpret attribute writes in Python as writing to content with the same
99
+ * name as the attribute and consider the following snippet
100
+ *
101
+ * ```python
102
+ * def foo(y):
103
+ * x = Foo()
104
+ * bar(x)
105
+ * x.attr = y
106
+ * baz(x)
107
+ *
108
+ * def bar(x):
109
+ * z = x.attr
110
+ * ```
111
+ * for the attribute write `x.attr = y`, we will have `content` being the literal string `"attr"`,
112
+ * `nodeFrom` will be `y`, and `nodeTo` will be the object `Foo()` created on the first line of the
113
+ * function. This means we will track the fact that `x.attr` can have the type of `y` into the
114
+ * assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called.
115
+ */
116
+ predicate localSourceStoreStep ( Node nodeFrom , LocalSourceNode nodeTo , string content ) {
117
+ exists ( Node obj | nodeTo .flowsTo ( obj ) and basicStoreStep ( nodeFrom , obj , content ) )
118
+ }
81
119
}
82
120
83
121
private newtype TTypeTracker = MkTypeTracker ( Boolean hasCall , OptionalContentName content )
@@ -92,7 +130,7 @@ private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalContentNam
92
130
*
93
131
* It is recommended that all uses of this type are written in the following form,
94
132
* for tracking some type `myType`:
95
- * ```
133
+ * ```ql
96
134
* DataFlow::LocalSourceNode myType(DataFlow::TypeTracker t) {
97
135
* t.start() and
98
136
* result = < source of myType >
@@ -253,7 +291,7 @@ private newtype TTypeBackTracker = MkTypeBackTracker(Boolean hasReturn, Optional
253
291
* It is recommended that all uses of this type are written in the following form,
254
292
* for back-tracking some callback type `myCallback`:
255
293
*
256
- * ```
294
+ * ```ql
257
295
* DataFlow::LocalSourceNode myCallback(DataFlow::TypeBackTracker t) {
258
296
* t.start() and
259
297
* result = (< some API call >).getArgument(< n >).getALocalSource()
0 commit comments