@@ -667,23 +667,78 @@ private module Stage1 implements StageSig {
667667 )
668668 or
669669 // flow into a callable
670- exists ( NodeEx arg |
671- fwdFlow ( arg , _, config ) and
672- viableParamArgEx ( _, node , arg ) and
673- cc = true and
674- not fullBarrier ( node , config )
675- )
670+ fwdFlowIn ( _, _, _, node , config ) and
671+ cc = true
676672 or
677673 // flow out of a callable
674+ fwdFlowOut ( _, node , false , config ) and
675+ cc = false
676+ or
677+ // flow through a callable
678678 exists ( DataFlowCall call |
679- fwdFlowOut ( call , node , false , config ) and
680- cc = false
681- or
682679 fwdFlowOutFromArg ( call , node , config ) and
683680 fwdFlowIsEntered ( call , cc , config )
684681 )
685682 }
686683
684+ // inline to reduce the number of iterations
685+ pragma [ inline]
686+ private predicate fwdFlowIn (
687+ DataFlowCall call , NodeEx arg , Cc cc , ParamNodeEx p , Configuration config
688+ ) {
689+ // call context cannot help reduce virtual dispatch
690+ fwdFlow ( arg , cc , config ) and
691+ viableParamArgEx ( call , p , arg ) and
692+ not fullBarrier ( p , config ) and
693+ (
694+ cc = false
695+ or
696+ cc = true and
697+ not reducedViableImplInCallContext ( call , _, _)
698+ )
699+ or
700+ // call context may help reduce virtual dispatch
701+ exists ( DataFlowCallable target |
702+ fwdFlowInReducedViableImplInSomeCallContext ( call , arg , p , target , config ) and
703+ target = viableImplInSomeFwdFlowCallContextExt ( call , config ) and
704+ cc = true
705+ )
706+ }
707+
708+ /**
709+ * Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
710+ */
711+ pragma [ nomagic]
712+ private predicate fwdFlowIsEntered ( DataFlowCall call , Cc cc , Configuration config ) {
713+ fwdFlowIn ( call , _, cc , _, config )
714+ }
715+
716+ pragma [ nomagic]
717+ private predicate fwdFlowInReducedViableImplInSomeCallContext (
718+ DataFlowCall call , NodeEx arg , ParamNodeEx p , DataFlowCallable target , Configuration config
719+ ) {
720+ fwdFlow ( arg , true , config ) and
721+ viableParamArgEx ( call , p , arg ) and
722+ reducedViableImplInCallContext ( call , _, _) and
723+ target = p .getEnclosingCallable ( ) and
724+ not fullBarrier ( p , config )
725+ }
726+
727+ /**
728+ * Gets a viable dispatch target of `call` in the context `ctx`. This is
729+ * restricted to those `call`s for which a context might make a difference,
730+ * and to `ctx`s that are reachable in `fwdFlow`.
731+ */
732+ pragma [ nomagic]
733+ private DataFlowCallable viableImplInSomeFwdFlowCallContextExt (
734+ DataFlowCall call , Configuration config
735+ ) {
736+ exists ( DataFlowCall ctx |
737+ fwdFlowIsEntered ( ctx , _, config ) and
738+ result = viableImplInCallContextExt ( call , ctx )
739+ )
740+ }
741+
687742 private predicate fwdFlow ( NodeEx node , Configuration config ) { fwdFlow ( node , _, config ) }
688743
689744 pragma [ nomagic]
@@ -726,7 +781,8 @@ private module Stage1 implements StageSig {
726781 )
727782 }
728783
729- pragma [ nomagic]
784+ // inline to reduce the number of iterations
785+ pragma [ inline]
730786 private predicate fwdFlowOut ( DataFlowCall call , NodeEx out , Cc cc , Configuration config ) {
731787 exists ( ReturnPosition pos |
732788 fwdFlowReturnPosition ( pos , cc , config ) and
@@ -740,17 +796,6 @@ private module Stage1 implements StageSig {
740796 fwdFlowOut ( call , out , true , config )
741797 }
742798
743- /**
744- * Holds if an argument to `call` is reached in the flow covered by `fwdFlow`.
745- */
746- pragma [ nomagic]
747- private predicate fwdFlowIsEntered ( DataFlowCall call , Cc cc , Configuration config ) {
748- exists ( ArgNodeEx arg |
749- fwdFlow ( arg , cc , config ) and
750- viableParamArgEx ( call , _, arg )
751- )
752- }
753-
754799 private predicate stateStepFwd ( FlowState state1 , FlowState state2 , Configuration config ) {
755800 exists ( NodeEx node1 |
756801 additionalLocalStateStep ( node1 , state1 , _, state2 , config ) or
@@ -817,20 +862,21 @@ private module Stage1 implements StageSig {
817862 )
818863 or
819864 // flow into a callable
820- exists ( DataFlowCall call |
821- revFlowIn ( call , node , false , config ) and
822- toReturn = false
823- or
824- revFlowInToReturn ( call , node , config ) and
825- revFlowIsReturned ( call , toReturn , config )
826- )
865+ revFlowIn ( _, node , false , config ) and
866+ toReturn = false
827867 or
828868 // flow out of a callable
829869 exists ( ReturnPosition pos |
830870 revFlowOut ( pos , config ) and
831871 node .( RetNodeEx ) .getReturnPosition ( ) = pos and
832872 toReturn = true
833873 )
874+ or
875+ // flow through a callable
876+ exists ( DataFlowCall call |
877+ revFlowInToReturn ( call , node , config ) and
878+ revFlowIsReturned ( call , toReturn , config )
879+ )
834880 }
835881
836882 /**
@@ -886,11 +932,11 @@ private module Stage1 implements StageSig {
886932 additional predicate viableParamArgNodeCandFwd1 (
887933 DataFlowCall call , ParamNodeEx p , ArgNodeEx arg , Configuration config
888934 ) {
889- viableParamArgEx ( call , p , arg ) and
890- fwdFlow ( arg , config )
935+ fwdFlowIn ( call , arg , _, p , config )
891936 }
892937
893- pragma [ nomagic]
938+ // inline to reduce the number of iterations
939+ pragma [ inline]
894940 private predicate revFlowIn (
895941 DataFlowCall call , ArgNodeEx arg , boolean toReturn , Configuration config
896942 ) {
0 commit comments