Skip to content

Commit 802cc77

Browse files
committed
Java: Make Virtual Dispatch Global, but keep SSA local.
Use forceLocal to achive this.
1 parent 028f1cb commit 802cc77

File tree

7 files changed

+40
-8
lines changed

7 files changed

+40
-8
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ private module SyntheticCallables {
5454
private import semmle.code.java.frameworks.Stream
5555
}
5656

57+
overlay[local]
5758
private newtype TSummarizedCallableBase =
5859
TSimpleCallable(Callable c) { c.isSourceDeclaration() } or
5960
TSyntheticCallable(SyntheticCallable c)

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

Lines changed: 10 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,13 @@ class SsaImplicitUpdate extends SsaUpdate {
287288
}
288289
}
289290

291+
overlay[global]
292+
private predicate isNonNonLocalImpl(SsaImplicitUpdate su) {
293+
exists(su.getANonLocalUpdate())
294+
}
295+
296+
private predicate isNonNonLocal(SsaImplicitUpdate su) = forceLocal(isNonNonLocalImpl/1)(su)
297+
290298
/**
291299
* An SSA variable that represents an uncertain implicit update of the value.
292300
* 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: 25 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> {
170175
private import java as J
171176

@@ -345,6 +350,7 @@ private module Cached {
345350
* Constructor --(intraInstanceCallEdge)-->+ Method(setter of this.f)
346351
* ```
347352
*/
353+
overlay[global]
348354
private predicate intraInstanceCallEdge(Callable c1, Method m2) {
349355
exists(MethodCall ma, RefType t1 |
350356
ma.getCaller() = c1 and
@@ -365,6 +371,7 @@ private module Cached {
365371
)
366372
}
367373

374+
overlay[global]
368375
private Callable tgt(Call c) {
369376
result = viableImpl_v2(c)
370377
or
@@ -374,11 +381,13 @@ private module Cached {
374381
}
375382

376383
/** Holds if `(c1,c2)` is an edge in the call graph. */
384+
overlay[global]
377385
private predicate callEdge(Callable c1, Callable c2) {
378386
exists(Call c | c.getCaller() = c1 and c2 = tgt(c))
379387
}
380388

381389
/** Holds if `(c1,c2)` is an edge in the call graph excluding `intraInstanceCallEdge`. */
390+
overlay[global]
382391
private predicate crossInstanceCallEdge(Callable c1, Callable c2) {
383392
callEdge(c1, c2) and not intraInstanceCallEdge(c1, c2)
384393
}
@@ -392,6 +401,7 @@ private module Cached {
392401
relevantFieldUpdate(_, f.getField(), _)
393402
}
394403

404+
overlay[global]
395405
private predicate source(Call call, TrackedField f, Field field, Callable c, boolean fresh) {
396406
relevantCall(call, f) and
397407
field = f.getField() and
@@ -405,9 +415,11 @@ private module Cached {
405415
* `fresh` indicates whether the instance `this` in `c` has been freshly
406416
* allocated along the call-chain.
407417
*/
418+
overlay[global]
408419
private newtype TCallableNode =
409420
MkCallableNode(Callable c, boolean fresh) { source(_, _, _, c, fresh) or edge(_, c, fresh) }
410421

422+
overlay[global]
411423
private predicate edge(TCallableNode n, Callable c2, boolean f2) {
412424
exists(Callable c1, boolean f1 | n = MkCallableNode(c1, f1) |
413425
intraInstanceCallEdge(c1, c2) and f2 = f1
@@ -417,13 +429,15 @@ private module Cached {
417429
)
418430
}
419431

432+
overlay[global]
420433
private predicate edge(TCallableNode n1, TCallableNode n2) {
421434
exists(Callable c2, boolean f2 |
422435
edge(n1, c2, f2) and
423436
n2 = MkCallableNode(c2, f2)
424437
)
425438
}
426439

440+
overlay[global]
427441
pragma[noinline]
428442
private predicate source(Call call, TrackedField f, Field field, TCallableNode n) {
429443
exists(Callable c, boolean fresh |
@@ -432,31 +446,36 @@ private module Cached {
432446
)
433447
}
434448

449+
overlay[global]
435450
private predicate sink(Callable c, Field f, TCallableNode n) {
436451
setsOwnField(c, f) and n = MkCallableNode(c, false)
437452
or
438453
setsOtherField(c, f) and n = MkCallableNode(c, _)
439454
}
440455

456+
overlay[global]
441457
private predicate prunedNode(TCallableNode n) {
442458
sink(_, _, n)
443459
or
444460
exists(TCallableNode mid | edge(n, mid) and prunedNode(mid))
445461
}
446462

463+
overlay[global]
447464
private predicate prunedEdge(TCallableNode n1, TCallableNode n2) {
448465
prunedNode(n1) and
449466
prunedNode(n2) and
450467
edge(n1, n2)
451468
}
452469

470+
overlay[global]
453471
private predicate edgePlus(TCallableNode c1, TCallableNode c2) = fastTC(prunedEdge/2)(c1, c2)
454472

455473
/**
456474
* Holds if there exists a call-chain originating in `call` that can update `f` on some instance
457475
* where `f` and `call` share the same enclosing callable in which a
458476
* `FieldRead` of `f` is reachable from `call`.
459477
*/
478+
overlay[global]
460479
pragma[noopt]
461480
private predicate updatesNamedFieldImpl(Call call, TrackedField f, Callable setter) {
462481
exists(TCallableNode src, TCallableNode sink, Field field |
@@ -467,17 +486,20 @@ private module Cached {
467486
}
468487

469488
bindingset[call, f]
489+
overlay[global]
470490
pragma[inline_late]
471491
private predicate updatesNamedField0(Call call, TrackedField f, Callable setter) {
472492
updatesNamedField(call, f, setter)
473493
}
474494

495+
overlay[global]
475496
cached
476497
predicate defUpdatesNamedField(SsaImplicitUpdate def, TrackedField f, Callable setter) {
477498
f = def.getSourceVariable() and
478499
updatesNamedField0(def.getCfgNode().asCall(), f, setter)
479500
}
480501

502+
481503
cached
482504
predicate ssaUncertainImplicitUpdate(SsaImplicitUpdate def) {
483505
exists(SsaSourceVariable v, BasicBlock bb, int i |
@@ -545,6 +567,7 @@ private module Cached {
545567
}
546568

547569
cached
570+
overlay[global]
548571
module DataFlowIntegration {
549572
import DataFlowIntegrationImpl
550573

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)