1010private import DataFlowImplCommon
1111private import DataFlowImplSpecific:: Private
1212import DataFlowImplSpecific:: Public
13+ import DataFlowImplCommonPublic
1314
1415/**
1516 * A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
9495 */
9596 int fieldFlowBranchLimit ( ) { result = 2 }
9697
98+ /**
99+ * Gets a data flow configuration feature to add restrictions to the set of
100+ * valid flow paths.
101+ *
102+ * - `FeatureHasSourceCallContext`:
103+ * Assume that sources have some existing call context to disallow
104+ * conflicting return-flow directly following the source.
105+ * - `FeatureHasSinkCallContext`:
106+ * Assume that sinks have some existing call context to disallow
107+ * conflicting argument-to-parameter flow directly preceding the sink.
108+ * - `FeatureEqualSourceSinkCallContext`:
109+ * Implies both of the above and additionally ensures that the entire flow
110+ * path preserves the call context.
111+ */
112+ FlowFeature getAFeature ( ) { none ( ) }
113+
97114 /**
98115 * Holds if data may flow from `source` to `sink` for this configuration.
99116 */
@@ -349,7 +366,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
349366 not outBarrier ( node1 , config ) and
350367 not inBarrier ( node2 , config ) and
351368 not fullBarrier ( node1 , config ) and
352- not fullBarrier ( node2 , config )
369+ not fullBarrier ( node2 , config ) and
370+ not config .getAFeature ( ) instanceof FeatureEqualSourceSinkCallContext
353371 )
354372}
355373
@@ -365,7 +383,8 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
365383 not outBarrier ( node1 , config ) and
366384 not inBarrier ( node2 , config ) and
367385 not fullBarrier ( node1 , config ) and
368- not fullBarrier ( node2 , config )
386+ not fullBarrier ( node2 , config ) and
387+ not config .getAFeature ( ) instanceof FeatureEqualSourceSinkCallContext
369388 )
370389}
371390
@@ -401,6 +420,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
401420 */
402421private predicate useFieldFlow ( Configuration config ) { config .fieldFlowBranchLimit ( ) >= 1 }
403422
423+ private predicate hasSourceCallCtx ( Configuration config ) {
424+ exists ( FlowFeature feature | feature = config .getAFeature ( ) |
425+ feature instanceof FeatureHasSourceCallContext or
426+ feature instanceof FeatureEqualSourceSinkCallContext
427+ )
428+ }
429+
430+ private predicate hasSinkCallCtx ( Configuration config ) {
431+ exists ( FlowFeature feature | feature = config .getAFeature ( ) |
432+ feature instanceof FeatureHasSinkCallContext or
433+ feature instanceof FeatureEqualSourceSinkCallContext
434+ )
435+ }
436+
404437private module Stage1 {
405438 class ApApprox = Unit ;
406439
@@ -421,7 +454,7 @@ private module Stage1 {
421454 not fullBarrier ( node , config ) and
422455 (
423456 sourceNode ( node , config ) and
424- cc = false
457+ if hasSourceCallCtx ( config ) then cc = true else cc = false
425458 or
426459 exists ( NodeEx mid |
427460 fwdFlow ( mid , cc , config ) and
@@ -551,7 +584,7 @@ private module Stage1 {
551584 private predicate revFlow0 ( NodeEx node , boolean toReturn , Configuration config ) {
552585 fwdFlow ( node , config ) and
553586 sinkNode ( node , config ) and
554- toReturn = false
587+ if hasSinkCallCtx ( config ) then toReturn = true else toReturn = false
555588 or
556589 exists ( NodeEx mid |
557590 localFlowStep ( node , mid , config ) and
@@ -937,6 +970,8 @@ private module Stage2 {
937970
938971 Cc ccNone ( ) { result instanceof CallContextAny }
939972
973+ CcCall ccSomeCall ( ) { result instanceof CallContextSomeCall }
974+
940975 private class LocalCc = Unit ;
941976
942977 bindingset [ call, c, outercc]
@@ -1004,7 +1039,7 @@ private module Stage2 {
10041039 predicate fwdFlow ( NodeEx node , Cc cc , ApOption argAp , Ap ap , Configuration config ) {
10051040 flowCand ( node , _, config ) and
10061041 sourceNode ( node , config ) and
1007- cc = ccNone ( ) and
1042+ ( if hasSourceCallCtx ( config ) then cc = ccSomeCall ( ) else cc = ccNone ( ) ) and
10081043 argAp = apNone ( ) and
10091044 ap = getApNil ( node )
10101045 or
@@ -1215,7 +1250,7 @@ private module Stage2 {
12151250 ) {
12161251 fwdFlow ( node , _, _, ap , config ) and
12171252 sinkNode ( node , config ) and
1218- toReturn = false and
1253+ ( if hasSinkCallCtx ( config ) then toReturn = true else toReturn = false ) and
12191254 returnAp = apNone ( ) and
12201255 ap instanceof ApNil
12211256 or
@@ -1616,6 +1651,8 @@ private module Stage3 {
16161651
16171652 Cc ccNone ( ) { result = false }
16181653
1654+ CcCall ccSomeCall ( ) { result = true }
1655+
16191656 private class LocalCc = Unit ;
16201657
16211658 bindingset [ call, c, outercc]
@@ -1697,7 +1734,7 @@ private module Stage3 {
16971734 private predicate fwdFlow0 ( NodeEx node , Cc cc , ApOption argAp , Ap ap , Configuration config ) {
16981735 flowCand ( node , _, config ) and
16991736 sourceNode ( node , config ) and
1700- cc = ccNone ( ) and
1737+ ( if hasSourceCallCtx ( config ) then cc = ccSomeCall ( ) else cc = ccNone ( ) ) and
17011738 argAp = apNone ( ) and
17021739 ap = getApNil ( node )
17031740 or
@@ -1908,7 +1945,7 @@ private module Stage3 {
19081945 ) {
19091946 fwdFlow ( node , _, _, ap , config ) and
19101947 sinkNode ( node , config ) and
1911- toReturn = false and
1948+ ( if hasSinkCallCtx ( config ) then toReturn = true else toReturn = false ) and
19121949 returnAp = apNone ( ) and
19131950 ap instanceof ApNil
19141951 or
@@ -2366,6 +2403,8 @@ private module Stage4 {
23662403
23672404 Cc ccNone ( ) { result instanceof CallContextAny }
23682405
2406+ CcCall ccSomeCall ( ) { result instanceof CallContextSomeCall }
2407+
23692408 private class LocalCc = LocalCallContext ;
23702409
23712410 bindingset [ call, c, outercc]
@@ -2461,7 +2500,7 @@ private module Stage4 {
24612500 private predicate fwdFlow0 ( NodeEx node , Cc cc , ApOption argAp , Ap ap , Configuration config ) {
24622501 flowCand ( node , _, config ) and
24632502 sourceNode ( node , config ) and
2464- cc = ccNone ( ) and
2503+ ( if hasSourceCallCtx ( config ) then cc = ccSomeCall ( ) else cc = ccNone ( ) ) and
24652504 argAp = apNone ( ) and
24662505 ap = getApNil ( node )
24672506 or
@@ -2672,7 +2711,7 @@ private module Stage4 {
26722711 ) {
26732712 fwdFlow ( node , _, _, ap , config ) and
26742713 sinkNode ( node , config ) and
2675- toReturn = false and
2714+ ( if hasSinkCallCtx ( config ) then toReturn = true else toReturn = false ) and
26762715 returnAp = apNone ( ) and
26772716 ap instanceof ApNil
26782717 or
@@ -3064,7 +3103,11 @@ private newtype TPathNode =
30643103 // A PathNode is introduced by a source ...
30653104 Stage4:: revFlow ( node , config ) and
30663105 sourceNode ( node , config ) and
3067- cc instanceof CallContextAny and
3106+ (
3107+ if hasSourceCallCtx ( config )
3108+ then cc instanceof CallContextSomeCall
3109+ else cc instanceof CallContextAny
3110+ ) and
30683111 sc instanceof SummaryCtxNone and
30693112 ap = TAccessPathNil ( node .getDataFlowType ( ) )
30703113 or
@@ -3076,17 +3119,10 @@ private newtype TPathNode =
30763119 )
30773120 } or
30783121 TPathNodeSink ( NodeEx node , Configuration config ) {
3079- sinkNode ( node , pragma [ only_bind_into ] ( config ) ) and
3080- Stage4:: revFlow ( node , pragma [ only_bind_into ] ( config ) ) and
3081- (
3082- // A sink that is also a source ...
3083- sourceNode ( node , config )
3084- or
3085- // ... or a sink that can be reached from a source
3086- exists ( PathNodeMid mid |
3087- pathStep ( mid , node , _, _, TAccessPathNil ( _) ) and
3088- pragma [ only_bind_into ] ( config ) = mid .getConfiguration ( )
3089- )
3122+ exists ( PathNodeMid sink |
3123+ sink .isAtSink ( ) and
3124+ node = sink .getNodeEx ( ) and
3125+ config = sink .getConfiguration ( )
30903126 )
30913127 }
30923128
@@ -3403,22 +3439,36 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
34033439 // an intermediate step to another intermediate node
34043440 result = this .getSuccMid ( )
34053441 or
3406- // a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
3407- exists ( PathNodeMid mid , PathNodeSink sink |
3408- mid = this .getSuccMid ( ) and
3409- mid .getNodeEx ( ) = sink .getNodeEx ( ) and
3410- mid .getAp ( ) instanceof AccessPathNil and
3411- sink .getConfiguration ( ) = unbindConf ( mid .getConfiguration ( ) ) and
3412- result = sink
3413- )
3442+ // a final step to a sink
3443+ result = this .getSuccMid ( ) .projectToSink ( )
34143444 }
34153445
34163446 override predicate isSource ( ) {
34173447 sourceNode ( node , config ) and
3418- cc instanceof CallContextAny and
3448+ (
3449+ if hasSourceCallCtx ( config )
3450+ then cc instanceof CallContextSomeCall
3451+ else cc instanceof CallContextAny
3452+ ) and
34193453 sc instanceof SummaryCtxNone and
34203454 ap instanceof AccessPathNil
34213455 }
3456+
3457+ predicate isAtSink ( ) {
3458+ sinkNode ( node , config ) and
3459+ ap instanceof AccessPathNil and
3460+ if hasSinkCallCtx ( config )
3461+ then
3462+ sc instanceof SummaryCtxNone or
3463+ cc instanceof CallContextNoCall
3464+ else any ( )
3465+ }
3466+
3467+ PathNodeSink projectToSink ( ) {
3468+ this .isAtSink ( ) and
3469+ result .getNodeEx ( ) = node and
3470+ result .getConfiguration ( ) = unbindConf ( config )
3471+ }
34223472}
34233473
34243474/**
@@ -3613,7 +3663,8 @@ private predicate pathIntoCallable(
36133663 sc = TSummaryCtxSome ( p , ap )
36143664 or
36153665 not exists ( TSummaryCtxSome ( p , ap ) ) and
3616- sc = TSummaryCtxNone ( )
3666+ sc = TSummaryCtxNone ( ) and
3667+ not config .getAFeature ( ) instanceof FeatureEqualSourceSinkCallContext
36173668 )
36183669 |
36193670 if recordDataFlowCallSite ( call , callable )
0 commit comments