@@ -567,7 +567,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
567567 ) {
568568 sourceNode ( node ) and
569569 ( if hasSourceCallCtx ( ) then cc = ccSomeCall ( ) else cc = ccNone ( ) ) and
570- summaryCtx = TSummaryCtxNone ( ) and
570+ summaryCtx . isSourceCtx ( ) and
571571 t = getNodeTyp ( node ) and
572572 ap instanceof ApNil and
573573 apa = getApprox ( ap ) and
@@ -602,18 +602,19 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
602602 apa = getApprox ( ap )
603603 or
604604 // flow into a callable without summary context
605- fwdFlowInNoFlowThrough ( node , cc , t , ap , stored ) and
605+ fwdFlowInNoFlowThrough ( node , cc , summaryCtx , t , ap , stored ) and
606606 apa = getApprox ( ap ) and
607- summaryCtx = TSummaryCtxNone ( ) and
608607 // When the call contexts of source and sink needs to match then there's
609608 // never any reason to enter a callable except to find a summary. See also
610609 // the comment in `PathNodeMid::isAtSink`.
611610 not Config:: getAFeature ( ) instanceof FeatureEqualSourceSinkCallContext
612611 or
613612 // flow into a callable with summary context (non-linear recursion)
614- fwdFlowInFlowThrough ( node , cc , t , ap , stored ) and
615- apa = getApprox ( ap ) and
616- summaryCtx = TSummaryCtxSome ( node , t , ap , stored )
613+ exists ( boolean mustReturn |
614+ fwdFlowInFlowThrough ( node , cc , t , ap , stored , mustReturn ) and
615+ apa = getApprox ( ap ) and
616+ summaryCtx = TSummaryCtxSome ( node , t , ap , stored , mustReturn )
617+ )
617618 or
618619 // flow out of a callable
619620 fwdFlowOut ( _, _, node , cc , summaryCtx , t , ap , stored ) and
@@ -630,9 +631,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
630631
631632 private newtype TSummaryCtx =
632633 TSummaryCtxNone ( ) or
633- TSummaryCtxSome ( ParamNd p , Typ t , Ap ap , TypOption stored ) {
634- fwdFlowInFlowThrough ( p , _, t , ap , stored )
635- }
634+ TSummaryCtxSome ( ParamNd p , Typ t , Ap ap , TypOption stored , Boolean mustReturn ) {
635+ fwdFlowInFlowThrough ( p , _, t , ap , stored , mustReturn )
636+ } or
637+ TSummaryCtxSource ( Boolean mustEscape )
636638
637639 /**
638640 * A context for generating flow summaries. This represents flow entry through
@@ -644,6 +646,69 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
644646 abstract string toString ( ) ;
645647
646648 abstract Location getLocation ( ) ;
649+
650+ /**
651+ * Holds if this context is the unique context used at flow sources.
652+ */
653+ predicate isSourceCtx ( ) {
654+ exists ( boolean strict |
655+ Stage1:: hasFeatureEscapesSourceCallContext ( strict ) and
656+ this = TSummaryCtxSource ( strict )
657+ )
658+ or
659+ not Stage1:: hasFeatureEscapesSourceCallContext ( _) and
660+ this = TSummaryCtxNone ( )
661+ }
662+
663+ pragma [ nomagic]
664+ private predicate isSome ( boolean mustReturn ) {
665+ this = TSummaryCtxSome ( _, _, _, _, mustReturn )
666+ }
667+
668+ /**
669+ * Holds if this context is valid as a flow-in context when no flow-through is possible,
670+ * in which case `innerSummaryCtx` is the summary context to be used when entering the
671+ * callable.
672+ */
673+ pragma [ nomagic]
674+ predicate isValidForFlowInNoThrough ( SummaryCtx innerSummaryCtx ) {
675+ this = TSummaryCtxNone ( ) and
676+ innerSummaryCtx = TSummaryCtxNone ( )
677+ or
678+ this .isSome ( false ) and
679+ innerSummaryCtx = TSummaryCtxNone ( )
680+ or
681+ // Even if we must escape the source call context, we can still allow for flow-in
682+ // without flow-through, as long as the inner context is escaped (which must then
683+ // necessarily be via a jump-step -- possibly after even more flow-in
684+ // without-flow-through steps).
685+ this = TSummaryCtxSource ( _) and
686+ innerSummaryCtx = TSummaryCtxSource ( true )
687+ }
688+
689+ /**
690+ * Holds if this context is valid as a flow-in context when flow-through is possible.
691+ *
692+ * The boolean `mustReturn` indicates whether flow must return.
693+ */
694+ predicate isValidForFlowThrough ( boolean mustReturn ) {
695+ this = TSummaryCtxSource ( _) and
696+ mustReturn = true
697+ or
698+ this = TSummaryCtxNone ( ) and
699+ mustReturn = false
700+ or
701+ this .isSome ( mustReturn )
702+ }
703+
704+ /** Holds if this context is valid as a sink context. */
705+ predicate isASinkCtx ( ) {
706+ this = TSummaryCtxNone ( )
707+ or
708+ this .isSome ( false )
709+ or
710+ this = TSummaryCtxSource ( false )
711+ }
647712 }
648713
649714 /** A summary context from which no flow summary can be generated. */
@@ -659,20 +724,43 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
659724 private Typ t ;
660725 private Ap ap ;
661726 private TypOption stored ;
727+ private boolean mustReturn ;
662728
663- SummaryCtxSome ( ) { this = TSummaryCtxSome ( p , t , ap , stored ) }
729+ SummaryCtxSome ( ) { this = TSummaryCtxSome ( p , t , ap , stored , mustReturn ) }
664730
665731 ParamNd getParamNode ( ) { result = p }
666732
667733 private string ppTyp ( ) { result = t .toString ( ) and result != "" }
668734
735+ private string ppMustReturn ( ) {
736+ if mustReturn = true then result = " <mustReturn>" else result = ""
737+ }
738+
669739 override string toString ( ) {
670- result = p + concat ( " : " + this .ppTyp ( ) ) + " " + ap + ppStored ( stored )
740+ result =
741+ p + concat ( " : " + this .ppTyp ( ) ) + " " + ap + ppStored ( stored ) + this .ppMustReturn ( )
671742 }
672743
673744 override Location getLocation ( ) { result = p .getLocation ( ) }
674745 }
675746
747+ /**
748+ * A special summary context that is used when the flow feature
749+ * `FeatureEscapesSourceCallContext(OrEqualSourceSinkCallContext)`
750+ * is enabled.
751+ */
752+ private class SummaryCtxSource extends SummaryCtx , TSummaryCtxSource {
753+ private boolean mustEscape ;
754+
755+ SummaryCtxSource ( ) { this = TSummaryCtxSource ( mustEscape ) }
756+
757+ override string toString ( ) {
758+ if mustEscape = true then result = "<source-must-escape>" else result = "<source>"
759+ }
760+
761+ override Location getLocation ( ) { result .hasLocationInfo ( "" , 0 , 0 , 0 , 0 ) }
762+ }
763+
676764 private predicate fwdFlowJump ( Nd node , Typ t , Ap ap , TypOption stored ) {
677765 exists ( Nd mid |
678766 fwdFlow ( mid , _, _, t , ap , stored ) and
@@ -915,9 +1003,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
9151003
9161004 pragma [ nomagic]
9171005 private predicate fwdFlowInNoFlowThrough (
918- ParamNd p , CcCall innercc , Typ t , Ap ap , TypOption stored
1006+ ParamNd p , CcCall innercc , SummaryCtx innerSummaryCtx , Typ t , Ap ap , TypOption stored
9191007 ) {
920- FwdFlowInNoThrough:: fwdFlowIn ( _, _, _, p , _, innercc , _, t , ap , stored , _)
1008+ exists ( SummaryCtx summaryCtx |
1009+ FwdFlowInNoThrough:: fwdFlowIn ( _, _, _, p , _, innercc , summaryCtx , t , ap , stored , _) and
1010+ summaryCtx .isValidForFlowInNoThrough ( innerSummaryCtx )
1011+ )
9211012 }
9221013
9231014 private predicate top ( ) { any ( ) }
@@ -926,9 +1017,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
9261017
9271018 pragma [ nomagic]
9281019 private predicate fwdFlowInFlowThrough (
929- ParamNd p , CcCall innercc , Typ t , Ap ap , TypOption stored
1020+ ParamNd p , CcCall innercc , Typ t , Ap ap , TypOption stored , boolean mustReturn
9301021 ) {
931- FwdFlowInThrough:: fwdFlowIn ( _, _, _, p , _, innercc , _, t , ap , stored , _)
1022+ exists ( SummaryCtx outerSummaryCtx |
1023+ FwdFlowInThrough:: fwdFlowIn ( _, _, _, p , _, innercc , outerSummaryCtx , t , ap , stored , _) and
1024+ outerSummaryCtx .isValidForFlowThrough ( mustReturn )
1025+ )
9321026 }
9331027
9341028 pragma [ nomagic]
@@ -999,7 +1093,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
9991093 TypOption stored
10001094 ) {
10011095 exists ( RetNd ret , CcNoCall innercc , boolean allowsFieldFlow |
1002- fwdFlowIntoRet ( ret , innercc , summaryCtx , t , ap , stored ) and
1096+ fwdFlowIntoRet ( ret , innercc , _, t , ap , stored ) and
1097+ summaryCtx = TSummaryCtxNone ( ) and
10031098 fwdFlowOutValidEdge ( call , ret , innercc , inner , out , outercc , allowsFieldFlow ) and
10041099 if allowsFieldFlow = false then ap instanceof ApNil else any ( )
10051100 )
@@ -1090,7 +1185,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
10901185 instanceofCcCall ( ccc ) and
10911186 fwdFlow ( pragma [ only_bind_into ] ( ret ) , ccc , summaryCtx , t , ap , stored ) and
10921187 summaryCtx =
1093- TSummaryCtxSome ( pragma [ only_bind_into ] ( p ) , _, pragma [ only_bind_into ] ( argAp ) , _) and
1188+ TSummaryCtxSome ( pragma [ only_bind_into ] ( p ) , _, pragma [ only_bind_into ] ( argAp ) , _, _ ) and
10941189 kind = ret .getKind ( ) and
10951190 Stage1:: parameterFlowThroughAllowed ( p , kind ) and
10961191 PrevStage:: returnMayFlowThrough ( ret , kind )
@@ -1116,9 +1211,10 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
11161211 pragma [ nomagic]
11171212 private predicate fwdFlowIsEntered0 (
11181213 Call call , ArgNd arg , Cc cc , CcCall innerCc , SummaryCtx summaryCtx , ParamNd p , Typ t ,
1119- Ap ap , TypOption stored
1214+ Ap ap , TypOption stored , boolean mustReturn
11201215 ) {
1121- FwdFlowInThrough:: fwdFlowIn ( call , arg , _, p , cc , innerCc , summaryCtx , t , ap , stored , _)
1216+ FwdFlowInThrough:: fwdFlowIn ( call , arg , _, p , cc , innerCc , summaryCtx , t , ap , stored , _) and
1217+ summaryCtx .isValidForFlowThrough ( mustReturn )
11221218 }
11231219
11241220 /**
@@ -1130,9 +1226,9 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
11301226 Call call , ArgNd arg , Cc cc , CcCall innerCc , SummaryCtx summaryCtx ,
11311227 SummaryCtxSome innerSummaryCtx
11321228 ) {
1133- exists ( ParamNd p , Typ t , Ap ap , TypOption stored |
1134- fwdFlowIsEntered0 ( call , arg , cc , innerCc , summaryCtx , p , t , ap , stored ) and
1135- innerSummaryCtx = TSummaryCtxSome ( p , t , ap , stored )
1229+ exists ( ParamNd p , Typ t , Ap ap , TypOption stored , boolean mustReturn |
1230+ fwdFlowIsEntered0 ( call , arg , cc , innerCc , summaryCtx , p , t , ap , stored , mustReturn ) and
1231+ innerSummaryCtx = TSummaryCtxSome ( p , t , ap , stored , mustReturn )
11361232 )
11371233 }
11381234
@@ -1160,7 +1256,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
11601256 TypOption argStored , Ap ap
11611257 ) {
11621258 exists ( Call call , boolean allowsFieldFlow |
1163- returnFlowsThrough0 ( call , ccc , ap , ret , TSummaryCtxSome ( p , argT , argAp , argStored ) ) and
1259+ returnFlowsThrough0 ( call , ccc , ap , ret , TSummaryCtxSome ( p , argT , argAp , argStored , _ ) ) and
11641260 flowThroughOutOfCall ( call , ret , _, allowsFieldFlow ) and
11651261 pos = ret .getReturnPosition ( ) and
11661262 if allowsFieldFlow = false then ap instanceof ApNil else any ( )
@@ -1216,7 +1312,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
12161312
12171313 pragma [ nomagic]
12181314 private predicate revFlow0 ( Nd node , ReturnCtx returnCtx , ApOption returnAp , Ap ap ) {
1219- fwdFlow ( node , _, _ , _, ap , _) and
1315+ fwdFlow ( node , _, any ( SummaryCtx sinkCtx | sinkCtx . isASinkCtx ( ) ) , _, ap , _) and
12201316 sinkNode ( node ) and
12211317 (
12221318 if hasSinkCallCtx ( )
@@ -1490,7 +1586,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
14901586 exists ( Ap ap0 |
14911587 parameterMayFlowThrough ( p , _) and
14921588 revFlow ( n , TReturnCtxMaybeFlowThrough ( _) , _, ap0 ) and
1493- fwdFlow ( n , any ( CcCall ccc ) , TSummaryCtxSome ( p , _, ap , _) , _, ap0 , _)
1589+ fwdFlow ( n , any ( CcCall ccc ) , TSummaryCtxSome ( p , _, ap , _, _ ) , _, ap0 , _)
14941590 )
14951591 }
14961592
@@ -1962,6 +2058,8 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
19622058 private string ppSummaryCtx ( ) {
19632059 summaryCtx instanceof SummaryCtxNone and result = ""
19642060 or
2061+ result = " " + summaryCtx .( SummaryCtxSource )
2062+ or
19652063 summaryCtx instanceof SummaryCtxSome and
19662064 result = " <" + summaryCtx + ">"
19672065 }
@@ -1983,14 +2081,15 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
19832081 override predicate isSource ( ) {
19842082 sourceNode ( node ) and
19852083 ( if hasSourceCallCtx ( ) then cc = ccSomeCall ( ) else cc = ccNone ( ) ) and
1986- summaryCtx = TSummaryCtxNone ( ) and
2084+ summaryCtx . isSourceCtx ( ) and
19872085 t = getNodeTyp ( node ) and
19882086 ap instanceof ApNil
19892087 }
19902088
19912089 predicate isAtSink ( ) {
19922090 sinkNode ( node ) and
19932091 ap instanceof ApNil and
2092+ summaryCtx .isASinkCtx ( ) and
19942093 // For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
19952094 // is exactly what we need to check.
19962095 // For `FeatureEqualSourceSinkCallContext` the initial call
@@ -2042,10 +2141,12 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
20422141 override predicate isSource ( ) { sourceNode ( node ) }
20432142 }
20442143
2045- bindingset [ p, t, ap, stored]
2144+ bindingset [ p, t, ap, stored, mustReturn ]
20462145 pragma [ inline_late]
2047- private SummaryCtxSome mkSummaryCtxSome ( ParamNd p , Typ t , Ap ap , TypOption stored ) {
2048- result = TSummaryCtxSome ( p , t , ap , stored )
2146+ private SummaryCtxSome mkSummaryCtxSome (
2147+ ParamNd p , Typ t , Ap ap , TypOption stored , boolean mustReturn
2148+ ) {
2149+ result = TSummaryCtxSome ( p , t , ap , stored , mustReturn )
20492150 }
20502151
20512152 pragma [ nomagic]
@@ -2055,11 +2156,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
20552156 ) {
20562157 FwdFlowInNoThrough:: fwdFlowIn ( _, arg , _, p , outercc , innercc , outerSummaryCtx , t , ap ,
20572158 stored , _) and
2058- innerSummaryCtx = TSummaryCtxNone ( )
2159+ outerSummaryCtx . isValidForFlowInNoThrough ( innerSummaryCtx )
20592160 or
2060- FwdFlowInThrough:: fwdFlowIn ( _, arg , _, p , outercc , innercc , outerSummaryCtx , t , ap ,
2061- stored , _) and
2062- innerSummaryCtx = mkSummaryCtxSome ( p , t , ap , stored )
2161+ exists ( boolean mustReturn |
2162+ FwdFlowInThrough:: fwdFlowIn ( _, arg , _, p , outercc , innercc , outerSummaryCtx , t , ap ,
2163+ stored , _) and
2164+ outerSummaryCtx .isValidForFlowThrough ( mustReturn ) and
2165+ innerSummaryCtx = mkSummaryCtxSome ( p , t , ap , stored , mustReturn )
2166+ )
20632167 }
20642168
20652169 pragma [ nomagic]
@@ -2098,7 +2202,7 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
20982202 |
20992203 fwdFlowThroughStep0 ( call , arg , cc , ccc , summaryCtx , t , ap , stored , ret ,
21002204 innerSummaryCtx ) and
2101- innerSummaryCtx = TSummaryCtxSome ( p , innerArgT , innerArgAp , innerArgStored ) and
2205+ innerSummaryCtx = TSummaryCtxSome ( p , innerArgT , innerArgAp , innerArgStored , _ ) and
21022206 pn1 = mkPathNode ( arg , cc , summaryCtx , innerArgT , innerArgAp , innerArgStored ) and
21032207 pn2 =
21042208 typeStrengthenToPathNode ( p , ccc , innerSummaryCtx , innerArgT , innerArgAp ,
@@ -2212,11 +2316,14 @@ module MakeImpl<LocationSig Location, InputSig<Location> Lang> {
22122316 )
22132317 or
22142318 // flow out of a callable
2215- exists ( RetNd ret , CcNoCall innercc , boolean allowsFieldFlow |
2216- pn1 = TPathNodeMid ( ret , innercc , summaryCtx , t , ap , stored ) and
2217- fwdFlowIntoRet ( ret , innercc , summaryCtx , t , ap , stored ) and
2319+ exists (
2320+ RetNd ret , CcNoCall innercc , SummaryCtx innerSummaryCtx , boolean allowsFieldFlow
2321+ |
2322+ pn1 = TPathNodeMid ( ret , innercc , innerSummaryCtx , t , ap , stored ) and
2323+ fwdFlowIntoRet ( ret , innercc , innerSummaryCtx , t , ap , stored ) and
22182324 fwdFlowOutValidEdge ( _, ret , innercc , _, node , cc , allowsFieldFlow ) and
22192325 label = "" and
2326+ summaryCtx = TSummaryCtxNone ( ) and
22202327 if allowsFieldFlow = false then ap instanceof ApNil else any ( )
22212328 )
22222329 }
0 commit comments