@@ -84,16 +84,17 @@ private module ArrayDataFlow {
84
84
* A step modelling the creation of an Array using the `Array.from(x)` method.
85
85
* The step copies the elements of the argument (set, array, or iterator elements) into the resulting array.
86
86
*/
87
- private class ArrayFrom extends DataFlow:: AdditionalFlowStep , DataFlow:: CallNode {
88
- ArrayFrom ( ) { this = DataFlow:: globalVarRef ( "Array" ) .getAMemberCall ( "from" ) }
89
-
87
+ private class ArrayFrom extends DataFlow:: SharedFlowStep {
90
88
override predicate loadStoreStep (
91
89
DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
92
90
) {
93
- pred = this .getArgument ( 0 ) and
94
- succ = this and
95
- fromProp = arrayLikeElement ( ) and
96
- toProp = arrayElement ( )
91
+ exists ( DataFlow:: CallNode call |
92
+ call = DataFlow:: globalVarRef ( "Array" ) .getAMemberCall ( "from" ) and
93
+ pred = call .getArgument ( 0 ) and
94
+ succ = call and
95
+ fromProp = arrayLikeElement ( ) and
96
+ toProp = arrayElement ( )
97
+ )
97
98
}
98
99
}
99
100
@@ -103,55 +104,45 @@ private module ArrayDataFlow {
103
104
*
104
105
* Such a step can occur both with the `push` and `unshift` methods, or when creating a new array.
105
106
*/
106
- private class ArrayCopySpread extends DataFlow:: AdditionalFlowStep {
107
- DataFlow:: Node spreadArgument ; // the spread argument containing the elements to be copied.
108
- DataFlow:: Node base ; // the object where the elements should be copied to.
109
-
110
- ArrayCopySpread ( ) {
111
- exists ( DataFlow:: MethodCallNode mcn | mcn = this |
112
- mcn .getMethodName ( ) = [ "push" , "unshift" ] and
113
- spreadArgument = mcn .getASpreadArgument ( ) and
114
- base = mcn .getReceiver ( ) .getALocalSource ( )
115
- )
116
- or
117
- spreadArgument = this .( DataFlow:: ArrayCreationNode ) .getASpreadArgument ( ) and
118
- base = this
119
- }
120
-
107
+ private class ArrayCopySpread extends DataFlow:: SharedFlowStep {
121
108
override predicate loadStoreStep (
122
109
DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
123
110
) {
124
- pred = spreadArgument and
125
- succ = base and
126
111
fromProp = arrayLikeElement ( ) and
127
- toProp = arrayElement ( )
112
+ toProp = arrayElement ( ) and
113
+ (
114
+ exists ( DataFlow:: MethodCallNode mcn |
115
+ mcn .getMethodName ( ) = [ "push" , "unshift" ] and
116
+ pred = mcn .getASpreadArgument ( ) and
117
+ succ = mcn .getReceiver ( ) .getALocalSource ( )
118
+ )
119
+ or
120
+ pred = succ .( DataFlow:: ArrayCreationNode ) .getASpreadArgument ( )
121
+ )
128
122
}
129
123
}
130
124
131
125
/**
132
126
* A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
133
127
*/
134
- private class ArrayAppendStep extends DataFlow:: AdditionalFlowStep , DataFlow:: MethodCallNode {
135
- ArrayAppendStep ( ) {
136
- this .getMethodName ( ) = "push" or
137
- this .getMethodName ( ) = "unshift"
138
- }
139
-
128
+ private class ArrayAppendStep extends DataFlow:: SharedFlowStep {
140
129
override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
141
130
prop = arrayElement ( ) and
142
- element = this .getAnArgument ( ) and
143
- obj .getAMethodCall ( ) = this
131
+ exists ( DataFlow:: MethodCallNode call |
132
+ call .getMethodName ( ) = [ "push" , "unshift" ] and
133
+ element = call .getAnArgument ( ) and
134
+ obj .getAMethodCall ( ) = call
135
+ )
144
136
}
145
137
}
146
138
147
139
/**
148
- * A step for reading/writing an element from an array inside a for-loop.
149
- * E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`.
140
+ * A node that reads or writes an element from an array inside a for-loop.
150
141
*/
151
- private class ArrayIndexingStep extends DataFlow :: AdditionalFlowStep , DataFlow:: Node {
142
+ private class ArrayIndexingAccess extends DataFlow:: Node {
152
143
DataFlow:: PropRef read ;
153
144
154
- ArrayIndexingStep ( ) {
145
+ ArrayIndexingAccess ( ) {
155
146
read = this and
156
147
TTNumber ( ) =
157
148
unique( InferredType type | type = read .getPropertyNameExpr ( ) .flow ( ) .analyze ( ) .getAType ( ) ) and
@@ -162,34 +153,42 @@ private module ArrayDataFlow {
162
153
i .getVariable ( ) .getADefinition ( ) .( VariableDeclarator ) .getDeclStmt ( ) = init
163
154
)
164
155
}
156
+ }
165
157
158
+ /**
159
+ * A step for reading/writing an element from an array inside a for-loop.
160
+ * E.g. a read from `foo[i]` to `bar` in `for(var i = 0; i < arr.length; i++) {bar = foo[i]}`.
161
+ */
162
+ private class ArrayIndexingStep extends DataFlow:: SharedFlowStep {
166
163
override predicate loadStep ( DataFlow:: Node obj , DataFlow:: Node element , string prop ) {
167
- prop = arrayElement ( ) and
168
- obj = this .( DataFlow:: PropRead ) .getBase ( ) and
169
- element = this
164
+ exists ( ArrayIndexingAccess access |
165
+ prop = arrayElement ( ) and
166
+ obj = access .( DataFlow:: PropRead ) .getBase ( ) and
167
+ element = access
168
+ )
170
169
}
171
170
172
171
override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
173
- prop = arrayElement ( ) and
174
- element = this .( DataFlow:: PropWrite ) .getRhs ( ) and
175
- this = obj .getAPropertyWrite ( )
172
+ exists ( ArrayIndexingAccess access |
173
+ prop = arrayElement ( ) and
174
+ element = access .( DataFlow:: PropWrite ) .getRhs ( ) and
175
+ access = obj .getAPropertyWrite ( )
176
+ )
176
177
}
177
178
}
178
179
179
180
/**
180
181
* A step for retrieving an element from an array using `.pop()` or `.shift()`.
181
182
* E.g. `array.pop()`.
182
183
*/
183
- private class ArrayPopStep extends DataFlow:: AdditionalFlowStep , DataFlow:: MethodCallNode {
184
- ArrayPopStep ( ) {
185
- getMethodName ( ) = "pop" or
186
- getMethodName ( ) = "shift"
187
- }
188
-
184
+ private class ArrayPopStep extends DataFlow:: SharedFlowStep {
189
185
override predicate loadStep ( DataFlow:: Node obj , DataFlow:: Node element , string prop ) {
190
- prop = arrayElement ( ) and
191
- obj = this .getReceiver ( ) and
192
- element = this
186
+ exists ( DataFlow:: MethodCallNode call |
187
+ call .getMethodName ( ) = [ "pop" , "shift" ] and
188
+ prop = arrayElement ( ) and
189
+ obj = call .getReceiver ( ) and
190
+ element = call
191
+ )
193
192
}
194
193
}
195
194
@@ -235,12 +234,12 @@ private module ArrayDataFlow {
235
234
/**
236
235
* A step for creating an array and storing the elements in the array.
237
236
*/
238
- private class ArrayCreationStep extends DataFlow:: AdditionalFlowStep , DataFlow :: ArrayCreationNode {
237
+ private class ArrayCreationStep extends DataFlow:: SharedFlowStep {
239
238
override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
240
- exists ( int i |
241
- element = this .getElement ( i ) and
242
- obj = this and
243
- if this = any ( PromiseAllCreation c ) .getArrayNode ( )
239
+ exists ( DataFlow :: ArrayCreationNode array , int i |
240
+ element = array .getElement ( i ) and
241
+ obj = array and
242
+ if array = any ( PromiseAllCreation c ) .getArrayNode ( )
244
243
then prop = arrayElement ( i )
245
244
else prop = arrayElement ( )
246
245
)
@@ -251,56 +250,42 @@ private module ArrayDataFlow {
251
250
* A step modelling that `splice` can insert elements into an array.
252
251
* For example in `array.splice(i, del, e)`: if `e` is tainted, then so is `array
253
252
*/
254
- private class ArraySpliceStep extends DataFlow:: AdditionalFlowStep , DataFlow:: MethodCallNode {
255
- ArraySpliceStep ( ) { this .getMethodName ( ) = "splice" }
256
-
253
+ private class ArraySpliceStep extends DataFlow:: SharedFlowStep {
257
254
override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
258
- prop = arrayElement ( ) and
259
- element = getArgument ( 2 ) and
260
- this = obj .getAMethodCall ( )
255
+ exists ( DataFlow:: MethodCallNode call |
256
+ call .getMethodName ( ) = "splice" and
257
+ prop = arrayElement ( ) and
258
+ element = call .getArgument ( 2 ) and
259
+ call = obj .getAMethodCall ( )
260
+ )
261
261
}
262
262
}
263
263
264
264
/**
265
265
* A step for modelling `concat`.
266
266
* For example in `e = arr1.concat(arr2, arr3)`: if any of the `arr` is tainted, then so is `e`.
267
267
*/
268
- private class ArrayConcatStep extends DataFlow:: AdditionalFlowStep , DataFlow:: MethodCallNode {
269
- ArrayConcatStep ( ) { this .getMethodName ( ) = "concat" }
270
-
268
+ private class ArrayConcatStep extends DataFlow:: SharedFlowStep {
271
269
override predicate loadStoreStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
272
- prop = arrayElement ( ) and
273
- ( pred = this .getReceiver ( ) or pred = this .getAnArgument ( ) ) and
274
- succ = this
270
+ exists ( DataFlow:: MethodCallNode call |
271
+ call .getMethodName ( ) = "concat" and
272
+ prop = arrayElement ( ) and
273
+ ( pred = call .getReceiver ( ) or pred = call .getAnArgument ( ) ) and
274
+ succ = call
275
+ )
275
276
}
276
277
}
277
278
278
279
/**
279
280
* A step for modelling that elements from an array `arr` also appear in the result from calling `slice`/`splice`/`filter`.
280
281
*/
281
- private class ArraySliceStep extends DataFlow:: AdditionalFlowStep , DataFlow:: MethodCallNode {
282
- ArraySliceStep ( ) {
283
- this .getMethodName ( ) = "slice" or
284
- this .getMethodName ( ) = "splice" or
285
- this .getMethodName ( ) = "filter"
286
- }
287
-
282
+ private class ArraySliceStep extends DataFlow:: SharedFlowStep {
288
283
override predicate loadStoreStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
289
- prop = arrayElement ( ) and
290
- pred = this .getReceiver ( ) and
291
- succ = this
292
- }
293
- }
294
-
295
- /**
296
- * A step for modelling `for of` iteration on arrays.
297
- */
298
- private class ForOfStep extends PreCallGraphStep {
299
- override predicate loadStep ( DataFlow:: Node obj , DataFlow:: Node e , string prop ) {
300
- exists ( ForOfStmt forOf |
301
- obj = forOf .getIterationDomain ( ) .flow ( ) and
302
- e = DataFlow:: lvalueNode ( forOf .getLValue ( ) ) and
303
- prop = arrayElement ( )
284
+ exists ( DataFlow:: MethodCallNode call |
285
+ call .getMethodName ( ) = [ "slice" , "splice" , "filter" ] and
286
+ prop = arrayElement ( ) and
287
+ pred = call .getReceiver ( ) and
288
+ succ = call
304
289
)
305
290
}
306
291
}
0 commit comments