@@ -26,6 +26,10 @@ module Public {
26
26
string toString ( ) {
27
27
exists ( ContentSet c | this = TContentSummaryComponent ( c ) and result = c .toString ( ) )
28
28
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
29
33
exists ( ArgumentPosition pos |
30
34
this = TParameterSummaryComponent ( pos ) and result = "parameter " + pos
31
35
)
@@ -43,6 +47,12 @@ module Public {
43
47
/** Gets a summary component for content `c`. */
44
48
SummaryComponent content ( ContentSet c ) { result = TContentSummaryComponent ( c ) }
45
49
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
+
46
56
/** Gets a summary component for a parameter at position `pos`. */
47
57
SummaryComponent parameter ( ArgumentPosition pos ) { result = TParameterSummaryComponent ( pos ) }
48
58
@@ -216,6 +226,8 @@ module Public {
216
226
/**
217
227
* Holds if values stored inside `content` are cleared on objects passed as
218
228
* arguments at position `pos` to this callable.
229
+ *
230
+ * TODO: Remove once all languages support `WithoutContent` tokens.
219
231
*/
220
232
pragma [ nomagic]
221
233
predicate clearsContent ( ParameterPosition pos , ContentSet content ) { none ( ) }
@@ -234,7 +246,9 @@ module Private {
234
246
TContentSummaryComponent ( ContentSet c ) or
235
247
TParameterSummaryComponent ( ArgumentPosition pos ) or
236
248
TArgumentSummaryComponent ( ParameterPosition pos ) or
237
- TReturnSummaryComponent ( ReturnKind rk )
249
+ TReturnSummaryComponent ( ReturnKind rk ) or
250
+ TWithoutContentSummaryComponent ( ContentSet c ) or
251
+ TWithContentSummaryComponent ( ContentSet c )
238
252
239
253
private TParameterSummaryComponent thisParam ( ) {
240
254
result = TParameterSummaryComponent ( instanceParameterPosition ( ) )
@@ -296,6 +310,23 @@ module Private {
296
310
SummaryComponentStack:: singleton ( TArgumentSummaryComponent ( _) ) ) and
297
311
preservesValue = preservesValue1 .booleanAnd ( preservesValue2 )
298
312
)
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
+ }
299
330
}
300
331
301
332
/**
@@ -378,10 +409,7 @@ module Private {
378
409
379
410
private newtype TSummaryNodeState =
380
411
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 ) }
385
413
386
414
/**
387
415
* A state used to break up (complex) flow summaries into atomic flow steps.
@@ -428,12 +456,6 @@ module Private {
428
456
this = TSummaryNodeOutputState ( s ) and
429
457
result = "to write: " + s
430
458
)
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
- )
437
459
}
438
460
}
439
461
@@ -457,11 +479,6 @@ module Private {
457
479
not parameterReadState ( c , state , _)
458
480
or
459
481
state .isOutputState ( c , _)
460
- or
461
- exists ( ParameterPosition pos |
462
- c .clearsContent ( pos , _) and
463
- state = TSummaryNodeClearsContentState ( pos , _)
464
- )
465
482
}
466
483
467
484
pragma [ noinline]
@@ -497,24 +514,22 @@ module Private {
497
514
parameterReadState ( c , _, pos )
498
515
or
499
516
isParameterPostUpdate ( _, c , pos )
500
- or
501
- c .clearsContent ( pos , _)
502
517
}
503
518
504
519
private predicate callbackOutput (
505
520
SummarizedCallable c , SummaryComponentStack s , Node receiver , ReturnKind rk
506
521
) {
507
522
any ( SummaryNodeState state ) .isInputState ( c , s ) and
508
523
s .head ( ) = TReturnSummaryComponent ( rk ) and
509
- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
524
+ receiver = summaryNodeInputState ( c , s .tail ( ) )
510
525
}
511
526
512
527
private predicate callbackInput (
513
528
SummarizedCallable c , SummaryComponentStack s , Node receiver , ArgumentPosition pos
514
529
) {
515
530
any ( SummaryNodeState state ) .isOutputState ( c , s ) and
516
531
s .head ( ) = TParameterSummaryComponent ( pos ) and
517
- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
532
+ receiver = summaryNodeInputState ( c , s .tail ( ) )
518
533
}
519
534
520
535
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
@@ -540,15 +555,21 @@ module Private {
540
555
exists ( SummarizedCallable c , SummaryComponentStack s , SummaryComponent head | head = s .head ( ) |
541
556
n = summaryNodeInputState ( c , s ) and
542
557
(
558
+ exists ( ContentSet cont | result = getContentType ( cont ) |
559
+ head = TContentSummaryComponent ( cont ) or
560
+ head = TWithContentSummaryComponent ( cont )
561
+ )
562
+ or
543
563
exists ( ContentSet cont |
544
- head = TContentSummaryComponent ( cont ) and result = getContentType ( cont )
564
+ head = TWithoutContentSummaryComponent ( cont ) and
565
+ result = getNodeType ( summaryNodeInputState ( c , s .tail ( ) ) )
545
566
)
546
567
or
547
568
exists ( ReturnKind rk |
548
569
head = TReturnSummaryComponent ( rk ) and
549
570
result =
550
571
getCallbackReturnType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
551
- s .drop ( 1 ) ) ) , rk )
572
+ s .tail ( ) ) ) , rk )
552
573
)
553
574
)
554
575
or
@@ -567,16 +588,10 @@ module Private {
567
588
exists ( ArgumentPosition pos | head = TParameterSummaryComponent ( pos ) |
568
589
result =
569
590
getCallbackParameterType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
570
- s .drop ( 1 ) ) ) , pos )
591
+ s .tail ( ) ) ) , pos )
571
592
)
572
593
)
573
594
)
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
- )
580
595
}
581
596
582
597
/** Holds if summary node `out` contains output of kind `rk` from call `c`. */
@@ -602,9 +617,6 @@ module Private {
602
617
exists ( SummarizedCallable c , ParameterPosition pos |
603
618
isParameterPostUpdate ( post , c , pos ) and
604
619
pre .( ParamNode ) .isParameterOf ( c , pos )
605
- or
606
- pre = summaryNode ( c , TSummaryNodeClearsContentState ( pos , false ) ) and
607
- post = summaryNode ( c , TSummaryNodeClearsContentState ( pos , true ) )
608
620
)
609
621
or
610
622
exists ( SummarizedCallable callable , SummaryComponentStack s |
@@ -628,8 +640,6 @@ module Private {
628
640
*/
629
641
predicate summaryAllowParameterReturnInSelf ( ParamNode p ) {
630
642
exists ( SummarizedCallable c , ParameterPosition ppos | p .isParameterOf ( c , ppos ) |
631
- c .clearsContent ( ppos , _)
632
- or
633
643
exists ( SummaryComponentStack inputContents , SummaryComponentStack outputContents |
634
644
summary ( c , inputContents , outputContents , _) and
635
645
inputContents .bottom ( ) = pragma [ only_bind_into ] ( TArgumentSummaryComponent ( ppos ) ) and
@@ -658,9 +668,10 @@ module Private {
658
668
preservesValue = false and not summary ( c , inputContents , outputContents , true )
659
669
)
660
670
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
664
675
preservesValue = true
665
676
)
666
677
}
@@ -671,7 +682,7 @@ module Private {
671
682
*/
672
683
predicate summaryReadStep ( Node pred , ContentSet c , Node succ ) {
673
684
exists ( SummarizedCallable sc , SummaryComponentStack s |
674
- pred = summaryNodeInputState ( sc , s .drop ( 1 ) ) and
685
+ pred = summaryNodeInputState ( sc , s .tail ( ) ) and
675
686
succ = summaryNodeInputState ( sc , s ) and
676
687
SummaryComponent:: content ( c ) = s .head ( )
677
688
)
@@ -684,7 +695,7 @@ module Private {
684
695
predicate summaryStoreStep ( Node pred , ContentSet c , Node succ ) {
685
696
exists ( SummarizedCallable sc , SummaryComponentStack s |
686
697
pred = summaryNodeOutputState ( sc , s ) and
687
- succ = summaryNodeOutputState ( sc , s .drop ( 1 ) ) and
698
+ succ = summaryNodeOutputState ( sc , s .tail ( ) ) and
688
699
SummaryComponent:: content ( c ) = s .head ( )
689
700
)
690
701
}
@@ -709,9 +720,22 @@ module Private {
709
720
* node where field `b` is cleared).
710
721
*/
711
722
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 )
715
739
)
716
740
}
717
741
@@ -723,27 +747,32 @@ module Private {
723
747
sc = viableCallable ( call )
724
748
}
725
749
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
- */
733
750
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 |
736
753
argumentPositionMatch ( call , arg , ppos ) and
737
- viableParam ( call , sc , ppos , _) and
738
- sc .clearsContent ( ppos , c )
754
+ viableParam ( call , sc , ppos , result )
739
755
)
740
756
}
741
757
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
+ */
742
765
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 , _)
747
776
)
748
777
}
749
778
@@ -1141,6 +1170,10 @@ module Private {
1141
1170
Private:: Steps:: summaryClearsContent ( a .asNode ( ) , c ) and
1142
1171
b = a and
1143
1172
value = "clear (" + c + ")"
1173
+ or
1174
+ Private:: Steps:: summaryExpectsContent ( a .asNode ( ) , c ) and
1175
+ b = a and
1176
+ value = "expect (" + c + ")"
1144
1177
)
1145
1178
or
1146
1179
summaryPostUpdateNode ( b .asNode ( ) , a .asNode ( ) ) and
0 commit comments