@@ -153,6 +153,12 @@ private predicate localFlowStep(Node node1, Node node2, boolean preservesValue,
153153 */
154154private predicate useFieldFlow ( Configuration config ) { config .fieldFlowBranchLimit ( ) >= 1 }
155155
156+ pragma [ noinline]
157+ private ReturnKind viableReturnKind ( DataFlowCall call , ReturnPosition pos ) {
158+ viableImpl ( call ) = pos .getCallable ( ) and
159+ result = pos .getKind ( )
160+ }
161+
156162/**
157163 * Holds if `node` is reachable from a source in the given configuration
158164 * ignoring call contexts.
@@ -193,20 +199,21 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
193199 // flow into a callable
194200 exists ( Node arg |
195201 nodeCandFwd1 ( arg , stored , config ) and
196- viableParamArg ( node , arg )
202+ viableParamArg ( _ , node , arg )
197203 )
198204 or
199205 // flow out of an argument
200206 exists ( PostUpdateNode mid , ParameterNode p |
201207 nodeCandFwd1 ( mid , stored , config ) and
202208 parameterValueFlowsToUpdate ( p , mid ) and
203- viableParamArg ( p , node .( PostUpdateNode ) .getPreUpdateNode ( ) )
209+ viableParamArg ( _ , p , node .( PostUpdateNode ) .getPreUpdateNode ( ) )
204210 )
205211 or
206212 // flow out of a callable
207- exists ( ReturnNode ret |
213+ exists ( DataFlowCall call , ReturnNode ret , ReturnKind kind |
208214 nodeCandFwd1 ( ret , stored , config ) and
209- node = getAViableOutNode ( ret .getPosition ( ) )
215+ kind = viableReturnKind ( call , getReturnPosition ( ret ) ) and
216+ node = getAnOutNode ( call , kind )
210217 )
211218 )
212219}
@@ -268,21 +275,22 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) {
268275 or
269276 // flow into a callable
270277 exists ( Node param |
271- viableParamArg ( param , node ) and
278+ viableParamArg ( _ , param , node ) and
272279 nodeCand1 ( param , stored , config )
273280 )
274281 or
275282 // flow out of an argument
276283 exists ( PostUpdateNode mid , ParameterNode p |
277284 parameterValueFlowsToUpdate ( p , node ) and
278- viableParamArg ( p , mid .getPreUpdateNode ( ) ) and
285+ viableParamArg ( _ , p , mid .getPreUpdateNode ( ) ) and
279286 nodeCand1 ( mid , stored , config )
280287 )
281288 or
282289 // flow out of a callable
283- exists ( Node out |
290+ exists ( DataFlowCall call , ReturnKind kind , OutNode out |
284291 nodeCand1 ( out , stored , config ) and
285- out = getAViableOutNode ( node .( ReturnNode ) .getPosition ( ) )
292+ kind = viableReturnKind ( call , getReturnPosition ( node ) ) and
293+ out = getAnOutNode ( call , kind )
286294 )
287295 )
288296}
@@ -314,7 +322,12 @@ private predicate simpleParameterFlow(
314322 nodeCand1 ( node , false , config ) and
315323 p = node and
316324 t = getErasedRepr ( node .getType ( ) ) and
317- not parameterValueFlowsThrough ( p , _)
325+ exists ( ReturnNode ret , CallContextCall cc |
326+ returnNodeGetEnclosingCallable ( ret ) = p .getEnclosingCallable ( ) and
327+ cc = getAValidCallContextForParameter ( p )
328+ |
329+ not parameterValueFlowsThrough ( p , ret .getKind ( ) , cc )
330+ )
318331 or
319332 nodeCand1 ( node , false , unbind ( config ) ) and
320333 exists ( Node mid |
@@ -341,7 +354,7 @@ private predicate simpleParameterFlow(
341354 nodeCand1 ( node , false , config ) and
342355 exists ( Node arg |
343356 simpleParameterFlow ( p , arg , t , config ) and
344- argumentValueFlowsThrough ( arg , node ) and
357+ argumentValueFlowsThrough ( arg , node , _ ) and
345358 compatibleTypes ( t , node .getType ( ) )
346359 )
347360 or
@@ -353,21 +366,31 @@ private predicate simpleParameterFlow(
353366 )
354367}
355368
369+ pragma [ noinline]
370+ private predicate simpleArgumentFlowsThrough0 (
371+ DataFlowCall call , ArgumentNode arg , ReturnKind kind , DataFlowType t , Configuration config
372+ ) {
373+ exists ( ParameterNode p , ReturnNode ret | simpleParameterFlow ( p , ret , t , config ) |
374+ kind = ret .getKind ( ) and
375+ viableParamArg ( call , p , arg )
376+ )
377+ }
378+
356379/**
357- * Holds if data can flow from `arg` through the ` call` taking simple call
358- * contexts into consideration and that this is part of a path from a source
359- * to a sink. This is restricted to paths through the `call` that does not
380+ * Holds if data can flow from `arg` through a call to `out`, taking simple
381+ * call contexts into consideration, and that this is part of a path from a
382+ * source to a sink. This is restricted to paths through calla that do not
360383 * necessarily preserve the value of `arg` by making use of at least one
361384 * additional step from the configuration.
362385 */
363386private predicate simpleArgumentFlowsThrough (
364387 ArgumentNode arg , Node out , DataFlowType t , Configuration config
365388) {
366- exists ( ParameterNode param , ReturnNode ret |
389+ exists ( DataFlowCall call , ReturnKind kind |
367390 nodeCand1 ( arg , false , unbind ( config ) ) and
368391 nodeCand1 ( out , false , unbind ( config ) ) and
369- viableParamArgOut ( param , arg , ret . getPosition ( ) , out ) and
370- simpleParameterFlow ( param , ret , t , config )
392+ simpleArgumentFlowsThrough0 ( call , arg , kind , t , config ) and
393+ out = getAnOutNode ( call , kind )
371394 )
372395}
373396
@@ -379,7 +402,7 @@ private predicate flowThroughCallableCand1(
379402) {
380403 simpleArgumentFlowsThrough ( node1 , node2 , _, config ) and preservesValue = false
381404 or
382- argumentValueFlowsThrough ( node1 , node2 ) and preservesValue = true
405+ argumentValueFlowsThrough ( node1 , node2 , _ ) and preservesValue = true
383406}
384407
385408/**
@@ -405,11 +428,15 @@ private predicate flowOutOfCallableCand1(Node node1, Node node2, Configuration c
405428 // flow out of an argument
406429 exists ( ParameterNode p |
407430 parameterValueFlowsToUpdate ( p , node1 ) and
408- viableParamArg ( p , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) )
431+ viableParamArg ( _ , p , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) )
409432 )
410433 or
411434 // flow out of a callable
412- node2 = getAViableOutNode ( node1 .( ReturnNode ) .getPosition ( ) )
435+ exists ( DataFlowCall call , ReturnKind kind |
436+ kind = viableReturnKind ( call , getReturnPosition ( node1 ) )
437+ |
438+ node2 = getAnOutNode ( call , kind )
439+ )
413440 )
414441}
415442
@@ -418,7 +445,7 @@ private predicate flowOutOfCallableCand1(Node node1, Node node2, Configuration c
418445 * path from a source to a sink.
419446 */
420447private predicate flowIntoCallableCand1 ( Node node1 , Node node2 , Configuration config ) {
421- viableParamArg ( node2 , node1 ) and
448+ viableParamArg ( _ , node2 , node1 ) and
422449 nodeCand1 ( node1 , _, unbind ( config ) ) and
423450 nodeCand1 ( node2 , _, config )
424451}
@@ -1438,7 +1465,9 @@ private predicate flowStep(PathNodeMid mid, Node node, CallContext cc, AccessPat
14381465 or
14391466 flowOutOfCallable ( mid , node , cc ) and ap = mid .getAp ( )
14401467 or
1441- flowThroughCallable ( mid , node , ap , cc )
1468+ flowThroughCallable ( mid , node , cc ) and ap = TNil ( getErasedRepr ( node .getType ( ) ) )
1469+ or
1470+ valueFlowThroughCallable ( mid , node , cc ) and ap = mid .getAp ( )
14421471}
14431472
14441473private predicate contentReadStep ( PathNodeMid mid , Node node , AccessPath ap ) {
@@ -1458,33 +1487,37 @@ private predicate contentStoreStep(
14581487 cc = mid .getCallContext ( )
14591488}
14601489
1461- /**
1462- * Holds if data may flow from `mid` to a return at position `pos` in the
1463- * context `innercc`, and the path did not flow through a parameter.
1464- */
14651490private predicate flowOutOfCallable0 ( PathNodeMid mid , ReturnPosition pos , CallContext innercc ) {
1466- pos . getAReturnNode ( ) = mid .getNode ( ) and
1491+ pos = getReturnPosition ( mid .getNode ( ) ) and
14671492 innercc = mid .getCallContext ( ) and
14681493 not innercc instanceof CallContextCall
14691494}
14701495
1471- /**
1472- * Holds if data may flow from `mid` to `out`. The last step of this path
1473- * is a return from a callable and is recorded by `cc`, if needed.
1474- */
14751496pragma [ noinline]
1476- private predicate flowOutOfCallable ( PathNodeMid mid , OutNode out , CallContext cc ) {
1477- exists ( ReturnPosition pos , DataFlowCallable c , DataFlowCall call , CallContext innercc |
1497+ private predicate flowOutOfCallable1 (
1498+ PathNodeMid mid , DataFlowCall call , ReturnKind kind , CallContext cc
1499+ ) {
1500+ exists ( ReturnPosition pos , DataFlowCallable c , CallContext innercc |
14781501 flowOutOfCallable0 ( mid , pos , innercc ) and
1479- out = getAViableOutNode ( pos ) and
14801502 c = pos .getCallable ( ) and
1481- call = out . getCall ( ) and
1503+ kind = pos . getKind ( ) and
14821504 resolveReturn ( innercc , c , call )
14831505 |
14841506 if reducedViableImplInReturn ( c , call ) then cc = TReturn ( c , call ) else cc = TAnyCallContext ( )
14851507 )
14861508}
14871509
1510+ /**
1511+ * Holds if data may flow from `mid` to `out`. The last step of this path
1512+ * is a return from a callable and is recorded by `cc`, if needed.
1513+ */
1514+ pragma [ noinline]
1515+ private predicate flowOutOfCallable ( PathNodeMid mid , OutNode out , CallContext cc ) {
1516+ exists ( ReturnKind kind , DataFlowCall call | flowOutOfCallable1 ( mid , call , kind , cc ) |
1517+ out = getAnOutNode ( call , kind )
1518+ )
1519+ }
1520+
14881521private predicate flowOutOfArgument ( PathNodeMid mid , PostUpdateNode node , CallContext cc ) {
14891522 exists (
14901523 PostUpdateNode n , ParameterNode p , DataFlowCallable callable , CallContext innercc , int i ,
@@ -1560,20 +1593,35 @@ private predicate flowIntoCallable(
15601593 )
15611594}
15621595
1563- /** Holds if data may flow from `p` to a return at position `pos `. */
1596+ /** Holds if data may flow from `p` to a return of kind `kind `. */
15641597pragma [ nomagic]
15651598private predicate paramFlowsThrough (
1566- ParameterNode p , ReturnPosition pos , AccessPath ap , CallContextCall cc , Configuration config
1599+ ParameterNode p , ReturnKind kind , CallContextCall cc , Configuration config
15671600) {
1568- exists ( PathNodeMid mid |
1569- mid .getNode ( ) = pos .getAReturnNode ( ) and
1601+ exists ( PathNodeMid mid , ReturnNode ret |
1602+ mid .getNode ( ) = ret and
1603+ kind = ret .getKind ( ) and
15701604 cc = mid .getCallContext ( ) and
1571- ap = mid .getAp ( ) and
1572- config = mid .getConfiguration ( )
1605+ config = mid .getConfiguration ( ) and
1606+ mid .getAp ( ) instanceof AccessPathNil
15731607 |
15741608 cc = TSomeCall ( p , true )
15751609 or
1576- exists ( int i | cc = TSpecificCall ( _, i , true ) | p .isParameterOf ( pos .getCallable ( ) , i ) )
1610+ exists ( int i | cc = TSpecificCall ( _, i , true ) |
1611+ p .isParameterOf ( returnNodeGetEnclosingCallable ( ret ) , i )
1612+ )
1613+ )
1614+ }
1615+
1616+ pragma [ noinline]
1617+ private predicate flowThroughCallable0 (
1618+ DataFlowCall call , PathNodeMid mid , ReturnKind kind , CallContext cc
1619+ ) {
1620+ exists ( ParameterNode p , CallContext innercc |
1621+ flowIntoCallable ( mid , p , cc , innercc , call ) and
1622+ paramFlowsThrough ( p , kind , innercc , unbind ( mid .getConfiguration ( ) ) ) and
1623+ not parameterValueFlowsThrough ( p , kind , innercc ) and
1624+ mid .getAp ( ) instanceof AccessPathNil
15771625 )
15781626}
15791627
@@ -1582,11 +1630,24 @@ private predicate paramFlowsThrough(
15821630 * The context `cc` is restored to its value prior to entering the callable.
15831631 */
15841632pragma [ noinline]
1585- private predicate flowThroughCallable ( PathNodeMid mid , OutNode out , AccessPath ap , CallContext cc ) {
1586- exists ( ParameterNode p , ReturnPosition pos , CallContext innercc |
1587- flowIntoCallable ( mid , p , cc , innercc , out .getCall ( ) ) and
1588- paramFlowsThrough ( p , pos , ap , innercc , unbind ( mid .getConfiguration ( ) ) ) and
1589- out = getAViableOutNode ( pos )
1633+ private predicate flowThroughCallable ( PathNodeMid mid , OutNode out , CallContext cc ) {
1634+ exists ( DataFlowCall call , ReturnKind kind | flowThroughCallable0 ( call , mid , kind , cc ) |
1635+ out = getAnOutNode ( call , kind )
1636+ )
1637+ }
1638+
1639+ pragma [ noinline]
1640+ private predicate valueFlowThroughCallable0 (
1641+ DataFlowCall call , PathNodeMid mid , ReturnKind kind , CallContext cc
1642+ ) {
1643+ exists ( ParameterNode p , CallContext innercc | flowIntoCallable ( mid , p , cc , innercc , call ) |
1644+ parameterValueFlowsThrough ( p , kind , innercc )
1645+ )
1646+ }
1647+
1648+ private predicate valueFlowThroughCallable ( PathNodeMid mid , OutNode out , CallContext cc ) {
1649+ exists ( ReturnKind kind | valueFlowThroughCallable0 ( out .getCall ( ) , mid , kind , cc ) |
1650+ out = getAnOutNode ( _, kind )
15901651 )
15911652}
15921653
0 commit comments