Skip to content

Commit a8eedce

Browse files
committed
Java: Replace ad-hoc variable tracking with union type flow in dispatch.
1 parent 6f06267 commit a8eedce

File tree

1 file changed

+41
-40
lines changed

1 file changed

+41
-40
lines changed

java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -62,17 +62,42 @@ private module Dispatch {
6262
cached
6363
Method viableImpl_v3(MethodAccess ma) { result = DispatchFlow::viableImpl_out(ma) }
6464

65-
private predicate qualType(VirtualMethodAccess ma, RefType t, boolean exact) {
66-
exprTypeFlow(ma.getQualifier(), t, exact)
67-
}
68-
6965
/**
7066
* INTERNAL: Use `viableImpl` instead.
7167
*
7268
* Gets a viable implementation of the method called in the given method access.
7369
*/
7470
cached
7571
Method viableImpl_v2(MethodAccess ma) {
72+
result = viableImpl_v2_cand(pragma[only_bind_into](ma)) and
73+
exists(Method def, RefType t, boolean exact |
74+
qualUnionType(pragma[only_bind_into](ma), pragma[only_bind_into](t),
75+
pragma[only_bind_into](exact)) and
76+
def = ma.getMethod().getSourceDeclaration()
77+
|
78+
exact = true and result = exactMethodImpl(def, t.getSourceDeclaration())
79+
or
80+
exact = false and
81+
exists(RefType t2 |
82+
result = viableMethodImpl(def, t.getSourceDeclaration(), t2) and
83+
not Unification_v2::failsUnification(t, t2)
84+
)
85+
)
86+
or
87+
result = viableImpl_v2_cand(ma) and
88+
not qualUnionType(ma, _, _)
89+
}
90+
91+
private predicate qualUnionType(VirtualMethodAccess ma, RefType t, boolean exact) {
92+
exprUnionTypeFlow(ma.getQualifier(), t, exact)
93+
}
94+
95+
private predicate unificationTargetLeft_v2(ParameterizedType t1) { qualUnionType(_, t1, _) }
96+
97+
private module Unification_v2 =
98+
MkUnification<unificationTargetLeft_v2/1, unificationTargetRight/1>;
99+
100+
private Method viableImpl_v2_cand(MethodAccess ma) {
76101
result = viableImpl_v1(ma) and
77102
(
78103
exists(Method def, RefType t, boolean exact |
@@ -84,18 +109,22 @@ private module Dispatch {
84109
exact = false and
85110
exists(RefType t2 |
86111
result = viableMethodImpl(def, t.getSourceDeclaration(), t2) and
87-
not Unification_v2::failsUnification(t, t2)
112+
not Unification_v2_cand::failsUnification(t, t2)
88113
)
89114
)
90115
or
91116
not qualType(ma, _, _)
92117
)
93118
}
94119

95-
private predicate unificationTargetLeft_v2(ParameterizedType t1) { qualType(_, t1, _) }
120+
private predicate qualType(VirtualMethodAccess ma, RefType t, boolean exact) {
121+
exprTypeFlow(ma.getQualifier(), t, exact)
122+
}
123+
124+
private predicate unificationTargetLeft_v2_cand(ParameterizedType t1) { qualType(_, t1, _) }
96125

97-
private module Unification_v2 =
98-
MkUnification<unificationTargetLeft_v2/1, unificationTargetRight/1>;
126+
private module Unification_v2_cand =
127+
MkUnification<unificationTargetLeft_v2_cand/1, unificationTargetRight/1>;
99128

100129
/**
101130
* INTERNAL: Use `viableImpl` instead.
@@ -161,9 +190,8 @@ private module Dispatch {
161190
}
162191

163192
private predicate hasQualifierType(VirtualMethodAccess ma, RefType t, boolean exact) {
164-
exists(Expr src | src = variableTrack(ma.getQualifier()) |
165-
// If we have a qualifier, then we track it through variable assignments
166-
// and take the type of the assigned value.
193+
exists(Expr src | src = ma.getQualifier() |
194+
// If we have a qualifier, then we take its type.
167195
exists(RefType srctype | srctype = getPreciseType(src) |
168196
exists(BoundedType bd | bd = srctype |
169197
t = bd.getAnUltimateUpperBoundType()
@@ -224,34 +252,7 @@ private module Dispatch {
224252

225253
import Dispatch
226254

227-
private Expr variableTrackStep(Expr use) {
228-
exists(Variable v |
229-
pragma[only_bind_out](use) = v.getAnAccess() and
230-
use.getType() instanceof RefType and
231-
not result instanceof NullLiteral and
232-
not v.(LocalVariableDecl).getDeclExpr().hasImplicitInit()
233-
|
234-
not v instanceof Parameter and
235-
result = v.getAnAssignedValue()
236-
or
237-
exists(Parameter p | p = v and p.getCallable().isPrivate() |
238-
result = p.getAnAssignedValue() or
239-
result = p.getAnArgument()
240-
)
241-
)
242-
}
243-
244-
private Expr variableTrackPath(Expr use) {
245-
result = variableTrackStep*(use) and
246-
not exists(variableTrackStep(result))
247-
}
248-
249255
/**
250-
* Gets an expression by tracking `use` backwards through variable assignments.
256+
* DEPRECATED: Use `TypeFlow` instead.
251257
*/
252-
pragma[inline]
253-
Expr variableTrack(Expr use) {
254-
result = variableTrackPath(use)
255-
or
256-
not exists(variableTrackPath(use)) and result = use
257-
}
258+
deprecated Expr variableTrack(Expr use) { result = use }

0 commit comments

Comments
 (0)