@@ -96,10 +96,55 @@ module ArrayTaintTracking {
9696 * Classes and predicates for modelling data-flow for arrays.
9797 */
9898private module ArrayDataFlow {
99+ private import DataFlow:: PseudoProperties
100+
99101 /**
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.
101104 */
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+ }
103148
104149 /**
105150 * A step for storing an element on an array using `arr.push(e)` or `arr.unshift(e)`.
@@ -110,10 +155,10 @@ private module ArrayDataFlow {
110155 this .getMethodName ( ) = "unshift"
111156 }
112157
113- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
158+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
114159 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
117162 }
118163 }
119164
@@ -143,10 +188,10 @@ private module ArrayDataFlow {
143188 element = this
144189 }
145190
146- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
191+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
147192 prop = arrayElement ( ) and
148193 element = this .( DataFlow:: PropWrite ) .getRhs ( ) and
149- this = obj .( DataFlow :: SourceNode ) . getAPropertyWrite ( )
194+ this = obj .getAPropertyWrite ( )
150195 }
151196 }
152197
@@ -189,7 +234,7 @@ private module ArrayDataFlow {
189234 element = getCallback ( 0 ) .getParameter ( 0 )
190235 }
191236
192- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
237+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
193238 this .getMethodName ( ) = "map" and
194239 prop = arrayElement ( ) and
195240 element = this .getCallback ( 0 ) .getAReturn ( ) and
@@ -209,7 +254,7 @@ private module ArrayDataFlow {
209254 private class ArrayCreationStep extends DataFlow:: AdditionalFlowStep , DataFlow:: Node {
210255 ArrayCreationStep ( ) { this instanceof DataFlow:: ArrayCreationNode }
211256
212- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
257+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
213258 prop = arrayElement ( ) and
214259 element = this .( DataFlow:: ArrayCreationNode ) .getAnElement ( ) and
215260 obj = this
@@ -223,10 +268,10 @@ private module ArrayDataFlow {
223268 private class ArraySpliceStep extends DataFlow:: AdditionalFlowStep , DataFlow:: MethodCallNode {
224269 ArraySpliceStep ( ) { this .getMethodName ( ) = "splice" }
225270
226- override predicate storeStep ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
271+ override predicate storeStep ( DataFlow:: Node element , DataFlow:: SourceNode obj , string prop ) {
227272 prop = arrayElement ( ) and
228273 element = getArgument ( 2 ) and
229- obj = this . getReceiver ( ) . getALocalSource ( )
274+ this = obj . getAMethodCall ( )
230275 }
231276 }
232277
@@ -260,4 +305,20 @@ private module ArrayDataFlow {
260305 succ = this
261306 }
262307 }
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+ }
263324}
0 commit comments