Skip to content

Commit 4070860

Browse files
authored
Merge pull request #10208 from aschackmull/java/dispatch-fixes
Java: A couple of small virtual dispatch fixes
2 parents e020ae7 + bd6acc0 commit 4070860

File tree

2 files changed

+35
-27
lines changed

2 files changed

+35
-27
lines changed

java/ql/lib/semmle/code/java/dataflow/TypeFlow.qll

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -204,38 +204,42 @@ private predicate exactType(TypeFlowNode n, RefType t) {
204204

205205
/**
206206
* Holds if `n` occurs in a position where type information might be discarded;
207-
* `t` is the potentially boxed type of `n`, `t1` is the erasure of `t`, and
208-
* `t2` is the erased type of the implicit or explicit cast.
207+
* `t1` is the type of `n`, `t1e` is the erasure of `t1`, `t2` is the type of
208+
* the implicit or explicit cast, and `t2e` is the erasure of `t2`.
209209
*/
210-
pragma[noinline]
211-
private predicate upcastCand(TypeFlowNode n, RefType t, RefType t1, RefType t2) {
212-
t = boxIfNeeded(n.getType()) and
213-
t.getErasure() = t1 and
214-
(
215-
exists(Variable v | v.getAnAssignedValue() = n.asExpr() and t2 = v.getType().getErasure())
216-
or
217-
exists(CastingExpr c | c.getExpr() = n.asExpr() and t2 = c.getType().getErasure())
218-
or
219-
exists(ReturnStmt ret |
220-
ret.getResult() = n.asExpr() and t2 = ret.getEnclosingCallable().getReturnType().getErasure()
221-
)
222-
or
223-
exists(MethodAccess ma | viableImpl_v1(ma) = n.asMethod() and t2 = ma.getType())
224-
or
225-
exists(Parameter p | privateParamArg(p, n.asExpr()) and t2 = p.getType().getErasure())
226-
or
227-
exists(ChooseExpr cond |
228-
cond.getAResultExpr() = n.asExpr() and
229-
t2 = cond.getType().getErasure()
210+
pragma[nomagic]
211+
private predicate upcastCand(TypeFlowNode n, RefType t1, RefType t1e, RefType t2, RefType t2e) {
212+
exists(TypeFlowNode next | step(n, next) or joinStep(n, next) |
213+
n.getType() = t1 and
214+
next.getType() = t2 and
215+
t1.getErasure() = t1e and
216+
t2.getErasure() = t2e and
217+
t1 != t2
218+
)
219+
}
220+
221+
/** Holds if `t` is a raw type or parameterised type with unrestricted type arguments. */
222+
private predicate unbound(RefType t) {
223+
t instanceof RawType
224+
or
225+
exists(ParameterizedType pt | pt = t |
226+
forex(RefType arg | arg = pt.getATypeArgument() |
227+
arg.(Wildcard).isUnconstrained()
228+
or
229+
arg.(BoundedType).getUpperBoundType() instanceof TypeObject and
230+
not arg.(Wildcard).hasLowerBound()
230231
)
231232
)
232233
}
233234

234235
/** Holds if `n` occurs in a position where type information is discarded. */
235-
private predicate upcast(TypeFlowNode n, RefType t) {
236-
exists(RefType t1, RefType t2 |
237-
upcastCand(n, t, t1, t2) and
238-
t1.getASourceSupertype+() = t2
236+
private predicate upcast(TypeFlowNode n, RefType t1) {
237+
exists(RefType t1e, RefType t2, RefType t2e | upcastCand(n, t1, t1e, t2, t2e) |
238+
t1e.getASourceSupertype+() = t2e
239+
or
240+
t1e = t2e and
241+
unbound(t2) and
242+
not unbound(t1)
239243
)
240244
}
241245

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,14 @@ private module Dispatch {
211211
exists(Method m | t.hasMethod(m, _, _) and impl = m.getSourceDeclaration())
212212
}
213213

214+
private predicate isAbstractWithSubclass(SrcRefType t) {
215+
t.isAbstract() and exists(Class c | c.getASourceSupertype() = t)
216+
}
217+
214218
private predicate hasViableSubtype(RefType t, SrcRefType sub) {
215219
sub.extendsOrImplements*(t) and
216220
not sub instanceof Interface and
217-
not sub.isAbstract()
221+
not isAbstractWithSubclass(sub)
218222
}
219223
}
220224

0 commit comments

Comments
 (0)