boomerang.results.ForwardBoomerangResults Maven / Gradle / Ivy
package boomerang.results;
import boomerang.ForwardQuery;
import boomerang.Util;
import boomerang.callgraph.CallerListener;
import boomerang.callgraph.ObservableICFG;
import boomerang.controlflowgraph.ObservableControlFlowGraph;
import boomerang.controlflowgraph.PredecessorListener;
import boomerang.scene.ControlFlowGraph.Edge;
import boomerang.scene.DeclaredMethod;
import boomerang.scene.Field;
import boomerang.scene.IfStatement;
import boomerang.scene.IfStatement.Evaluation;
import boomerang.scene.Method;
import boomerang.scene.Statement;
import boomerang.scene.Val;
import boomerang.scene.jimple.JimpleVal;
import boomerang.solver.AbstractBoomerangSolver;
import boomerang.solver.ForwardBoomerangSolver;
import boomerang.stats.IBoomerangStats;
import boomerang.util.DefaultValueMap;
import boomerang.weights.DataFlowPathWeight;
import boomerang.weights.PathConditionWeight.ConditionDomain;
import com.google.common.base.Stopwatch;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.collect.Table;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import soot.jimple.IntConstant;
import sync.pds.solver.nodes.GeneratedState;
import sync.pds.solver.nodes.INode;
import sync.pds.solver.nodes.Node;
import wpds.impl.Transition;
import wpds.impl.Weight;
import wpds.impl.WeightedPAutomaton;
import wpds.interfaces.State;
public class ForwardBoomerangResults extends AbstractBoomerangResults {
private final ForwardQuery query;
private final boolean timedout;
private final IBoomerangStats stats;
private Stopwatch analysisWatch;
private long maxMemory;
private ObservableICFG icfg;
private Set visitedMethods;
private final boolean trackDataFlowPath;
private final boolean pruneContradictoryDataFlowPath;
private ObservableControlFlowGraph cfg;
private boolean pruneImplictFlows;
public ForwardBoomerangResults(
ForwardQuery query,
ObservableICFG icfg,
ObservableControlFlowGraph cfg,
boolean timedout,
DefaultValueMap> queryToSolvers,
IBoomerangStats stats,
Stopwatch analysisWatch,
Set visitedMethods,
boolean trackDataFlowPath,
boolean pruneContradictoryDataFlowPath,
boolean pruneImplictFlows) {
super(queryToSolvers);
this.query = query;
this.icfg = icfg;
this.cfg = cfg;
this.timedout = timedout;
this.stats = stats;
this.analysisWatch = analysisWatch;
this.visitedMethods = visitedMethods;
this.trackDataFlowPath = trackDataFlowPath;
this.pruneContradictoryDataFlowPath = pruneContradictoryDataFlowPath;
this.pruneImplictFlows = pruneImplictFlows;
stats.terminated(query, this);
this.maxMemory = Util.getReallyUsedMemory();
}
public Stopwatch getAnalysisWatch() {
return analysisWatch;
}
public boolean isTimedout() {
return timedout;
}
public Table getObjectDestructingStatements() {
AbstractBoomerangSolver solver = queryToSolvers.get(query);
if (solver == null) {
return HashBasedTable.create();
}
Table res = asStatementValWeightTable();
Set visitedMethods = Sets.newHashSet();
for (Edge s : res.rowKeySet()) {
visitedMethods.add(s.getMethod());
}
ForwardBoomerangSolver forwardSolver = queryToSolvers.get(query);
Table destructingStatement = HashBasedTable.create();
for (Method flowReaches : visitedMethods) {
for (Statement exitStmt : icfg.getEndPointsOf(flowReaches)) {
for (Statement predOfExit :
exitStmt.getMethod().getControlFlowGraph().getPredsOf(exitStmt)) {
Edge exitEdge = new Edge(predOfExit, exitStmt);
Set escapes = Sets.newHashSet();
icfg.addCallerListener(
new CallerListener() {
@Override
public Method getObservedCallee() {
return flowReaches;
}
@Override
public void onCallerAdded(Statement callSite, Method m) {
Method callee = callSite.getMethod();
if (visitedMethods.contains(callee)) {
for (Entry valAndW : res.row(exitEdge).entrySet()) {
escapes.addAll(
forwardSolver.computeReturnFlow(flowReaches, exitStmt, valAndW.getKey()));
}
}
}
});
if (escapes.isEmpty()) {
Map row = res.row(exitEdge);
findLastUsage(exitEdge, row, destructingStatement, forwardSolver);
}
}
}
}
return destructingStatement;
}
public Table asStatementValWeightTable() {
return asStatementValWeightTable(query);
}
private void findLastUsage(
Edge exitStmt,
Map row,
Table destructingStatement,
ForwardBoomerangSolver forwardSolver) {
LinkedList worklist = Lists.newLinkedList();
worklist.add(exitStmt);
Set visited = Sets.newHashSet();
while (!worklist.isEmpty()) {
Edge curr = worklist.poll();
if (!visited.add(curr)) {
continue;
}
boolean valueUsedInStmt = false;
for (Entry e : row.entrySet()) {
if (curr.getTarget().uses(e.getKey())) {
destructingStatement.put(curr, e.getKey(), e.getValue());
valueUsedInStmt = true;
}
}
if (!valueUsedInStmt
&&
/** Do not continue over CatchStmt */
!(curr.getTarget().isIdentityStmt())) {
cfg.addPredsOfListener(
new PredecessorListener(curr.getStart()) {
@Override
public void getPredecessor(Statement succ) {
worklist.add(new Edge(succ, curr.getStart()));
}
});
}
}
}
public IBoomerangStats getStats() {
return stats;
}
public Map getInvokedMethodOnInstance() {
Map invokedMethodsOnInstance = Maps.newHashMap();
if (query.cfgEdge().getStart().containsInvokeExpr()) {
invokedMethodsOnInstance.put(
query.cfgEdge(), query.cfgEdge().getStart().getInvokeExpr().getMethod());
}
queryToSolvers
.get(query)
.getFieldAutomaton()
.registerListener(
(t, w, aut) -> {
if (!t.getLabel().equals(Field.empty()) || t.getStart() instanceof GeneratedState) {
return;
}
Node node = t.getStart().fact();
Val fact = node.fact();
Edge currEdge = node.stmt();
Statement curr = currEdge.getStart();
if (curr.containsInvokeExpr()) {
if (curr.getInvokeExpr().isInstanceInvokeExpr()) {
Val base = curr.getInvokeExpr().getBase();
if (base.equals(fact)) {
invokedMethodsOnInstance.put(currEdge, curr.getInvokeExpr().getMethod());
}
}
}
});
return invokedMethodsOnInstance;
}
public QueryResults getPotentialNullPointerDereferences() {
// FIXME this should be located nullpointer analysis
Set> res = Sets.newHashSet();
for (Transition>> t :
queryToSolvers.get(query).getFieldAutomaton().getTransitions()) {
if (!t.getLabel().equals(Field.empty()) || t.getStart() instanceof GeneratedState) {
continue;
}
Node nullPointerNode = t.getStart().fact();
if (NullPointerDereference.isNullPointerNode(nullPointerNode)
&& queryToSolvers.get(query).getReachedStates().contains(nullPointerNode)) {
res.add(nullPointerNode);
}
}
Set resWithContext = Sets.newHashSet();
for (Node r : res) {
// Context context = constructContextGraph(query, r);
if (trackDataFlowPath) {
DataFlowPathWeight dataFlowPath = getDataFlowPathWeight(query, r);
if (isValidPath(dataFlowPath)) {
List p = transformPath(dataFlowPath.getAllStatements(), r);
resWithContext.add(new NullPointerDereference(query, r.stmt(), r.fact(), null, null, p));
}
} else {
List dataFlowPath = Lists.newArrayList();
resWithContext.add(
new NullPointerDereference(query, r.stmt(), r.fact(), null, null, dataFlowPath));
}
}
QueryResults nullPointerResult =
new QueryResults(query, resWithContext, visitedMethods, timedout);
return nullPointerResult;
}
private boolean isValidPath(DataFlowPathWeight dataFlowPath) {
if (!pruneContradictoryDataFlowPath) {
return true;
}
Map conditions = dataFlowPath.getConditions();
for (Entry c : conditions.entrySet()) {
if (contradiction(c.getKey(), c.getValue(), dataFlowPath.getEvaluationMap())) {
return false;
}
}
return true;
}
private DataFlowPathWeight getDataFlowPathWeight(
ForwardQuery query, Node sinkLocation) {
WeightedPAutomaton, W> callAut =
queryToSolvers.getOrCreate(query).getCallAutomaton();
// Iterating over whole set to find the matching transition is not the most elegant solution....
for (Entry>, W> e :
callAut.getTransitionsToFinalWeights().entrySet()) {
Transition> t = e.getKey();
if (t.getLabel().equals(new Edge(Statement.epsilon(), Statement.epsilon()))) {
continue;
}
if (t.getStart().fact().isLocal()
&& !t.getLabel().getMethod().equals(t.getStart().fact().m())) {
continue;
}
if (t.getStart().fact().equals(sinkLocation.fact())
&& t.getLabel().equals(sinkLocation.stmt())) {
if (e.getValue() instanceof DataFlowPathWeight) {
DataFlowPathWeight v = (DataFlowPathWeight) e.getValue();
return v;
}
}
}
return null;
}
private boolean contradiction(
Statement ifStmt, ConditionDomain mustBeVal, Map evaluationMap) {
if (ifStmt.isIfStmt()) {
IfStatement ifStmt1 = ifStmt.getIfStmt();
for (Transition>> t :
queryToSolvers.get(query).getFieldAutomaton().getTransitions()) {
if (!t.getStart().fact().stmt().equals(ifStmt)) {
continue;
}
if (!t.getLabel().equals(Field.empty()) || t.getStart() instanceof GeneratedState) {
continue;
}
Node node = t.getStart().fact();
Val fact = node.fact();
switch (ifStmt1.evaluate(fact)) {
case TRUE:
if (mustBeVal.equals(ConditionDomain.FALSE)) {
return true;
}
break;
case FALSE:
if (mustBeVal.equals(ConditionDomain.TRUE)) {
return true;
}
}
}
if (pruneImplictFlows) {
for (Entry e : evaluationMap.entrySet()) {
if (ifStmt1.uses(e.getKey())) {
Evaluation eval = null;
if (e.getValue().equals(ConditionDomain.TRUE)) {
// Map first to JimpleVal
eval = ifStmt1.evaluate(new JimpleVal(IntConstant.v(1), e.getKey().m()));
} else if (e.getValue().equals(ConditionDomain.FALSE)) {
// Map first to JimpleVal
eval = ifStmt1.evaluate(new JimpleVal(IntConstant.v(0), e.getKey().m()));
}
if (eval != null) {
if (mustBeVal.equals(ConditionDomain.FALSE)) {
if (eval.equals(Evaluation.FALSE)) {
return true;
}
} else if (mustBeVal.equals(ConditionDomain.TRUE)) {
if (eval.equals(Evaluation.TRUE)) {
return true;
}
}
}
}
}
}
}
return false;
}
private List transformPath(
List> allStatements, Node sinkLocation) {
List res = Lists.newArrayList();
int index = 0;
for (Node x : allStatements) {
res.add(new PathElement(x.stmt(), x.fact(), index++));
}
// TODO The analysis misses
if (!allStatements.contains(sinkLocation)) {
res.add(new PathElement(sinkLocation.stmt(), sinkLocation.fact(), index));
}
for (PathElement n : res) {
LOGGER.trace(
"Statement: {}, Variable {}, Index {}", n.getEdge(), n.getVariable(), n.stepIndex());
}
return res;
}
public Context getContext(Node node) {
return constructContextGraph(query, node);
}
public boolean containsCallRecursion() {
for (Entry> e : queryToSolvers.entrySet()) {
if (e.getValue().getCallAutomaton().containsLoop()) {
return true;
}
}
return false;
}
public boolean containsFieldLoop() {
for (Entry> e : queryToSolvers.entrySet()) {
if (e.getValue().getFieldAutomaton().containsLoop()) {
return true;
}
}
return false;
}
public Set getVisitedMethods() {
return visitedMethods;
}
public long getMaxMemory() {
return maxMemory;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy