Skip to content

Fix dropped call summaries for AllocVal-wrapped facts, and cut peak memory - #333

Merged
swissiety merged 9 commits into
secure-software-engineering:developfrom
Hazem-Gamall:all-optimizations
Sep 23, 2026
Merged

swissiety merged 9 commits into
secure-software-engineering:developfrom
Hazem-Gamall:all-optimizations

Conversation

@Hazem-Gamall

Copy link
Copy Markdown
Member

Summary

Four independent changes: one correctness fix, three memory reductions.

Forward the locality checks through AllocVal

AllocVal decorates Val and forwards nearly every method to its delegate, but not
isThisLocal, isReturnLocal and isParameterLocal. Those are implemented in Val
in terms of this, and AllocVal.equals requires both sides to be an AllocVal
while a method's locals are always plain values — so all three answer false for any
wrapped local.

ForwardBoomerangSolver.applyCallSummary branches on them to build its out-set, so a
returned seed never produced the this/return/parameter entries and the call summary was
dropped silently. It surfaces as an assertion in computeSuccessor, but only with -ea;
without assertions it just loses flows.

Also unwraps the wrapper where a fact is lifted off a transition's start state before
being propagated on (ForwardBoomerangSolver, IDEALSeedSolver).

New tests in SootAllocValTest fail on the unmodified code and pass with the fix.

Drop the transitions set

It held exactly the same elements as transitionToWeights.keySet() — every transition
added to one was put in the other in the same call, and a fresh transition always has a
null old weight so the put always fires. transitionToWeights becomes a LinkedHashMap
to preserve the iteration order getTransitions() callers relied on.

~32 bytes per transition, ~1.3 GB on the workload below.

Small inline set for multimap values

SimpleSetMultimap's per-key sets are usually tiny; a LinkedHashSet costs ~190 bytes
for a single element. SmallOrderedSet holds 1 element in a field, 2–8 in an array, and
promotes to a LinkedHashSet beyond that. Representation is chosen by size alone, never
instanceof, and insertion order and add()'s contract are preserved.

The measured distribution behind this (88.5% singletons) came from a smaller workload and
did not hold on the large one, where most sets promote past the array limit. Benefit
there is correspondingly smaller.

Release a seed's phase-1 solver, and optionally its query solvers

IDEALSeedSolver constructs both phase solvers up front, so phase 1's automata stay
reachable for all of phase 2. Clearing them halves the in-flight live set.
clearListeners() is required, not tidying: runPhase registers a lambda on the shared
idealWeightFunctions that captures the phase's solver.

Separately, releaseSolversAfterQuery (default off) drops queryToSolvers once every
query-scoped result has been materialized.

Measurements

APK tested with 166 seeds, 5 GB heap, 3 runs per config, means:

config peak live set wall total GC pause
baseline 3080 MB 152.0 s 5764 ms
+ releaseSolvers() 3232 MB (+4.9%) 150.0 s 5729 ms
+ both 2564 MB (−16.8%) 150.7 s 5292 ms

The phase-1 release accounts for all of the win. releaseSolvers() nets out to nothing
measurable here, and the reason is a trade rather than a no-op: it breaks a real retention
chain -- queryToSolvers is an anonymous inner class capturing its WeightedBoomerang, so
a result held by StoreIDEALResultHandler otherwise pins that instance and all its solvers
-- but to do so it must eagerly materialize the query-scoped views, which are then retained
for the life of the result. On this bounded workload the two roughly cancel. On a larger,
unbounded analysis, where solver graphs per seed are far bigger relative to those tables,
the balance should favour releasing. That is not measured here, which is why it is opt-in
and defaults to off.

Testing

Full suite green under -DtestSetup=SootUp: boomerangPDS 352/0, idealPDS 113/0/5 skipped,
matching baseline. Under -DtestSetup=Soot, typestate.IteratorHasNextTest test1/2/4 fail —
these reproduce on unmodified develop and are unrelated to this PR.

@swissiety
swissiety enabled auto-merge September 23, 2026 08:52
@swissiety
swissiety merged commit 268be53 into secure-software-engineering:develop Sep 23, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants