All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boomerang.solver.ForwardBoomerangSolver Maven / Gradle / Ivy

There is a newer version: 3.2.2
Show newest version
/**
 * ***************************************************************************** Copyright (c) 2018
 * Fraunhofer IEM, Paderborn, Germany. 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.
 *
 * 

SPDX-License-Identifier: EPL-2.0 * *

Contributors: Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.solver; import boomerang.BoomerangOptions; import boomerang.ForwardQuery; import boomerang.Query; import boomerang.callgraph.CalleeListener; import boomerang.callgraph.ObservableICFG; import boomerang.controlflowgraph.*; import boomerang.flowfunction.IForwardFlowFunction; import boomerang.scene.AllocVal; import boomerang.scene.ControlFlowGraph; import boomerang.scene.ControlFlowGraph.Edge; import boomerang.scene.DataFlowScope; import boomerang.scene.Field; import boomerang.scene.InvokeExpr; import boomerang.scene.Method; import boomerang.scene.Statement; import boomerang.scene.Type; import boomerang.scene.Val; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import java.util.Collection; import java.util.Collections; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.stream.Collectors; import org.slf4j.LoggerFactory; import sync.pds.solver.nodes.GeneratedState; import sync.pds.solver.nodes.INode; import sync.pds.solver.nodes.Node; import sync.pds.solver.nodes.PopNode; import sync.pds.solver.nodes.PushNode; import sync.pds.solver.nodes.SingleNode; import wpds.impl.NestedWeightedPAutomatons; import wpds.impl.Transition; import wpds.impl.Weight; import wpds.impl.WeightedPAutomaton; import wpds.interfaces.Location; import wpds.interfaces.State; import wpds.interfaces.WPAStateListener; public abstract class ForwardBoomerangSolver extends AbstractBoomerangSolver { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ForwardBoomerangSolver.class); private final ForwardQuery query; private final IForwardFlowFunction flowFunctions; public ForwardBoomerangSolver( ObservableICFG callGraph, ObservableControlFlowGraph cfg, ForwardQuery query, Map>, Field>, INode>> genField, BoomerangOptions options, NestedWeightedPAutomatons, W> callSummaries, NestedWeightedPAutomatons>, W> fieldSummaries, DataFlowScope scope, IForwardFlowFunction flowFunctions, Multimap fieldLoadStatements, Multimap fieldStoreStatements, Type propagationType) { super(callGraph, cfg, genField, options, callSummaries, fieldSummaries, scope, propagationType); this.query = query; this.flowFunctions = flowFunctions; this.flowFunctions.setSolver(this, fieldLoadStatements, fieldStoreStatements); } @Override public void processPush( Node curr, Location location, PushNode succ, PDSSystem system) { if (PDSSystem.CALLS == system) { if (!((PushNode) succ).location().getStart().equals(curr.stmt().getTarget()) || !curr.stmt().getTarget().containsInvokeExpr()) { throw new RuntimeException("Invalid push rule"); } } super.processPush(curr, location, succ, system); } private final class OverwriteAtFieldStore extends WPAStateListener>, W> { private final Edge nextStmt; private OverwriteAtFieldStore(INode> state, Edge nextEdge) { super(state); this.nextStmt = nextEdge; } @Override public void onOutTransitionAdded( Transition>> t, W w, WeightedPAutomaton>, W> weightedPAutomaton) { if (t.getLabel().equals(nextStmt.getTarget().getFieldStore().getY())) { LOGGER.trace("Overwriting field {} at {}", t.getLabel(), nextStmt); overwriteFieldAtStatement(nextStmt, t); } } @Override public void onInTransitionAdded( Transition>> t, W w, WeightedPAutomaton>, W> weightedPAutomaton) {} @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + getEnclosingInstance().hashCode(); result = prime * result + ((nextStmt == null) ? 0 : nextStmt.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; OverwriteAtFieldStore other = (OverwriteAtFieldStore) obj; if (!getEnclosingInstance().equals(other.getEnclosingInstance())) return false; if (nextStmt == null) { if (other.nextStmt != null) return false; } else if (!nextStmt.equals(other.nextStmt)) return false; return true; } private ForwardBoomerangSolver getEnclosingInstance() { return ForwardBoomerangSolver.this; } } private final class OverwriteAtArrayStore extends WPAStateListener>, W> { private final Edge nextStmt; private OverwriteAtArrayStore(INode> state, Edge nextStmt) { super(state); this.nextStmt = nextStmt; } @Override public void onOutTransitionAdded( Transition>> t, W w, WeightedPAutomaton>, W> weightedPAutomaton) { if (t.getLabel().equals(Field.array(nextStmt.getTarget().getArrayBase().getY()))) { LOGGER.trace("Overwriting field {} at {}", t.getLabel(), nextStmt); overwriteFieldAtStatement(nextStmt, t); } } @Override public void onInTransitionAdded( Transition>> t, W w, WeightedPAutomaton>, W> weightedPAutomaton) {} @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + getEnclosingInstance().hashCode(); result = prime * result + ((nextStmt == null) ? 0 : nextStmt.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; OverwriteAtArrayStore other = (OverwriteAtArrayStore) obj; if (!getEnclosingInstance().equals(other.getEnclosingInstance())) return false; if (nextStmt == null) { if (other.nextStmt != null) return false; } else if (!nextStmt.equals(other.nextStmt)) return false; return true; } private ForwardBoomerangSolver getEnclosingInstance() { return ForwardBoomerangSolver.this; } } @Override protected void propagateUnbalancedToCallSite( Statement callSite, Transition> transInCallee) { GeneratedState target = (GeneratedState) transInCallee.getTarget(); if (!callSite.containsInvokeExpr()) { throw new RuntimeException("Invalid propagate Unbalanced return"); } if (!isMatchingCallSiteCalleePair(callSite, transInCallee.getLabel().getMethod())) { return; } cfg.addSuccsOfListener( new SuccessorListener(callSite) { @Override public void getSuccessor(Statement succ) { cfg.addPredsOfListener( new PredecessorListener(callSite) { @Override public void getPredecessor(Statement pred) { Node curr = new Node<>(new Edge(pred, callSite), query.var()); /** * Transition>> fieldTrans = new * Transition<>(new SingleNode<>(curr), emptyField(), new SingleNode<>(curr)); * fieldAutomaton.addTransition(fieldTrans);* */ Transition> callTrans = new Transition<>( wrap(curr.fact()), curr.stmt(), generateCallState(wrap(curr.fact()), curr.stmt())); callAutomaton.addTransition(callTrans); callAutomaton.addUnbalancedState( generateCallState(wrap(curr.fact()), curr.stmt()), target); State s = new PushNode<>( target.location(), target.node().fact(), new Edge(callSite, succ), PDSSystem.CALLS); propagate(curr, s); } }); } }); } private final class CallSiteCalleeListener implements CalleeListener { private final Method caller; private final Statement callSite; private final Edge callSiteEdge; private final Node currNode; private final InvokeExpr invokeExpr; private CallSiteCalleeListener( Method caller, Edge callSiteEdge, Node currNode, InvokeExpr invokeExpr) { this.caller = caller; this.callSiteEdge = callSiteEdge; this.callSite = callSiteEdge.getStart(); this.currNode = currNode; this.invokeExpr = invokeExpr; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + getOuterType().hashCode(); result = prime * result + ((callSiteEdge == null) ? 0 : callSiteEdge.hashCode()); result = prime * result + ((caller == null) ? 0 : caller.hashCode()); result = prime * result + ((currNode == null) ? 0 : currNode.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; CallSiteCalleeListener other = (CallSiteCalleeListener) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (callSiteEdge == null) { if (other.callSiteEdge != null) return false; } else if (!callSiteEdge.equals(other.callSiteEdge)) return false; if (caller == null) { if (other.caller != null) return false; } else if (!caller.equals(other.caller)) return false; if (currNode == null) { if (other.currNode != null) return false; } else if (!currNode.equals(other.currNode)) return false; return true; } @Override public void onCalleeAdded(Statement callSite, Method callee) { if (callee.isStaticInitializer()) { return; } LOGGER.trace( "Call-flow of {} at callsite: {} to callee method: {} for {}", currNode.fact(), callSite, callee, this); for (Statement calleeSp : icfg.getStartPointsOf(callee)) { Collection res = computeCallFlow( caller, callSite, callSiteEdge, currNode, callee, new Edge(calleeSp, calleeSp)); for (State s : res) { propagate(currNode, s); } } } @Override public void onNoCalleeFound() { byPassFlowAtCallSite(caller, currNode, callSite); } @Override public Statement getObservedCaller() { return callSite; } private ForwardBoomerangSolver getOuterType() { return ForwardBoomerangSolver.this; } } @Override public void applyCallSummary( ControlFlowGraph.Edge returnSiteStatement, Val factInCallee, Edge spInCallee, Edge lastCfgEdgeInCallee, Val returnedFact) { Statement callSite = returnSiteStatement.getStart(); Set> out = Sets.newHashSet(); if (callSite.containsInvokeExpr()) { if (returnedFact.isThisLocal()) { if (callSite.getInvokeExpr().isInstanceInvokeExpr()) { out.add(new Node<>(returnSiteStatement, callSite.getInvokeExpr().getBase())); } } if (returnedFact.isReturnLocal()) { if (callSite.isAssign()) { out.add(new Node<>(returnSiteStatement, callSite.getLeftOp())); } } for (int i = 0; i < callSite.getInvokeExpr().getArgs().size(); i++) { if (returnedFact.isParameterLocal(i)) { out.add(new Node<>(returnSiteStatement, callSite.getInvokeExpr().getArg(i))); } } } if (returnedFact.isStatic()) { out.add( new Node<>( returnSiteStatement, returnedFact.withNewMethod(returnSiteStatement.getStart().getMethod()))); } for (Node xs : out) { addNormalCallFlow(new Node<>(returnSiteStatement, returnedFact), xs); addNormalFieldFlow(new Node<>(lastCfgEdgeInCallee, returnedFact), xs); } } public Collection computeCallFlow( Method caller, Statement callSite, Edge succOfCallSite, Node currNode, Method callee, Edge calleeStartEdge) { if (dataFlowScope.isExcluded(callee)) { byPassFlowAtCallSite(caller, currNode, callSite); return Collections.emptySet(); } Val fact = currNode.fact(); return flowFunctions.callFlow(callSite, fact, callee).stream() .map(x -> new PushNode<>(calleeStartEdge, x, succOfCallSite, PDSSystem.CALLS)) .collect(Collectors.toSet()); } public Query getQuery() { return query; } @Override public void computeSuccessor(Node node) { Edge curr = node.stmt(); Val value = node.fact(); assert !(value instanceof AllocVal); Method method = curr.getTarget().getMethod(); if (method == null) return; if (dataFlowScope.isExcluded(method)) { return; } if (icfg.isExitStmt(curr.getTarget())) { returnFlow(method, node); return; } ((StaticCFG) cfg).setCurrentVal(value); cfg.addSuccsOfListener( new ForwardSolverSuccessorListener(curr, query, value, method, node, LOGGER, this)); } public BoomerangOptions getOptions() { return options; } public void checkForFieldOverwrite(Edge curr, Val value) { if ((curr.getTarget().isFieldStore() && curr.getTarget().getFieldStore().getX().equals(value))) { Node node = new Node<>(curr, value); fieldAutomaton.registerListener(new OverwriteAtFieldStore(new SingleNode<>(node), curr)); } else if ((curr.getTarget().isArrayStore() && curr.getTarget().getArrayBase().getX().equals(value))) { Node node = new Node<>(curr, value); fieldAutomaton.registerListener(new OverwriteAtArrayStore(new SingleNode<>(node), curr)); } } protected abstract void overwriteFieldAtStatement( Edge fieldWriteStatementEdge, Transition>> killedTransition); @Override public Collection computeNormalFlow(Method method, Edge nextEdge, Val fact) { return flowFunctions.normalFlow(query, nextEdge, fact); } public void callFlow( Method caller, Node currNode, Edge callSiteEdge, InvokeExpr invokeExpr) { assert icfg.isCallStmt(callSiteEdge.getStart()); if (dataFlowScope.isExcluded(invokeExpr.getMethod())) { byPassFlowAtCallSite(caller, currNode, callSiteEdge.getStart()); } icfg.addCalleeListener(new CallSiteCalleeListener(caller, callSiteEdge, currNode, invokeExpr)); } private void byPassFlowAtCallSite( Method caller, Node currNode, Statement callSite) { LOGGER.trace( "Bypassing call flow of {} at callsite: {} for {}", currNode.fact(), callSite, this); cfg.addSuccsOfListener( new SuccessorListener(currNode.stmt().getTarget()) { @Override public void getSuccessor(Statement returnSite) { for (State s : flowFunctions.callToReturnFlow( query, new Edge(callSite, returnSite), currNode.fact())) { propagate(currNode, s); } } }); } @Override public Collection computeReturnFlow(Method method, Statement curr, Val value) { return flowFunctions.returnFlow(method, curr, value).stream() .map(x -> new PopNode<>(x, PDSSystem.CALLS)) .collect(Collectors.toSet()); } @Override public String toString() { return "ForwardSolver: " + query; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy