@@ -624,6 +624,12 @@ module RustDataFlow implements InputSig<Location> {
624624 model = ""
625625 or
626626 LocalFlow:: flowSummaryLocalStep ( nodeFrom , nodeTo , model )
627+ or
628+ // Add flow through optional barriers. This step is then blocked by the barrier for queries that choose to use the barrier.
629+ FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( nodeFrom
630+ .( Node:: FlowSummaryNode )
631+ .getSummaryNode ( ) , TOptionalBarrier ( _) , nodeTo .( Node:: FlowSummaryNode ) .getSummaryNode ( ) ) and
632+ model = ""
627633 }
628634
629635 /**
@@ -753,7 +759,17 @@ module RustDataFlow implements InputSig<Location> {
753759 )
754760 or
755761 FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , cs ,
756- node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
762+ node2 .( FlowSummaryNode ) .getSummaryNode ( ) ) and
763+ not isSpecialContentSet ( cs )
764+ }
765+
766+ /**
767+ * Holds if `cs` is used to encode a special operation as a content component, but should not
768+ * be treated as an ordinary content component.
769+ */
770+ private predicate isSpecialContentSet ( ContentSet cs ) {
771+ cs instanceof TOptionalStep or
772+ cs instanceof TOptionalBarrier
757773 }
758774
759775 pragma [ nomagic]
@@ -850,7 +866,8 @@ module RustDataFlow implements InputSig<Location> {
850866 storeContentStep ( node1 , cs .( SingletonContentSet ) .getContent ( ) , node2 )
851867 or
852868 FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , cs ,
853- node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
869+ node2 .( FlowSummaryNode ) .getSummaryNode ( ) ) and
870+ not isSpecialContentSet ( cs )
854871 }
855872
856873 /**
@@ -1136,7 +1153,14 @@ private module Cached {
11361153 newtype TReturnKind = TNormalReturnKind ( )
11371154
11381155 cached
1139- newtype TContentSet = TSingletonContentSet ( Content c )
1156+ newtype TContentSet =
1157+ TSingletonContentSet ( Content c ) or
1158+ TOptionalStep ( string name ) {
1159+ name = any ( FlowSummaryImpl:: Private:: AccessPathToken tok ) .getAnArgument ( "OptionalStep" )
1160+ } or
1161+ TOptionalBarrier ( string name ) {
1162+ name = any ( FlowSummaryImpl:: Private:: AccessPathToken tok ) .getAnArgument ( "OptionalBarrier" )
1163+ }
11401164
11411165 /** Holds if `n` is a flow source of kind `kind`. */
11421166 cached
@@ -1145,6 +1169,27 @@ private module Cached {
11451169 /** Holds if `n` is a flow sink of kind `kind`. */
11461170 cached
11471171 predicate sinkNode ( Node n , string kind ) { n .( FlowSummaryNode ) .isSink ( kind , _) }
1172+
1173+ /**
1174+ * A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means
1175+ * that by default the step is not present in the flow summary and needs to be explicitly enabled by defining
1176+ * an additional flow step.
1177+ */
1178+ cached
1179+ predicate optionalStep ( Node node1 , string name , Node node2 ) {
1180+ FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) ,
1181+ TOptionalStep ( name ) , node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
1182+ }
1183+
1184+ /**
1185+ * A step in a flow summary defined using `OptionalBarrier[name]`. An `OptionalBarrier` is "opt-out", by default
1186+ * data can flow freely through the step. Flow through the step can be explicity blocked by defining its node as a barrier.
1187+ */
1188+ cached
1189+ predicate optionalBarrier ( Node node , string name ) {
1190+ FlowSummaryImpl:: Private:: Steps:: summaryReadStep ( _, TOptionalBarrier ( name ) ,
1191+ node .( FlowSummaryNode ) .getSummaryNode ( ) )
1192+ }
11481193}
11491194
11501195import Cached
0 commit comments