Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ jobs:
fail-fast: false
matrix:
framework: [ Soot, SootUp, Opal ]
enableOnTheFlyCallGraph: [ false, true ]
runs-on: ubuntu-latest
steps:
- name: Checkout source code
Expand All @@ -26,4 +27,4 @@ jobs:
java-package: jdk
java-version: 11
- name: Build with Maven
run: mvn -B clean verify -DtestSetup=${{ matrix.framework }}
run: mvn -B clean verify -DtestSetup=${{ matrix.framework }} -DenableOnTheFlyCallGraph=${{ matrix.enableOnTheFlyCallGraph }}
5 changes: 5 additions & 0 deletions WPDS/src/main/java/wpds/impl/StackListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ public StackListener(WeightedPAutomaton<N, D, W> weightedPAutomaton, D state, N
public void onOutTransitionAdded(
Transition<N, D> t, W w, WeightedPAutomaton<N, D, W> weightedPAutomaton) {
if (t.getLabel().equals(aut.epsilon())) return;
/*
* XXX: Does this always work, if the BoomerangOptions.onTheFlyCallGraph
* option is active? For now, the testcases seem to pass - reconsider this
* (that is, try to use an InitialStateListener).
*/
if (this.aut.getInitialStates().contains(t.getTarget())) {
if (t.getLabel().equals(source)) {
anyContext(source);
Expand Down
29 changes: 23 additions & 6 deletions WPDS/src/main/java/wpds/impl/WeightedPAutomaton.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import com.google.common.base.Joiner;
import com.google.common.base.Stopwatch;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
Expand All @@ -42,6 +42,7 @@
import pathexpression.RegEx;
import wpds.interfaces.ForwardDFSEpsilonVisitor;
import wpds.interfaces.ForwardDFSVisitor;
import wpds.interfaces.InitialStateListener;
import wpds.interfaces.ReachabilityListener;
import wpds.interfaces.State;
import wpds.interfaces.WPAStateListener;
Expand All @@ -57,13 +58,14 @@ public abstract class WeightedPAutomaton<N extends Location, D extends State, W
protected Set<Transition<N, D>> transitions = new LinkedHashSet<>();
// set F in paper [Reps2003]
protected Set<D> finalState = new LinkedHashSet<>();
protected Multimap<D, D> initialStatesToSource = HashMultimap.create();
protected Multimap<D, D> initialStatesToSource = LinkedHashMultimap.create();
// set P in paper [Reps2003]
protected Set<D> states = new LinkedHashSet<>();
private final Multimap<D, Transition<N, D>> transitionsOutOf = HashMultimap.create();
private final Multimap<D, Transition<N, D>> transitionsInto = HashMultimap.create();
private final Multimap<D, Transition<N, D>> transitionsOutOf = LinkedHashMultimap.create();
private final Multimap<D, Transition<N, D>> transitionsInto = LinkedHashMultimap.create();
private final Set<WPAUpdateListener<N, D, W>> listeners = new LinkedHashSet<>();
private final Multimap<D, WPAStateListener<N, D, W>> stateListeners = HashMultimap.create();
private final Set<InitialStateListener<D>> initialStateListeners = new LinkedHashSet<>();
private final Multimap<D, WPAStateListener<N, D, W>> stateListeners = LinkedHashMultimap.create();
private final Map<D, ForwardDFSVisitor<N, D, W>> stateToDFS = Maps.newHashMap();
private final Map<D, ForwardDFSVisitor<N, D, W>> stateToEpsilonDFS = Maps.newHashMap();
private final Set<WeightedPAutomaton<N, D, W>> nestedAutomatons = new LinkedHashSet<>();
Expand Down Expand Up @@ -371,6 +373,15 @@ public void registerListener(WPAUpdateListener<N, D, W> listener) {
}
}

public void registerListener(InitialStateListener<D> listener) {
if (!initialStateListeners.add(listener)) {
return;
}
for (D initialState : Lists.newArrayList(getInitialStates())) {
listener.onInitialStateAdded(initialState);
}
}

private static int count = 0;

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

public boolean addInitialState(D state) {
return initialStatesToSource.put(state, state);
if (!initialStatesToSource.get(state).add(state)) {
return false;
}
for (InitialStateListener<D> listener : Lists.newArrayList(initialStateListeners)) {
listener.onInitialStateAdded(state);
}
return true;
}

public void unregisterAllListeners() {
Expand Down
19 changes: 19 additions & 0 deletions WPDS/src/main/java/wpds/interfaces/InitialStateListener.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* *****************************************************************************
* Copyright (c) 2018 Fraunhofer IEM, Paderborn, Germany
* <p>
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
* <p>
* SPDX-License-Identifier: EPL-2.0
* <p>
* Contributors:
* Johannes Spaeth - initial API and implementation
* *****************************************************************************
*/
package wpds.interfaces;

public interface InitialStateListener<D extends State> {
void onInitialStateAdded(D initialState);
}
167 changes: 94 additions & 73 deletions boomerangPDS/src/main/java/boomerang/WeightedBoomerang.java
Original file line number Diff line number Diff line change
Expand Up @@ -267,21 +267,24 @@ public void getPredecessor(Statement pred) {
BackwardQuery bwq =
BackwardQuery.make(new Edge(pred, stmt), stmt.getInvokeExpr().getArg(0));
backwardSolve(bwq);
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
AllocVal v = q.getAllocVal();
if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
backwardSolverIns.propagate(
node,
new PushNode<>(
new Edge(pred, stmt),
stmt.getInvokeExpr().getBase(),
StringBasedField.getInstance(key),
PDSSystem.FIELDS));
}
}
}
WeightedBoomerang.this.registerSolverCreationListener(
(q, solver) ->
solver.registerListener(
n -> {
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
AllocVal v = ((ForwardQuery) q).getAllocVal();
if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
backwardSolverIns.propagate(
node,
new PushNode<>(
new Edge(pred, stmt),
stmt.getInvokeExpr().getBase(),
StringBasedField.getInstance(key),
PDSSystem.FIELDS));
}
}
}));
}
});
}
Expand All @@ -296,21 +299,25 @@ public void getPredecessor(Statement pred) {
BackwardQuery bwq =
BackwardQuery.make(new Edge(pred, stmt), stmt.getInvokeExpr().getArg(0));
backwardSolve(bwq);
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
AllocVal v = q.getAllocVal();

if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
NodeWithLocation<Edge, Val, Field> succNode =
new NodeWithLocation<>(
new Edge(pred, stmt),
stmt.getInvokeExpr().getArg(1),
StringBasedField.getInstance(key));
backwardSolverIns.propagate(node, new PopNode<>(succNode, PDSSystem.FIELDS));
}
}
}
WeightedBoomerang.this.registerSolverCreationListener(
(q, solver) ->
solver.registerListener(
n -> {
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
AllocVal v = ((ForwardQuery) q).getAllocVal();

if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
NodeWithLocation<Edge, Val, Field> succNode =
new NodeWithLocation<>(
new Edge(pred, stmt),
stmt.getInvokeExpr().getArg(1),
StringBasedField.getInstance(key));
backwardSolverIns.propagate(
node, new PopNode<>(succNode, PDSSystem.FIELDS));
}
}
}));
}
});
}
Expand All @@ -325,55 +332,60 @@ protected void handleMapsForward(ForwardBoomerangSolver<W> solver, Node<Edge, Va
if (stmt.getInvokeExpr().getBase().equals(node.fact())) {
BackwardQuery bwq = BackwardQuery.make(node.stmt(), stmt.getInvokeExpr().getArg(0));
backwardSolve(bwq);
cfg.addSuccsOfListener(
new SuccessorListener(stmt) {
@Override
public void getSuccessor(Statement succ) {
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
AllocVal v = q.getAllocVal();

if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
NodeWithLocation<Edge, Val, Field> succNode =
new NodeWithLocation<>(
new Edge(stmt, succ),
stmt.getLeftOp(),
StringBasedField.getInstance(key));
solver.propagate(node, new PopNode<>(succNode, PDSSystem.FIELDS));
}
}
}
}
});
registerSolverCreationListener(
(q, solverForKeyArg) ->
solverForKeyArg.registerListener(
n ->
cfg.addSuccsOfListener(
new SuccessorListener(stmt) {
@Override
public void getSuccessor(Statement succ) {
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
AllocVal v = ((ForwardQuery) q).getAllocVal();

if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
NodeWithLocation<Edge, Val, Field> succNode =
new NodeWithLocation<>(
new Edge(stmt, succ),
stmt.getLeftOp(),
StringBasedField.getInstance(key));
solver.propagate(
node, new PopNode<>(succNode, PDSSystem.FIELDS));
}
}
}
})));
}
}
if (stmt.getInvokeExpr().getDeclaredMethod().toMethodWrapper().equals(MAP_PUT_SIGNATURE)) {
if (stmt.getInvokeExpr().getArg(1).equals(node.fact())) {

BackwardQuery bwq = BackwardQuery.make(node.stmt(), stmt.getInvokeExpr().getArg(0));
backwardSolve(bwq);
cfg.addSuccsOfListener(
new SuccessorListener(stmt) {
@Override
public void getSuccessor(Statement succ) {
for (ForwardQuery q : Lists.newArrayList(queryToSolvers.keySet())) {
if (queryToSolvers.get(q).getReachedStates().contains(bwq.asNode())) {
AllocVal v = q.getAllocVal();
if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
solver.propagate(
node,
new PushNode<>(
new Edge(stmt, succ),
stmt.getInvokeExpr().getBase(),
StringBasedField.getInstance(key),
PDSSystem.FIELDS));
}
}
}
}
});
registerSolverCreationListener(
(q, solverForKeyArg) ->
solverForKeyArg.registerListener(
n ->
cfg.addSuccsOfListener(
new SuccessorListener(stmt) {
@Override
public void getSuccessor(Statement succ) {
if (n.equals(bwq.asNode()) && q instanceof ForwardQuery) {
AllocVal v = ((ForwardQuery) q).getAllocVal();
if (v.getAllocVal().isStringConstant()) {
String key = v.getAllocVal().getStringValue();
solver.propagate(
node,
new PushNode<>(
new Edge(stmt, succ),
stmt.getInvokeExpr().getBase(),
StringBasedField.getInstance(key),
PDSSystem.FIELDS));
}
}
}
})));
}
}
}
Expand Down Expand Up @@ -988,10 +1000,14 @@ public ForwardBoomerangResults<W> solve(ForwardQuery query) {
}

