@@ -8,6 +8,22 @@ import javascript
8
8
private import semmle.javascript.dataflow.internal.StepSummary
9
9
private import DataFlow:: PseudoProperties
10
10
11
+ /**
12
+ * A pseudo-property used in a data-flow/type-tracking step for collections.
13
+ *
14
+ * By extending `TypeTrackingPseudoProperty` the class enables the use of the collection related pseudo-properties in type-tracking predicates.
15
+ */
16
+ private class PseudoProperty extends TypeTrackingPseudoProperty {
17
+ PseudoProperty ( ) {
18
+ this = [ arrayLikeElement ( ) , "1" ] or // the "1" is required for the `ForOfStep`.
19
+ this = any ( CollectionDataFlow:: MapSet step ) .getAPseudoProperty ( )
20
+ }
21
+
22
+ override PseudoProperty getLoadStoreToProp ( ) {
23
+ exists ( CollectionFlowStep step | step .loadStore ( _, _, this , result ) )
24
+ }
25
+ }
26
+
11
27
/**
12
28
* An `AdditionalFlowStep` used to model a data-flow step related to standard library collections.
13
29
*
@@ -27,7 +43,7 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
27
43
/**
28
44
* Holds if the property `prop` of the object `pred` should be loaded into `succ`.
29
45
*/
30
- predicate load ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) { none ( ) }
46
+ predicate load ( DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty prop ) { none ( ) }
31
47
32
48
final override predicate loadStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
33
49
this .load ( pred , succ , prop )
@@ -36,7 +52,7 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
36
52
/**
37
53
* Holds if `pred` should be stored in the object `succ` under the property `prop`.
38
54
*/
39
- predicate store ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) { none ( ) }
55
+ predicate store ( DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty prop ) { none ( ) }
40
56
41
57
final override predicate storeStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
42
58
this .store ( pred , succ , prop )
@@ -45,7 +61,7 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
45
61
/**
46
62
* Holds if the property `prop` should be copied from the object `pred` to the object `succ`.
47
63
*/
48
- predicate loadStore ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) { none ( ) }
64
+ predicate loadStore ( DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty prop ) { none ( ) }
49
65
50
66
final override predicate loadStoreStep ( DataFlow:: Node pred , DataFlow:: Node succ , string prop ) {
51
67
this .loadStore ( pred , succ , prop , prop )
@@ -54,7 +70,9 @@ abstract private class CollectionFlowStep extends DataFlow::AdditionalFlowStep {
54
70
/**
55
71
* Holds if the property `loadProp` should be copied from the object `pred` to the property `storeProp` of object `succ`.
56
72
*/
57
- predicate loadStore ( DataFlow:: Node pred , DataFlow:: Node succ , string loadProp , string storeProp ) {
73
+ predicate loadStore (
74
+ DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty loadProp , PseudoProperty storeProp
75
+ ) {
58
76
none ( )
59
77
}
60
78
@@ -79,7 +97,7 @@ module CollectionsTypeTracking {
79
97
*/
80
98
pragma [ inline]
81
99
DataFlow:: SourceNode collectionStep ( DataFlow:: Node pred , StepSummary summary ) {
82
- exists ( CollectionFlowStep step , string field |
100
+ exists ( CollectionFlowStep step , PseudoProperty field |
83
101
summary = LoadStep ( field ) and
84
102
step .load ( pred , result , field ) and
85
103
not (
@@ -93,7 +111,7 @@ module CollectionsTypeTracking {
93
111
summary = CopyStep ( field ) and
94
112
step .loadStore ( pred , result , field )
95
113
or
96
- exists ( string toField | summary = LoadStoreStep ( field , toField ) |
114
+ exists ( PseudoProperty toField | summary = LoadStoreStep ( field , toField ) |
97
115
step .loadStore ( pred , result , field , toField )
98
116
)
99
117
)
@@ -110,20 +128,6 @@ module CollectionsTypeTracking {
110
128
result = collectionStep ( mid , summary )
111
129
)
112
130
}
113
-
114
- /**
115
- * A class enabling the use of the collection related pseudo-properties in type-tracking predicates.
116
- */
117
- private class MapRelatedPseudoFieldAsTypeTrackingProperty extends TypeTrackingPseudoProperty {
118
- MapRelatedPseudoFieldAsTypeTrackingProperty ( ) {
119
- this = [ setElement ( ) , iteratorElement ( ) ] or
120
- any ( CollectionFlowStep step ) .store ( _, _, this )
121
- }
122
-
123
- override string getLoadStoreToProp ( ) {
124
- exists ( CollectionFlowStep step | step .loadStore ( _, _, this , result ) )
125
- }
126
- }
127
131
}
128
132
129
133
/**
@@ -136,7 +140,7 @@ private module CollectionDataFlow {
136
140
private class SetAdd extends CollectionFlowStep , DataFlow:: MethodCallNode {
137
141
SetAdd ( ) { this .getMethodName ( ) = "add" }
138
142
139
- override predicate store ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
143
+ override predicate store ( DataFlow:: Node element , DataFlow:: Node obj , PseudoProperty prop ) {
140
144
obj = this .getReceiver ( ) .getALocalSource ( ) and
141
145
element = this .getArgument ( 0 ) and
142
146
prop = setElement ( )
@@ -150,7 +154,7 @@ private module CollectionDataFlow {
150
154
SetConstructor ( ) { this = DataFlow:: globalVarRef ( "Set" ) .getAnInstantiation ( ) }
151
155
152
156
override predicate loadStore (
153
- DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
157
+ DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty fromProp , PseudoProperty toProp
154
158
) {
155
159
pred = this .getArgument ( 0 ) and
156
160
succ = this and
@@ -176,14 +180,14 @@ private module CollectionDataFlow {
176
180
element = DataFlow:: lvalueNode ( forOf .getLValue ( ) )
177
181
}
178
182
179
- override predicate load ( DataFlow:: Node obj , DataFlow:: Node e , string prop ) {
183
+ override predicate load ( DataFlow:: Node obj , DataFlow:: Node e , PseudoProperty prop ) {
180
184
obj = this and
181
185
e = element and
182
186
prop = arrayLikeElement ( )
183
187
}
184
188
185
189
override predicate loadStore (
186
- DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
190
+ DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty fromProp , PseudoProperty toProp
187
191
) {
188
192
pred = this and
189
193
succ = element and
@@ -198,7 +202,7 @@ private module CollectionDataFlow {
198
202
private class SetMapForEach extends CollectionFlowStep , DataFlow:: MethodCallNode {
199
203
SetMapForEach ( ) { this .getMethodName ( ) = "forEach" }
200
204
201
- override predicate load ( DataFlow:: Node obj , DataFlow:: Node element , string prop ) {
205
+ override predicate load ( DataFlow:: Node obj , DataFlow:: Node element , PseudoProperty prop ) {
202
206
obj = this .getReceiver ( ) and
203
207
element = this .getCallback ( 0 ) .getParameter ( 0 ) and
204
208
prop = [ setElement ( ) , mapValueUnknownKey ( ) ]
@@ -207,12 +211,12 @@ private module CollectionDataFlow {
207
211
208
212
/**
209
213
* A call to the `get` method on a Map.
210
- * If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved.
214
+ * If the key of the call to `get` has a known string value, then only the value corresponding to that key will be retrieved. (The known string value is encoded as part of the pseudo-property)
211
215
*/
212
216
private class MapGet extends CollectionFlowStep , DataFlow:: MethodCallNode {
213
217
MapGet ( ) { this .getMethodName ( ) = "get" }
214
218
215
- override predicate load ( DataFlow:: Node obj , DataFlow:: Node element , string prop ) {
219
+ override predicate load ( DataFlow:: Node obj , DataFlow:: Node element , PseudoProperty prop ) {
216
220
obj = this .getReceiver ( ) and
217
221
element = this and
218
222
prop = mapValue ( this .getArgument ( 0 ) )
@@ -228,15 +232,23 @@ private module CollectionDataFlow {
228
232
* then the value will be saved into a pseudo-property corresponding to the known string value.
229
233
* The value will additionally be saved into a pseudo-property corresponding to values with unknown keys.
230
234
*/
231
- private class MapSet extends CollectionFlowStep , DataFlow:: MethodCallNode {
235
+ class MapSet extends CollectionFlowStep , DataFlow:: MethodCallNode {
232
236
MapSet ( ) { this .getMethodName ( ) = "set" }
233
237
234
- override predicate store ( DataFlow:: Node element , DataFlow:: Node obj , string prop ) {
238
+ override predicate store ( DataFlow:: Node element , DataFlow:: Node obj , PseudoProperty prop ) {
235
239
obj = this .getReceiver ( ) .getALocalSource ( ) and
236
240
element = this .getArgument ( 1 ) and
237
- // Makes sure that both known and unknown gets will work.
238
- prop = [ mapValue ( this .getArgument ( 0 ) ) , mapValueUnknownKey ( ) ]
241
+ prop = getAPseudoProperty ( )
239
242
}
243
+
244
+ /**
245
+ * Gets a pseudo-property used to store an element in a map.
246
+ * The pseudo-property represents both values where the key is a known string value (which is encoded in the pseudo-property),
247
+ * and values where the key is unknown.
248
+ *
249
+ * The return-type is `string` as this predicate is used to define which pseudo-properties exist.
250
+ */
251
+ string getAPseudoProperty ( ) { result = [ mapValue ( this .getArgument ( 0 ) ) , mapValueUnknownKey ( ) ] }
240
252
}
241
253
242
254
/**
@@ -246,7 +258,7 @@ private module CollectionDataFlow {
246
258
MapAndSetValues ( ) { this .getMethodName ( ) = "values" }
247
259
248
260
override predicate loadStore (
249
- DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
261
+ DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty fromProp , PseudoProperty toProp
250
262
) {
251
263
pred = this .getReceiver ( ) and
252
264
succ = this and
@@ -262,7 +274,7 @@ private module CollectionDataFlow {
262
274
SetKeys ( ) { this .getMethodName ( ) = "keys" }
263
275
264
276
override predicate loadStore (
265
- DataFlow:: Node pred , DataFlow:: Node succ , string fromProp , string toProp
277
+ DataFlow:: Node pred , DataFlow:: Node succ , PseudoProperty fromProp , PseudoProperty toProp
266
278
) {
267
279
pred = this .getReceiver ( ) and
268
280
succ = this and
0 commit comments