Skip to content

Commit 2fb711e

Browse files
authored
Merge pull request github#3169 from erik-krogh/Maps
Approved by asgerf, esbena
2 parents 53abf83 + aee7cc1 commit 2fb711e

File tree

16 files changed

+694
-101
lines changed

16 files changed

+694
-101
lines changed

change-notes/1.25/analysis-javascript.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@
1919

2020
## Changes to libraries
2121

22-
22+
* Added data flow for `Map` and `Set`, and added matching type-tracking steps that can accessed using the `CollectionsTypeTracking` module.

javascript/ql/src/javascript.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import semmle.javascript.Base64
1212
import semmle.javascript.CFG
1313
import semmle.javascript.Classes
1414
import semmle.javascript.Closure
15+
import semmle.javascript.Collections
1516
import semmle.javascript.Comments
1617
import semmle.javascript.Concepts
1718
import semmle.javascript.Constants

javascript/ql/src/semmle/javascript/Arrays.qll

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,55 @@ module ArrayTaintTracking {
9696
* Classes and predicates for modelling data-flow for arrays.
9797
*/
9898
private 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

Comments
 (0)