Skip to content

Commit 1d8c324

Browse files
committed
Java: Make Virtual Dispatch Global, but keep SSA local.
Use forceLocal to achive this.
1 parent c5e5b8a commit 1d8c324

File tree

6 files changed

+36
-8
lines changed

6 files changed

+36
-8
lines changed

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,17 +253,18 @@ class SsaImplicitUpdate extends SsaUpdate {
253253
or
254254
if this.hasImplicitQualifierUpdate()
255255
then
256-
if exists(this.getANonLocalUpdate())
256+
if isNonNonLocal(this)
257257
then result = "nonlocal + nonlocal qualifier"
258258
else result = "nonlocal qualifier"
259259
else (
260-
exists(this.getANonLocalUpdate()) and result = "nonlocal"
260+
isNonNonLocal(this) and result = "nonlocal"
261261
)
262262
}
263263

264264
/**
265265
* Gets a reachable `FieldWrite` that might represent this ssa update, if any.
266266
*/
267+
overlay[global]
267268
FieldWrite getANonLocalUpdate() {
268269
exists(SsaSourceField f, Callable setter |
269270
relevantFieldUpdate(setter, f.getField(), result) and
@@ -287,6 +288,11 @@ class SsaImplicitUpdate extends SsaUpdate {
287288
}
288289
}
289290

291+
overlay[global]
292+
private predicate isNonNonLocalImpl(SsaImplicitUpdate su) { exists(su.getANonLocalUpdate()) }
293+
294+
private predicate isNonNonLocal(SsaImplicitUpdate su) = forceLocal(isNonNonLocalImpl/1)(su)
295+
290296
/**
291297
* An SSA variable that represents an uncertain implicit update of the value.
292298
* This is a `Call` that might reach a non-local update of the field or one of

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

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,15 +157,20 @@ private predicate hasEntryDef(TrackedVar v, BasicBlock b) {
157157
}
158158

159159
/** Holds if `n` might update the locally tracked variable `v`. */
160+
overlay[global]
160161
pragma[nomagic]
161-
private predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) {
162+
private predicate uncertainVariableUpdateImpl(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) {
162163
exists(Call c | c = n.asCall() | updatesNamedField(c, v, _)) and
163164
b.getNode(i) = n and
164165
hasDominanceInformation(b)
165166
or
166-
uncertainVariableUpdate(v.getQualifier(), n, b, i)
167+
uncertainVariableUpdateImpl(v.getQualifier(), n, b, i)
167168
}
168169

170+
/** Holds if `n` might update the locally tracked variable `v`. */
171+
predicate uncertainVariableUpdate(TrackedVar v, ControlFlowNode n, BasicBlock b, int i) =
172+
forceLocal(uncertainVariableUpdateImpl/4)(v, n, b, i)
173+
169174
private module SsaInput implements SsaImplCommon::InputSig<Location, BasicBlock> {
170175
class SourceVariable = SsaSourceVariable;
171176

@@ -335,6 +340,7 @@ private module Cached {
335340
* Constructor --(intraInstanceCallEdge)-->+ Method(setter of this.f)
336341
* ```
337342
*/
343+
overlay[global]
338344
private predicate intraInstanceCallEdge(Callable c1, Method m2) {
339345
exists(MethodCall ma, RefType t1 |
340346
ma.getCaller() = c1 and
@@ -355,6 +361,7 @@ private module Cached {
355361
)
356362
}
357363

364+
overlay[global]
358365
private Callable tgt(Call c) {
359366
result = viableImpl_v2(c)
360367
or
@@ -364,11 +371,13 @@ private module Cached {
364371
}
365372

366373
/** Holds if `(c1,c2)` is an edge in the call graph. */
374+
overlay[global]
367375
private predicate callEdge(Callable c1, Callable c2) {
368376
exists(Call c | c.getCaller() = c1 and c2 = tgt(c))
369377
}
370378

371379
/** Holds if `(c1,c2)` is an edge in the call graph excluding `intraInstanceCallEdge`. */
380+
overlay[global]
372381
private predicate crossInstanceCallEdge(Callable c1, Callable c2) {
373382
callEdge(c1, c2) and not intraInstanceCallEdge(c1, c2)
374383
}
@@ -382,6 +391,7 @@ private module Cached {
382391
relevantFieldUpdate(_, f.getField(), _)
383392
}
384393

394+
overlay[global]
385395
private predicate source(Call call, TrackedField f, Field field, Callable c, boolean fresh) {
386396
relevantCall(call, f) and
387397
field = f.getField() and
@@ -395,9 +405,11 @@ private module Cached {
395405
* `fresh` indicates whether the instance `this` in `c` has been freshly
396406
* allocated along the call-chain.
397407
*/
408+
overlay[global]
398409
private newtype TCallableNode =
399410
MkCallableNode(Callable c, boolean fresh) { source(_, _, _, c, fresh) or edge(_, c, fresh) }
400411

412+
overlay[global]
401413
private predicate edge(TCallableNode n, Callable c2, boolean f2) {
402414
exists(Callable c1, boolean f1 | n = MkCallableNode(c1, f1) |
403415
intraInstanceCallEdge(c1, c2) and f2 = f1
@@ -407,13 +419,15 @@ private module Cached {
407419
)
408420
}
409421

422+
overlay[global]
410423
private predicate edge(TCallableNode n1, TCallableNode n2) {
411424
exists(Callable c2, boolean f2 |
412425
edge(n1, c2, f2) and
413426
n2 = MkCallableNode(c2, f2)
414427
)
415428
}
416429

430+
overlay[global]
417431
pragma[noinline]
418432
private predicate source(Call call, TrackedField f, Field field, TCallableNode n) {
419433
exists(Callable c, boolean fresh |
@@ -422,31 +436,36 @@ private module Cached {
422436
)
423437
}
424438

439+
overlay[global]
425440
private predicate sink(Callable c, Field f, TCallableNode n) {
426441
setsOwnField(c, f) and n = MkCallableNode(c, false)
427442
or
428443
setsOtherField(c, f) and n = MkCallableNode(c, _)
429444
}
430445

446+
overlay[global]
431447
private predicate prunedNode(TCallableNode n) {
432448
sink(_, _, n)
433449
or
434450
exists(TCallableNode mid | edge(n, mid) and prunedNode(mid))
435451
}
436452

453+
overlay[global]
437454
private predicate prunedEdge(TCallableNode n1, TCallableNode n2) {
438455
prunedNode(n1) and
439456
prunedNode(n2) and
440457
edge(n1, n2)
441458
}
442459

460+
overlay[global]
443461
private predicate edgePlus(TCallableNode c1, TCallableNode c2) = fastTC(prunedEdge/2)(c1, c2)
444462

445463
/**
446464
* Holds if there exists a call-chain originating in `call` that can update `f` on some instance
447465
* where `f` and `call` share the same enclosing callable in which a
448466
* `FieldRead` of `f` is reachable from `call`.
449467
*/
468+
overlay[global]
450469
pragma[noopt]
451470
private predicate updatesNamedFieldImpl(Call call, TrackedField f, Callable setter) {
452471
exists(TCallableNode src, TCallableNode sink, Field field |
@@ -457,11 +476,13 @@ private module Cached {
457476
}
458477

459478
bindingset[call, f]
479+
overlay[global]
460480
pragma[inline_late]
461481
private predicate updatesNamedField0(Call call, TrackedField f, Callable setter) {
462482
updatesNamedField(call, f, setter)
463483
}
464484

485+
overlay[global]
465486
cached
466487
predicate defUpdatesNamedField(SsaImplicitUpdate def, TrackedField f, Callable setter) {
467488
f = def.getSourceVariable() and
@@ -534,6 +555,7 @@ private module Cached {
534555
Impl::phiHasInputFromBlock(phi, inp, bb)
535556
}
536557

558+
overlay[global]
537559
cached
538560
module DataFlowIntegration {
539561
import DataFlowIntegrationImpl

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* data flow check for lambdas, anonymous classes, and other sufficiently
66
* private classes where all object instantiations are accounted for.
77
*/
8-
overlay[local?]
8+
overlay[global]
99
module;
1010

1111
import java

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* The set of dispatch targets for `Object.toString()` calls are reduced based
77
* on possible data flow from objects of more specific types to the qualifier.
88
*/
9-
overlay[local?]
9+
overlay[global]
1010
module;
1111

1212
import java

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Provides predicates for reasoning about runtime call targets through virtual
33
* dispatch.
44
*/
5-
overlay[local?]
5+
overlay[global]
66
module;
77

88
import java

java/ql/lib/semmle/code/java/dispatch/internal/Unification.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Provides a module to check whether two `ParameterizedType`s are unifiable.
33
*/
4-
overlay[local?]
4+
overlay[global]
55
module;
66

77
import java

0 commit comments

Comments
 (0)