Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ private import DataFlowUtil
private import semmle.code.java.dataflow.InstanceAccess
private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
private import semmle.code.java.dispatch.internal.Unification

private module DispatchImpl {
/** Gets a viable implementation of the target of the given `Call`. */
Expand Down Expand Up @@ -115,74 +116,20 @@ private module DispatchImpl {
exact = false and
exists(RefType t2 |
result.asCallable() = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and
not failsUnification(t, t2)
not Unification::failsUnification(t, t2)
)
or
result.asSummarizedCallable() = def
)
}

pragma[noinline]
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
contextArgHasType(_, _, t1, _) and t1.getGenericType() = g
}

pragma[noinline]
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
exists(VirtualDispatch::viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
}

private predicate unificationTargets(Type t1, Type t2) {
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
or
exists(Array a1, Array a2 |
unificationTargets(a1, a2) and
t1 = a1.getComponentType() and
t2 = a2.getComponentType()
)
or
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
unificationTargets(pt1, pt2) and
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
t1 = pt1.getTypeArgument(pos) and
t2 = pt2.getTypeArgument(pos)
)
}
private predicate unificationTargetLeft(ParameterizedType t1) { contextArgHasType(_, _, t1, _) }

pragma[noinline]
private predicate typeArgsOfUnificationTargets(
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
) {
unificationTargets(t1, t2) and
arg1 = t1.getTypeArgument(pos) and
arg2 = t2.getTypeArgument(pos)
private predicate unificationTargetRight(ParameterizedType t2) {
exists(VirtualDispatch::viableMethodImpl(_, _, t2))
}

private predicate failsUnification(Type t1, Type t2) {
unificationTargets(t1, t2) and
(
exists(RefType arg1, RefType arg2 |
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
failsUnification(arg1, arg2)
)
or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
or
not (
t1 instanceof Array and t2 instanceof Array
or
t1.(PrimitiveType) = t2.(PrimitiveType)
or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
or
t1 instanceof BoundedType and t2 instanceof RefType
or
t1 instanceof RefType and t2 instanceof BoundedType
)
)
}
private module Unification = MkUnification<unificationTargetLeft/1, unificationTargetRight/1>;

private int parameterPosition() { result in [-1, any(Parameter p).getPosition()] }

Expand Down
68 changes: 6 additions & 62 deletions java/ql/lib/semmle/code/java/dispatch/ObjFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ private import semmle.code.java.dataflow.internal.DataFlowUtil
private import semmle.code.java.dataflow.internal.DataFlowPrivate
private import semmle.code.java.dataflow.internal.ContainerFlow
private import semmle.code.java.dataflow.InstanceAccess
private import semmle.code.java.dispatch.internal.Unification

/**
* Gets a viable dispatch target for `ma`. This is the input dispatch relation.
Expand Down Expand Up @@ -266,67 +267,10 @@ Method viableImpl_out(MethodAccess ma) {
)
}

private module Unification {
pragma[noinline]
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
objectToStringQualType(_, t1) and t1.getGenericType() = g
}
private predicate unificationTargetLeft(ParameterizedType t1) { objectToStringQualType(_, t1) }

pragma[noinline]
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
exists(viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
}

private predicate unificationTargets(Type t1, Type t2) {
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
or
exists(Array a1, Array a2 |
unificationTargets(a1, a2) and
t1 = a1.getComponentType() and
t2 = a2.getComponentType()
)
or
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
unificationTargets(pt1, pt2) and
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
t1 = pt1.getTypeArgument(pos) and
t2 = pt2.getTypeArgument(pos)
)
}

pragma[noinline]
private predicate typeArgsOfUnificationTargets(
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
) {
unificationTargets(t1, t2) and
arg1 = t1.getTypeArgument(pos) and
arg2 = t2.getTypeArgument(pos)
}

pragma[nomagic]
predicate failsUnification(Type t1, Type t2) {
unificationTargets(t1, t2) and
(
exists(RefType arg1, RefType arg2 |
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
failsUnification(arg1, arg2)
)
or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
or
not (
t1 instanceof Array and t2 instanceof Array
or
t1.(PrimitiveType) = t2.(PrimitiveType)
or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
or
t1 instanceof BoundedType and t2 instanceof RefType
or
t1 instanceof RefType and t2 instanceof BoundedType
)
)
}
private predicate unificationTargetRight(ParameterizedType t2) {
exists(viableMethodImpl(_, _, t2))
}

private module Unification = MkUnification<unificationTargetLeft/1, unificationTargetRight/1>;
133 changes: 10 additions & 123 deletions java/ql/lib/semmle/code/java/dispatch/VirtualDispatch.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ private import DispatchFlow as DispatchFlow
private import ObjFlow as ObjFlow
private import semmle.code.java.dataflow.internal.BaseSSA
private import semmle.code.java.controlflow.Guards
private import semmle.code.java.dispatch.internal.Unification

/**
* A conservative analysis that returns a single method - if we can establish
Expand Down Expand Up @@ -91,69 +92,10 @@ private module Dispatch {
)
}

private module Unification_v2 {
pragma[noinline]
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
qualType(_, t1, _) and t1.getGenericType() = g
}
private predicate unificationTargetLeft_v2(ParameterizedType t1) { qualType(_, t1, _) }

pragma[noinline]
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
exists(viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
}

private predicate unificationTargets(Type t1, Type t2) {
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
or
exists(Array a1, Array a2 |
unificationTargets(a1, a2) and
t1 = a1.getComponentType() and
t2 = a2.getComponentType()
)
or
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
unificationTargets(pt1, pt2) and
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
t1 = pt1.getTypeArgument(pos) and
t2 = pt2.getTypeArgument(pos)
)
}

pragma[noinline]
private predicate typeArgsOfUnificationTargets(
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
) {
unificationTargets(t1, t2) and
arg1 = t1.getTypeArgument(pos) and
arg2 = t2.getTypeArgument(pos)
}

predicate failsUnification(Type t1, Type t2) {
unificationTargets(t1, t2) and
(
exists(RefType arg1, RefType arg2 |
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
failsUnification(arg1, arg2)
)
or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
or
not (
t1 instanceof Array and t2 instanceof Array
or
t1.(PrimitiveType) = t2.(PrimitiveType)
or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
or
t1 instanceof BoundedType and t2 instanceof RefType
or
t1 instanceof RefType and t2 instanceof BoundedType
)
)
}
}
private module Unification_v2 =
MkUnification<unificationTargetLeft_v2/1, unificationTargetRight/1>;

/**
* INTERNAL: Use `viableImpl` instead.
Expand Down Expand Up @@ -203,70 +145,15 @@ private module Dispatch {
else result = source.getMethod().getSourceDeclaration()
}

private module Unification_v1 {
pragma[noinline]
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
hasQualifierType(_, t1, _) and t1.getGenericType() = g
}
private predicate unificationTargetLeft_v1(ParameterizedType t1) { hasQualifierType(_, t1, _) }

pragma[noinline]
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
exists(viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
}

private predicate unificationTargets(Type t1, Type t2) {
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
or
exists(Array a1, Array a2 |
unificationTargets(a1, a2) and
t1 = a1.getComponentType() and
t2 = a2.getComponentType()
)
or
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
unificationTargets(pt1, pt2) and
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
t1 = pt1.getTypeArgument(pos) and
t2 = pt2.getTypeArgument(pos)
)
}

pragma[noinline]
private predicate typeArgsOfUnificationTargets(
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
) {
unificationTargets(t1, t2) and
arg1 = t1.getTypeArgument(pos) and
arg2 = t2.getTypeArgument(pos)
}

predicate failsUnification(Type t1, Type t2) {
unificationTargets(t1, t2) and
(
exists(RefType arg1, RefType arg2 |
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
failsUnification(arg1, arg2)
)
or
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
or
not (
t1 instanceof Array and t2 instanceof Array
or
t1.(PrimitiveType) = t2.(PrimitiveType)
or
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
or
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
or
t1 instanceof BoundedType and t2 instanceof RefType
or
t1 instanceof RefType and t2 instanceof BoundedType
)
)
}
private predicate unificationTargetRight(ParameterizedType t2) {
exists(viableMethodImpl(_, _, t2))
}

private module Unification_v1 =
MkUnification<unificationTargetLeft_v1/1, unificationTargetRight/1>;

private RefType getPreciseType(Expr e) {
result = e.(FunctionalExpr).getConstructedType()
or
Expand Down
Loading