2
2
3
3
private import TypeTrackerSpecific
4
4
5
- /**
6
- * A string that may appear as the name of a piece of content. This will usually include things like:
7
- * - Attribute names (in Python)
8
- * - Property names (in JavaScript)
9
- *
10
- * In general, this can also be used to model things like stores to specific list indices. To ensure
11
- * correctness, it is important that
12
- *
13
- * - different types of content do not have overlapping names, and
14
- * - the empty string `""` is not a valid piece of content, as it is used to indicate the absence of
15
- * content instead.
16
- */
17
- class ContentName extends string {
18
- ContentName ( ) { this = getPossibleContentName ( ) }
19
- }
20
-
21
- /** A content name, or the empty string (representing no content). */
22
- class OptionalContentName extends string {
23
- OptionalContentName ( ) { this instanceof ContentName or this = "" }
24
- }
25
-
26
5
cached
27
6
private module Cached {
28
7
/**
@@ -33,48 +12,78 @@ private module Cached {
33
12
LevelStep ( ) or
34
13
CallStep ( ) or
35
14
ReturnStep ( ) or
36
- StoreStep ( ContentName content ) or
37
- LoadStep ( ContentName content ) or
15
+ StoreStep ( TypeTrackerContent content ) { basicStoreStep ( _ , _ , content ) } or
16
+ LoadStep ( TypeTrackerContent content ) { basicLoadStep ( _ , _ , content ) } or
38
17
JumpStep ( )
39
18
19
+ pragma [ nomagic]
20
+ private TypeTracker noContentTypeTracker ( boolean hasCall ) {
21
+ result = MkTypeTracker ( hasCall , noContent ( ) )
22
+ }
23
+
40
24
/** Gets the summary resulting from appending `step` to type-tracking summary `tt`. */
41
25
cached
42
26
TypeTracker append ( TypeTracker tt , StepSummary step ) {
43
- exists ( Boolean hasCall , OptionalContentName content | tt = MkTypeTracker ( hasCall , content ) |
27
+ exists ( Boolean hasCall , OptionalTypeTrackerContent currentContents |
28
+ tt = MkTypeTracker ( hasCall , currentContents )
29
+ |
44
30
step = LevelStep ( ) and result = tt
45
31
or
46
- step = CallStep ( ) and result = MkTypeTracker ( true , content )
32
+ step = CallStep ( ) and result = MkTypeTracker ( true , currentContents )
47
33
or
48
34
step = ReturnStep ( ) and hasCall = false and result = tt
49
35
or
50
- step = LoadStep ( content ) and result = MkTypeTracker ( hasCall , "" )
51
- or
52
- exists ( string p | step = StoreStep ( p ) and content = "" and result = MkTypeTracker ( hasCall , p ) )
53
- or
54
36
step = JumpStep ( ) and
55
- result = MkTypeTracker ( false , content )
37
+ result = MkTypeTracker ( false , currentContents )
38
+ )
39
+ or
40
+ exists ( TypeTrackerContent storeContents , boolean hasCall |
41
+ exists ( TypeTrackerContent loadContents |
42
+ step = LoadStep ( pragma [ only_bind_into ] ( loadContents ) ) and
43
+ tt = MkTypeTracker ( hasCall , storeContents ) and
44
+ compatibleContents ( storeContents , loadContents ) and
45
+ result = noContentTypeTracker ( hasCall )
46
+ )
47
+ or
48
+ step = StoreStep ( pragma [ only_bind_into ] ( storeContents ) ) and
49
+ tt = noContentTypeTracker ( hasCall ) and
50
+ result = MkTypeTracker ( hasCall , storeContents )
56
51
)
57
52
}
58
53
54
+ pragma [ nomagic]
55
+ private TypeBackTracker noContentTypeBackTracker ( boolean hasReturn ) {
56
+ result = MkTypeBackTracker ( hasReturn , noContent ( ) )
57
+ }
58
+
59
59
/** Gets the summary resulting from prepending `step` to this type-tracking summary. */
60
60
cached
61
61
TypeBackTracker prepend ( TypeBackTracker tbt , StepSummary step ) {
62
- exists ( Boolean hasReturn , string content | tbt = MkTypeBackTracker ( hasReturn , content ) |
62
+ exists ( Boolean hasReturn , OptionalTypeTrackerContent content |
63
+ tbt = MkTypeBackTracker ( hasReturn , content )
64
+ |
63
65
step = LevelStep ( ) and result = tbt
64
66
or
65
67
step = CallStep ( ) and hasReturn = false and result = tbt
66
68
or
67
69
step = ReturnStep ( ) and result = MkTypeBackTracker ( true , content )
68
70
or
69
- exists ( string p |
70
- step = LoadStep ( p ) and content = "" and result = MkTypeBackTracker ( hasReturn , p )
71
- )
72
- or
73
- step = StoreStep ( content ) and result = MkTypeBackTracker ( hasReturn , "" )
74
- or
75
71
step = JumpStep ( ) and
76
72
result = MkTypeBackTracker ( false , content )
77
73
)
74
+ or
75
+ exists ( TypeTrackerContent loadContents , boolean hasReturn |
76
+ exists ( TypeTrackerContent storeContents |
77
+ step = StoreStep ( pragma [ only_bind_into ] ( storeContents ) ) and
78
+ tbt = MkTypeBackTracker ( hasReturn , loadContents ) and
79
+ compatibleContents ( storeContents , loadContents ) and
80
+ result = noContentTypeBackTracker ( hasReturn )
81
+ )
82
+ or
83
+ step = LoadStep ( pragma [ only_bind_into ] ( loadContents ) ) and
84
+ tbt = noContentTypeBackTracker ( hasReturn ) and
85
+ result = MkTypeBackTracker ( hasReturn , loadContents )
86
+ )
78
87
}
79
88
80
89
/**
@@ -114,9 +123,9 @@ class StepSummary extends TStepSummary {
114
123
or
115
124
this instanceof ReturnStep and result = "return"
116
125
or
117
- exists ( string content | this = StoreStep ( content ) | result = "store " + content )
126
+ exists ( TypeTrackerContent content | this = StoreStep ( content ) | result = "store " + content )
118
127
or
119
- exists ( string content | this = LoadStep ( content ) | result = "load " + content )
128
+ exists ( TypeTrackerContent content | this = LoadStep ( content ) | result = "load " + content )
120
129
or
121
130
this instanceof JumpStep and result = "jump"
122
131
}
@@ -130,7 +139,7 @@ private predicate smallstepNoCall(Node nodeFrom, TypeTrackingNode nodeTo, StepSu
130
139
levelStep ( nodeFrom , nodeTo ) and
131
140
summary = LevelStep ( )
132
141
or
133
- exists ( string content |
142
+ exists ( TypeTrackerContent content |
134
143
StepSummary:: localSourceStoreStep ( nodeFrom , nodeTo , content ) and
135
144
summary = StoreStep ( content )
136
145
or
@@ -180,7 +189,7 @@ module StepSummary {
180
189
}
181
190
182
191
/**
183
- * Holds if `nodeFrom` is being written to the `content` content of the object in `nodeTo`.
192
+ * Holds if `nodeFrom` is being written to the `content` of the object in `nodeTo`.
184
193
*
185
194
* Note that `nodeTo` will always be a local source node that flows to the place where the content
186
195
* is written in `basicStoreStep`. This may lead to the flow of information going "back in time"
@@ -204,12 +213,23 @@ module StepSummary {
204
213
* function. This means we will track the fact that `x.attr` can have the type of `y` into the
205
214
* assignment to `z` inside `bar`, even though this attribute write happens _after_ `bar` is called.
206
215
*/
207
- predicate localSourceStoreStep ( Node nodeFrom , TypeTrackingNode nodeTo , string content ) {
216
+ predicate localSourceStoreStep ( Node nodeFrom , TypeTrackingNode nodeTo , TypeTrackerContent content ) {
208
217
exists ( Node obj | nodeTo .flowsTo ( obj ) and basicStoreStep ( nodeFrom , obj , content ) )
209
218
}
210
219
}
211
220
212
- private newtype TTypeTracker = MkTypeTracker ( Boolean hasCall , OptionalContentName content )
221
+ private newtype TTypeTracker =
222
+ MkTypeTracker ( Boolean hasCall , OptionalTypeTrackerContent content ) {
223
+ content = noContent ( )
224
+ or
225
+ // Restrict `content` to those that might eventually match a load.
226
+ // We can't rely on `basicStoreStep` since `startInContent` might be used with
227
+ // a content that has no corresponding store.
228
+ exists ( TypeTrackerContent loadContents |
229
+ basicLoadStep ( _, _, loadContents ) and
230
+ compatibleContents ( content , loadContents )
231
+ )
232
+ }
213
233
214
234
/**
215
235
* A summary of the steps needed to track a value to a given dataflow node.
@@ -240,7 +260,7 @@ private newtype TTypeTracker = MkTypeTracker(Boolean hasCall, OptionalContentNam
240
260
*/
241
261
class TypeTracker extends TTypeTracker {
242
262
Boolean hasCall ;
243
- OptionalContentName content ;
263
+ OptionalTypeTrackerContent content ;
244
264
245
265
TypeTracker ( ) { this = MkTypeTracker ( hasCall , content ) }
246
266
@@ -251,32 +271,38 @@ class TypeTracker extends TTypeTracker {
251
271
string toString ( ) {
252
272
exists ( string withCall , string withContent |
253
273
( if hasCall = true then withCall = "with" else withCall = "without" ) and
254
- ( if content != "" then withContent = " with content " + content else withContent = "" ) and
274
+ (
275
+ if content != noContent ( )
276
+ then withContent = " with content " + content
277
+ else withContent = ""
278
+ ) and
255
279
result = "type tracker " + withCall + " call steps" + withContent
256
280
)
257
281
}
258
282
259
283
/**
260
284
* Holds if this is the starting point of type tracking.
261
285
*/
262
- predicate start ( ) { hasCall = false and content = "" }
286
+ predicate start ( ) { hasCall = false and content = noContent ( ) }
263
287
264
288
/**
265
289
* Holds if this is the starting point of type tracking, and the value starts in the content named `contentName`.
266
290
* The type tracking only ends after the content has been loaded.
267
291
*/
268
- predicate startInContent ( ContentName contentName ) { hasCall = false and content = contentName }
292
+ predicate startInContent ( TypeTrackerContent contentName ) {
293
+ hasCall = false and content = contentName
294
+ }
269
295
270
296
/**
271
297
* Holds if this is the starting point of type tracking
272
298
* when tracking a parameter into a call, but not out of it.
273
299
*/
274
- predicate call ( ) { hasCall = true and content = "" }
300
+ predicate call ( ) { hasCall = true and content = noContent ( ) }
275
301
276
302
/**
277
303
* Holds if this is the end point of type tracking.
278
304
*/
279
- predicate end ( ) { content = "" }
305
+ predicate end ( ) { content = noContent ( ) }
280
306
281
307
/**
282
308
* INTERNAL. DO NOT USE.
@@ -290,15 +316,15 @@ class TypeTracker extends TTypeTracker {
290
316
*
291
317
* Gets the content associated with this type tracker.
292
318
*/
293
- string getContent ( ) { result = content }
319
+ OptionalTypeTrackerContent getContent ( ) { result = content }
294
320
295
321
/**
296
322
* Gets a type tracker that starts where this one has left off to allow continued
297
323
* tracking.
298
324
*
299
325
* This predicate is only defined if the type is not associated to a piece of content.
300
326
*/
301
- TypeTracker continue ( ) { content = "" and result = this }
327
+ TypeTracker continue ( ) { content = noContent ( ) and result = this }
302
328
303
329
/**
304
330
* Gets the summary that corresponds to having taken a forwards
@@ -356,7 +382,16 @@ module TypeTracker {
356
382
TypeTracker end ( ) { result .end ( ) }
357
383
}
358
384
359
- private newtype TTypeBackTracker = MkTypeBackTracker ( Boolean hasReturn , OptionalContentName content )
385
+ private newtype TTypeBackTracker =
386
+ MkTypeBackTracker ( Boolean hasReturn , OptionalTypeTrackerContent content ) {
387
+ content = noContent ( )
388
+ or
389
+ // As in MkTypeTracker, restrict `content` to those that might eventually match a store.
390
+ exists ( TypeTrackerContent storeContent |
391
+ basicStoreStep ( _, _, storeContent ) and
392
+ compatibleContents ( storeContent , content )
393
+ )
394
+ }
360
395
361
396
/**
362
397
* A summary of the steps needed to back-track a use of a value to a given dataflow node.
@@ -390,7 +425,7 @@ private newtype TTypeBackTracker = MkTypeBackTracker(Boolean hasReturn, Optional
390
425
*/
391
426
class TypeBackTracker extends TTypeBackTracker {
392
427
Boolean hasReturn ;
393
- string content ;
428
+ OptionalTypeTrackerContent content ;
394
429
395
430
TypeBackTracker ( ) { this = MkTypeBackTracker ( hasReturn , content ) }
396
431
@@ -401,20 +436,24 @@ class TypeBackTracker extends TTypeBackTracker {
401
436
string toString ( ) {
402
437
exists ( string withReturn , string withContent |
403
438
( if hasReturn = true then withReturn = "with" else withReturn = "without" ) and
404
- ( if content != "" then withContent = " with content " + content else withContent = "" ) and
439
+ (
440
+ if content != noContent ( )
441
+ then withContent = " with content " + content
442
+ else withContent = ""
443
+ ) and
405
444
result = "type back-tracker " + withReturn + " return steps" + withContent
406
445
)
407
446
}
408
447
409
448
/**
410
449
* Holds if this is the starting point of type tracking.
411
450
*/
412
- predicate start ( ) { hasReturn = false and content = "" }
451
+ predicate start ( ) { hasReturn = false and content = noContent ( ) }
413
452
414
453
/**
415
454
* Holds if this is the end point of type tracking.
416
455
*/
417
- predicate end ( ) { content = "" }
456
+ predicate end ( ) { content = noContent ( ) }
418
457
419
458
/**
420
459
* INTERNAL. DO NOT USE.
@@ -429,7 +468,7 @@ class TypeBackTracker extends TTypeBackTracker {
429
468
*
430
469
* This predicate is only defined if the type has not been tracked into a piece of content.
431
470
*/
432
- TypeBackTracker continue ( ) { content = "" and result = this }
471
+ TypeBackTracker continue ( ) { content = noContent ( ) and result = this }
433
472
434
473
/**
435
474
* Gets the summary that corresponds to having taken a backwards
0 commit comments