@@ -96,10 +96,55 @@ module ArrayTaintTracking {
96
96
* Classes and predicates for modelling data-flow for arrays.
97
97
*/
98
98
private module ArrayDataFlow {
99
+ private import DataFlow:: PseudoProperties
100
+
99
101
/**
100
- * Gets a pseudo-field representing an element inside an array.
102
+ * A step modelling the creation of an Array using the `Array.from(x)` method.
103
+ * The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
101
104
*/
102
- private string arrayElement ( ) { result = "$arrayElement$" }
105
+ private class ArrayFrom extends DataFlow:: AdditionalFlowStep , DataFlow:: CallNode {
106
+ ArrayFrom ( ) { this = DataFlow:: globalVarRef ( "Array" ) .getAMemberCall ( "from" ) }
107
+
108
+ override predicate loadStoreStep (
109
+ DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
110
+ ) {
111
+ pred = this .getArgument ( 0 ) and
112
+ succ = this and
113
+ fromProp = arrayLikeElement ( ) and
114
+ toProp = arrayElement ( )
115
+ }
116
+ }
117
+
118
+ /**
119
+ * A step modelling an array copy where the spread operator is used.
120
+ * The result is essentially array concatenation.
121
+ *
122
+ * Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
123
+ */
124
+ private class ArrayCopySpread extends DataFlow:: AdditionalFlowStep {
125
+ DataFlow:: Node spreadArgument ; // the spread argument containing the elements to be copied.
126
+ DataFlow:: Node base ; // the object where the elements should be copied to.
127
+
128
+ ArrayCopySpread ( ) {
129
+ exists ( DataFlow:: MethodCallNode mcn | mcn = this |
130
+ mcn .getMethodName ( ) = [ "push" , "unshift" ] and
131
+ spreadArgument = mcn .getASpreadArgument ( ) and
132
+ base = mcn .getReceiver ( ) .getALocalSource ( )
133
+ )
134
+ or
135
+ spreadArgument = this .( DataFlow:: ArrayCreationNode ) .getASpreadArgument ( ) and
136
+ base = this
137
+ }
138
+
139
+ override predicate loadStoreStep (
140
+ DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
141
+ ) {
142
+ pred = spreadArgument and
143
+ succ = base and
144
+ fromProp = arrayLikeElement ( ) and
145
+ toProp = arrayElement ( )
146
+ }
147
+ }
103
148
104
149
/**
105
150
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
@@ -110,10 +155,10 @@ private module ArrayDataFlow {
110
155
this .getMethodName ( ) = "unshift"
111
156
}
112
157
113
- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
158
+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
114
159
prop = arrayElement ( ) and
115
- ( element = this .getAnArgument ( ) or element = this . getASpreadArgument ( ) ) and
116
- obj = this . getReceiver ( ) . getALocalSource ( )
160
+ element = this .getAnArgument ( ) and
161
+ obj . getAMethodCall ( ) = this
117
162
}
118
163
}
119
164
@@ -143,10 +188,10 @@ private module ArrayDataFlow {
143
188
element = this
144
189
}
145
190
146
- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
191
+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
147
192
prop = arrayElement ( ) and
148
193
element = this .( DataFlow:: PropWrite ) .getRhs ( ) and
149
- this = obj .( DataFlow :: SourceNode ) . getAPropertyWrite ( )
194
+ this = obj .getAPropertyWrite ( )
150
195
}
151
196
}
152
197
@@ -189,7 +234,7 @@ private module ArrayDataFlow {
189
234
element = getCallback ( 0 ) .getParameter ( 0 )
190
235
}
191
236
192
- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
237
+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
193
238
this .getMethodName ( ) = "map" and
194
239
prop = arrayElement ( ) and
195
240
element = this .getCallback ( 0 ) .getAReturn ( ) and
@@ -209,7 +254,7 @@ private module ArrayDataFlow {
209
254
private class ArrayCreationStep extends DataFlow:: AdditionalFlowStep , DataFlow:: Node {
210
255
ArrayCreationStep ( ) { this instanceof DataFlow:: ArrayCreationNode }
211
256
212
- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
257
+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
213
258
prop = arrayElement ( ) and
214
259
element = this .( DataFlow:: ArrayCreationNode ) .getAnElement ( ) and
215
260
obj = this
@@ -223,10 +268,10 @@ private module ArrayDataFlow {
223
268
private class ArraySpliceStep extends DataFlow:: AdditionalFlowStep , DataFlow:: MethodCallNode {
224
269
ArraySpliceStep ( ) { this .getMethodName ( ) = "splice" }
225
270
226
- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
271
+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
227
272
prop = arrayElement ( ) and
228
273
element = getArgument ( 2 ) and
229
- obj = this . getReceiver ( ) . getALocalSource ( )
274
+ this = obj . getAMethodCall ( )
230
275
}
231
276
}
232
277
@@ -260,4 +305,20 @@ private module ArrayDataFlow {
260
305
succ = this
261
306
}
262
307
}
308
+
309
+ /**
310
+ * A step for modelling `for of` iteration on arrays.
311
+ */
312
+ private class ForOfStep extends DataFlow:: AdditionalFlowStep , DataFlow:: ValueNode {
313
+ ForOfStmt forOf ;
314
+ DataFlow:: Node element ;
315
+
316
+ ForOfStep ( ) { this .asExpr ( ) = forOf .getIterationDomain ( ) }
317
+
318
+ override predicate loadStep ( DataFlow:: Node obj , DataFlow:: Node e , string prop ) {
319
+ obj = this and
320
+ e = DataFlow:: lvalueNode ( forOf .getLValue ( ) ) and
321
+ prop = arrayElement ( )
322
+ }
323
+ }
263
324
}
0 commit comments