public BackwardBoomerangResults<W> solve(BackwardQuery query) {
return solve(query, true);
return solve(query, true, true);
}

public BackwardBoomerangResults<W> solve(BackwardQuery query, boolean timing) {
return solve(query, timing, true);
}

public BackwardBoomerangResults<W> solve(BackwardQuery query, boolean timing, boolean fallback) {
if (!options.allowMultipleQueries() && solving) {
throw new RuntimeException(
"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.");
Expand All @@ -1005,6 +1021,9 @@ public BackwardBoomerangResults<W> solve(BackwardQuery query, boolean timing) {
queryGraph.addRoot(query);
LOGGER.trace("Starting backward analysis of: {}", query);
backwardSolve(query);
if (fallback) {
icfg.computeFallback();
}
} catch (BoomerangTimeoutException e) {
timedout = true;
LOGGER.trace("Timeout ({}) of query: {} ", analysisWatch, query);
Expand Down Expand Up @@ -1037,6 +1056,7 @@ public BackwardBoomerangResults<W> solveUnderScope(
LOGGER.trace("Starting backward analysis of: {}", query);
backwardSolve(query);
queryGraph.addEdge(parentQuery, triggeringNode, query);
icfg.computeFallback();
this.debugOutput();
} catch (BoomerangTimeoutException e) {
timedout = true;
Expand Down Expand Up @@ -1064,6 +1084,7 @@ public ForwardBoomerangResults<W> solveUnderScope(
LOGGER.trace("Starting forward analysis of: {}", query);
forwardSolve(query);
queryGraph.addEdge(parentQuery, triggeringNode, query);
icfg.computeFallback();
LOGGER.trace(
"Query terminated in {} ({}), visited methods {}",
analysisWatch,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public void computeFallback() {
}

@Override
public void addEdges(Edge e) {
this.delegate.addEdges(e);
public void addEdge(Edge e) {
this.delegate.addEdge(e);
}
}
Loading