@@ -615,9 +615,9 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
615615 exact = true
616616 or
617617 // `self.new` inside a singleton method
618- exists ( MethodBase target |
619- selfInMethod ( sourceNode .( SsaSelfDefinitionNode ) .getVariable ( ) , target , tp ) and
620- singletonMethod ( target , _, _) and
618+ exists ( MethodBase caller |
619+ selfInMethod ( sourceNode .( SsaSelfDefinitionNode ) .getVariable ( ) , caller , tp ) and
620+ singletonMethod ( caller , _, _) and
621621 exact = false
622622 )
623623 )
@@ -991,14 +991,13 @@ private predicate isInstanceLocalMustFlow(DataFlow::Node n, Module tp, boolean e
991991 * `name` is the name of the method being called by `call`.
992992 */
993993pragma [ nomagic]
994- private predicate mayBenefitFromCallContext0 (
994+ private predicate argFlowsToReceiver (
995995 RelevantCall ctx , ArgumentNode arg , RelevantCall call , Callable encl , string name
996996) {
997997 exists (
998998 ParameterNodeImpl p , SsaDefinitionNode ssaNode , ParameterPosition ppos , ArgumentPosition apos
999999 |
10001000 // the receiver of `call` references `p`
1001- ssaNode = trackInstance ( _, _) and
10021001 LocalFlow:: localFlowSsaParamInput ( p , ssaNode ) and
10031002 flowsToMethodCallReceiver ( pragma [ only_bind_into ] ( call ) , pragma [ only_bind_into ] ( ssaNode ) ,
10041003 pragma [ only_bind_into ] ( name ) ) and
@@ -1016,32 +1015,76 @@ private predicate mayBenefitFromCallContext0(
10161015/**
10171016 * Holds if `ctx` targets `encl`, which is the enclosing callable of `call`, and
10181017 * the receiver of `call` is a parameter access, where the corresponding argument
1019- * of `ctx` has type `tp`.
1018+ * `arg` of `ctx` has type `tp`.
10201019 *
10211020 * `name` is the name of the method being called by `call`, and `exact` is pertaining
10221021 * to the type of the argument.
10231022 */
10241023pragma [ nomagic]
1025- private predicate mayBenefitFromCallContext1 (
1026- RelevantCall ctx , RelevantCall call , Callable encl , Module tp , boolean exact , string name
1024+ private predicate mayBenefitFromCallContextInstance (
1025+ RelevantCall ctx , RelevantCall call , ArgumentNode arg , Callable encl , Module tp , boolean exact ,
1026+ string name
10271027) {
1028- exists ( ArgumentNode arg |
1029- mayBenefitFromCallContext0 ( ctx , pragma [ only_bind_into ] ( arg ) , call , encl ,
1030- pragma [ only_bind_into ] ( name ) ) and
1031- // `arg` has a relevant instance type
1032- isInstanceLocalMustFlow ( arg , tp , exact ) and
1033- exists ( lookupMethod ( tp , pragma [ only_bind_into ] ( name ) ) )
1028+ argFlowsToReceiver ( ctx , pragma [ only_bind_into ] ( arg ) , call , encl , pragma [ only_bind_into ] ( name ) ) and
1029+ // `arg` has a relevant instance type
1030+ isInstanceLocalMustFlow ( arg , tp , exact ) and
1031+ exists ( lookupMethod ( tp , pragma [ only_bind_into ] ( name ) ) )
1032+ }
1033+
1034+ /** Same as `resolveConstantReadAccess`, but includes local must-flow through SSA definitions. */
1035+ private predicate resolveConstantReadAccessMustFlow ( DataFlow:: Node n , Module tp ) {
1036+ tp = resolveConstantReadAccess ( n .asExpr ( ) .getExpr ( ) )
1037+ or
1038+ exists ( DataFlow:: Node mid | resolveConstantReadAccessMustFlow ( mid , tp ) |
1039+ n .asExpr ( ) = mid .( SsaDefinitionNode ) .getDefinition ( ) .getARead ( )
1040+ or
1041+ n .( SsaDefinitionNode ) .getDefinition ( ) .( Ssa:: WriteDefinition ) .assigns ( mid .asExpr ( ) )
10341042 )
10351043}
10361044
1045+ /**
1046+ * Holds if `ctx` targets `encl`, which is the enclosing callable of `call`, and
1047+ * the receiver of `call` is a parameter access, where the corresponding argument
1048+ * `arg` of `ctx` is a module access targeting a module of type `tp`.
1049+ *
1050+ * `name` is the name of the method being called by `call`, and `exact` is pertaining
1051+ * to the type of the argument.
1052+ */
1053+ pragma [ nomagic]
1054+ private predicate mayBenefitFromCallContextSingleton (
1055+ RelevantCall ctx , RelevantCall call , ArgumentNode arg , Callable encl , Module tp , boolean exact ,
1056+ string name
1057+ ) {
1058+ argFlowsToReceiver ( ctx , pragma [ only_bind_into ] ( arg ) , call , encl , pragma [ only_bind_into ] ( name ) ) and
1059+ // `arg` has a relevant module type
1060+ (
1061+ resolveConstantReadAccessMustFlow ( arg , tp ) and
1062+ exact = true
1063+ or
1064+ exists ( SelfVariable self | arg .asExpr ( ) .getExpr ( ) = self .getAnAccess ( ) |
1065+ selfInModule ( self , tp ) and
1066+ exact = true
1067+ or
1068+ exists ( MethodBase caller |
1069+ selfInMethod ( self , caller , tp ) and
1070+ singletonMethod ( caller , _, _) and
1071+ exact = false
1072+ )
1073+ )
1074+ ) and
1075+ exists ( lookupSingletonMethod ( tp , pragma [ only_bind_into ] ( name ) , exact ) )
1076+ }
1077+
10371078/**
10381079 * Holds if the set of viable implementations that can be called by `call`
10391080 * might be improved by knowing the call context. This is the case if the
10401081 * receiver accesses a parameter of the enclosing callable `c` (including
10411082 * the implicit `self` parameter).
10421083 */
10431084predicate mayBenefitFromCallContext ( DataFlowCall call , DataFlowCallable c ) {
1044- mayBenefitFromCallContext1 ( _, call .asCall ( ) , c .asCallable ( ) , _, _, _)
1085+ mayBenefitFromCallContextInstance ( _, call .asCall ( ) , _, c .asCallable ( ) , _, _, _)
1086+ or
1087+ mayBenefitFromCallContextSingleton ( _, call .asCall ( ) , _, c .asCallable ( ) , _, _, _)
10451088}
10461089
10471090/**
@@ -1050,28 +1093,38 @@ predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
10501093 */
10511094pragma [ nomagic]
10521095DataFlowCallable viableImplInCallContext ( DataFlowCall call , DataFlowCall ctx ) {
1053- // `ctx` can provide a potentially better type bound
1054- exists ( RelevantCall call0 , Callable res |
1055- call0 = call .asCall ( ) and
1056- res = result .asCallable ( ) and
1057- res = getTarget ( call0 ) and // make sure to not include e.g. private methods
1058- exists ( Module m , boolean exact , string name |
1059- res = lookupMethod ( m , name , exact ) and
1060- mayBenefitFromCallContext1 ( ctx .asCall ( ) , pragma [ only_bind_into ] ( call0 ) , _,
1061- pragma [ only_bind_into ] ( m ) , exact , pragma [ only_bind_into ] ( name ) )
1096+ mayBenefitFromCallContext ( call , _) and
1097+ (
1098+ // `ctx` can provide a potentially better type bound
1099+ exists ( RelevantCall call0 , Callable res |
1100+ call0 = call .asCall ( ) and
1101+ res = result .asCallable ( ) and
1102+ res = getTarget ( call0 ) and // make sure to not include e.g. private methods
1103+ exists ( Module m , boolean exact , string name |
1104+ mayBenefitFromCallContextInstance ( ctx .asCall ( ) , pragma [ only_bind_into ] ( call0 ) , _, _,
1105+ pragma [ only_bind_into ] ( m ) , exact , pragma [ only_bind_into ] ( name ) ) and
1106+ res = lookupMethod ( m , name , exact )
1107+ or
1108+ mayBenefitFromCallContextSingleton ( ctx .asCall ( ) , pragma [ only_bind_into ] ( call0 ) , _, _,
1109+ pragma [ only_bind_into ] ( m ) , exact , pragma [ only_bind_into ] ( name ) ) and
1110+ res = lookupSingletonMethod ( m , name , exact )
1111+ )
10621112 )
1113+ or
1114+ // `ctx` cannot provide a type bound
1115+ exists ( RelevantCall call0 , RelevantCall ctx0 , ArgumentNode arg , string name |
1116+ call0 = call .asCall ( ) and
1117+ ctx0 = ctx .asCall ( ) and
1118+ argFlowsToReceiver ( ctx0 , arg , call0 , _, name ) and
1119+ not mayBenefitFromCallContextInstance ( ctx0 , call0 , arg , _, _, _, name ) and
1120+ not mayBenefitFromCallContextSingleton ( ctx0 , call0 , arg , _, _, _, name ) and
1121+ result = viableSourceCallable ( call )
1122+ )
1123+ or
1124+ // library calls should always be able to resolve
1125+ argFlowsToReceiver ( ctx .asCall ( ) , _, call .asCall ( ) , _, _) and
1126+ result = viableLibraryCallable ( call )
10631127 )
1064- or
1065- // `ctx` cannot provide a type bound
1066- exists ( ArgumentNode arg |
1067- mayBenefitFromCallContext0 ( ctx .asCall ( ) , arg , call .asCall ( ) , _, _) and
1068- not isInstanceLocalMustFlow ( arg , _, _) and
1069- result = viableSourceCallable ( call )
1070- )
1071- or
1072- // library calls should always be able to resolve
1073- mayBenefitFromCallContext0 ( ctx .asCall ( ) , _, call .asCall ( ) , _, _) and
1074- result = viableLibraryCallable ( call )
10751128}
10761129
10771130predicate exprNodeReturnedFrom = exprNodeReturnedFromCached / 2 ;
0 commit comments