@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
3313
3313
}
3314
3314
3315
3315
/** Holds if `n` can reach a sink. */
3316
- private predicate reach ( PathNode n ) { n instanceof PathNodeSink or reach ( n .getASuccessor ( ) ) }
3316
+ private predicate directReach ( PathNode n ) {
3317
+ n instanceof PathNodeSink or directReach ( n .getASuccessor ( ) )
3318
+ }
3319
+
3320
+ /** Holds if `n` can reach a sink or is used in a subpath. */
3321
+ private predicate reach ( PathNode n ) { directReach ( n ) or Subpaths:: retReach ( n ) }
3317
3322
3318
- /** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
3323
+ /** Holds if `n1.getSucc() = n2` and `n2` can reach a sink or is used in a subpath . */
3319
3324
private predicate pathSucc ( PathNode n1 , PathNode n2 ) { n1 .getASuccessor ( ) = n2 and reach ( n2 ) }
3320
3325
3321
3326
private predicate pathSuccPlus ( PathNode n1 , PathNode n2 ) = fastTC( pathSucc / 2 ) ( n1 , n2 )
@@ -3331,6 +3336,8 @@ module PathGraph {
3331
3336
query predicate nodes ( PathNode n , string key , string val ) {
3332
3337
reach ( n ) and key = "semmle.label" and val = n .toString ( )
3333
3338
}
3339
+
3340
+ query predicate subpaths = Subpaths:: subpaths / 4 ;
3334
3341
}
3335
3342
3336
3343
/**
@@ -3622,6 +3629,85 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
3622
3629
)
3623
3630
}
3624
3631
3632
+ private module Subpaths {
3633
+ /**
3634
+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
3635
+ * `kind`, `sc`, `apout`, and `innercc`.
3636
+ */
3637
+ pragma [ nomagic]
3638
+ private predicate subpaths01 (
3639
+ PathNode arg , ParamNodeEx par , SummaryCtxSome sc , CallContext innercc , ReturnKindExt kind ,
3640
+ NodeEx out , AccessPath apout
3641
+ ) {
3642
+ pathThroughCallable ( arg , out , _, apout ) and
3643
+ pathIntoCallable ( arg , par , _, innercc , sc , _) and
3644
+ paramFlowsThrough ( kind , innercc , sc , apout , _, unbindConf ( arg .getConfiguration ( ) ) )
3645
+ }
3646
+
3647
+ /**
3648
+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
3649
+ * `kind`, `sc`, `apout`, and `innercc`.
3650
+ */
3651
+ pragma [ nomagic]
3652
+ private predicate subpaths02 (
3653
+ PathNode arg , ParamNodeEx par , SummaryCtxSome sc , CallContext innercc , ReturnKindExt kind ,
3654
+ NodeEx out , AccessPath apout
3655
+ ) {
3656
+ subpaths01 ( arg , par , sc , innercc , kind , out , apout ) and
3657
+ out .asNode ( ) = kind .getAnOutNode ( _)
3658
+ }
3659
+
3660
+ pragma [ nomagic]
3661
+ private Configuration getPathNodeConf ( PathNode n ) { result = n .getConfiguration ( ) }
3662
+
3663
+ /**
3664
+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
3665
+ */
3666
+ pragma [ nomagic]
3667
+ private predicate subpaths03 (
3668
+ PathNode arg , ParamNodeEx par , PathNodeMid ret , NodeEx out , AccessPath apout
3669
+ ) {
3670
+ exists ( SummaryCtxSome sc , CallContext innercc , ReturnKindExt kind , RetNodeEx retnode |
3671
+ subpaths02 ( arg , par , sc , innercc , kind , out , apout ) and
3672
+ ret .getNodeEx ( ) = retnode and
3673
+ kind = retnode .getKind ( ) and
3674
+ innercc = ret .getCallContext ( ) and
3675
+ sc = ret .getSummaryCtx ( ) and
3676
+ ret .getConfiguration ( ) = unbindConf ( getPathNodeConf ( arg ) ) and
3677
+ apout = ret .getAp ( )
3678
+ )
3679
+ }
3680
+
3681
+ /**
3682
+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
3683
+ * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
3684
+ * `ret -> out` is summarized as the edge `arg -> out`.
3685
+ */
3686
+ predicate subpaths ( PathNode arg , PathNodeImpl par , PathNodeMid ret , PathNodeMid out ) {
3687
+ exists ( ParamNodeEx p , NodeEx o , AccessPath apout |
3688
+ arg .getASuccessor ( ) = par and
3689
+ arg .getASuccessor ( ) = out and
3690
+ subpaths03 ( arg , p , ret , o , apout ) and
3691
+ par .getNodeEx ( ) = p and
3692
+ out .getNodeEx ( ) = o and
3693
+ out .getAp ( ) = apout
3694
+ )
3695
+ }
3696
+
3697
+ /**
3698
+ * Holds if `n` can reach `ret` in a summarized subpath.
3699
+ */
3700
+ predicate retReach ( PathNode n ) {
3701
+ subpaths ( _, _, n , _)
3702
+ or
3703
+ exists ( PathNode mid |
3704
+ retReach ( mid ) and
3705
+ n .getASuccessor ( ) = mid and
3706
+ not subpaths ( _, mid , _, _)
3707
+ )
3708
+ }
3709
+ }
3710
+
3625
3711
/**
3626
3712
* Holds if data can flow (inter-procedurally) from `source` to `sink`.
3627
3713
*
0 commit comments