@@ -105,7 +105,11 @@ private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) {
105
105
}
106
106
107
107
/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */
108
- predicate levelStep ( Node nodeFrom , Node nodeTo ) { summarizedLocalStep ( nodeFrom , nodeTo ) }
108
+ predicate levelStep ( Node nodeFrom , Node nodeTo ) {
109
+ summarizedLocalStep ( nodeFrom , nodeTo )
110
+ or
111
+ TypeTrackingStep:: step ( nodeFrom , nodeTo )
112
+ }
109
113
110
114
pragma [ noinline]
111
115
private predicate argumentPositionMatch (
@@ -234,6 +238,8 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet conten
234
238
not exists ( pair .getKey ( ) .getConstantValue ( ) ) and
235
239
contents .isAnyElement ( )
236
240
)
241
+ or
242
+ TypeTrackingStep:: storeStep ( nodeFrom , nodeTo , contents )
237
243
}
238
244
239
245
private predicate hashLiteralStore ( DataFlow:: CallNode hashCreation , DataFlow:: Node argument ) {
@@ -279,6 +285,8 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet content
279
285
nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
280
286
nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
281
287
)
288
+ or
289
+ TypeTrackingStep:: loadStep ( nodeFrom , nodeTo , contents )
282
290
}
283
291
284
292
/**
@@ -297,6 +305,8 @@ predicate basicLoadStoreStep(
297
305
nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
298
306
nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
299
307
)
308
+ or
309
+ TypeTrackingStep:: loadStoreStep ( nodeFrom , nodeTo , loadContent , storeContent )
300
310
}
301
311
302
312
predicate basicWithoutContentStep ( Node nodeFrom , Node nodeTo , ContentFilter filter ) {
@@ -310,6 +320,8 @@ predicate basicWithoutContentStep(Node nodeFrom, Node nodeTo, ContentFilter filt
310
320
nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
311
321
nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
312
322
)
323
+ or
324
+ TypeTrackingStep:: withoutContentStep ( nodeFrom , nodeTo , filter )
313
325
}
314
326
315
327
predicate basicWithContentStep ( Node nodeFrom , Node nodeTo , ContentFilter filter ) {
@@ -331,6 +343,8 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter)
331
343
nodeFrom .asExpr ( ) = node .asExpr ( ) .( Cfg:: CfgNodes:: ExprNodes:: UnaryOperationCfgNode ) .getOperand ( ) and
332
344
filter = MkElementFilter ( )
333
345
)
346
+ or
347
+ TypeTrackingStep:: withContentStep ( nodeFrom , nodeTo , filter )
334
348
}
335
349
336
350
/**
@@ -555,3 +569,104 @@ private DataFlow::Node evaluateSummaryComponentStackLocal(
555
569
)
556
570
)
557
571
}
572
+
573
+ private newtype TUnit = MkUnit ( )
574
+
575
+ /**
576
+ * A data flow edge that should be followed by type tracking.
577
+ *
578
+ * This type of edge does not affect the local data flow graph, and is not used by data-flow configurations.
579
+ *
580
+ * Note: For performance reasons, all subclasses of this class should be part
581
+ * of the standard library, and their implementations may not depend on API graphs.
582
+ * For query-specific steps, consider including the custom steps in the type-tracking predicate itself.
583
+ */
584
+ class TypeTrackingStep extends TUnit {
585
+ /** Gets the string `"unit"`. */
586
+ string toString ( ) { result = "unit" }
587
+
588
+ /**
589
+ * Holds if type-tracking should step from `pred` to `succ`.
590
+ */
591
+ predicate step ( Node pred , Node succ ) { none ( ) }
592
+
593
+ /**
594
+ * Holds if type-tracking should step from `pred` into the `content` of `succ`.
595
+ */
596
+ predicate storeStep ( Node pred , TypeTrackingNode succ , TypeTrackerContent content ) { none ( ) }
597
+
598
+ /**
599
+ * Holds if type-tracking should step from the `content` of `pred` to `succ`.
600
+ */
601
+ predicate loadStep ( Node pred , Node succ , TypeTrackerContent content ) { none ( ) }
602
+
603
+ /**
604
+ * Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`.
605
+ */
606
+ predicate loadStoreStep (
607
+ Node pred , TypeTrackingNode succ , TypeTrackerContent loadContent ,
608
+ TypeTrackerContent storeContent
609
+ ) {
610
+ none ( )
611
+ }
612
+
613
+ /**
614
+ * Holds if type-tracking should step from `pred` to `succ` but block flow of `props` through here.
615
+ *
616
+ * This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
617
+ */
618
+ predicate withoutContentStep ( Node pred , Node succ , ContentFilter filter ) { none ( ) }
619
+
620
+ /**
621
+ * Holds if type-tracking should step from `pred` to `succ` but block flow of `props` through here.
622
+ *
623
+ * This can be seen as taking a copy of the value in `pred` but without the properties in `props`.
624
+ */
625
+ predicate withContentStep ( Node pred , Node succ , ContentFilter filter ) { none ( ) }
626
+ }
627
+
628
+ /** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
629
+ module TypeTrackingStep {
630
+ /**
631
+ * Holds if type-tracking should step from `pred` to `succ`.
632
+ */
633
+ predicate step ( Node pred , Node succ ) { any ( TypeTrackingStep st ) .step ( pred , succ ) }
634
+
635
+ /**
636
+ * Holds if type-tracking should step from `pred` into the `content` of `succ`.
637
+ */
638
+ predicate storeStep ( Node pred , TypeTrackingNode succ , TypeTrackerContent content ) {
639
+ any ( TypeTrackingStep st ) .storeStep ( pred , succ , content )
640
+ }
641
+
642
+ /**
643
+ * Holds if type-tracking should step from the `content` of `pred` to `succ`.
644
+ */
645
+ predicate loadStep ( Node pred , Node succ , TypeTrackerContent content ) {
646
+ any ( TypeTrackingStep st ) .loadStep ( pred , succ , content )
647
+ }
648
+
649
+ /**
650
+ * Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`.
651
+ */
652
+ predicate loadStoreStep (
653
+ Node pred , TypeTrackingNode succ , TypeTrackerContent loadContent ,
654
+ TypeTrackerContent storeContent
655
+ ) {
656
+ any ( TypeTrackingStep st ) .loadStoreStep ( pred , succ , loadContent , storeContent )
657
+ }
658
+
659
+ /**
660
+ * Holds if type-tracking should step from `pred` to `succ` but block flow of contents matched by `filter` through here.
661
+ */
662
+ predicate withoutContentStep ( Node pred , Node succ , ContentFilter filter ) {
663
+ any ( TypeTrackingStep st ) .withoutContentStep ( pred , succ , filter )
664
+ }
665
+
666
+ /**
667
+ * Holds if type-tracking should step from `pred` to `succ` if inside a content matched by `filter`.
668
+ */
669
+ predicate withContentStep ( Node pred , Node succ , ContentFilter filter ) {
670
+ any ( TypeTrackingStep st ) .withContentStep ( pred , succ , filter )
671
+ }
672
+ }
0 commit comments