@@ -27,6 +27,12 @@ import DataFlowImplSpecific::Public
2727 * // Optionally override `isAdditionalFlowStep`.
2828 * }
2929 * ```
30+ * Conceptually, this defines a graph where the nodes are `DataFlow::Node`s and
31+ * the edges are those data-flow steps that preserve the value of the node
32+ * along with any additional edges defined by `isAdditionalFlowStep`.
33+ * Specifying nodes in `isBarrier` will remove those nodes from the graph, and
34+ * specifying nodes in `isBarrierIn` and/or `isBarrierOut` will remove in-going
35+ * and/or out-going edges from those nodes, respectively.
3036 *
3137 * Then, to query whether there is flow between some `source` and `sink`,
3238 * write
@@ -54,11 +60,20 @@ abstract class Configuration extends string {
5460 */
5561 abstract predicate isSink ( Node sink ) ;
5662
57- /** Holds if data flow through `node` is prohibited. */
63+ /**
64+ * Holds if data flow through `node` is prohibited. This completely removes
65+ * `node` from the data flow graph.
66+ */
5867 predicate isBarrier ( Node node ) { none ( ) }
5968
60- /** Holds if data flow from `node1` to `node2` is prohibited. */
61- predicate isBarrierEdge ( Node node1 , Node node2 ) { none ( ) }
69+ /** DEPRECATED: override `isBarrierIn` and `isBarrierOut` instead. */
70+ deprecated predicate isBarrierEdge ( Node node1 , Node node2 ) { none ( ) }
71+
72+ /** Holds if data flow into `node` is prohibited. */
73+ predicate isBarrierIn ( Node node ) { none ( ) }
74+
75+ /** Holds if data flow out of `node` is prohibited. */
76+ predicate isBarrierOut ( Node node ) { none ( ) }
6277
6378 /**
6479 * Holds if the additional flow step from `node1` to `node2` must be taken
@@ -103,6 +118,26 @@ abstract class Configuration extends string {
103118 deprecated predicate hasFlowBackward ( Node source , Node sink ) { hasFlow ( source , sink ) }
104119}
105120
121+ private predicate inBarrier ( Node node , Configuration config ) {
122+ config .isBarrierIn ( node ) and
123+ config .isSource ( node )
124+ }
125+
126+ private predicate outBarrier ( Node node , Configuration config ) {
127+ config .isBarrierOut ( node ) and
128+ config .isSink ( node )
129+ }
130+
131+ private predicate fullBarrier ( Node node , Configuration config ) {
132+ config .isBarrier ( node )
133+ or
134+ config .isBarrierIn ( node ) and
135+ not config .isSource ( node )
136+ or
137+ config .isBarrierOut ( node ) and
138+ not config .isSink ( node )
139+ }
140+
106141private class AdditionalFlowStepSource extends Node {
107142 AdditionalFlowStepSource ( ) { any ( Configuration c ) .isAdditionalFlowStep ( this , _) }
108143}
@@ -119,22 +154,46 @@ private predicate isAdditionalFlowStep(
119154 * Holds if data can flow in one local step from `node1` to `node2`.
120155 */
121156private predicate localFlowStep ( Node node1 , Node node2 , Configuration config ) {
122- localFlowStep ( node1 , node2 ) and not config .isBarrierEdge ( node1 , node2 )
157+ localFlowStep ( node1 , node2 ) and
158+ not outBarrier ( node1 , config ) and
159+ not inBarrier ( node2 , config ) and
160+ not fullBarrier ( node1 , config ) and
161+ not fullBarrier ( node2 , config )
123162}
124163
125164/**
126165 * Holds if the additional step from `node1` to `node2` does not jump between callables.
127166 */
128167private predicate additionalLocalFlowStep ( Node node1 , Node node2 , Configuration config ) {
129- isAdditionalFlowStep ( node1 , node2 , node2 .getEnclosingCallable ( ) , config )
168+ isAdditionalFlowStep ( node1 , node2 , node2 .getEnclosingCallable ( ) , config ) and
169+ not outBarrier ( node1 , config ) and
170+ not inBarrier ( node2 , config ) and
171+ not fullBarrier ( node1 , config ) and
172+ not fullBarrier ( node2 , config )
173+ }
174+
175+ /**
176+ * Holds if data can flow from `node1` to `node2` in a way that discards call contexts.
177+ */
178+ private predicate jumpStep ( Node node1 , Node node2 , Configuration config ) {
179+ jumpStep ( node1 , node2 ) and
180+ not outBarrier ( node1 , config ) and
181+ not inBarrier ( node2 , config ) and
182+ not fullBarrier ( node1 , config ) and
183+ not fullBarrier ( node2 , config )
130184}
131185
132186/**
133187 * Holds if the additional step from `node1` to `node2` jumps between callables.
134188 */
135189private predicate additionalJumpStep ( Node node1 , Node node2 , Configuration config ) {
136- exists ( DataFlowCallable callable1 | isAdditionalFlowStep ( node1 , node2 , callable1 , config ) |
137- node2 .getEnclosingCallable ( ) != callable1
190+ exists ( DataFlowCallable callable1 |
191+ isAdditionalFlowStep ( node1 , node2 , callable1 , config ) and
192+ node2 .getEnclosingCallable ( ) != callable1 and
193+ not outBarrier ( node1 , config ) and
194+ not inBarrier ( node2 , config ) and
195+ not fullBarrier ( node1 , config ) and
196+ not fullBarrier ( node2 , config )
138197 )
139198}
140199
@@ -154,7 +213,7 @@ private ReturnPosition viableReturnPos(DataFlowCall call, ReturnKind kind) {
154213 * ignoring call contexts.
155214 */
156215private predicate nodeCandFwd1 ( Node node , boolean stored , Configuration config ) {
157- not config . isBarrier ( node ) and
216+ not fullBarrier ( node , config ) and
158217 (
159218 config .isSource ( node ) and stored = false
160219 or
@@ -171,7 +230,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
171230 or
172231 exists ( Node mid |
173232 nodeCandFwd1 ( mid , stored , config ) and
174- jumpStep ( mid , node )
233+ jumpStep ( mid , node , config )
175234 )
176235 or
177236 exists ( Node mid |
@@ -185,15 +244,17 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
185244 useFieldFlow ( config ) and
186245 nodeCandFwd1 ( mid , _, config ) and
187246 store ( mid , _, node ) and
188- stored = true
247+ stored = true and
248+ not outBarrier ( mid , config )
189249 )
190250 or
191251 // read
192252 exists ( Node mid , Content f |
193253 nodeCandFwd1 ( mid , true , config ) and
194254 read ( mid , f , node ) and
195255 storeCandFwd1 ( f , unbind ( config ) ) and
196- ( stored = false or stored = true )
256+ ( stored = false or stored = true ) and
257+ not inBarrier ( node , config )
197258 )
198259 or
199260 // flow into a callable
@@ -223,7 +284,7 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
223284 */
224285private predicate storeCandFwd1 ( Content f , Configuration config ) {
225286 exists ( Node mid , Node node |
226- not config . isBarrier ( node ) and
287+ not fullBarrier ( node , config ) and
227288 useFieldFlow ( config ) and
228289 nodeCandFwd1 ( mid , _, config ) and
229290 store ( mid , f , node )
@@ -257,7 +318,7 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) {
257318 )
258319 or
259320 exists ( Node mid |
260- jumpStep ( node , mid ) and
321+ jumpStep ( node , mid , config ) and
261322 nodeCand1 ( mid , stored , config )
262323 )
263324 or
@@ -318,6 +379,13 @@ private predicate readCand1(Content f, Configuration config) {
318379 )
319380}
320381
382+ private predicate throughFlowNodeCand ( Node node , Configuration config ) {
383+ nodeCand1 ( node , false , config ) and
384+ not fullBarrier ( node , config ) and
385+ not inBarrier ( node , config ) and
386+ not outBarrier ( node , config )
387+ }
388+
321389/**
322390 * Holds if there is a path from `p` to `node` in the same callable that is
323391 * part of a path from a source to a sink taking simple call contexts into
@@ -329,7 +397,7 @@ pragma[nomagic]
329397private predicate simpleParameterFlow (
330398 ParameterNode p , Node node , DataFlowType t , Configuration config
331399) {
332- nodeCand1 ( node , false , config ) and
400+ throughFlowNodeCand ( node , config ) and
333401 p = node and
334402 t = getErasedRepr ( node .getType ( ) ) and
335403 exists ( ReturnNode ret , ReturnKind kind |
@@ -338,37 +406,37 @@ private predicate simpleParameterFlow(
338406 not parameterValueFlowsThrough ( p , kind , _)
339407 )
340408 or
341- nodeCand1 ( node , false , unbind ( config ) ) and
409+ throughFlowNodeCand ( node , unbind ( config ) ) and
342410 exists ( Node mid |
343411 simpleParameterFlow ( p , mid , t , config ) and
344412 localFlowStep ( mid , node , config ) and
345413 compatibleTypes ( t , node .getType ( ) )
346414 )
347415 or
348- nodeCand1 ( node , false , unbind ( config ) ) and
416+ throughFlowNodeCand ( node , unbind ( config ) ) and
349417 exists ( Node mid |
350418 simpleParameterFlow ( p , mid , _, config ) and
351419 additionalLocalFlowStep ( mid , node , config ) and
352420 t = getErasedRepr ( node .getType ( ) )
353421 )
354422 or
355- nodeCand1 ( node , false , unbind ( config ) ) and
423+ throughFlowNodeCand ( node , unbind ( config ) ) and
356424 exists ( Node mid |
357425 simpleParameterFlow ( p , mid , t , config ) and
358426 localStoreReadStep ( mid , node ) and
359427 compatibleTypes ( t , node .getType ( ) )
360428 )
361429 or
362430 // value flow through a callable
363- nodeCand1 ( node , false , unbind ( config ) ) and
431+ throughFlowNodeCand ( node , unbind ( config ) ) and
364432 exists ( Node arg |
365433 simpleParameterFlow ( p , arg , t , config ) and
366434 argumentValueFlowsThrough ( arg , node , _) and
367435 compatibleTypes ( t , node .getType ( ) )
368436 )
369437 or
370438 // flow through a callable
371- nodeCand1 ( node , false , unbind ( config ) ) and
439+ throughFlowNodeCand ( node , unbind ( config ) ) and
372440 exists ( Node arg |
373441 simpleParameterFlow ( p , arg , _, config ) and
374442 simpleArgumentFlowsThrough ( arg , node , t , config )
@@ -380,6 +448,7 @@ private predicate simpleArgumentFlowsThrough0(
380448 DataFlowCall call , ArgumentNode arg , ReturnKind kind , DataFlowType t , Configuration config
381449) {
382450 nodeCand1 ( arg , false , unbind ( config ) ) and
451+ not outBarrier ( arg , config ) and
383452 exists ( ParameterNode p , ReturnNode ret |
384453 simpleParameterFlow ( p , ret , t , config ) and
385454 kind = ret .getKind ( ) and
@@ -399,6 +468,7 @@ private predicate simpleArgumentFlowsThrough(
399468) {
400469 exists ( DataFlowCall call , ReturnKind kind |
401470 nodeCand1 ( out , false , unbind ( config ) ) and
471+ not inBarrier ( out , config ) and
402472 simpleArgumentFlowsThrough0 ( call , arg , kind , t , config ) and
403473 out = getAnOutNode ( call , kind )
404474 )
@@ -440,6 +510,8 @@ private predicate additionalLocalFlowStepOrFlowThroughCallable(
440510private predicate flowOutOfCallable ( Node node1 , Node node2 , Configuration config ) {
441511 nodeCand1 ( node1 , _, unbind ( config ) ) and
442512 nodeCand1 ( node2 , _, config ) and
513+ not outBarrier ( node1 , config ) and
514+ not inBarrier ( node2 , config ) and
443515 (
444516 // flow out of an argument
445517 exists ( ParameterNode p |
@@ -462,7 +534,9 @@ private predicate flowOutOfCallable(Node node1, Node node2, Configuration config
462534private predicate flowIntoCallable ( Node node1 , Node node2 , Configuration config ) {
463535 viableParamArg ( _, node2 , node1 ) and
464536 nodeCand1 ( node1 , _, unbind ( config ) ) and
465- nodeCand1 ( node2 , _, config )
537+ nodeCand1 ( node2 , _, config ) and
538+ not outBarrier ( node1 , config ) and
539+ not inBarrier ( node2 , config )
466540}
467541
468542/**
@@ -546,7 +620,7 @@ private predicate nodeCandFwd2(Node node, boolean fromArg, boolean stored, Confi
546620 or
547621 exists ( Node mid |
548622 nodeCandFwd2 ( mid , _, stored , config ) and
549- jumpStep ( mid , node ) and
623+ jumpStep ( mid , node , config ) and
550624 fromArg = false
551625 )
552626 or
@@ -626,7 +700,7 @@ private predicate nodeCand2(Node node, boolean toReturn, boolean stored, Configu
626700 )
627701 or
628702 exists ( Node mid |
629- jumpStep ( node , mid ) and
703+ jumpStep ( node , mid , config ) and
630704 nodeCand2 ( mid , _, stored , config ) and
631705 toReturn = false
632706 )
@@ -714,7 +788,7 @@ private predicate localFlowEntry(Node node, Configuration config) {
714788 nodeCand ( node , config ) and
715789 (
716790 config .isSource ( node ) or
717- jumpStep ( _, node ) or
791+ jumpStep ( _, node , config ) or
718792 additionalJumpStep ( _, node , config ) or
719793 node instanceof ParameterNode or
720794 node instanceof OutNode or
@@ -730,7 +804,7 @@ private predicate localFlowEntry(Node node, Configuration config) {
730804 */
731805private predicate localFlowExit ( Node node , Configuration config ) {
732806 exists ( Node next | nodeCand ( next , config ) |
733- jumpStep ( node , next ) or
807+ jumpStep ( node , next , config ) or
734808 additionalJumpStep ( node , next , config ) or
735809 flowIntoCallable ( node , next , config ) or
736810 flowOutOfCallable ( node , next , config ) or
@@ -882,7 +956,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
882956 or
883957 exists ( Node mid |
884958 flowCandFwd ( mid , _, apf , config ) and
885- jumpStep ( mid , node ) and
959+ jumpStep ( mid , node , config ) and
886960 fromArg = false
887961 )
888962 or
@@ -973,7 +1047,7 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
9731047 )
9741048 or
9751049 exists ( Node mid |
976- jumpStep ( node , mid ) and
1050+ jumpStep ( node , mid , config ) and
9771051 flowCand ( mid , _, apf , config ) and
9781052 toReturn = false
9791053 )
@@ -1154,7 +1228,7 @@ private predicate flowFwd0(
11541228 or
11551229 exists ( Node mid |
11561230 flowFwd ( mid , _, apf , ap , config ) and
1157- jumpStep ( mid , node ) and
1231+ jumpStep ( mid , node , config ) and
11581232 fromArg = false
11591233 )
11601234 or
@@ -1263,7 +1337,7 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
12631337 )
12641338 or
12651339 exists ( Node mid |
1266- jumpStep ( node , mid ) and
1340+ jumpStep ( node , mid , config ) and
12671341 flow ( mid , _, ap , config ) and
12681342 toReturn = false
12691343 )
@@ -1518,7 +1592,7 @@ private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPat
15181592 mid .getAp ( ) instanceof AccessPathNil and
15191593 ap = node .( AccessPathNilNode ) .getAp ( )
15201594 or
1521- jumpStep ( mid .getNode ( ) , node ) and
1595+ jumpStep ( mid .getNode ( ) , node , mid . getConfiguration ( ) ) and
15221596 cc instanceof CallContextAny and
15231597 ap = mid .getAp ( )
15241598 or
0 commit comments