@@ -153,6 +153,12 @@ private predicate localFlowStep(Node node1, Node node2, boolean preservesValue,
153
153
*/
154
154
private predicate useFieldFlow ( Configuration config ) { config .fieldFlowBranchLimit ( ) >= 1 }
155
155
156
+ pragma [ noinline]
157
+ private ReturnKind viableReturnKind ( DataFlowCall call , ReturnPosition pos ) {
158
+ viableImpl ( call ) = pos .getCallable ( ) and
159
+ result = pos .getKind ( )
160
+ }
161
+
156
162
/**
157
163
* Holds if `node` is reachable from a source in the given configuration
158
164
* ignoring call contexts.
@@ -193,20 +199,21 @@ private predicate nodeCandFwd1(Node node, boolean stored, Configuration config)
193
199
// flow into a callable
194
200
exists ( Node arg |
195
201
nodeCandFwd1 ( arg , stored , config ) and
196
- viableParamArg ( node , arg )
202
+ viableParamArg ( _ , node , arg )
197
203
)
198
204
or
199
205
// flow out of an argument
200
206
exists ( PostUpdateNode mid , ParameterNode p |
201
207
nodeCandFwd1 ( mid , stored , config ) and
202
208
parameterValueFlowsToUpdate ( p , mid ) and
203
- viableParamArg ( p , node .( PostUpdateNode ) .getPreUpdateNode ( ) )
209
+ viableParamArg ( _ , p , node .( PostUpdateNode ) .getPreUpdateNode ( ) )
204
210
)
205
211
or
206
212
// flow out of a callable
207
- exists ( ReturnNode ret |
213
+ exists ( DataFlowCall call , ReturnNode ret , ReturnKind kind |
208
214
nodeCandFwd1 ( ret , stored , config ) and
209
- node = getAViableOutNode ( ret .getPosition ( ) )
215
+ kind = viableReturnKind ( call , getReturnPosition ( ret ) ) and
216
+ node = getAnOutNode ( call , kind )
210
217
)
211
218
)
212
219
}
@@ -268,21 +275,22 @@ private predicate nodeCand1(Node node, boolean stored, Configuration config) {
268
275
or
269
276
// flow into a callable
270
277
exists ( Node param |
271
- viableParamArg ( param , node ) and
278
+ viableParamArg ( _ , param , node ) and
272
279
nodeCand1 ( param , stored , config )
273
280
)
274
281
or
275
282
// flow out of an argument
276
283
exists ( PostUpdateNode mid , ParameterNode p |
277
284
parameterValueFlowsToUpdate ( p , node ) and
278
- viableParamArg ( p , mid .getPreUpdateNode ( ) ) and
285
+ viableParamArg ( _ , p , mid .getPreUpdateNode ( ) ) and
279
286
nodeCand1 ( mid , stored , config )
280
287
)
281
288
or
282
289
// flow out of a callable
283
- exists ( Node out |
290
+ exists ( DataFlowCall call , ReturnKind kind , OutNode out |
284
291
nodeCand1 ( out , stored , config ) and
285
- out = getAViableOutNode ( node .( ReturnNode ) .getPosition ( ) )
292
+ kind = viableReturnKind ( call , getReturnPosition ( node ) ) and
293
+ out = getAnOutNode ( call , kind )
286
294
)
287
295
)
288
296
}
@@ -314,7 +322,12 @@ private predicate simpleParameterFlow(
314
322
nodeCand1 ( node , false , config ) and
315
323
p = node and
316
324
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
+ )
318
331
or
319
332
nodeCand1 ( node , false , unbind ( config ) ) and
320
333
exists ( Node mid |
@@ -341,7 +354,7 @@ private predicate simpleParameterFlow(
341
354
nodeCand1 ( node , false , config ) and
342
355
exists ( Node arg |
343
356
simpleParameterFlow ( p , arg , t , config ) and
344
- argumentValueFlowsThrough ( arg , node ) and
357
+ argumentValueFlowsThrough ( arg , node , _ ) and
345
358
compatibleTypes ( t , node .getType ( ) )
346
359
)
347
360
or
@@ -353,21 +366,31 @@ private predicate simpleParameterFlow(
353
366
)
354
367
}
355
368
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
+
356
379
/**
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
360
383
* necessarily preserve the value of `arg` by making use of at least one
361
384
* additional step from the configuration.
362
385
*/
363
386
private predicate simpleArgumentFlowsThrough (
364
387
ArgumentNode arg , Node out , DataFlowType t , Configuration config
365
388
) {
366
- exists ( ParameterNode param , ReturnNode ret |
389
+ exists ( DataFlowCall call , ReturnKind kind |
367
390
nodeCand1 ( arg , false , unbind ( config ) ) and
368
391
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 )
371
394
)
372
395
}
373
396
@@ -379,7 +402,7 @@ private predicate flowThroughCallableCand1(
379
402
) {
380
403
simpleArgumentFlowsThrough ( node1 , node2 , _, config ) and preservesValue = false
381
404
or
382
- argumentValueFlowsThrough ( node1 , node2 ) and preservesValue = true
405
+ argumentValueFlowsThrough ( node1 , node2 , _ ) and preservesValue = true
383
406
}
384
407
385
408
/**
@@ -405,11 +428,15 @@ private predicate flowOutOfCallableCand1(Node node1, Node node2, Configuration c
405
428
// flow out of an argument
406
429
exists ( ParameterNode p |
407
430
parameterValueFlowsToUpdate ( p , node1 ) and
408
- viableParamArg ( p , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) )
431
+ viableParamArg ( _ , p , node2 .( PostUpdateNode ) .getPreUpdateNode ( ) )
409
432
)
410
433
or
411
434
// 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
+ )
413
440
)
414
441
}
415
442
@@ -418,7 +445,7 @@ private predicate flowOutOfCallableCand1(Node node1, Node node2, Configuration c
418
445
* path from a source to a sink.
419
446
*/
420
447
private predicate flowIntoCallableCand1 ( Node node1 , Node node2 , Configuration config ) {
421
- viableParamArg ( node2 , node1 ) and
448
+ viableParamArg ( _ , node2 , node1 ) and
422
449
nodeCand1 ( node1 , _, unbind ( config ) ) and
423
450
nodeCand1 ( node2 , _, config )
424
451
}
@@ -1438,7 +1465,9 @@ private predicate flowStep(PathNodeMid mid, Node node, CallContext cc, AccessPat
1438
1465
or
1439
1466
flowOutOfCallable ( mid , node , cc ) and ap = mid .getAp ( )
1440
1467
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 ( )
1442
1471
}
1443
1472
1444
1473
private predicate contentReadStep ( PathNodeMid mid , Node node , AccessPath ap ) {
@@ -1458,33 +1487,37 @@ private predicate contentStoreStep(
1458
1487
cc = mid .getCallContext ( )
1459
1488
}
1460
1489
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
- */
1465
1490
private predicate flowOutOfCallable0 ( PathNodeMid mid , ReturnPosition pos , CallContext innercc ) {
1466
- pos . getAReturnNode ( ) = mid .getNode ( ) and
1491
+ pos = getReturnPosition ( mid .getNode ( ) ) and
1467
1492
innercc = mid .getCallContext ( ) and
1468
1493
not innercc instanceof CallContextCall
1469
1494
}
1470
1495
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
- */
1475
1496
pragma [ 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 |
1478
1501
flowOutOfCallable0 ( mid , pos , innercc ) and
1479
- out = getAViableOutNode ( pos ) and
1480
1502
c = pos .getCallable ( ) and
1481
- call = out . getCall ( ) and
1503
+ kind = pos . getKind ( ) and
1482
1504
resolveReturn ( innercc , c , call )
1483
1505
|
1484
1506
if reducedViableImplInReturn ( c , call ) then cc = TReturn ( c , call ) else cc = TAnyCallContext ( )
1485
1507
)
1486
1508
}
1487
1509
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
+
1488
1521
private predicate flowOutOfArgument ( PathNodeMid mid , PostUpdateNode node , CallContext cc ) {
1489
1522
exists (
1490
1523
PostUpdateNode n , ParameterNode p , DataFlowCallable callable , CallContext innercc , int i ,
@@ -1560,20 +1593,35 @@ private predicate flowIntoCallable(
1560
1593
)
1561
1594
}
1562
1595
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 `. */
1564
1597
pragma [ nomagic]
1565
1598
private predicate paramFlowsThrough (
1566
- ParameterNode p , ReturnPosition pos , AccessPath ap , CallContextCall cc , Configuration config
1599
+ ParameterNode p , ReturnKind kind , CallContextCall cc , Configuration config
1567
1600
) {
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
1570
1604
cc = mid .getCallContext ( ) and
1571
- ap = mid .getAp ( ) and
1572
- config = mid .getConfiguration ( )
1605
+ config = mid .getConfiguration ( ) and
1606
+ mid .getAp ( ) instanceof AccessPathNil
1573
1607
|
1574
1608
cc = TSomeCall ( p , true )
1575
1609
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
1577
1625
)
1578
1626
}
1579
1627
@@ -1582,11 +1630,24 @@ private predicate paramFlowsThrough(
1582
1630
* The context `cc` is restored to its value prior to entering the callable.
1583
1631
*/
1584
1632
pragma [ 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 )
1590
1651
)
1591
1652
}
1592
1653
0 commit comments