boomerang.flowfunction.DefaultForwardFlowFunction Maven / Gradle / Ivy
package boomerang.flowfunction;
import boomerang.BoomerangOptions;
import boomerang.ForwardQuery;
import boomerang.scene.ControlFlowGraph.Edge;
import boomerang.scene.Field;
import boomerang.scene.InvokeExpr;
import boomerang.scene.Method;
import boomerang.scene.Pair;
import boomerang.scene.Statement;
import boomerang.scene.StaticFieldVal;
import boomerang.scene.Val;
import boomerang.solver.ForwardBoomerangSolver;
import boomerang.solver.Strategies;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import sync.pds.solver.SyncPDSSolver.PDSSystem;
import sync.pds.solver.nodes.ExclusionNode;
import sync.pds.solver.nodes.Node;
import sync.pds.solver.nodes.NodeWithLocation;
import sync.pds.solver.nodes.PopNode;
import sync.pds.solver.nodes.PushNode;
import wpds.interfaces.State;
public class DefaultForwardFlowFunction implements IForwardFlowFunction {
private final BoomerangOptions options;
private Strategies strategies;
private ForwardBoomerangSolver solver;
public DefaultForwardFlowFunction(BoomerangOptions opts) {
this.options = opts;
}
@Override
public Set returnFlow(Method method, Statement curr, Val value) {
Set out = Sets.newHashSet();
if (curr.isThrowStmt() && !options.throwFlows()) {
return Collections.emptySet();
}
if (curr.isReturnStmt()) {
if (curr.getReturnOp().equals(value)) {
out.add(value);
}
}
if (!method.isStatic()) {
if (method.getThisLocal().equals(value)) {
out.add(value);
}
}
for (Val param : method.getParameterLocals()) {
if (param.equals(value)) {
out.add(value);
}
}
if (value.isStatic()) {
out.add(value);
}
return out;
}
@Override
public Set callFlow(Statement callSite, Val fact, Method callee) {
if (!callSite.containsInvokeExpr()) {
throw new RuntimeException("Call site does not contain an invoke expression.");
}
if (callee.isStaticInitializer()) {
return Collections.emptySet();
}
Set out = Sets.newHashSet();
InvokeExpr invokeExpr = callSite.getInvokeExpr();
if (invokeExpr.isInstanceInvokeExpr()) {
if (invokeExpr.getBase().equals(fact) && !callee.isStatic()) {
out.add(callee.getThisLocal());
}
}
int i = 0;
List parameterLocals = callee.getParameterLocals();
for (Val arg : invokeExpr.getArgs()) {
if (arg.equals(fact) && parameterLocals.size() > i) {
out.add(parameterLocals.get(i));
}
i++;
}
if (fact.isStatic()) {
out.add(fact.withNewMethod(callee));
}
return out;
}
@Override
public Set normalFlow(ForwardQuery query, Edge nextEdge, Val fact) {
Statement succ = nextEdge.getStart();
Set out = Sets.newHashSet();
if (killFlow(succ, fact)) {
return out;
}
if (!succ.isFieldWriteWithBase(fact)) {
// always maintain data-flow if not a field write // killFlow has
// been taken care of
if (!options.trackReturnOfInstanceOf()
|| !(query.getType().isNullType() && succ.isInstanceOfStatement(fact))) {
out.add(new Node<>(nextEdge, fact));
}
} else {
out.add(new ExclusionNode<>(nextEdge, fact, succ.getWrittenField()));
}
if (succ.isAssign()) {
Val leftOp = succ.getLeftOp();
Val rightOp = succ.getRightOp();
if (rightOp.equals(fact)) {
if (succ.isFieldStore()) {
Pair ifr = succ.getFieldStore();
if (options.trackFields()) {
if (!options.ignoreInnerClassFields() || !ifr.getY().isInnerClassField()) {
out.add(new PushNode<>(nextEdge, ifr.getX(), ifr.getY(), PDSSystem.FIELDS));
}
}
} else if (succ.isStaticFieldStore()) {
StaticFieldVal sf = succ.getStaticField();
if (options.trackFields()) {
strategies.getStaticFieldStrategy().handleForward(nextEdge, rightOp, sf, out);
}
} else if (leftOp.isArrayRef()) {
Pair arrayBase = succ.getArrayBase();
if (options.trackFields()) {
strategies.getArrayHandlingStrategy().handleForward(nextEdge, arrayBase, out);
}
} else {
out.add(new Node<>(nextEdge, leftOp));
}
}
if (succ.isFieldLoad()) {
Pair ifr = succ.getFieldLoad();
if (ifr.getX().equals(fact)) {
NodeWithLocation succNode =
new NodeWithLocation<>(nextEdge, leftOp, ifr.getY());
out.add(new PopNode<>(succNode, PDSSystem.FIELDS));
}
} else if (succ.isStaticFieldLoad()) {
StaticFieldVal sf = succ.getStaticField();
if (fact.isStatic() && fact.equals(sf)) {
out.add(new Node<>(nextEdge, leftOp));
}
} else if (rightOp.isArrayRef()) {
Pair arrayBase = succ.getArrayBase();
if (arrayBase.getX().equals(fact)) {
NodeWithLocation succNode =
new NodeWithLocation<>(nextEdge, leftOp, Field.array(arrayBase.getY()));
out.add(new PopNode<>(succNode, PDSSystem.FIELDS));
}
} else if (rightOp.isCast()) {
if (rightOp.getCastOp().equals(fact)) {
out.add(new Node<>(nextEdge, leftOp));
}
} else if (rightOp.isInstanceOfExpr()
&& query.getType().isNullType()
&& options.trackReturnOfInstanceOf()) {
if (rightOp.getInstanceOfOp().equals(fact)) {
out.add(new Node<>(nextEdge, fact.withSecondVal(leftOp)));
}
} else if (succ.isPhiStatement()) {
Collection phiVals = succ.getPhiVals();
if (phiVals.contains(fact)) {
out.add(new Node<>(nextEdge, succ.getLeftOp()));
}
}
}
return out;
}
protected boolean killFlow(Statement curr, Val value) {
if (curr.isThrowStmt() || curr.isCatchStmt()) {
return true;
}
if (curr.isAssign()) {
// Kill x at any statement x = * during propagation.
if (curr.getLeftOp().equals(value)) {
// But not for a statement x = x.f
if (curr.isFieldLoad()) {
Pair ifr = curr.getFieldLoad();
if (ifr.getX().equals(value)) {
return false;
}
}
return true;
}
if (curr.isStaticFieldStore()) {
StaticFieldVal sf = curr.getStaticField();
if (value.isStatic() && value.equals(sf)) {
return true;
}
}
}
return false;
}
@Override
public Collection callToReturnFlow(ForwardQuery query, Edge edge, Val fact) {
if (FlowFunctionUtils.isSystemArrayCopy(edge.getStart().getInvokeExpr().getMethod())) {
return systemArrayCopyFlow(edge, fact);
}
return normalFlow(query, edge, fact);
}
protected Collection systemArrayCopyFlow(Edge edge, Val value) {
Statement callSite = edge.getStart();
if (value.equals(callSite.getInvokeExpr().getArg(0))) {
Val arg = callSite.getInvokeExpr().getArg(2);
return Collections.singleton(new Node<>(edge, arg));
}
return Collections.emptySet();
}
@Override
public void setSolver(
ForwardBoomerangSolver solver,
Multimap fieldLoadStatements,
Multimap fieldStoreStatements) {
this.solver = solver;
this.strategies = new Strategies<>(options, solver, fieldLoadStatements, fieldStoreStatements);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy