@@ -615,9 +615,9 @@ private predicate isInstance(DataFlow::Node n, Module tp, boolean exact) {
615
615
exact = true
616
616
or
617
617
// `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
621
621
exact = false
622
622
)
623
623
)
@@ -991,14 +991,13 @@ private predicate isInstanceLocalMustFlow(DataFlow::Node n, Module tp, boolean e
991
991
* `name` is the name of the method being called by `call`.
992
992
*/
993
993
pragma [ nomagic]
994
- private predicate mayBenefitFromCallContext0 (
994
+ private predicate argFlowsToReceiver (
995
995
RelevantCall ctx , ArgumentNode arg , RelevantCall call , Callable encl , string name
996
996
) {
997
997
exists (
998
998
ParameterNodeImpl p , SsaDefinitionNode ssaNode , ParameterPosition ppos , ArgumentPosition apos
999
999
|
1000
1000
// the receiver of `call` references `p`
1001
- ssaNode = trackInstance ( _, _) and
1002
1001
LocalFlow:: localFlowSsaParamInput ( p , ssaNode ) and
1003
1002
flowsToMethodCallReceiver ( pragma [ only_bind_into ] ( call ) , pragma [ only_bind_into ] ( ssaNode ) ,
1004
1003
pragma [ only_bind_into ] ( name ) ) and
@@ -1016,32 +1015,75 @@ private predicate mayBenefitFromCallContext0(
1016
1015
/**
1017
1016
* Holds if `ctx` targets `encl`, which is the enclosing callable of `call`, and
1018
1017
* 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`.
1020
1019
*
1021
1020
* `name` is the name of the method being called by `call`, and `exact` is pertaining
1022
1021
* to the type of the argument.
1023
1022
*/
1024
1023
pragma [ 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
1027
1027
) {
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 ( ) )
1034
1042
)
1035
1043
}
1036
1044
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 , _, _)
1071
+ )
1072
+ )
1073
+ ) and
1074
+ exists ( lookupSingletonMethod ( tp , pragma [ only_bind_into ] ( name ) , exact ) )
1075
+ }
1076
+
1037
1077
/**
1038
1078
* Holds if the set of viable implementations that can be called by `call`
1039
1079
* might be improved by knowing the call context. This is the case if the
1040
1080
* receiver accesses a parameter of the enclosing callable `c` (including
1041
1081
* the implicit `self` parameter).
1042
1082
*/
1043
1083
predicate mayBenefitFromCallContext ( DataFlowCall call , DataFlowCallable c ) {
1044
- mayBenefitFromCallContext1 ( _, call .asCall ( ) , c .asCallable ( ) , _, _, _)
1084
+ mayBenefitFromCallContextInstance ( _, call .asCall ( ) , _, c .asCallable ( ) , _, _, _)
1085
+ or
1086
+ mayBenefitFromCallContextSingleton ( _, call .asCall ( ) , _, c .asCallable ( ) , _, _, _)
1045
1087
}
1046
1088
1047
1089
/**
@@ -1050,28 +1092,38 @@ predicate mayBenefitFromCallContext(DataFlowCall call, DataFlowCallable c) {
1050
1092
*/
1051
1093
pragma [ nomagic]
1052
1094
DataFlowCallable 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 ) )
1095
+ mayBenefitFromCallContext ( call , _) and
1096
+ (
1097
+ // `ctx` can provide a potentially better type bound
1098
+ exists ( RelevantCall call0 , Callable res |
1099
+ call0 = call .asCall ( ) and
1100
+ res = result .asCallable ( ) and
1101
+ res = getTarget ( call0 ) and // make sure to not include e.g. private methods
1102
+ exists ( Module m , boolean exact , string name |
1103
+ mayBenefitFromCallContextInstance ( ctx .asCall ( ) , pragma [ only_bind_into ] ( call0 ) , _, _,
1104
+ pragma [ only_bind_into ] ( m ) , exact , pragma [ only_bind_into ] ( name ) ) and
1105
+ res = lookupMethod ( m , name , exact )
1106
+ or
1107
+ mayBenefitFromCallContextSingleton ( ctx .asCall ( ) , pragma [ only_bind_into ] ( call0 ) , _, _,
1108
+ pragma [ only_bind_into ] ( m ) , exact , pragma [ only_bind_into ] ( name ) ) and
1109
+ res = lookupSingletonMethod ( m , name , exact )
1110
+ )
1062
1111
)
1112
+ or
1113
+ // `ctx` cannot provide a type bound
1114
+ exists ( RelevantCall call0 , RelevantCall ctx0 , ArgumentNode arg , string name |
1115
+ call0 = call .asCall ( ) and
1116
+ ctx0 = ctx .asCall ( ) and
1117
+ argFlowsToReceiver ( ctx0 , arg , call0 , _, name ) and
1118
+ not mayBenefitFromCallContextInstance ( ctx0 , call0 , arg , _, _, _, name ) and
1119
+ not mayBenefitFromCallContextSingleton ( ctx0 , call0 , arg , _, _, _, name ) and
1120
+ result = viableSourceCallable ( call )
1121
+ )
1122
+ or
1123
+ // library calls should always be able to resolve
1124
+ argFlowsToReceiver ( ctx .asCall ( ) , _, call .asCall ( ) , _, _) and
1125
+ result = viableLibraryCallable ( call )
1063
1126
)
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 )
1075
1127
}
1076
1128
1077
1129
predicate exprNodeReturnedFrom = exprNodeReturnedFromCached / 2 ;
0 commit comments