@@ -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 ( ) }
@@ -234,7 +246,9 @@ module Private {
234246 TContentSummaryComponent ( ContentSet c ) or
235247 TParameterSummaryComponent ( ArgumentPosition pos ) or
236248 TArgumentSummaryComponent ( ParameterPosition pos ) or
237- TReturnSummaryComponent ( ReturnKind rk )
249+ TReturnSummaryComponent ( ReturnKind rk ) or
250+ TWithoutContentSummaryComponent ( ContentSet c ) or
251+ TWithContentSummaryComponent ( ContentSet c )
238252
239253 private TParameterSummaryComponent thisParam ( ) {
240254 result = TParameterSummaryComponent ( instanceParameterPosition ( ) )
@@ -296,6 +310,23 @@ module Private {
296310 SummaryComponentStack:: singleton ( TArgumentSummaryComponent ( _) ) ) and
297311 preservesValue = preservesValue1 .booleanAnd ( preservesValue2 )
298312 )
313+ or
314+ exists ( ParameterPosition ppos , ContentSet cs |
315+ c .clearsContent ( ppos , cs ) and
316+ input = SummaryComponentStack:: push ( SummaryComponent:: withoutContent ( cs ) , output ) and
317+ output = SummaryComponentStack:: argument ( ppos ) and
318+ preservesValue = true
319+ )
320+ }
321+
322+ private class MkClearStack extends RequiredSummaryComponentStack {
323+ override predicate required ( SummaryComponent head , SummaryComponentStack tail ) {
324+ exists ( SummarizedCallable sc , ParameterPosition ppos , ContentSet cs |
325+ sc .clearsContent ( ppos , cs ) and
326+ head = SummaryComponent:: withoutContent ( cs ) and
327+ tail = SummaryComponentStack:: argument ( ppos )
328+ )
329+ }
299330 }
300331
301332 /**
@@ -378,10 +409,7 @@ module Private {
378409
379410 private newtype TSummaryNodeState =
380411 TSummaryNodeInputState ( SummaryComponentStack s ) { inputState ( _, s ) } or
381- TSummaryNodeOutputState ( SummaryComponentStack s ) { outputState ( _, s ) } or
382- TSummaryNodeClearsContentState ( ParameterPosition pos , boolean post ) {
383- any ( SummarizedCallable sc ) .clearsContent ( pos , _) and post in [ false , true ]
384- }
412+ TSummaryNodeOutputState ( SummaryComponentStack s ) { outputState ( _, s ) }
385413
386414 /**
387415 * A state used to break up (complex) flow summaries into atomic flow steps.
@@ -428,12 +456,6 @@ module Private {
428456 this = TSummaryNodeOutputState ( s ) and
429457 result = "to write: " + s
430458 )
431- or
432- exists ( ParameterPosition pos , boolean post , string postStr |
433- this = TSummaryNodeClearsContentState ( pos , post ) and
434- ( if post = true then postStr = " (post)" else postStr = "" ) and
435- result = "clear: " + pos + postStr
436- )
437459 }
438460 }
439461
@@ -457,11 +479,6 @@ module Private {
457479 not parameterReadState ( c , state , _)
458480 or
459481 state .isOutputState ( c , _)
460- or
461- exists ( ParameterPosition pos |
462- c .clearsContent ( pos , _) and
463- state = TSummaryNodeClearsContentState ( pos , _)
464- )
465482 }
466483
467484 pragma [ noinline]
@@ -497,24 +514,22 @@ module Private {
497514 parameterReadState ( c , _, pos )
498515 or
499516 isParameterPostUpdate ( _, c , pos )
500- or
501- c .clearsContent ( pos , _)
502517 }
503518
504519 private predicate callbackOutput (
505520 SummarizedCallable c , SummaryComponentStack s , Node receiver , ReturnKind rk
506521 ) {
507522 any ( SummaryNodeState state ) .isInputState ( c , s ) and
508523 s .head ( ) = TReturnSummaryComponent ( rk ) and
509- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
524+ receiver = summaryNodeInputState ( c , s .tail ( ) )
510525 }
511526
512527 private predicate callbackInput (
513528 SummarizedCallable c , SummaryComponentStack s , Node receiver , ArgumentPosition pos
514529 ) {
515530 any ( SummaryNodeState state ) .isOutputState ( c , s ) and
516531 s .head ( ) = TParameterSummaryComponent ( pos ) and
517- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
532+ receiver = summaryNodeInputState ( c , s .tail ( ) )
518533 }
519534
520535 /** Holds if a call targeting `receiver` should be synthesized inside `c`. */
@@ -540,15 +555,21 @@ module Private {
540555 exists ( SummarizedCallable c , SummaryComponentStack s , SummaryComponent head | head = s .head ( ) |
541556 n = summaryNodeInputState ( c , s ) and
542557 (
558+ exists ( ContentSet cont | result = getContentType ( cont ) |
559+ head = TContentSummaryComponent ( cont ) or
560+ head = TWithContentSummaryComponent ( cont )
561+ )
562+ or
543563 exists ( ContentSet cont |
544- head = TContentSummaryComponent ( cont ) and result = getContentType ( cont )
564+ head = TWithoutContentSummaryComponent ( cont ) and
565+ result = getNodeType ( summaryNodeInputState ( c , s .tail ( ) ) )
545566 )
546567 or
547568 exists ( ReturnKind rk |
548569 head = TReturnSummaryComponent ( rk ) and
549570 result =
550571 getCallbackReturnType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
551- s .drop ( 1 ) ) ) , rk )
572+ s .tail ( ) ) ) , rk )
552573 )
553574 )
554575 or
@@ -567,16 +588,10 @@ module Private {
567588 exists ( ArgumentPosition pos | head = TParameterSummaryComponent ( pos ) |
568589 result =
569590 getCallbackParameterType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
570- s .drop ( 1 ) ) ) , pos )
591+ s .tail ( ) ) ) , pos )
571592 )
572593 )
573594 )
574- or
575- exists ( SummarizedCallable c , ParameterPosition pos , ParamNode p |
576- n = summaryNode ( c , TSummaryNodeClearsContentState ( pos , false ) ) and
577- p .isParameterOf ( c , pos ) and
578- result = getNodeType ( p )
579- )
580595 }
581596
582597 /** Holds if summary node `out` contains output of kind `rk` from call `c`. */
@@ -602,9 +617,6 @@ module Private {
602617 exists ( SummarizedCallable c , ParameterPosition pos |
603618 isParameterPostUpdate ( post , c , pos ) and
604619 pre .( ParamNode ) .isParameterOf ( c , pos )
605- or
606- pre = summaryNode ( c , TSummaryNodeClearsContentState ( pos , false ) ) and
607- post = summaryNode ( c , TSummaryNodeClearsContentState ( pos , true ) )
608620 )
609621 or
610622 exists ( SummarizedCallable callable , SummaryComponentStack s |
@@ -628,8 +640,6 @@ module Private {
628640 */
629641 predicate summaryAllowParameterReturnInSelf ( ParamNode p ) {
630642 exists ( SummarizedCallable c , ParameterPosition ppos | p .isParameterOf ( c , ppos ) |
631- c .clearsContent ( ppos , _)
632- or
633643 exists ( SummaryComponentStack inputContents , SummaryComponentStack outputContents |
634644 summary ( c , inputContents , outputContents , _) and
635645 inputContents .bottom ( ) = pragma [ only_bind_into ] ( TArgumentSummaryComponent ( ppos ) ) and
@@ -658,9 +668,10 @@ module Private {
658668 preservesValue = false and not summary ( c , inputContents , outputContents , true )
659669 )
660670 or
661- exists ( SummarizedCallable c , ParameterPosition pos |
662- pred .( ParamNode ) .isParameterOf ( c , pos ) and
663- succ = summaryNode ( c , TSummaryNodeClearsContentState ( pos , _) ) and
671+ exists ( SummarizedCallable c , SummaryComponentStack s |
672+ pred = summaryNodeInputState ( c , s .tail ( ) ) and
673+ succ = summaryNodeInputState ( c , s ) and
674+ s .head ( ) = [ SummaryComponent:: withContent ( _) , SummaryComponent:: withoutContent ( _) ] and
664675 preservesValue = true
665676 )
666677 }
@@ -671,7 +682,7 @@ module Private {
671682 */
672683 predicate summaryReadStep ( Node pred , ContentSet c , Node succ ) {
673684 exists ( SummarizedCallable sc , SummaryComponentStack s |
674- pred = summaryNodeInputState ( sc , s .drop ( 1 ) ) and
685+ pred = summaryNodeInputState ( sc , s .tail ( ) ) and
675686 succ = summaryNodeInputState ( sc , s ) and
676687 SummaryComponent:: content ( c ) = s .head ( )
677688 )
@@ -684,7 +695,7 @@ module Private {
684695 predicate summaryStoreStep ( Node pred , ContentSet c , Node succ ) {
685696 exists ( SummarizedCallable sc , SummaryComponentStack s |
686697 pred = summaryNodeOutputState ( sc , s ) and
687- succ = summaryNodeOutputState ( sc , s .drop ( 1 ) ) and
698+ succ = summaryNodeOutputState ( sc , s .tail ( ) ) and
688699 SummaryComponent:: content ( c ) = s .head ( )
689700 )
690701 }
@@ -709,9 +720,22 @@ module Private {
709720 * node where field `b` is cleared).
710721 */
711722 predicate summaryClearsContent ( Node n , ContentSet c ) {
712- exists ( SummarizedCallable sc , ParameterPosition pos |
713- n = summaryNode ( sc , TSummaryNodeClearsContentState ( pos , true ) ) and
714- sc .clearsContent ( pos , c )
723+ exists ( SummarizedCallable sc , SummaryNodeState state , SummaryComponentStack stack |
724+ n = summaryNode ( sc , state ) and
725+ state .isInputState ( sc , stack ) and
726+ stack .head ( ) = SummaryComponent:: withoutContent ( c )
727+ )
728+ }
729+
730+ /**
731+ * Holds if the value that is being tracked is expected to be stored inside
732+ * content `c` at `n`.
733+ */
734+ predicate summaryExpectsContent ( Node n , ContentSet c ) {
735+ exists ( SummarizedCallable sc , SummaryNodeState state , SummaryComponentStack stack |
736+ n = summaryNode ( sc , state ) and
737+ state .isInputState ( sc , stack ) and
738+ stack .head ( ) = SummaryComponent:: withContent ( c )
715739 )
716740 }
717741
@@ -723,27 +747,32 @@ module Private {
723747 sc = viableCallable ( call )
724748 }
725749
726- /**
727- * Holds if values stored inside content `c` are cleared inside a
728- * callable to which `arg` is an argument.
729- *
730- * In such cases, it is important to prevent use-use flow out of
731- * `arg` (see comment for `summaryClearsContent`).
732- */
733750 pragma [ nomagic]
734- predicate summaryClearsContentArg ( ArgNode arg , ContentSet c ) {
735- exists ( DataFlowCall call , SummarizedCallable sc , ParameterPosition ppos |
751+ private ParamNode summaryArgParam0 ( DataFlowCall call , ArgNode arg ) {
752+ exists ( ParameterPosition ppos , SummarizedCallable sc |
736753 argumentPositionMatch ( call , arg , ppos ) and
737- viableParam ( call , sc , ppos , _) and
738- sc .clearsContent ( ppos , c )
754+ viableParam ( call , sc , ppos , result )
739755 )
740756 }
741757
758+ /**
759+ * Holds if use-use flow starting from `arg` should be prohibited.
760+ *
761+ * This is the case when `arg` is the argument of a call that targets a
762+ * flow summary where the corresponding parameter either clears contents
763+ * or expects contents.
764+ */
742765 pragma [ nomagic]
743- private ParamNode summaryArgParam0 ( DataFlowCall call , ArgNode arg ) {
744- exists ( ParameterPosition ppos , SummarizedCallable sc |
745- argumentPositionMatch ( call , arg , ppos ) and
746- viableParam ( call , sc , ppos , result )
766+ predicate prohibitsUseUseFlow ( ArgNode arg ) {
767+ exists ( ParamNode p , Node mid , ParameterPosition ppos , Node ret |
768+ p = summaryArgParam0 ( _, arg ) and
769+ p .isParameterOf ( _, ppos ) and
770+ summaryLocalStep ( p , mid , true ) and
771+ summaryLocalStep ( mid , ret , true ) and
772+ isParameterPostUpdate ( ret , _, ppos )
773+ |
774+ summaryClearsContent ( mid , _) or
775+ summaryExpectsContent ( mid , _)
747776 )
748777 }
749778
@@ -1141,6 +1170,10 @@ module Private {
11411170 Private:: Steps:: summaryClearsContent ( a .asNode ( ) , c ) and
11421171 b = a and
11431172 value = "clear (" + c + ")"
1173+ or
1174+ Private:: Steps:: summaryExpectsContent ( a .asNode ( ) , c ) and
1175+ b = a and
1176+ value = "expect (" + c + ")"
11441177 )
11451178 or
11461179 summaryPostUpdateNode ( b .asNode ( ) , a .asNode ( ) ) and
0 commit comments