@@ -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 ( ) }
@@ -239,7 +251,9 @@ module Private {
239
251
TContentSummaryComponent ( ContentSet c ) or
240
252
TParameterSummaryComponent ( ArgumentPosition pos ) or
241
253
TArgumentSummaryComponent ( ParameterPosition pos ) or
242
- TReturnSummaryComponent ( ReturnKind rk )
254
+ TReturnSummaryComponent ( ReturnKind rk ) or
255
+ TWithoutContentSummaryComponent ( ContentSet c ) or
256
+ TWithContentSummaryComponent ( ContentSet c )
243
257
244
258
private TParameterSummaryComponent thisParam ( ) {
245
259
result = TParameterSummaryComponent ( instanceParameterPosition ( ) )
@@ -301,6 +315,23 @@ module Private {
301
315
SummaryComponentStack:: singleton ( TArgumentSummaryComponent ( _) ) ) and
302
316
preservesValue = preservesValue1 .booleanAnd ( preservesValue2 )
303
317
)
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
+ }
304
335
}
305
336
306
337
/**
@@ -383,10 +414,7 @@ module Private {
383
414
384
415
private newtype TSummaryNodeState =
385
416
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 ) }
390
418
391
419
/**
392
420
* A state used to break up (complex) flow summaries into atomic flow steps.
@@ -433,12 +461,6 @@ module Private {
433
461
this = TSummaryNodeOutputState ( s ) and
434
462
result = "to write: " + s
435
463
)
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
- )
442
464
}
443
465
}
444
466
@@ -462,11 +484,6 @@ module Private {
462
484
not parameterReadState ( c , state , _)
463
485
or
464
486
state .isOutputState ( c , _)
465
- or
466
- exists ( ParameterPosition pos |
467
- c .clearsContent ( pos , _) and
468
- state = TSummaryNodeClearsContentState ( pos , _)
469
- )
470
487
}
471
488
472
489
pragma [ noinline]
@@ -502,24 +519,22 @@ module Private {
502
519
parameterReadState ( c , _, pos )
503
520
or
504
521
isParameterPostUpdate ( _, c , pos )
505
- or
506
- c .clearsContent ( pos , _)
507
522
}
508
523
509
524
private predicate callbackOutput (
510
525
SummarizedCallable c , SummaryComponentStack s , Node receiver , ReturnKind rk
511
526
) {
512
527
any ( SummaryNodeState state ) .isInputState ( c , s ) and
513
528
s .head ( ) = TReturnSummaryComponent ( rk ) and
514
- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
529
+ receiver = summaryNodeInputState ( c , s .tail ( ) )
515
530
}
516
531
517
532
private predicate callbackInput (
518
533
SummarizedCallable c , SummaryComponentStack s , Node receiver , ArgumentPosition pos
519
534
) {
520
535
any ( SummaryNodeState state ) .isOutputState ( c , s ) and
521
536
s .head ( ) = TParameterSummaryComponent ( pos ) and
522
- receiver = summaryNodeInputState ( c , s .drop ( 1 ) )
537
+ receiver = summaryNodeInputState ( c , s .tail ( ) )
523
538
}
524
539
525
540
/** Holds if a call targeting `receiver` should be synthesized inside `c`. */
@@ -545,15 +560,21 @@ module Private {
545
560
exists ( SummarizedCallable c , SummaryComponentStack s , SummaryComponent head | head = s .head ( ) |
546
561
n = summaryNodeInputState ( c , s ) and
547
562
(
563
+ exists ( ContentSet cont | result = getContentType ( cont ) |
564
+ head = TContentSummaryComponent ( cont ) or
565
+ head = TWithContentSummaryComponent ( cont )
566
+ )
567
+ or
548
568
exists ( ContentSet cont |
549
- head = TContentSummaryComponent ( cont ) and result = getContentType ( cont )
569
+ head = TWithoutContentSummaryComponent ( cont ) and
570
+ result = getNodeType ( summaryNodeInputState ( c , s .tail ( ) ) )
550
571
)
551
572
or
552
573
exists ( ReturnKind rk |
553
574
head = TReturnSummaryComponent ( rk ) and
554
575
result =
555
576
getCallbackReturnType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
556
- s .drop ( 1 ) ) ) , rk )
577
+ s .tail ( ) ) ) , rk )
557
578
)
558
579
)
559
580
or
@@ -572,16 +593,10 @@ module Private {
572
593
exists ( ArgumentPosition pos | head = TParameterSummaryComponent ( pos ) |
573
594
result =
574
595
getCallbackParameterType ( getNodeType ( summaryNodeInputState ( pragma [ only_bind_out ] ( c ) ,
575
- s .drop ( 1 ) ) ) , pos )
596
+ s .tail ( ) ) ) , pos )
576
597
)
577
598
)
578
599
)
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
- )
585
600
}
586
601
587
602
/** Holds if summary node `out` contains output of kind `rk` from call `c`. */
@@ -607,9 +622,6 @@ module Private {
607
622
exists ( SummarizedCallable c , ParameterPosition pos |
608
623
isParameterPostUpdate ( post , c , pos ) and
609
624
pre .( ParamNode ) .isParameterOf ( c , pos )
610
- or
611
- pre = summaryNode ( c , TSummaryNodeClearsContentState ( pos , false ) ) and
612
- post = summaryNode ( c , TSummaryNodeClearsContentState ( pos , true ) )
613
625
)
614
626
or
615
627
exists ( SummarizedCallable callable , SummaryComponentStack s |
@@ -633,8 +645,6 @@ module Private {
633
645
*/
634
646
predicate summaryAllowParameterReturnInSelf ( ParamNode p ) {
635
647
exists ( SummarizedCallable c , ParameterPosition ppos | p .isParameterOf ( c , ppos ) |
636
- c .clearsContent ( ppos , _)
637
- or
638
648
exists ( SummaryComponentStack inputContents , SummaryComponentStack outputContents |
639
649
summary ( c , inputContents , outputContents , _) and
640
650
inputContents .bottom ( ) = pragma [ only_bind_into ] ( TArgumentSummaryComponent ( ppos ) ) and
@@ -663,9 +673,10 @@ module Private {
663
673
preservesValue = false and not summary ( c , inputContents , outputContents , true )
664
674
)
665
675
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
669
680
preservesValue = true
670
681
)
671
682
}
@@ -676,7 +687,7 @@ module Private {
676
687
*/
677
688
predicate summaryReadStep ( Node pred , ContentSet c , Node succ ) {
678
689
exists ( SummarizedCallable sc , SummaryComponentStack s |
679
- pred = summaryNodeInputState ( sc , s .drop ( 1 ) ) and
690
+ pred = summaryNodeInputState ( sc , s .tail ( ) ) and
680
691
succ = summaryNodeInputState ( sc , s ) and
681
692
SummaryComponent:: content ( c ) = s .head ( )
682
693
)
@@ -689,7 +700,7 @@ module Private {
689
700
predicate summaryStoreStep ( Node pred , ContentSet c , Node succ ) {
690
701
exists ( SummarizedCallable sc , SummaryComponentStack s |
691
702
pred = summaryNodeOutputState ( sc , s ) and
692
- succ = summaryNodeOutputState ( sc , s .drop ( 1 ) ) and
703
+ succ = summaryNodeOutputState ( sc , s .tail ( ) ) and
693
704
SummaryComponent:: content ( c ) = s .head ( )
694
705
)
695
706
}
@@ -714,9 +725,22 @@ module Private {
714
725
* node where field `b` is cleared).
715
726
*/
716
727
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 )
720
744
)
721
745
}
722
746
@@ -728,27 +752,32 @@ module Private {
728
752
sc = viableCallable ( call )
729
753
}
730
754
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
- */
738
755
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 |
741
758
argumentPositionMatch ( call , arg , ppos ) and
742
- viableParam ( call , sc , ppos , _) and
743
- sc .clearsContent ( ppos , c )
759
+ viableParam ( call , sc , ppos , result )
744
760
)
745
761
}
746
762
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
+ */
747
770
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 , _)
752
781
)
753
782
}
754
783
@@ -1152,6 +1181,10 @@ module Private {
1152
1181
Private:: Steps:: summaryClearsContent ( a .asNode ( ) , c ) and
1153
1182
b = a and
1154
1183
value = "clear (" + c + ")"
1184
+ or
1185
+ Private:: Steps:: summaryExpectsContent ( a .asNode ( ) , c ) and
1186
+ b = a and
1187
+ value = "expect (" + c + ")"
1155
1188
)
1156
1189
or
1157
1190
summaryPostUpdateNode ( b .asNode ( ) , a .asNode ( ) ) and
0 commit comments