@@ -624,6 +624,12 @@ module RustDataFlow implements InputSig<Location> {
624
624
model = ""
625
625
or
626
626
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 = ""
627
633
}
628
634
629
635
/**
@@ -753,7 +759,17 @@ module RustDataFlow implements InputSig<Location> {
753
759
)
754
760
or
755
761
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
757
773
}
758
774
759
775
pragma [ nomagic]
@@ -850,7 +866,8 @@ module RustDataFlow implements InputSig<Location> {
850
866
storeContentStep ( node1 , cs .( SingletonContentSet ) .getContent ( ) , node2 )
851
867
or
852
868
FlowSummaryImpl:: Private:: Steps:: summaryStoreStep ( node1 .( FlowSummaryNode ) .getSummaryNode ( ) , cs ,
853
- node2 .( FlowSummaryNode ) .getSummaryNode ( ) )
869
+ node2 .( FlowSummaryNode ) .getSummaryNode ( ) ) and
870
+ not isSpecialContentSet ( cs )
854
871
}
855
872
856
873
/**
@@ -1136,7 +1153,14 @@ private module Cached {
1136
1153
newtype TReturnKind = TNormalReturnKind ( )
1137
1154
1138
1155
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
+ }
1140
1164
1141
1165
/** Holds if `n` is a flow source of kind `kind`. */
1142
1166
cached
@@ -1145,6 +1169,27 @@ private module Cached {
1145
1169
/** Holds if `n` is a flow sink of kind `kind`. */
1146
1170
cached
1147
1171
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
+ }
1148
1193
}
1149
1194
1150
1195
import Cached
0 commit comments