@@ -106,7 +106,11 @@ private predicate summarizedLocalStep(Node nodeFrom, Node nodeTo) {
106106}
107107
108108/** Holds if there is a level step from `nodeFrom` to `nodeTo`. */
109- predicate levelStep ( Node nodeFrom , Node nodeTo ) { summarizedLocalStep ( nodeFrom , nodeTo ) }
109+ predicate levelStep ( Node nodeFrom , Node nodeTo ) {
110+ summarizedLocalStep ( nodeFrom , nodeTo )
111+ or
112+ TypeTrackingStep:: step ( nodeFrom , nodeTo )
113+ }
110114
111115pragma [ noinline]
112116private predicate argumentPositionMatch (
@@ -235,6 +239,8 @@ predicate basicStoreStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet conten
235239 not exists ( pair .getKey ( ) .getConstantValue ( ) ) and
236240 contents .isAnyElement ( )
237241 )
242+ or
243+ TypeTrackingStep:: storeStep ( nodeFrom , nodeTo , contents )
238244}
239245
240246private predicate hashLiteralStore ( DataFlow:: CallNode hashCreation , DataFlow:: Node argument ) {
@@ -280,6 +286,8 @@ predicate basicLoadStep(Node nodeFrom, Node nodeTo, DataFlow::ContentSet content
280286 nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
281287 nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
282288 )
289+ or
290+ TypeTrackingStep:: loadStep ( nodeFrom , nodeTo , contents )
283291}
284292
285293/**
@@ -298,6 +306,8 @@ predicate basicLoadStoreStep(
298306 nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
299307 nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
300308 )
309+ or
310+ TypeTrackingStep:: loadStoreStep ( nodeFrom , nodeTo , loadContent , storeContent )
301311}
302312
303313/**
@@ -314,6 +324,8 @@ predicate basicWithoutContentStep(Node nodeFrom, Node nodeTo, ContentFilter filt
314324 nodeFrom = evaluateSummaryComponentStackLocal ( callable , call , input ) and
315325 nodeTo = evaluateSummaryComponentStackLocal ( callable , call , output )
316326 )
327+ or
328+ TypeTrackingStep:: withoutContentStep ( nodeFrom , nodeTo , filter )
317329}
318330
319331/**
@@ -338,6 +350,8 @@ predicate basicWithContentStep(Node nodeFrom, Node nodeTo, ContentFilter filter)
338350 nodeFrom .asExpr ( ) = node .asExpr ( ) .( Cfg:: CfgNodes:: ExprNodes:: UnaryOperationCfgNode ) .getOperand ( ) and
339351 filter = MkElementFilter ( )
340352 )
353+ or
354+ TypeTrackingStep:: withContentStep ( nodeFrom , nodeTo , filter )
341355}
342356
343357/**
@@ -562,3 +576,100 @@ private DataFlow::Node evaluateSummaryComponentStackLocal(
562576 )
563577 )
564578}
579+
580+ private newtype TUnit = MkUnit ( )
581+
582+ /**
583+ * A data flow edge that should be followed by type tracking.
584+ *
585+ * This type of edge does not affect the local data flow graph, and is not used by data-flow configurations.
586+ *
587+ * Note: For performance reasons, all subclasses of this class should be part
588+ * of the standard library, and their implementations may not depend on API graphs.
589+ * For query-specific steps, consider including the custom steps in the type-tracking predicate itself.
590+ */
591+ class TypeTrackingStep extends TUnit {
592+ /** Gets the string `"unit"`. */
593+ string toString ( ) { result = "unit" }
594+
595+ /**
596+ * Holds if type-tracking should step from `pred` to `succ`.
597+ */
598+ predicate step ( Node pred , Node succ ) { none ( ) }
599+
600+ /**
601+ * Holds if type-tracking should step from `pred` into the `content` of `succ`.
602+ */
603+ predicate storeStep ( Node pred , TypeTrackingNode succ , TypeTrackerContent content ) { none ( ) }
604+
605+ /**
606+ * Holds if type-tracking should step from the `content` of `pred` to `succ`.
607+ */
608+ predicate loadStep ( Node pred , Node succ , TypeTrackerContent content ) { none ( ) }
609+
610+ /**
611+ * Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`.
612+ */
613+ predicate loadStoreStep (
614+ Node pred , TypeTrackingNode succ , TypeTrackerContent loadContent ,
615+ TypeTrackerContent storeContent
616+ ) {
617+ none ( )
618+ }
619+
620+ /**
621+ * Holds if type-tracking should step from `pred` to `succ` but block flow of contents matched by `filter` through here.
622+ */
623+ predicate withoutContentStep ( Node pred , Node succ , ContentFilter filter ) { none ( ) }
624+
625+ /**
626+ * Holds if type-tracking should step from `pred` to `succ` if inside a content matched by `filter`.
627+ */
628+ predicate withContentStep ( Node pred , Node succ , ContentFilter filter ) { none ( ) }
629+ }
630+
631+ /** Provides access to the steps contributed by subclasses of `SharedTypeTrackingStep`. */
632+ module TypeTrackingStep {
633+ /**
634+ * Holds if type-tracking should step from `pred` to `succ`.
635+ */
636+ predicate step ( Node pred , Node succ ) { any ( TypeTrackingStep st ) .step ( pred , succ ) }
637+
638+ /**
639+ * Holds if type-tracking should step from `pred` into the `content` of `succ`.
640+ */
641+ predicate storeStep ( Node pred , TypeTrackingNode succ , TypeTrackerContent content ) {
642+ any ( TypeTrackingStep st ) .storeStep ( pred , succ , content )
643+ }
644+
645+ /**
646+ * Holds if type-tracking should step from the `content` of `pred` to `succ`.
647+ */
648+ predicate loadStep ( Node pred , Node succ , TypeTrackerContent content ) {
649+ any ( TypeTrackingStep st ) .loadStep ( pred , succ , content )
650+ }
651+
652+ /**
653+ * Holds if type-tracking should step from the `loadContent` of `pred` to the `storeContent` in `succ`.
654+ */
655+ predicate loadStoreStep (
656+ Node pred , TypeTrackingNode succ , TypeTrackerContent loadContent ,
657+ TypeTrackerContent storeContent
658+ ) {
659+ any ( TypeTrackingStep st ) .loadStoreStep ( pred , succ , loadContent , storeContent )
660+ }
661+
662+ /**
663+ * Holds if type-tracking should step from `pred` to `succ` but block flow of contents matched by `filter` through here.
664+ */
665+ predicate withoutContentStep ( Node pred , Node succ , ContentFilter filter ) {
666+ any ( TypeTrackingStep st ) .withoutContentStep ( pred , succ , filter )
667+ }
668+
669+ /**
670+ * Holds if type-tracking should step from `pred` to `succ` if inside a content matched by `filter`.
671+ */
672+ predicate withContentStep ( Node pred , Node succ , ContentFilter filter ) {
673+ any ( TypeTrackingStep st ) .withContentStep ( pred , succ , filter )
674+ }
675+ }
0 commit comments