@@ -638,12 +638,24 @@ private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
638
638
)
639
639
}
640
640
641
+ /**
642
+ * Holds if `nodeFrom` flows to `nodeTo` because there is `def-use` or
643
+ * `use-use` flow from `defOrUse` to `use`.
644
+ *
645
+ * `uncertain` is `true` if the `defOrUse` is an uncertain definition.
646
+ */
647
+ private predicate localSsaFlow (
648
+ SsaDefOrUse defOrUse , Node nodeFrom , UseOrPhi use , Node nodeTo , boolean uncertain
649
+ ) {
650
+ nodeToDefOrUse ( nodeFrom , defOrUse , uncertain ) and
651
+ adjacentDefRead ( defOrUse , use ) and
652
+ useToNode ( use , nodeTo ) and
653
+ nodeFrom != nodeTo
654
+ }
655
+
641
656
private predicate ssaFlowImpl ( SsaDefOrUse defOrUse , Node nodeFrom , Node nodeTo , boolean uncertain ) {
642
657
exists ( UseOrPhi use |
643
- nodeToDefOrUse ( nodeFrom , defOrUse , uncertain ) and
644
- adjacentDefRead ( defOrUse , use ) and
645
- useToNode ( use , nodeTo ) and
646
- nodeFrom != nodeTo
658
+ localSsaFlow ( defOrUse , nodeFrom , use , nodeTo , uncertain )
647
659
or
648
660
// Initial global variable value to a first use
649
661
nodeFrom .( InitialGlobalValue ) .getGlobalDef ( ) = defOrUse and
@@ -721,15 +733,62 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
721
733
)
722
734
}
723
735
724
- /** Holds if there is def-use or use-use flow from `pun` to `nodeTo`. */
725
- predicate postUpdateFlow ( PostUpdateNode pun , Node nodeTo ) {
726
- exists ( UseOrPhi use , Node preUpdate |
736
+ /**
737
+ * Holds if there is use-use flow from `pun`'s pre-update node to `n`.
738
+ */
739
+ private predicate postUpdateNodeToFirstUse ( PostUpdateNode pun , Node n ) {
740
+ exists ( UseOrPhi use |
727
741
adjustForPointerArith ( pun , use ) and
728
- useToNode ( use , nodeTo ) and
742
+ useToNode ( use , n )
743
+ )
744
+ }
745
+
746
+ private predicate stepUntilNotInCall ( DataFlowCall call , Node n1 , Node n2 ) {
747
+ isArgumentOfCallable ( call , n1 ) and
748
+ exists ( Node mid | localSsaFlow ( _, n1 , _, mid , _) |
749
+ isArgumentOfCallable ( call , mid ) and
750
+ stepUntilNotInCall ( call , mid , n2 )
751
+ or
752
+ not isArgumentOfCallable ( call , mid ) and
753
+ mid = n2
754
+ )
755
+ }
756
+
757
+ bindingset [ n1, n2]
758
+ pragma [ inline_late]
759
+ private predicate isArgumentOfSameCall ( DataFlowCall call , Node n1 , Node n2 ) {
760
+ isArgumentOfCallable ( call , n1 ) and isArgumentOfCallable ( call , n2 )
761
+ }
762
+
763
+ /**
764
+ * Holds if there is def-use or use-use flow from `pun` to `nodeTo`.
765
+ *
766
+ * Note: This is more complex than it sounds. Consider a call such as:
767
+ * ```cpp
768
+ * write_first_argument(x, x);
769
+ * sink(x);
770
+ * ```
771
+ * Assume flow comes out of the first argument to `write_first_argument`. We
772
+ * don't want flow to go to the `x` that's also an argument to
773
+ * `write_first_argument` (because we just flowed out of that function, and we
774
+ * don't want to flow back into it again).
775
+ *
776
+ * We do, however, want flow from the output argument to `x` on the next line, and
777
+ * similarly we want flow from the second argument of `write_first_argument` to `x`
778
+ * on the next line.
779
+ */
780
+ predicate postUpdateFlow ( PostUpdateNode pun , Node nodeTo ) {
781
+ exists ( Node preUpdate , Node mid |
729
782
preUpdate = pun .getPreUpdateNode ( ) and
730
- not exists ( DataFlowCall call |
731
- isArgumentOfCallable ( call , preUpdate ) and isArgumentOfCallable ( call , nodeTo )
783
+ postUpdateNodeToFirstUse ( pun , mid )
784
+ |
785
+ exists ( DataFlowCall call |
786
+ isArgumentOfSameCall ( call , preUpdate , mid ) and
787
+ stepUntilNotInCall ( call , mid , nodeTo )
732
788
)
789
+ or
790
+ not isArgumentOfSameCall ( _, preUpdate , mid ) and
791
+ nodeTo = mid
733
792
)
734
793
}
735
794
0 commit comments