Skip to content

Commit 1dbb620

Browse files
authored
Merge pull request #240 from marcus-h/otf_cg
Improve the on the fly call graph code a bit
2 parents 95fd88d + 007724b commit 1dbb620

23 files changed

Lines changed: 547 additions & 286 deletions

.github/workflows/tests.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ on:
1111

1212
jobs:
1313
BuildAndTest:
14+
name: Test with ${{ matrix.framework }} , ${{ matrix.enableOnTheFlyCallGraph }}
1415
strategy:
1516
fail-fast: false
1617
matrix:
1718
framework: [ Soot, SootUp, Opal ]
19+
enableOnTheFlyCallGraph: [ false, true ]
1820
runs-on: ubuntu-latest
1921
steps:
2022
- name: Checkout source code
@@ -26,4 +28,4 @@ jobs:
2628
java-package: jdk
2729
java-version: 11
2830
- name: Build with Maven
29-
run: mvn -B clean verify -DtestSetup=${{ matrix.framework }}
31+
run: mvn -B clean verify -DtestSetup=${{ matrix.framework }} -DenableOnTheFlyCallGraph=${{ matrix.enableOnTheFlyCallGraph }}

WPDS/src/main/java/wpds/impl/StackListener.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public StackListener(WeightedPAutomaton<N, D, W> weightedPAutomaton, D state, N
3838
public void onOutTransitionAdded(
3939
Transition<N, D> t, W w, WeightedPAutomaton<N, D, W> weightedPAutomaton) {
4040
if (t.getLabel().equals(aut.epsilon())) return;
41+
/*
42+
* XXX: Does this always work, if the BoomerangOptions.onTheFlyCallGraph
43+
* option is active? For now, the testcases seem to pass - reconsider this
44+
* (that is, try to use an InitialStateListener).
45+
*/
4146
if (this.aut.getInitialStates().contains(t.getTarget())) {
4247
if (t.getLabel().equals(source)) {
4348
anyContext(source);

WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import com.google.common.base.Joiner;
1818
import com.google.common.base.Stopwatch;
1919
import com.google.common.collect.HashBasedTable;
20-
import com.google.common.collect.HashMultimap;
20+
import com.google.common.collect.LinkedHashMultimap;
2121
import com.google.common.collect.Lists;
2222
import com.google.common.collect.Maps;
2323
import com.google.common.collect.Multimap;
@@ -42,6 +42,7 @@
4242
import pathexpression.RegEx;
4343
import wpds.interfaces.ForwardDFSEpsilonVisitor;
4444
import wpds.interfaces.ForwardDFSVisitor;
45+
import wpds.interfaces.InitialStateListener;
4546
import wpds.interfaces.ReachabilityListener;
4647
import wpds.interfaces.State;
4748
import wpds.interfaces.WPAStateListener;
@@ -57,13 +58,14 @@ public abstract class WeightedPAutomaton<N extends Location, D extends State, W
5758
protected Set<Transition<N, D>> transitions = new LinkedHashSet<>();
5859
// set F in paper [Reps2003]
5960
protected Set<D> finalState = new LinkedHashSet<>();
60-
protected Multimap<D, D> initialStatesToSource = HashMultimap.create();
61+
protected Multimap<D, D> initialStatesToSource = LinkedHashMultimap.create();
6162
// set P in paper [Reps2003]
6263
protected Set<D> states = new LinkedHashSet<>();
63-
private final Multimap<D, Transition<N, D>> transitionsOutOf = HashMultimap.create();
64-
private final Multimap<D, Transition<N, D>> transitionsInto = HashMultimap.create();
64+
private final Multimap<D, Transition<N, D>> transitionsOutOf = LinkedHashMultimap.create();
65+
private final Multimap<D, Transition<N, D>> transitionsInto = LinkedHashMultimap.create();
6566
private final Set<WPAUpdateListener<N, D, W>> listeners = new LinkedHashSet<>();
66-
private final Multimap<D, WPAStateListener<N, D, W>> stateListeners = HashMultimap.create();
67+
private final Set<InitialStateListener<D>> initialStateListeners = new LinkedHashSet<>();
68+
private final Multimap<D, WPAStateListener<N, D, W>> stateListeners = LinkedHashMultimap.create();
6769
private final Map<D, ForwardDFSVisitor<N, D, W>> stateToDFS = Maps.newHashMap();
6870
private final Map<D, ForwardDFSVisitor<N, D, W>> stateToEpsilonDFS = Maps.newHashMap();
6971
private final Set<WeightedPAutomaton<N, D, W>> nestedAutomatons = new LinkedHashSet<>();
@@ -371,6 +373,15 @@ public void registerListener(WPAUpdateListener<N, D, W> listener) {
371373
}
372374
}
373375

376+
public void registerListener(InitialStateListener<D> listener) {
377+
if (!initialStateListeners.add(listener)) {
378+
return;
379+
}
380+
for (D initialState : Lists.newArrayList(getInitialStates())) {
381+
listener.onInitialStateAdded(initialState);
382+
}
383+
}
384+
374385
private static int count = 0;
375386

376387
private void increaseListenerCount(WPAStateListener<N, D, W> l) {
@@ -825,7 +836,13 @@ public boolean addUnbalancedState(D state, D parent) {
825836
}
826837

827838
public boolean addInitialState(D state) {
828-
return initialStatesToSource.put(state, state);
839+
if (!initialStatesToSource.get(state).add(state)) {
840+
return false;
841+
}
842+
for (InitialStateListener<D> listener : Lists.newArrayList(initialStateListeners)) {
843+
listener.onInitialStateAdded(state);
844+
}
845+
return true;
829846
}
830847

831848
public void unregisterAllListeners() {
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* *****************************************************************************
3+
* Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany
4+
* <p>
5+
* This program and the accompanying materials are made available under the
6+
* terms of the Eclipse Public License 2.0 which is available at
7+
* http://www.eclipse.org/legal/epl-2.0.
8+
* <p>
9+
* SPDX-License-Identifier: EPL-2.0
10+
* <p>
11+
* Contributors:
12+
* Johannes Spaeth - initial API and implementation
13+
* *****************************************************************************
14+
*/
15+
package wpds.interfaces;
16+
17+
public interface InitialStateListener<D extends State> {
18+
void onInitialStateAdded(D initialState);
19+
}

boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java

Lines changed: 94 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -267,21 +267,24 @@ public void getPredecessor(Statement pred) {
267267
BackwardQuery bwq =
268268
BackwardQuery.make(new Edge(pred, stmt), stmt.getInvokeExpr().getArg(0));
269269
backwardSolve(bwq);
270-
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
271-
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
272-
AllocVal v = q.getAllocVal();
273-
if (v.getAllocVal().isStringConstant()) {
274-
String key = v.getAllocVal().getStringValue();
275-
backwardSolverIns.propagate(
276-
node,
277-
new PushNode<>(
278-
new Edge(pred, stmt),
279-
stmt.getInvokeExpr().getBase(),
280-
StringBasedField.getInstance(key),
281-
PDSSystem.FIELDS));
282-
}
283-
}
284-
}
270+
WeightedBoomerang.this.registerSolverCreationListener(
271+
(q, solver) ->
272+
solver.registerListener(
273+
n -> {
274+
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
275+
AllocVal v = ((ForwardQuery) q).getAllocVal();
276+
if (v.getAllocVal().isStringConstant()) {
277+
String key = v.getAllocVal().getStringValue();
278+
backwardSolverIns.propagate(
279+
node,
280+
new PushNode<>(
281+
new Edge(pred, stmt),
282+
stmt.getInvokeExpr().getBase(),
283+
StringBasedField.getInstance(key),
284+
PDSSystem.FIELDS));
285+
}
286+
}
287+
}));
285288
}
286289
});
287290
}
@@ -296,21 +299,25 @@ public void getPredecessor(Statement pred) {
296299
BackwardQuery bwq =
297300
BackwardQuery.make(new Edge(pred, stmt), stmt.getInvokeExpr().getArg(0));
298301
backwardSolve(bwq);
299-
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
300-
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
301-
AllocVal v = q.getAllocVal();
302-
303-
if (v.getAllocVal().isStringConstant()) {
304-
String key = v.getAllocVal().getStringValue();
305-
NodeWithLocation<Edge, Val, Field> succNode =
306-
new NodeWithLocation<>(
307-
new Edge(pred, stmt),
308-
stmt.getInvokeExpr().getArg(1),
309-
StringBasedField.getInstance(key));
310-
backwardSolverIns.propagate(node, new PopNode<>(succNode, PDSSystem.FIELDS));
311-
}
312-
}
313-
}
302+
WeightedBoomerang.this.registerSolverCreationListener(
303+
(q, solver) ->
304+
solver.registerListener(
305+
n -> {
306+
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
307+
AllocVal v = ((ForwardQuery) q).getAllocVal();
308+
309+
if (v.getAllocVal().isStringConstant()) {
310+
String key = v.getAllocVal().getStringValue();
311+
NodeWithLocation<Edge, Val, Field> succNode =
312+
new NodeWithLocation<>(
313+
new Edge(pred, stmt),
314+
stmt.getInvokeExpr().getArg(1),
315+
StringBasedField.getInstance(key));
316+
backwardSolverIns.propagate(
317+
node, new PopNode<>(succNode, PDSSystem.FIELDS));
318+
}
319+
}
320+
}));
314321
}
315322
});
316323
}
@@ -325,55 +332,60 @@ protected void handleMapsForward(ForwardBoomerangSolver<W> solver, Node<Edge, Va
325332
if (stmt.getInvokeExpr().getBase().equals(node.fact())) {
326333
BackwardQuery bwq = BackwardQuery.make(node.stmt(), stmt.getInvokeExpr().getArg(0));
327334
backwardSolve(bwq);
328-
cfg.addSuccsOfListener(
329-
new SuccessorListener(stmt) {
330-
@Override
331-
public void getSuccessor(Statement succ) {
332-
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
333-
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
334-
AllocVal v = q.getAllocVal();
335-
336-
if (v.getAllocVal().isStringConstant()) {
337-
String key = v.getAllocVal().getStringValue();
338-
NodeWithLocation<Edge, Val, Field> succNode =
339-
new NodeWithLocation<>(
340-
new Edge(stmt, succ),
341-
stmt.getLeftOp(),
342-
StringBasedField.getInstance(key));
343-
solver.propagate(node, new PopNode<>(succNode, PDSSystem.FIELDS));
344-
}
345-
}
346-
}
347-
}
348-
});
335+
registerSolverCreationListener(
336+
(q, solverForKeyArg) ->
337+
solverForKeyArg.registerListener(
338+
n ->
339+
cfg.addSuccsOfListener(
340+
new SuccessorListener(stmt) {
341+
@Override
342+
public void getSuccessor(Statement succ) {
343+
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
344+
AllocVal v = ((ForwardQuery) q).getAllocVal();
345+
346+
if (v.getAllocVal().isStringConstant()) {
347+
String key = v.getAllocVal().getStringValue();
348+
NodeWithLocation<Edge, Val, Field> succNode =
349+
new NodeWithLocation<>(
350+
new Edge(stmt, succ),
351+
stmt.getLeftOp(),
352+
StringBasedField.getInstance(key));
353+
solver.propagate(
354+
node, new PopNode<>(succNode, PDSSystem.FIELDS));
355+
}
356+
}
357+
}
358+
})));
349359
}
350360
}
351361
if (stmt.getInvokeExpr().getDeclaredMethod().toMethodWrapper().equals(MAP_PUT_SIGNATURE)) {
352362
if (stmt.getInvokeExpr().getArg(1).equals(node.fact())) {
353363

354364
BackwardQuery bwq = BackwardQuery.make(node.stmt(), stmt.getInvokeExpr().getArg(0));
355365
backwardSolve(bwq);
356-
cfg.addSuccsOfListener(
357-
new SuccessorListener(stmt) {
358-
@Override
359-
public void getSuccessor(Statement succ) {
360-
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
361-
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
362-
AllocVal v = q.getAllocVal();
363-
if (v.getAllocVal().isStringConstant()) {
364-
String key = v.getAllocVal().getStringValue();
365-
solver.propagate(
366-
node,
367-
new PushNode<>(
368-
new Edge(stmt, succ),
369-
stmt.getInvokeExpr().getBase(),
370-
StringBasedField.getInstance(key),
371-
PDSSystem.FIELDS));
372-
}
373-
}
374-
}
375-
}
376-
});
366+
registerSolverCreationListener(
367+
(q, solverForKeyArg) ->
368+
solverForKeyArg.registerListener(
369+
n ->
370+
cfg.addSuccsOfListener(
371+
new SuccessorListener(stmt) {
372+
@Override
373+
public void getSuccessor(Statement succ) {
374+
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
375+
AllocVal v = ((ForwardQuery) q).getAllocVal();
376+
if (v.getAllocVal().isStringConstant()) {
377+
String key = v.getAllocVal().getStringValue();
378+
solver.propagate(
379+
node,
380+
new PushNode<>(
381+
new Edge(stmt, succ),
382+
stmt.getInvokeExpr().getBase(),
383+
StringBasedField.getInstance(key),
384+
PDSSystem.FIELDS));
385+
}
386+
}
387+
}
388+
})));
377389
}
378390
}
379391
}
@@ -988,10 +1000,14 @@ public ForwardBoomerangResults<W> solve(ForwardQuery query) {
9881000
}
9891001

