@@ -581,6 +581,12 @@ module RustDataFlow implements InputSig<Location> {
581581 model = ""
582582 or
583583 LocalFlow:: flowSummaryLocalStep ( nodeFrom , nodeTo , model )
584+ or
585+ // Add flow through optional barriers. This step is then blocked by the barrier for queries that choose to use the barrier.
586+ FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( nodeFrom
587+ .( Node:: FlowSummaryNode )
588+ .getSummaryNode ( ) , TOptionalBarrier ( _) , nodeTo .( Node:: FlowSummaryNode ) .getSummaryNode ( ) ) and
589+ model = ""
584590 }
585591
586592 /**
@@ -710,7 +716,8 @@ module RustDataFlow implements InputSig<Location> {
710716 )
711717 or
712718 FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , cs ,
713- node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
719+ node2 .( FlowSummaryNode ) .getSummaryNode ( ) ) and
720+ not isSpecialContentSet ( cs )
714721 }
715722
716723 pragma [ nomagic]
@@ -807,7 +814,8 @@ module RustDataFlow implements InputSig<Location> {
807814 storeContentStep ( node1 , cs .( SingletonContentSet ) .getContent ( ) , node2 )
808815 or
809816 FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , cs ,
810- node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
817+ node2 .( FlowSummaryNode ) .getSummaryNode ( ) ) and
818+ not isSpecialContentSet ( cs )
811819 }
812820
813821 /**
@@ -1093,7 +1101,24 @@ private module Cached {
10931101 newtype TReturnKind = TNormalReturnKind ( )
10941102
10951103 cached
1096- newtype TContentSet = TSingletonContentSet ( Content c )
1104+ newtype TContentSet =
1105+ TSingletonContentSet ( Content c ) or
1106+ TOptionalStep ( string name ) {
1107+ name = any ( FlowSummaryImpl:: Private:: AccessPathToken tok ) .getAnArgument ( "OptionalStep" )
1108+ } or
1109+ TOptionalBarrier ( string name ) {
1110+ name = any ( FlowSummaryImpl:: Private:: AccessPathToken tok ) .getAnArgument ( "OptionalBarrier" )
1111+ }
1112+
1113+ /**
1114+ * Holds if `cs` is used to encode a special operation as a content component, but should not
1115+ * be treated as an ordinary content component.
1116+ */
1117+ cached
1118+ predicate isSpecialContentSet ( ContentSet cs ) {
1119+ cs instanceof TOptionalStep or
1120+ cs instanceof TOptionalBarrier
1121+ }
10971122
10981123 /** Holds if `n` is a flow source of kind `kind`. */
10991124 cached
@@ -1105,3 +1130,31 @@ private module Cached {
11051130}
11061131
11071132import Cached
1133+
1134+ cached
1135+ private module OptionalSteps {
1136+ /**
1137+ * A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means
1138+ * that by default the step is not present in the flow summary and needs to be explicitly enabled by defining
1139+ * an additional flow step.
1140+ */
1141+ cached
1142+ predicate optionalStep ( Node node1 , string name , Node node2 ) {
1143+ FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) ,
1144+ TOptionalStep ( name ) , node2 .( FlowSummaryNode ) .getSummaryNode ( ) ) or
1145+ FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) ,
1146+ TOptionalStep ( name ) , node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
1147+ }
1148+
1149+ /**
1150+ * A step in a flow summary defined using `OptionalBarrier[name]`. An `OptionalBarrier` is "opt-out", by default
1151+ * data can flow freely through the step. Flow through the step can be explicity blocked by defining its node as a barrier.
1152+ */
1153+ cached
1154+ predicate optionalBarrier ( Node node , string name ) {
1155+ FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( _, TOptionalBarrier ( name ) ,
1156+ node .( FlowSummaryNode ) .getSummaryNode ( ) )
1157+ }
1158+ }
1159+
1160+ import OptionalSteps
0 commit comments