@@ -923,28 +923,29 @@ private module Stage2 {
923923
924924 ApOption apSome ( Ap ap ) { result = TBooleanSome ( ap ) }
925925
926- class Cc = boolean ;
927-
928- class CcCall extends Cc {
929- CcCall ( ) { this = true }
926+ class Cc = CallContext ;
930927
931- /** Holds if this call context may be `call`. */
932- predicate matchesCall ( DataFlowCall call ) { any ( ) }
933- }
928+ class CcCall = CallContextCall ;
934929
935- class CcNoCall extends Cc {
936- CcNoCall ( ) { this = false }
937- }
930+ class CcNoCall = CallContextNoCall ;
938931
939- Cc ccNone ( ) { result = false }
932+ Cc ccNone ( ) { result instanceof CallContextAny }
940933
941934 private class LocalCc = Unit ;
942935
943936 bindingset [ call, c, outercc]
944- private CcCall getCallContextCall ( DataFlowCall call , DataFlowCallable c , Cc outercc ) { any ( ) }
937+ private CcCall getCallContextCall ( DataFlowCall call , DataFlowCallable c , Cc outercc ) {
938+ checkCallContextCall ( outercc , call , c ) and
939+ if recordDataFlowCallSiteDispatch ( call , c )
940+ then result = TSpecificCall ( call )
941+ else result = TSomeCall ( )
942+ }
945943
946944 bindingset [ call, c, innercc]
947- private CcNoCall getCallContextReturn ( DataFlowCallable c , DataFlowCall call , Cc innercc ) { any ( ) }
945+ private CcNoCall getCallContextReturn ( DataFlowCallable c , DataFlowCall call , Cc innercc ) {
946+ checkCallContextReturn ( innercc , c , call ) and
947+ if reducedViableImplInReturn ( c , call ) then result = TReturn ( c , call ) else result = ccNone ( )
948+ }
948949
949950 bindingset [ node, cc, config]
950951 private LocalCc getLocalCc ( NodeEx node , Cc cc , Configuration config ) { any ( ) }
@@ -1172,7 +1173,8 @@ private module Stage2 {
11721173 fwdFlow ( out , pragma [ only_bind_into ] ( cc ) , pragma [ only_bind_into ] ( argAp ) , ap ,
11731174 pragma [ only_bind_into ] ( config ) ) and
11741175 fwdFlowOutFromArg ( call , out , argAp0 , ap , config ) and
1175- fwdFlowIsEntered ( call , pragma [ only_bind_into ] ( cc ) , pragma [ only_bind_into ] ( argAp ) , argAp0 ,
1176+ fwdFlowIsEntered ( pragma [ only_bind_into ] ( call ) , pragma [ only_bind_into ] ( cc ) ,
1177+ pragma [ only_bind_into ] ( argAp ) , pragma [ only_bind_into ] ( argAp0 ) ,
11761178 pragma [ only_bind_into ] ( config ) )
11771179 )
11781180 }
@@ -1860,7 +1862,8 @@ private module Stage3 {
18601862 fwdFlow ( out , pragma [ only_bind_into ] ( cc ) , pragma [ only_bind_into ] ( argAp ) , ap ,
18611863 pragma [ only_bind_into ] ( config ) ) and
18621864 fwdFlowOutFromArg ( call , out , argAp0 , ap , config ) and
1863- fwdFlowIsEntered ( call , pragma [ only_bind_into ] ( cc ) , pragma [ only_bind_into ] ( argAp ) , argAp0 ,
1865+ fwdFlowIsEntered ( pragma [ only_bind_into ] ( call ) , pragma [ only_bind_into ] ( cc ) ,
1866+ pragma [ only_bind_into ] ( argAp ) , pragma [ only_bind_into ] ( argAp0 ) ,
18641867 pragma [ only_bind_into ] ( config ) )
18651868 )
18661869 }
@@ -2117,7 +2120,7 @@ private module Stage3 {
21172120private predicate flowCandSummaryCtx ( NodeEx node , AccessPathFront argApf , Configuration config ) {
21182121 exists ( AccessPathFront apf |
21192122 Stage3:: revFlow ( node , true , _, apf , config ) and
2120- Stage3:: fwdFlow ( node , true , TAccessPathFrontSome ( argApf ) , apf , config )
2123+ Stage3:: fwdFlow ( node , any ( Stage3 :: CcCall ccc ) , TAccessPathFrontSome ( argApf ) , apf , config )
21212124 )
21222125}
21232126
@@ -2618,7 +2621,8 @@ private module Stage4 {
26182621 fwdFlow ( out , pragma [ only_bind_into ] ( cc ) , pragma [ only_bind_into ] ( argAp ) , ap ,
26192622 pragma [ only_bind_into ] ( config ) ) and
26202623 fwdFlowOutFromArg ( call , out , argAp0 , ap , config ) and
2621- fwdFlowIsEntered ( call , pragma [ only_bind_into ] ( cc ) , pragma [ only_bind_into ] ( argAp ) , argAp0 ,
2624+ fwdFlowIsEntered ( pragma [ only_bind_into ] ( call ) , pragma [ only_bind_into ] ( cc ) ,
2625+ pragma [ only_bind_into ] ( argAp ) , pragma [ only_bind_into ] ( argAp0 ) ,
26222626 pragma [ only_bind_into ] ( config ) )
26232627 )
26242628 }
@@ -3258,24 +3262,16 @@ class PathNode extends TPathNode {
32583262 /** Gets the associated configuration. */
32593263 Configuration getConfiguration ( ) { none ( ) }
32603264
3261- private predicate isHidden ( ) {
3262- hiddenNode ( this .( PathNodeImpl ) .getNodeEx ( ) .asNode ( ) ) and
3263- not this .isSource ( ) and
3264- not this instanceof PathNodeSink
3265- or
3266- this .( PathNodeImpl ) .getNodeEx ( ) instanceof TNodeImplicitRead
3267- }
3268-
32693265 private PathNode getASuccessorIfHidden ( ) {
3270- this .isHidden ( ) and
3266+ this .( PathNodeImpl ) . isHidden ( ) and
32713267 result = this .( PathNodeImpl ) .getASuccessorImpl ( )
32723268 }
32733269
32743270 /** Gets a successor of this node, if any. */
32753271 final PathNode getASuccessor ( ) {
32763272 result = this .( PathNodeImpl ) .getASuccessorImpl ( ) .getASuccessorIfHidden * ( ) and
3277- not this .isHidden ( ) and
3278- not result .isHidden ( )
3273+ not this .( PathNodeImpl ) . isHidden ( ) and
3274+ not result .( PathNodeImpl ) . isHidden ( )
32793275 }
32803276
32813277 /** Holds if this node is a source. */
@@ -3287,6 +3283,14 @@ abstract private class PathNodeImpl extends PathNode {
32873283
32883284 abstract NodeEx getNodeEx ( ) ;
32893285
3286+ predicate isHidden ( ) {
3287+ hiddenNode ( this .getNodeEx ( ) .asNode ( ) ) and
3288+ not this .isSource ( ) and
3289+ not this instanceof PathNodeSink
3290+ or
3291+ this .getNodeEx ( ) instanceof TNodeImplicitRead
3292+ }
3293+
32903294 private string ppAp ( ) {
32913295 this instanceof PathNodeSink and result = ""
32923296 or
@@ -3313,10 +3317,15 @@ abstract private class PathNodeImpl extends PathNode {
33133317}
33143318
33153319/** Holds if `n` can reach a sink. */
3316- private predicate reach ( PathNode n ) { n instanceof PathNodeSink or reach ( n .getASuccessor ( ) ) }
3320+ private predicate directReach ( PathNode n ) {
3321+ n instanceof PathNodeSink or directReach ( n .getASuccessor ( ) )
3322+ }
33173323
3318- /** Holds if `n1.getSucc() = n2` and `n2` can reach a sink. */
3319- private predicate pathSucc ( PathNode n1 , PathNode n2 ) { n1 .getASuccessor ( ) = n2 and reach ( n2 ) }
3324+ /** Holds if `n` can reach a sink or is used in a subpath. */
3325+ private predicate reach ( PathNode n ) { directReach ( n ) or Subpaths:: retReach ( n ) }
3326+
3327+ /** Holds if `n1.getASuccessor() = n2` and `n2` can reach a sink. */
3328+ private predicate pathSucc ( PathNode n1 , PathNode n2 ) { n1 .getASuccessor ( ) = n2 and directReach ( n2 ) }
33203329
33213330private predicate pathSuccPlus ( PathNode n1 , PathNode n2 ) = fastTC( pathSucc / 2 ) ( n1 , n2 )
33223331
@@ -3325,12 +3334,14 @@ private predicate pathSuccPlus(PathNode n1, PathNode n2) = fastTC(pathSucc/2)(n1
33253334 */
33263335module PathGraph {
33273336 /** Holds if `(a,b)` is an edge in the graph of data flow path explanations. */
3328- query predicate edges ( PathNode a , PathNode b ) { pathSucc ( a , b ) }
3337+ query predicate edges ( PathNode a , PathNode b ) { a . getASuccessor ( ) = b and reach ( b ) }
33293338
33303339 /** Holds if `n` is a node in the graph of data flow path explanations. */
33313340 query predicate nodes ( PathNode n , string key , string val ) {
33323341 reach ( n ) and key = "semmle.label" and val = n .toString ( )
33333342 }
3343+
3344+ query predicate subpaths = Subpaths:: subpaths / 4 ;
33343345}
33353346
33363347/**
@@ -3622,6 +3633,86 @@ private predicate pathThroughCallable(PathNodeMid mid, NodeEx out, CallContext c
36223633 )
36233634}
36243635
3636+ private module Subpaths {
3637+ /**
3638+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
3639+ * `kind`, `sc`, `apout`, and `innercc`.
3640+ */
3641+ pragma [ nomagic]
3642+ private predicate subpaths01 (
3643+ PathNode arg , ParamNodeEx par , SummaryCtxSome sc , CallContext innercc , ReturnKindExt kind ,
3644+ NodeEx out , AccessPath apout
3645+ ) {
3646+ pathThroughCallable ( arg , out , _, apout ) and
3647+ pathIntoCallable ( arg , par , _, innercc , sc , _) and
3648+ paramFlowsThrough ( kind , innercc , sc , apout , _, unbindConf ( arg .getConfiguration ( ) ) )
3649+ }
3650+
3651+ /**
3652+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple and `ret` is determined by
3653+ * `kind`, `sc`, `apout`, and `innercc`.
3654+ */
3655+ pragma [ nomagic]
3656+ private predicate subpaths02 (
3657+ PathNode arg , ParamNodeEx par , SummaryCtxSome sc , CallContext innercc , ReturnKindExt kind ,
3658+ NodeEx out , AccessPath apout
3659+ ) {
3660+ subpaths01 ( arg , par , sc , innercc , kind , out , apout ) and
3661+ out .asNode ( ) = kind .getAnOutNode ( _)
3662+ }
3663+
3664+ pragma [ nomagic]
3665+ private Configuration getPathNodeConf ( PathNode n ) { result = n .getConfiguration ( ) }
3666+
3667+ /**
3668+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple.
3669+ */
3670+ pragma [ nomagic]
3671+ private predicate subpaths03 (
3672+ PathNode arg , ParamNodeEx par , PathNodeMid ret , NodeEx out , AccessPath apout
3673+ ) {
3674+ exists ( SummaryCtxSome sc , CallContext innercc , ReturnKindExt kind , RetNodeEx retnode |
3675+ subpaths02 ( arg , par , sc , innercc , kind , out , apout ) and
3676+ ret .getNodeEx ( ) = retnode and
3677+ kind = retnode .getKind ( ) and
3678+ innercc = ret .getCallContext ( ) and
3679+ sc = ret .getSummaryCtx ( ) and
3680+ ret .getConfiguration ( ) = unbindConf ( getPathNodeConf ( arg ) ) and
3681+ apout = ret .getAp ( ) and
3682+ not ret .isHidden ( )
3683+ )
3684+ }
3685+
3686+ /**
3687+ * Holds if `(arg, par, ret, out)` forms a subpath-tuple, that is, flow through
3688+ * a subpath between `par` and `ret` with the connecting edges `arg -> par` and
3689+ * `ret -> out` is summarized as the edge `arg -> out`.
3690+ */
3691+ predicate subpaths ( PathNode arg , PathNodeImpl par , PathNodeMid ret , PathNodeMid out ) {
3692+ exists ( ParamNodeEx p , NodeEx o , AccessPath apout |
3693+ arg .getASuccessor ( ) = par and
3694+ arg .getASuccessor ( ) = out and
3695+ subpaths03 ( arg , p , ret , o , apout ) and
3696+ par .getNodeEx ( ) = p and
3697+ out .getNodeEx ( ) = o and
3698+ out .getAp ( ) = apout
3699+ )
3700+ }
3701+
3702+ /**
3703+ * Holds if `n` can reach a return node in a summarized subpath.
3704+ */
3705+ predicate retReach ( PathNode n ) {
3706+ subpaths ( _, _, n , _)
3707+ or
3708+ exists ( PathNode mid |
3709+ retReach ( mid ) and
3710+ n .getASuccessor ( ) = mid and
3711+ not subpaths ( _, mid , _, _)
3712+ )
3713+ }
3714+ }
3715+
36253716/**
36263717 * Holds if data can flow (inter-procedurally) from `source` to `sink`.
36273718 *
0 commit comments