9901002
public BackwardBoomerangResults<W> solve(BackwardQuery query) {
991-
return solve(query, true);
1003+
return solve(query, true, true);
9921004
}
9931005

9941006
public BackwardBoomerangResults<W> solve(BackwardQuery query, boolean timing) {
1007+
return solve(query, timing, true);
1008+
}
1009+
1010+
public BackwardBoomerangResults<W> solve(BackwardQuery query, boolean timing, boolean fallback) {
9951011
if (!options.allowMultipleQueries() && solving) {
9961012
throw new RuntimeException(
9971013
"One cannot re-use the same Boomerang solver for more than one query, unless option allowMultipleQueries is enabled. If allowMultipleQueries is enabled, ensure to call unregisterAllListeners() on this instance upon termination of all queries.");
@@ -1005,6 +1021,9 @@ public BackwardBoomerangResults<W> solve(BackwardQuery query, boolean timing) {
10051021
queryGraph.addRoot(query);
10061022
LOGGER.trace("Starting backward analysis of: {}", query);
10071023
backwardSolve(query);
1024+
if (fallback) {
1025+
icfg.computeFallback();
1026+
}
10081027
} catch (BoomerangTimeoutException e) {
10091028
timedout = true;
10101029
LOGGER.trace("Timeout ({}) of query: {} ", analysisWatch, query);
@@ -1037,6 +1056,7 @@ public BackwardBoomerangResults<W> solveUnderScope(
10371056
LOGGER.trace("Starting backward analysis of: {}", query);
10381057
backwardSolve(query);
10391058
queryGraph.addEdge(parentQuery, triggeringNode, query);
1059+
icfg.computeFallback();
10401060
this.debugOutput();
10411061
} catch (BoomerangTimeoutException e) {
10421062
timedout = true;
@@ -1064,6 +1084,7 @@ public ForwardBoomerangResults<W> solveUnderScope(
10641084
LOGGER.trace("Starting forward analysis of: {}", query);
10651085
forwardSolve(query);
10661086
queryGraph.addEdge(parentQuery, triggeringNode, query);
1087+
icfg.computeFallback();
10671088
LOGGER.trace(
10681089
"Query terminated in {} ({}), visited methods {}",
10691090
analysisWatch,

boomerangPDS/src/main/java/boomerang/callgraph/BackwardsObservableICFG.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void computeFallback() {
7777
}
7878

7979
@Override
80-
public void addEdges(Edge e) {
81-
this.delegate.addEdges(e);
80+
public void addEdge(Edge e) {
81+
this.delegate.addEdge(e);
8282
}
8383
}

0 commit comments

Comments
 (0)