Skip to content

Commit 6e7dcfc

Browse files
authored
Merge pull request #10097 from aschackmull/java/unification
Java: Improve virtual dispatch via better unification check and deduplicate code with parameterised module
2 parents 68bf9f3 + adfd474 commit 6e7dcfc

File tree

4 files changed

+158
-244
lines changed

4 files changed

+158
-244
lines changed

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowDispatch.qll

Lines changed: 6 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private import DataFlowUtil
44
private import semmle.code.java.dataflow.InstanceAccess
55
private import semmle.code.java.dataflow.FlowSummary
66
private import semmle.code.java.dispatch.VirtualDispatch as VirtualDispatch
7+
private import semmle.code.java.dispatch.internal.Unification
78

89
private module DispatchImpl {
910
/** Gets a viable implementation of the target of the given `Call`. */
@@ -115,74 +116,20 @@ private module DispatchImpl {
115116
exact = false and
116117
exists(RefType t2 |
117118
result.asCallable() = VirtualDispatch::viableMethodImpl(def, t.getSourceDeclaration(), t2) and
118-
not failsUnification(t, t2)
119+
not Unification::failsUnification(t, t2)
119120
)
120121
or
121122
result.asSummarizedCallable() = def
122123
)
123124
}
124125

125-
pragma[noinline]
126-
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
127-
contextArgHasType(_, _, t1, _) and t1.getGenericType() = g
128-
}
129-
130-
pragma[noinline]
131-
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
132-
exists(VirtualDispatch::viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
133-
}
134-
135-
private predicate unificationTargets(Type t1, Type t2) {
136-
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
137-
or
138-
exists(Array a1, Array a2 |
139-
unificationTargets(a1, a2) and
140-
t1 = a1.getComponentType() and
141-
t2 = a2.getComponentType()
142-
)
143-
or
144-
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
145-
unificationTargets(pt1, pt2) and
146-
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
147-
t1 = pt1.getTypeArgument(pos) and
148-
t2 = pt2.getTypeArgument(pos)
149-
)
150-
}
126+
private predicate unificationTargetLeft(ParameterizedType t1) { contextArgHasType(_, _, t1, _) }
151127

152-
pragma[noinline]
153-
private predicate typeArgsOfUnificationTargets(
154-
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
155-
) {
156-
unificationTargets(t1, t2) and
157-
arg1 = t1.getTypeArgument(pos) and
158-
arg2 = t2.getTypeArgument(pos)
128+
private predicate unificationTargetRight(ParameterizedType t2) {
129+
exists(VirtualDispatch::viableMethodImpl(_, _, t2))
159130
}
160131

161-
private predicate failsUnification(Type t1, Type t2) {
162-
unificationTargets(t1, t2) and
163-
(
164-
exists(RefType arg1, RefType arg2 |
165-
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
166-
failsUnification(arg1, arg2)
167-
)
168-
or
169-
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
170-
or
171-
not (
172-
t1 instanceof Array and t2 instanceof Array
173-
or
174-
t1.(PrimitiveType) = t2.(PrimitiveType)
175-
or
176-
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
177-
or
178-
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
179-
or
180-
t1 instanceof BoundedType and t2 instanceof RefType
181-
or
182-
t1 instanceof RefType and t2 instanceof BoundedType
183-
)
184-
)
185-
}
132+
private module Unification = MkUnification<unificationTargetLeft/1, unificationTargetRight/1>;
186133

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

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

Lines changed: 6 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ private import semmle.code.java.dataflow.internal.DataFlowUtil
1515
private import semmle.code.java.dataflow.internal.DataFlowPrivate
1616
private import semmle.code.java.dataflow.internal.ContainerFlow
1717
private import semmle.code.java.dataflow.InstanceAccess
18+
private import semmle.code.java.dispatch.internal.Unification
1819

1920
/**
2021
* Gets a viable dispatch target for `ma`. This is the input dispatch relation.
@@ -266,67 +267,10 @@ Method viableImpl_out(MethodAccess ma) {
266267
)
267268
}
268269

269-
private module Unification {
270-
pragma[noinline]
271-
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
272-
objectToStringQualType(_, t1) and t1.getGenericType() = g
273-
}
270+
private predicate unificationTargetLeft(ParameterizedType t1) { objectToStringQualType(_, t1) }
274271

275-
pragma[noinline]
276-
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
277-
exists(viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
278-
}
279-
280-
private predicate unificationTargets(Type t1, Type t2) {
281-
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
282-
or
283-
exists(Array a1, Array a2 |
284-
unificationTargets(a1, a2) and
285-
t1 = a1.getComponentType() and
286-
t2 = a2.getComponentType()
287-
)
288-
or
289-
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
290-
unificationTargets(pt1, pt2) and
291-
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
292-
t1 = pt1.getTypeArgument(pos) and
293-
t2 = pt2.getTypeArgument(pos)
294-
)
295-
}
296-
297-
pragma[noinline]
298-
private predicate typeArgsOfUnificationTargets(
299-
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
300-
) {
301-
unificationTargets(t1, t2) and
302-
arg1 = t1.getTypeArgument(pos) and
303-
arg2 = t2.getTypeArgument(pos)
304-
}
305-
306-
pragma[nomagic]
307-
predicate failsUnification(Type t1, Type t2) {
308-
unificationTargets(t1, t2) and
309-
(
310-
exists(RefType arg1, RefType arg2 |
311-
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
312-
failsUnification(arg1, arg2)
313-
)
314-
or
315-
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
316-
or
317-
not (
318-
t1 instanceof Array and t2 instanceof Array
319-
or
320-
t1.(PrimitiveType) = t2.(PrimitiveType)
321-
or
322-
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
323-
or
324-
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
325-
or
326-
t1 instanceof BoundedType and t2 instanceof RefType
327-
or
328-
t1 instanceof RefType and t2 instanceof BoundedType
329-
)
330-
)
331-
}
272+
private predicate unificationTargetRight(ParameterizedType t2) {
273+
exists(viableMethodImpl(_, _, t2))
332274
}
275+
276+
private module Unification = MkUnification<unificationTargetLeft/1, unificationTargetRight/1>;

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

Lines changed: 10 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ private import DispatchFlow as DispatchFlow
99
private import ObjFlow as ObjFlow
1010
private import semmle.code.java.dataflow.internal.BaseSSA
1111
private import semmle.code.java.controlflow.Guards
12+
private import semmle.code.java.dispatch.internal.Unification
1213

1314
/**
1415
* A conservative analysis that returns a single method - if we can establish
@@ -91,69 +92,10 @@ private module Dispatch {
9192
)
9293
}
9394

94-
private module Unification_v2 {
95-
pragma[noinline]
96-
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
97-
qualType(_, t1, _) and t1.getGenericType() = g
98-
}
95+
private predicate unificationTargetLeft_v2(ParameterizedType t1) { qualType(_, t1, _) }
9996

100-
pragma[noinline]
101-
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
102-
exists(viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
103-
}
104-
105-
private predicate unificationTargets(Type t1, Type t2) {
106-
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
107-
or
108-
exists(Array a1, Array a2 |
109-
unificationTargets(a1, a2) and
110-
t1 = a1.getComponentType() and
111-
t2 = a2.getComponentType()
112-
)
113-
or
114-
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
115-
unificationTargets(pt1, pt2) and
116-
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
117-
t1 = pt1.getTypeArgument(pos) and
118-
t2 = pt2.getTypeArgument(pos)
119-
)
120-
}
121-
122-
pragma[noinline]
123-
private predicate typeArgsOfUnificationTargets(
124-
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
125-
) {
126-
unificationTargets(t1, t2) and
127-
arg1 = t1.getTypeArgument(pos) and
128-
arg2 = t2.getTypeArgument(pos)
129-
}
130-
131-
predicate failsUnification(Type t1, Type t2) {
132-
unificationTargets(t1, t2) and
133-
(
134-
exists(RefType arg1, RefType arg2 |
135-
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
136-
failsUnification(arg1, arg2)
137-
)
138-
or
139-
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
140-
or
141-
not (
142-
t1 instanceof Array and t2 instanceof Array
143-
or
144-
t1.(PrimitiveType) = t2.(PrimitiveType)
145-
or
146-
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
147-
or
148-
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
149-
or
150-
t1 instanceof BoundedType and t2 instanceof RefType
151-
or
152-
t1 instanceof RefType and t2 instanceof BoundedType
153-
)
154-
)
155-
}
156-
}
97+
private module Unification_v2 =
98+
MkUnification<unificationTargetLeft_v2/1, unificationTargetRight/1>;
15799

158100
/**
159101
* INTERNAL: Use `viableImpl` instead.
@@ -203,70 +145,15 @@ private module Dispatch {
203145
else result = source.getMethod().getSourceDeclaration()
204146
}
205147

206-
private module Unification_v1 {
207-
pragma[noinline]
208-
private predicate unificationTargetLeft(ParameterizedType t1, GenericType g) {
209-
hasQualifierType(_, t1, _) and t1.getGenericType() = g
210-
}
148+
private predicate unificationTargetLeft_v1(ParameterizedType t1) { hasQualifierType(_, t1, _) }
211149

212-
pragma[noinline]
213-
private predicate unificationTargetRight(ParameterizedType t2, GenericType g) {
214-
exists(viableMethodImpl(_, _, t2)) and t2.getGenericType() = g
215-
}
216-
217-
private predicate unificationTargets(Type t1, Type t2) {
218-
exists(GenericType g | unificationTargetLeft(t1, g) and unificationTargetRight(t2, g))
219-
or
220-
exists(Array a1, Array a2 |
221-
unificationTargets(a1, a2) and
222-
t1 = a1.getComponentType() and
223-
t2 = a2.getComponentType()
224-
)
225-
or
226-
exists(ParameterizedType pt1, ParameterizedType pt2, int pos |
227-
unificationTargets(pt1, pt2) and
228-
not pt1.getSourceDeclaration() != pt2.getSourceDeclaration() and
229-
t1 = pt1.getTypeArgument(pos) and
230-
t2 = pt2.getTypeArgument(pos)
231-
)
232-
}
233-
234-
pragma[noinline]
235-
private predicate typeArgsOfUnificationTargets(
236-
ParameterizedType t1, ParameterizedType t2, int pos, RefType arg1, RefType arg2
237-
) {
238-
unificationTargets(t1, t2) and
239-
arg1 = t1.getTypeArgument(pos) and
240-
arg2 = t2.getTypeArgument(pos)
241-
}
242-
243-
predicate failsUnification(Type t1, Type t2) {
244-
unificationTargets(t1, t2) and
245-
(
246-
exists(RefType arg1, RefType arg2 |
247-
typeArgsOfUnificationTargets(t1, t2, _, arg1, arg2) and
248-
failsUnification(arg1, arg2)
249-
)
250-
or
251-
failsUnification(t1.(Array).getComponentType(), t2.(Array).getComponentType())
252-
or
253-
not (
254-
t1 instanceof Array and t2 instanceof Array
255-
or
256-
t1.(PrimitiveType) = t2.(PrimitiveType)
257-
or
258-
t1.(Class).getSourceDeclaration() = t2.(Class).getSourceDeclaration()
259-
or
260-
t1.(Interface).getSourceDeclaration() = t2.(Interface).getSourceDeclaration()
261-
or
262-
t1 instanceof BoundedType and t2 instanceof RefType
263-
or
264-
t1 instanceof RefType and t2 instanceof BoundedType
265-
)
266-
)
267-
}
150+
private predicate unificationTargetRight(ParameterizedType t2) {
151+
exists(viableMethodImpl(_, _, t2))
268152
}
269153

154+
private module Unification_v1 =
155+
MkUnification<unificationTargetLeft_v1/1, unificationTargetRight/1>;
156+
270157
private RefType getPreciseType(Expr e) {
271158
result = e.(FunctionalExpr).getConstructedType()
272159
or

0 commit comments

Comments
 (0)