@@ -3313,9 +3313,14 @@ abstract private class PathNodeImpl extends PathNode {
33133313}
33143314
33153315/** 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 ) }
33173322
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 . */
33193324private predicate pathSucc ( PathNode n1 , PathNode n2 ) { n1 .getASuccessor ( ) = n2 and reach ( n2 ) }
33203325
33213326private predicate pathSuccPlus ( PathNode n1 , PathNode n2 ) = fastTC( pathSucc / 2 ) ( n1 , n2 )
@@ -3331,6 +3336,8 @@ module PathGraph {
33313336 query predicate nodes ( PathNode n , string key , string val ) {
33323337 reach ( n ) and key = "semmle.label" and val = n .toString ( )
33333338 }
3339+
3340+ query predicate subpaths = Subpaths:: subpaths / 4 ;
33343341}
33353342
33363343/**
@@ -3622,6 +3629,85 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
36223629 )
36233630}
36243631
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+
36253711/**
36263712 * Holds if data can flow (inter-procedurally) from `source` to `sink`.
36273713 *
0 commit comments