@@ -26,6 +26,10 @@ module Public {
2626 string toString ( ) {
2727 exists ( ContentSet c | this = TContentSummaryComponent ( c ) and result = c .toString ( ) )
2828 or
29+ exists ( ContentSet c | this = TWithoutContentSummaryComponent ( c ) and result = "without " + c )
30+ or
31+ exists ( ContentSet c | this = TWithContentSummaryComponent ( c ) and result = "with " + c )
32+ or
2933 exists ( ArgumentPosition pos |
3034 this = TParameterSummaryComponent ( pos ) and result = "parameter " + pos
3135 )
@@ -43,6 +47,12 @@ module Public {
4347 /** Gets a summary component for content `c`. */
4448 SummaryComponent content ( ContentSet c ) { result = TContentSummaryComponent ( c ) }
4549
50+ /** Gets a summary component where data is not allowed to be stored in `c`. */
51+ SummaryComponent withoutContent ( ContentSet c ) { result = TWithoutContentSummaryComponent ( c ) }
52+
53+ /** Gets a summary component where data must be stored in `c`. */
54+ SummaryComponent withContent ( ContentSet c ) { result = TWithContentSummaryComponent ( c ) }
55+
4656 /** Gets a summary component for a parameter at position `pos`. */
4757 SummaryComponent parameter ( ArgumentPosition pos ) { result = TParameterSummaryComponent ( pos ) }
4858
@@ -216,6 +226,8 @@ module Public {
216226 /**
217227 * Holds if values stored inside `content` are cleared on objects passed as
218228 * arguments at position `pos` to this callable.
229+ *
230+ * TODO: Remove once all languages support `WithoutContent` tokens.
219231 */
220232 pragma [ nomagic]
221233 predicate clearsContent ( ParameterPosition pos , ContentSet content ) { none ( ) }
@@ -239,7 +251,9 @@ module Private {
239251 TContentSummaryComponent ( ContentSet c ) or
240252 TParameterSummaryComponent ( ArgumentPosition pos ) or
241253 TArgumentSummaryComponent ( ParameterPosition pos ) or
242- TReturnSummaryComponent ( ReturnKind rk )
254+ TReturnSummaryComponent ( ReturnKind rk ) or
255+ TWithoutContentSummaryComponent ( ContentSet c ) or
256+ TWithContentSummaryComponent ( ContentSet c )
243257
244258 private TParameterSummaryComponent thisParam ( ) {
245259 result = TParameterSummaryComponent ( instanceParameterPosition ( ) )
@@ -301,6 +315,23 @@ module Private {
301315 SummaryComponentStack:: singleton ( TArgumentSummaryComponent ( _) ) ) and
302316 preservesValue = preservesValue1 .booleanAnd ( preservesValue2 )
303317 )
318+ or
319+ exists ( ParameterPosition ppos , ContentSet cs |
320+ c .clearsContent ( ppos , cs ) and
321+ input = SummaryComponentStack:: push ( SummaryComponent:: withoutContent ( cs ) , output ) and
322+ output = SummaryComponentStack:: argument ( ppos ) and
323+ preservesValue = true
324+ )
325+ }
326+
327+ private class MkClearStack extends RequiredSummaryComponentStack {
328+ override predicate required ( SummaryComponent head , SummaryComponentStack tail ) {
329+ exists ( SummarizedCallable sc , ParameterPosition ppos , ContentSet cs |
330+ sc .clearsContent ( ppos , cs ) and
331+ head = SummaryComponent:: withoutContent ( cs ) and
332+ tail = SummaryComponentStack:: argument ( ppos )
333+ )
334+ }
304335 }
305336
306337 /**
@@ -383,10 +414,7 @@ module Private {
383414
384415 private newtype TSummaryNodeState =
385416 TSummaryNodeInputState ( SummaryComponentStack s ) { inputState ( _, s ) } or
386- TSummaryNodeOutputState ( SummaryComponentStack s ) { outputState ( _, s ) } or
387- TSummaryNodeClearsContentState ( ParameterPosition pos , boolean post ) {
388- any ( SummarizedCallable sc ) .clearsContent ( pos , _) and post in [ false , true ]
389- }
417+ TSummaryNodeOutputState ( SummaryComponentStack s ) { outputState ( _, s ) }
390418
391419 /**
392420 * A state used to break up (complex) flow summaries into atomic flow steps.
@@ -433,12 +461,6 @@ module Private {
433461 this = TSummaryNodeOutputState ( s ) and
434462 result = "to write: " + s
435463 )
436- or
437- exists ( ParameterPosition pos , boolean post , string postStr |
438- this = TSummaryNodeClearsContentState ( pos , post ) and
439- ( if post = true then postStr = " (post)" else postStr = "" ) and
440- result = "clear: " + pos + postStr
441- )
442464 }
443465 }
444466
@@ -462,11 +484,6 @@ module Private {
462484 not parameterReadState ( c , state , _)
463485 or
464486 state .isOutputState ( c , _)
465- or
466- exists ( ParameterPosition pos |
467- c .clearsContent ( pos , _) and
468- state = TSummaryNodeClearsContentState ( pos , _)
469- )
470487 }
471488
472489 pragma [ noinline]
@@ -502,24 +519,22 @@ module Private {
502519 parameterReadState ( c , _, pos )
503520 or
504521 isParameterPostUpdate ( _, c , pos )
505- or
506- c .clearsContent ( pos , _)
507522 }
508523
509524 private predicate callbackOutput (
510525 SummarizedCallable c , SummaryComponentStack s , Node receiver , ReturnKind rk
511526 ) {
512527 any ( SummaryNodeState state ) .isInputState ( c , s ) and
513528 s .head ( ) = TReturnSummaryComponent ( rk ) and
514- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
529+ receiver = summaryNodeInputState ( c , s .tail ( ) )
515530 }
516531
517532 private predicate callbackInput (
518533 SummarizedCallable c , SummaryComponentStack s , Node receiver , ArgumentPosition pos
519534 ) {
520535 any ( SummaryNodeState state ) .isOutputState ( c , s ) and
521536 s .head ( ) = TParameterSummaryComponent ( pos ) and
522- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
537+ receiver = summaryNodeInputState ( c , s .tail ( ) )
523538 }
524539
525540 /** Holds if a call targeting `receiver` should be synthesized inside `c`. */
@@ -545,15 +560,21 @@ module Private {
545560 exists ( SummarizedCallable c , SummaryComponentStack s , SummaryComponent head | head = s .head ( ) |
546561 n = summaryNodeInputState ( c , s ) and
547562 (
563+ exists ( ContentSet cont | result = getContentType ( cont ) |
564+ head = TContentSummaryComponent ( cont ) or
565+ head = TWithContentSummaryComponent ( cont )
566+ )
567+ or
548568 exists ( ContentSet cont |
549- head = TContentSummaryComponent ( cont ) and result = getContentType ( cont )
569+ head = TWithoutContentSummaryComponent ( cont ) and
570+ result = getNodeType ( summaryNodeInputState ( c , s .tail ( ) ) )
550571 )
551572 or
552573 exists ( ReturnKind rk |
553574 head = TReturnSummaryComponent ( rk ) and
554575 result =
555576 getCallbackReturnType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
556- s .drop ( 1 ) ) ) , rk )
577+ s .tail ( ) ) ) , rk )
557578 )
558579 )
559580 or
@@ -572,16 +593,10 @@ module Private {
572593 exists ( ArgumentPosition pos | head = TParameterSummaryComponent ( pos ) |
573594 result =
574595 getCallbackParameterType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
575- s .drop ( 1 ) ) ) , pos )
596+ s .tail ( ) ) ) , pos )
576597 )
577598 )
578599 )
579- or
580- exists ( SummarizedCallable c , ParameterPosition pos , ParamNode p |
581- n = summaryNode ( c , TSummaryNodeClearsContentState ( pos , false ) ) and
582- p .isParameterOf ( c , pos ) and
583- result = getNodeType ( p )
584- )
585600 }
586601
587602 /** Holds if summary node `out` contains output of kind `rk` from call `c`. */
@@ -607,9 +622,6 @@ module Private {
607622 exists ( SummarizedCallable c , ParameterPosition pos |
608623 isParameterPostUpdate ( post , c , pos ) and
609624 pre .( ParamNode ) .isParameterOf ( c , pos )
610- or
611- pre = summaryNode ( c , TSummaryNodeClearsContentState ( pos , false ) ) and
612- post = summaryNode ( c , TSummaryNodeClearsContentState ( pos , true ) )
613625 )
614626 or
615627 exists ( SummarizedCallable callable , SummaryComponentStack s |
@@ -633,8 +645,6 @@ module Private {
633645 */
634646 predicate summaryAllowParameterReturnInSelf ( ParamNode p ) {
635647 exists ( SummarizedCallable c , ParameterPosition ppos | p .isParameterOf ( c , ppos ) |
636- c .clearsContent ( ppos , _)
637- or
638648 exists ( SummaryComponentStack inputContents , SummaryComponentStack outputContents |
639649 summary ( c , inputContents , outputContents , _) and
640650 inputContents .bottom ( ) = pragma [ only_bind_into ] ( TArgumentSummaryComponent ( ppos ) ) and
@@ -663,9 +673,10 @@ module Private {
663673 preservesValue = false and not summary ( c , inputContents , outputContents , true )
664674 )
665675 or
666- exists ( SummarizedCallable c , ParameterPosition pos |
667- pred .( ParamNode ) .isParameterOf ( c , pos ) and
668- succ = summaryNode ( c , TSummaryNodeClearsContentState ( pos , _) ) and
676+ exists ( SummarizedCallable c , SummaryComponentStack s |
677+ pred = summaryNodeInputState ( c , s .tail ( ) ) and
678+ succ = summaryNodeInputState ( c , s ) and
679+ s .head ( ) = [ SummaryComponent:: withContent ( _) , SummaryComponent:: withoutContent ( _) ] and
669680 preservesValue = true
670681 )
671682 }
@@ -676,7 +687,7 @@ module Private {
676687 */
677688 predicate summaryReadStep ( Node pred , ContentSet c , Node succ ) {
678689 exists ( SummarizedCallable sc , SummaryComponentStack s |
679- pred = summaryNodeInputState ( sc , s .drop ( 1 ) ) and
690+ pred = summaryNodeInputState ( sc , s .tail ( ) ) and
680691 succ = summaryNodeInputState ( sc , s ) and
681692 SummaryComponent:: content ( c ) = s .head ( )
682693 )
@@ -689,7 +700,7 @@ module Private {
689700 predicate summaryStoreStep ( Node pred , ContentSet c , Node succ ) {
690701 exists ( SummarizedCallable sc , SummaryComponentStack s |
691702 pred = summaryNodeOutputState ( sc , s ) and
692- succ = summaryNodeOutputState ( sc , s .drop ( 1 ) ) and
703+ succ = summaryNodeOutputState ( sc , s .tail ( ) ) and
693704 SummaryComponent:: content ( c ) = s .head ( )
694705 )
695706 }
@@ -714,9 +725,22 @@ module Private {
714725 * node where field `b` is cleared).
715726 */
716727 predicate summaryClearsContent ( Node n , ContentSet c ) {
717- exists ( SummarizedCallable sc , ParameterPosition pos |
718- n = summaryNode ( sc , TSummaryNodeClearsContentState ( pos , true ) ) and
719- sc .clearsContent ( pos , c )
728+ exists ( SummarizedCallable sc , SummaryNodeState state , SummaryComponentStack stack |
729+ n = summaryNode ( sc , state ) and
730+ state .isInputState ( sc , stack ) and
731+ stack .head ( ) = SummaryComponent:: withoutContent ( c )
732+ )
733+ }
734+
735+ /**
736+ * Holds if the value that is being tracked is expected to be stored inside
737+ * content `c` at `n`.
738+ */
739+ predicate summaryExpectsContent ( Node n , ContentSet c ) {
740+ exists ( SummarizedCallable sc , SummaryNodeState state , SummaryComponentStack stack |
741+ n = summaryNode ( sc , state ) and
742+ state .isInputState ( sc , stack ) and
743+ stack .head ( ) = SummaryComponent:: withContent ( c )
720744 )
721745 }
722746
@@ -728,27 +752,32 @@ module Private {
728752 sc = viableCallable ( call )
729753 }
730754
731- /**
732- * Holds if values stored inside content `c` are cleared inside a
733- * callable to which `arg` is an argument.
734- *
735- * In such cases, it is important to prevent use-use flow out of
736- * `arg` (see comment for `summaryClearsContent`).
737- */
738755 pragma [ nomagic]
739- predicate summaryClearsContentArg ( ArgNode arg , ContentSet c ) {
740- exists ( DataFlowCall call , SummarizedCallable sc , ParameterPosition ppos |
756+ private ParamNode summaryArgParam0 ( DataFlowCall call , ArgNode arg ) {
757+ exists ( ParameterPosition ppos , SummarizedCallable sc |
741758 argumentPositionMatch ( call , arg , ppos ) and
742- viableParam ( call , sc , ppos , _) and
743- sc .clearsContent ( ppos , c )
759+ viableParam ( call , sc , ppos , result )
744760 )
745761 }
746762
763+ /**
764+ * Holds if use-use flow starting from `arg` should be prohibited.
765+ *
766+ * This is the case when `arg` is the argument of a call that targets a
767+ * flow summary where the corresponding parameter either clears contents
768+ * or expects contents.
769+ */
747770 pragma [ nomagic]
748- private ParamNode summaryArgParam0 ( DataFlowCall call , ArgNode arg ) {
749- exists ( ParameterPosition ppos , SummarizedCallable sc |
750- argumentPositionMatch ( call , arg , ppos ) and
751- viableParam ( call , sc , ppos , result )
771+ predicate prohibitsUseUseFlow ( ArgNode arg ) {
772+ exists ( ParamNode p , Node mid , ParameterPosition ppos , Node ret |
773+ p = summaryArgParam0 ( _, arg ) and
774+ p .isParameterOf ( _, ppos ) and
775+ summaryLocalStep ( p , mid , true ) and
776+ summaryLocalStep ( mid , ret , true ) and
777+ isParameterPostUpdate ( ret , _, ppos )
778+ |
779+ summaryClearsContent ( mid , _) or
780+ summaryExpectsContent ( mid , _)
752781 )
753782 }
754783
@@ -1152,6 +1181,10 @@ module Private {
11521181 Private:: Steps:: summaryClearsContent ( a .asNode ( ) , c ) and
11531182 b = a and
11541183 value = "clear (" + c + ")"
1184+ or
1185+ Private:: Steps:: summaryExpectsContent ( a .asNode ( ) , c ) and
1186+ b = a and
1187+ value = "expect (" + c + ")"
11551188 )
11561189 or
11571190 summaryPostUpdateNode ( b .asNode ( ) , a .asNode ( ) ) and
0 commit comments