@@ -975,42 +975,35 @@ private DataFlow::Node trackSingletonMethodOnInstance(MethodBase method, string
975
975
result = trackSingletonMethodOnInstance ( method , name , TypeTracker:: end ( ) )
976
976
}
977
977
978
- /** Same as `isInstance`, but includes local must-flow through SSA definitions. */
979
- private predicate isInstanceLocalMustFlow ( DataFlow:: Node n , Module tp , boolean exact ) {
980
- isInstance ( n , tp , exact )
981
- or
982
- exists ( DataFlow:: Node mid | isInstanceLocalMustFlow ( mid , tp , exact ) |
983
- n .asExpr ( ) = mid .( SsaDefinitionNode ) .getDefinition ( ) .getARead ( )
984
- or
985
- n .( SsaDefinitionNode ) .getDefinition ( ) .( Ssa:: WriteDefinition ) .assigns ( mid .asExpr ( ) )
986
- )
987
- }
988
-
989
978
/**
990
979
* Holds if `ctx` targets `encl`, which is the enclosing callable of `call`, the receiver
991
980
* of `call` is a parameter access, where the corresponding argument of `ctx` is `arg`.
992
981
*
993
- * `name` is the name of the method being called by `call`.
982
+ * `name` is the name of the method being called by `call`, `source` is a
983
+ * `LocalSourceNode` that flows to `arg`, and `paramDef` is the SSA definition for the
984
+ * parameter that is the receiver of `call`.
994
985
*/
995
986
pragma [ nomagic]
996
- private predicate argFlowsToReceiver (
997
- RelevantCall ctx , ArgumentNode arg , RelevantCall call , Callable encl , string name
987
+ private predicate argMustFlowToReceiver (
988
+ RelevantCall ctx , DataFlow:: LocalSourceNode source , ArgumentNode arg , SsaDefinitionNode paramDef ,
989
+ RelevantCall call , Callable encl , string name
998
990
) {
999
- exists (
1000
- ParameterNodeImpl p , SsaDefinitionNode ssaNode , ParameterPosition ppos , ArgumentPosition apos
1001
- |
991
+ exists ( ParameterNodeImpl p , ParameterPosition ppos , ArgumentPosition apos |
1002
992
// the receiver of `call` references `p`
1003
- LocalFlow:: localFlowSsaParamInput ( p , ssaNode ) and
1004
- flowsToMethodCallReceiver ( pragma [ only_bind_into ] ( call ) , pragma [ only_bind_into ] ( ssaNode ) ,
1005
- pragma [ only_bind_into ] ( name ) ) and
993
+ exists ( DataFlow:: Node receiver |
994
+ LocalFlow:: localFlowSsaParamInput ( p , paramDef ) and
995
+ methodCall ( pragma [ only_bind_into ] ( call ) , receiver , pragma [ only_bind_into ] ( name ) ) and
996
+ receiver .asExpr ( ) = paramDef .getDefinition ( ) .getARead ( )
997
+ ) and
1006
998
// `p` is a parameter of `encl`,
1007
999
encl = call .getScope ( ) and
1008
1000
p .isParameterOf ( TCfgScope ( encl ) , ppos ) and
1009
1001
// `ctx` targets `encl`
1010
1002
getTarget ( ctx ) = encl and
1011
1003
// `arg` is the argument for `p` in the call `ctx`
1012
1004
arg .sourceArgumentOf ( ctx , apos ) and
1013
- parameterMatch ( ppos , apos )
1005
+ parameterMatch ( ppos , apos ) and
1006
+ source .flowsTo ( arg )
1014
1007
)
1015
1008
}
1016
1009
@@ -1027,20 +1020,11 @@ private predicate mayBenefitFromCallContextInstance(
1027
1020
RelevantCall ctx , RelevantCall call , ArgumentNode arg , Callable encl , Module tp , boolean exact ,
1028
1021
string name
1029
1022
) {
1030
- argFlowsToReceiver ( ctx , pragma [ only_bind_into ] ( arg ) , call , encl , 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 ) ) )
1034
- }
1035
-
1036
- /** Same as `resolveConstantReadAccess`, but includes local must-flow through SSA definitions. */
1037
- private predicate resolveConstantReadAccessMustFlow ( DataFlow:: Node n , Module tp ) {
1038
- tp = resolveConstantReadAccess ( n .asExpr ( ) .getExpr ( ) )
1039
- or
1040
- exists ( DataFlow:: Node mid | resolveConstantReadAccessMustFlow ( mid , tp ) |
1041
- n .asExpr ( ) = mid .( SsaDefinitionNode ) .getDefinition ( ) .getARead ( )
1042
- or
1043
- n .( SsaDefinitionNode ) .getDefinition ( ) .( Ssa:: WriteDefinition ) .assigns ( mid .asExpr ( ) )
1023
+ exists ( DataFlow:: LocalSourceNode source |
1024
+ argMustFlowToReceiver ( ctx , pragma [ only_bind_into ] ( source ) , arg , _, call , encl ,
1025
+ pragma [ only_bind_into ] ( name ) ) and
1026
+ source = trackInstance ( tp , exact ) and
1027
+ exists ( lookupMethod ( tp , pragma [ only_bind_into ] ( name ) ) )
1044
1028
)
1045
1029
}
1046
1030
@@ -1057,10 +1041,12 @@ private predicate mayBenefitFromCallContextSingleton(
1057
1041
RelevantCall ctx , RelevantCall call , ArgumentNode arg , Callable encl , Module tp , boolean exact ,
1058
1042
string name
1059
1043
) {
1060
- argFlowsToReceiver ( ctx , pragma [ only_bind_into ] ( arg ) , call , encl , pragma [ only_bind_into ] ( name ) ) and
1061
- // `arg` has a relevant module type
1062
- (
1063
- resolveConstantReadAccessMustFlow ( arg , tp ) and
1044
+ exists ( DataFlow:: LocalSourceNode source |
1045
+ argMustFlowToReceiver ( ctx , pragma [ only_bind_into ] ( source ) , pragma [ only_bind_into ] ( arg ) , _, call ,
1046
+ encl , pragma [ only_bind_into ] ( name ) ) and
1047
+ exists ( lookupSingletonMethod ( tp , pragma [ only_bind_into ] ( name ) , exact ) )
1048
+ |
1049
+ source = trackModuleAccess ( tp ) and
1064
1050
exact = true
1065
1051
or
1066
1052
exists ( SelfVariable self | arg .asExpr ( ) .getExpr ( ) = self .getAnAccess ( ) |
@@ -1073,8 +1059,7 @@ private predicate mayBenefitFromCallContextSingleton(
1073
1059
exact = false
1074
1060
)
1075
1061
)
1076
- ) and
1077
- exists ( lookupSingletonMethod ( tp , pragma [ only_bind_into ] ( name ) , exact ) )
1062
+ )
1078
1063
}
1079
1064
1080
1065
/**
@@ -1101,7 +1086,7 @@ DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
1101
1086
exists ( RelevantCall call0 , Callable res |
1102
1087
call0 = call .asCall ( ) and
1103
1088
res = result .asCallable ( ) and
1104
- res = getTarget ( call0 ) and // make sure to not include e.g. private methods
1089
+ result = viableSourceCallable ( call ) and // make sure to not include e.g. private methods
1105
1090
exists ( Module m , boolean exact , string name |
1106
1091
mayBenefitFromCallContextInstance ( ctx .asCall ( ) , pragma [ only_bind_into ] ( call0 ) , _, _,
1107
1092
pragma [ only_bind_into ] ( m ) , exact , pragma [ only_bind_into ] ( name ) ) and
@@ -1113,18 +1098,22 @@ DataFlowCallable viableImplInCallContext(DataFlowCall call, DataFlowCall ctx) {
1113
1098
)
1114
1099
)
1115
1100
or
1116
- // `ctx` cannot provide a type bound
1117
- exists ( RelevantCall call0 , RelevantCall ctx0 , ArgumentNode arg , string name |
1101
+ // `ctx` cannot provide a type bound, and the receiver of the call is `self`;
1102
+ // in this case, still apply an open-world assumption
1103
+ exists (
1104
+ RelevantCall call0 , RelevantCall ctx0 , ArgumentNode arg , SsaSelfDefinitionNode self ,
1105
+ string name
1106
+ |
1118
1107
call0 = call .asCall ( ) and
1119
1108
ctx0 = ctx .asCall ( ) and
1120
- argFlowsToReceiver ( ctx0 , arg , call0 , _, name ) and
1109
+ argMustFlowToReceiver ( ctx0 , _ , arg , self , call0 , _, name ) and
1121
1110
not mayBenefitFromCallContextInstance ( ctx0 , call0 , arg , _, _, _, name ) and
1122
1111
not mayBenefitFromCallContextSingleton ( ctx0 , call0 , arg , _, _, _, name ) and
1123
1112
result = viableSourceCallable ( call )
1124
1113
)
1125
1114
or
1126
1115
// library calls should always be able to resolve
1127
- argFlowsToReceiver ( ctx .asCall ( ) , _, call .asCall ( ) , _, _) and
1116
+ argMustFlowToReceiver ( ctx .asCall ( ) , _ , _ , _, call .asCall ( ) , _, _) and
1128
1117
result = viableLibraryCallable ( call )
1129
1118
)
1130
1119
}
0 commit comments