diff --git a/src/main/java/analysis/IDELinearConstantAnalysisProblem.java b/src/main/java/analysis/IDELinearConstantAnalysisProblem.java index 607ef61..6bf0c72 100644 --- a/src/main/java/analysis/IDELinearConstantAnalysisProblem.java +++ b/src/main/java/analysis/IDELinearConstantAnalysisProblem.java @@ -9,7 +9,9 @@ import heros.*; import heros.edgefunc.EdgeIdentity; import heros.flowfunc.Identity; +import heros.flowfunc.KillAll; import soot.*; +import soot.jimple.StaticFieldRef; import soot.jimple.internal.JimpleLocal; import soot.jimple.toolkits.ide.DefaultJimpleIDETabulationProblem; import soot.toolkits.graph.BriefUnitGraph; @@ -17,6 +19,7 @@ import util.CFGUtil; import java.util.Collections; +import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -107,13 +110,24 @@ public FlowFunction getCallFlowFunction(Unit callStmt, SootMethod dest) { @Override public FlowFunction getReturnFlowFunction(Unit callSite, SootMethod calleeMethod, Unit exitStmt, Unit returnSite) { - CPAReturnFlowFunctionProvider ffp = new CPAReturnFlowFunctionProvider(callSite, exitStmt, icfg.getMethodOf(callSite)); + CPAReturnFlowFunctionProvider ffp = new CPAReturnFlowFunctionProvider(callSite, exitStmt, icfg.getMethodOf(callSite), icfg.getMethodOf(exitStmt)); return ffp.getFlowFunction(); } @Override public FlowFunction getCallToReturnFlowFunction(Unit callSite, Unit returnSite) { - return Identity.v(); + // we kill statics and keep rest as id + return new FlowFunction() { + @Override + public Set computeTargets(DFF source) { + if(source.getValue() instanceof StaticFieldRef){ + return Collections.emptySet(); + } + Set res = new HashSet<>(); + res.add(source); + return res; + } + }; } }; } diff --git a/src/main/java/analysis/edgefunctions/normal/IntegerBinop.java b/src/main/java/analysis/edgefunctions/normal/IntegerBinop.java index f9afa01..47276d4 100644 --- a/src/main/java/analysis/edgefunctions/normal/IntegerBinop.java +++ b/src/main/java/analysis/edgefunctions/normal/IntegerBinop.java @@ -98,7 +98,7 @@ public EdgeFunction meetWith(EdgeFunction otherFunction) { } else if (otherFunction instanceof IntegerAllBottom) { return otherFunction; } - throw new RuntimeException("can't meeet: " + this.toString() + " and " + otherFunction.toString()); + throw new RuntimeException("can't meet: " + this.toString() + " and " + otherFunction.toString()); } @Override diff --git a/src/main/java/analysis/flowfunctions/CPAReturnFlowFunctionProvider.java b/src/main/java/analysis/flowfunctions/CPAReturnFlowFunctionProvider.java index 33541ef..c9727c6 100644 --- a/src/main/java/analysis/flowfunctions/CPAReturnFlowFunctionProvider.java +++ b/src/main/java/analysis/flowfunctions/CPAReturnFlowFunctionProvider.java @@ -4,6 +4,7 @@ import analysis.data.DFF; import analysis.flowfunctions.call.CallFF; import analysis.flowfunctions.call.ReturnFF; +import analysis.flowfunctions.call.ReturnVoidFF; import analysis.flowfunctions.normal.FieldStoreAliasHandler; import heros.FlowFunction; import heros.flowfunc.KillAll; @@ -15,6 +16,7 @@ import soot.jimple.InvokeExpr; import soot.jimple.ReturnStmt; import soot.jimple.Stmt; +import soot.jimple.internal.JReturnVoidStmt; import java.util.ArrayList; import java.util.Collections; @@ -26,7 +28,7 @@ public class CPAReturnFlowFunctionProvider implements FlowFunctionProvider private FlowFunction flowFunction; - public CPAReturnFlowFunctionProvider(Unit callSite, Unit exitStmt, SootMethod method){ + public CPAReturnFlowFunctionProvider(Unit callSite, Unit exitStmt, SootMethod caller, SootMethod callee){ flowFunction = KillAll.v(); // we want to kill everything else when returning from a nested context if (exitStmt instanceof ReturnStmt) { ReturnStmt returnStmt = (ReturnStmt) exitStmt; @@ -38,10 +40,12 @@ public CPAReturnFlowFunctionProvider(Unit callSite, Unit exitStmt, SootMethod me if (leftOp instanceof Local) { final Local tgtLocal = (Local) leftOp; final Local retLocal = (Local) op; - flowFunction = new ReturnFF(tgtLocal, retLocal, new FieldStoreAliasHandler(method, callSite, tgtLocal)); + flowFunction = new ReturnFF(tgtLocal, retLocal, new FieldStoreAliasHandler(caller, callSite, tgtLocal)); } } } + }else if(exitStmt instanceof JReturnVoidStmt){ + flowFunction = new ReturnVoidFF(callSite, callee); } } diff --git a/src/main/java/analysis/flowfunctions/call/CallFF.java b/src/main/java/analysis/flowfunctions/call/CallFF.java index 17f0de5..1104922 100644 --- a/src/main/java/analysis/flowfunctions/call/CallFF.java +++ b/src/main/java/analysis/flowfunctions/call/CallFF.java @@ -6,6 +6,7 @@ import soot.SootMethod; import soot.Value; import soot.jimple.IntConstant; +import soot.jimple.StaticFieldRef; import java.util.Collections; import java.util.HashSet; @@ -34,6 +35,9 @@ public Set computeTargets(DFF source) { return Collections.emptySet(); } Set res = new HashSet<>(); + if(source==zeroValue || source.getValue() instanceof StaticFieldRef){ + res.add(source); + } for (int i = 0; i < callArgs.size(); i++) { // Special case: check if function is called with integer literals as params if (callArgs.get(i) instanceof IntConstant && source == zeroValue) { diff --git a/src/main/java/analysis/flowfunctions/call/ReturnFF.java b/src/main/java/analysis/flowfunctions/call/ReturnFF.java index 48af136..7e7e1f0 100644 --- a/src/main/java/analysis/flowfunctions/call/ReturnFF.java +++ b/src/main/java/analysis/flowfunctions/call/ReturnFF.java @@ -4,6 +4,7 @@ import analysis.flowfunctions.normal.FieldStoreAliasHandler; import heros.FlowFunction; import soot.Local; +import soot.jimple.StaticFieldRef; import java.util.Collections; import java.util.HashSet; @@ -29,6 +30,9 @@ public Set computeTargets(DFF source) { res.add(DFF.asDFF(tgtLocal)); aliasHandler.handleAliases(res); } + if(source.getValue() instanceof StaticFieldRef){ + res.add(source); + } return res; } } diff --git a/src/main/java/analysis/flowfunctions/call/ReturnVoidFF.java b/src/main/java/analysis/flowfunctions/call/ReturnVoidFF.java new file mode 100644 index 0000000..9b735dd --- /dev/null +++ b/src/main/java/analysis/flowfunctions/call/ReturnVoidFF.java @@ -0,0 +1,75 @@ +package analysis.flowfunctions.call; + +import analysis.data.DFF; +import analysis.flowfunctions.normal.FieldStoreAliasHandler; +import heros.FlowFunction; +import heros.solver.Pair; +import soot.*; +import soot.jimple.InvokeStmt; +import soot.jimple.StaticFieldRef; +import soot.jimple.internal.JIdentityStmt; +import soot.jimple.internal.JInstanceFieldRef; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class ReturnVoidFF implements FlowFunction { + private Unit callsite; + private SootMethod method; + + public ReturnVoidFF(Unit callsite, SootMethod method) { + this.callsite = callsite; + this.method = method; + } + + + @Override + public Set computeTargets(DFF source) { + callsite.toString(); + Set res = new HashSet<>(); + Value d = source.getValue(); + if(d instanceof JInstanceFieldRef){ + if(callsite instanceof InvokeStmt){ + InvokeStmt invoke = (InvokeStmt) callsite; + List args = invoke.getInvokeExpr().getArgs(); + JInstanceFieldRef fieldRef = (JInstanceFieldRef) d; + Value base = fieldRef.getBase(); + int argIndex = 0; + for (Value arg : args) { + Pair mArg = new Pair<>(arg, argIndex); + if(isSameParam(method, mArg, base)){ + JInstanceFieldRef mapRef = new JInstanceFieldRef(arg, fieldRef.getFieldRef()); + res.add(DFF.asDFF(mapRef)); + } + argIndex++; + } + } + } + if(d instanceof StaticFieldRef){ + res.add(source); + } + return res; + } + + boolean isSameParam(SootMethod method, Pair actualParam, Value formalParam){ + if(actualParam.getO1().getType() instanceof RefType){ + Body activeBody = method.getActiveBody(); + UnitPatchingChain units = activeBody.getUnits(); + int idIndex = -1; // @this + for (Unit unit : units) { + if(unit instanceof JIdentityStmt){ + JIdentityStmt id = (JIdentityStmt) unit; + Value rightOp = id.getRightOp(); + Value leftOp = id.getLeftOp(); + if(rightOp.getType().equals(actualParam.getO1().getType()) && leftOp.equals(formalParam) && actualParam.getO2().equals(idIndex)){ + return true; + } + idIndex++; + } + } + } + return false; + } + +} diff --git a/src/main/java/solver/JimpleIDESolver.java b/src/main/java/solver/JimpleIDESolver.java index 5f25b76..fb6a61e 100644 --- a/src/main/java/solver/JimpleIDESolver.java +++ b/src/main/java/solver/JimpleIDESolver.java @@ -27,7 +27,7 @@ public JimpleIDESolver(IDETabulationProblem problem) public void solve(String targetClassName) { super.solve(); - this.dumpResults(targetClassName); + //this.dumpResults(targetClassName); } private static List>> checked = new ArrayList<>(); diff --git a/src/main/java/sparse/DefaultSparseCFGBuilder.java b/src/main/java/sparse/DefaultSparseCFGBuilder.java index c032c2e..16fc06c 100644 --- a/src/main/java/sparse/DefaultSparseCFGBuilder.java +++ b/src/main/java/sparse/DefaultSparseCFGBuilder.java @@ -28,6 +28,8 @@ public class DefaultSparseCFGBuilder implements SparseCFGBuilder buildSparseCFG(SootMethod m, DFF d, SparseCFGQueryStat queryStat) { this.m = m; + //log = m.getSignature().contains("com.google.common.util.concurrent.ExecutionList: void execute()"); DirectedGraph rawGraph = new BriefUnitGraph(m.getActiveBody()); - //handle zero - if (d.toString().equals("<>")) { - JimpleDefaultSparseCFG cfg = new JimpleDefaultSparseCFG(d, rawGraph, null, rawGraph.size()); - return cfg; - } + //handle Source +// if (d.toString().equals("<>")) { +// //logCFG(LOGGER, mCFG, "original", m.getActiveBody(), d); +// JimpleDefaultSparseCFG cfg = new JimpleDefaultSparseCFG(d, rawGraph, null, rawGraph.size()); +// if(m.getSignature().contains("com.google.common.base.Preconditions: java.lang.String badElementIndex(int,int,java.lang.String)")){ +// System.out.println(cfg.toString()); +// } + //System.out.println(cfg.toString()); +// return cfg; +// } Map jumps = sparsify(d, m, rawGraph); - + //logCFG(LOGGER, mCFG, "sparse", m.getActiveBody(), d); JimpleDefaultSparseCFG cfg = new JimpleDefaultSparseCFG(d, rawGraph, jumps, rawGraph.size() - stmsToRemove.size()); - +// if(m.getSignature().contains("com.google.common.base.Preconditions: java.lang.String badElementIndex(int,int,java.lang.String)")){ +// System.out.println(cfg.toString()); +// } + //System.out.println(cfg.toString()); return cfg; } private Map sparsify(DFF d, SootMethod m, DirectedGraph graph) { stmsToRemove = new LinkedHashSet<>(); Iterator iter = graph.iterator(); - while (iter.hasNext()) { + while (iter.hasNext()){ Unit unit = iter.next(); if (!stmsToRemove.contains(unit) && !shouldKeepStmt(unit, d, m, graph)) { stmsToRemove.add(unit); @@ -71,8 +82,8 @@ private Map sparsify(DFF d, SootMethod m, DirectedGraph graph) for (Unit unit : stmsToRemove) { Unit pred = units.getPredOf(unit); Unit succ = units.getSuccOf(unit); - if (!stmsToRemove.contains(pred)) { - while (stmsToRemove.contains(succ)) { + if(!stmsToRemove.contains(pred)){ + while(stmsToRemove.contains(succ)){ succ = units.getSuccOf(succ); } jumps.put(pred, succ); @@ -82,8 +93,133 @@ private Map sparsify(DFF d, SootMethod m, DirectedGraph graph) } + protected Iterator getBFSIterator(MutableGraph graph, Unit head) { + Traverser traverser = Traverser.forGraph(graph); + return traverser.breadthFirst(head).iterator(); + } + + + protected MutableGraph convertToMutableGraph(DirectedGraph rawGraph) { + MutableGraph mGraph = GraphBuilder.directed().build(); + Iterator iterator = rawGraph.iterator(); + while (iterator.hasNext()){ + Unit next = iterator.next(); + List succsOf = rawGraph.getSuccsOf(next); + for (Unit unit : succsOf) { + mGraph.putEdge(next, unit); + } + } + int initialSize = rawGraph.size(); + int finalSize = mGraph.nodes().size(); + if (initialSize != finalSize) { + System.out.println("Graph size differs after conversion to mutable graph"); + } + return mGraph; + } + +// protected MutableGraph convertToMutableGraph(DirectedGraph rawGraph) { +// int initialSize = rawGraph.size(); +// MutableGraph mGraph = GraphBuilder.directed().build(); +// List heads = rawGraph.getHeads(); +// for (Unit head : heads) { +// addToMutableGraph(rawGraph, head, mGraph); +// } +// int finalSize = mGraph.nodes().size(); +// if (initialSize != finalSize) { +// System.out.println("Graph size differs after conversion to mutable graph"); +// } +// return mGraph; +// } + + protected void addToMutableGraph( + DirectedGraph graph, Unit curr, MutableGraph mutableGraph) { + List succsOf = graph.getSuccsOf(curr); + for (Unit succ : succsOf) { + if (!mutableGraph.hasEdgeConnecting(curr, succ) && !curr.equals(succ)) { + mutableGraph.putEdge(curr, succ); + addToMutableGraph(graph, succ, mutableGraph); + }else{ + if(m.getSignature().equals("")){ + System.out.println(curr); + } + } + } + } + + + /** + * DFS traverse Original Graph and keep all the stmts + * + * @param curr + * @param graph + * @param cfg + */ + private void buildCompleteCFG(Unit curr, DirectedGraph graph, JimpleSparseCFG cfg) { + List succs = graph.getSuccsOf(curr); + if (succs == null || succs.isEmpty()) { + return; + } + for (Unit succ : succs) { + if (cfg.addEdge(curr, succ)) { + buildCompleteCFG(succ, graph, cfg); + } + } + } + + /** + * DFS traverse Original Graph and keep only required stmts + * + * @param curr + * @param graph + * @param cfg + */ + private void buildSparseCFG(Unit curr, Unit prev, DirectedGraph graph, JimpleSparseCFG cfg, DFF d, SootMethod m) { + List succs = graph.getSuccsOf(curr); + if (succs == null || succs.isEmpty()) { + return; + } + for (Unit succ : succs) { + if (shouldKeepStmt(succ, d, m, graph)) { + boolean addedEdge; + if (prev != null) { + addedEdge = cfg.addEdge(prev, succ); + } else { + addedEdge = cfg.addEdge(curr, succ); + } + if (addedEdge) { + buildSparseCFG(succ, null, graph, cfg, d, m); + } + } else { + if (prev == null) { + buildSparseCFG(succ, curr, graph, cfg, d, m); + } else { + buildSparseCFG(succ, prev, graph, cfg, d, m); + } + } + } + } + + private boolean shouldKeepStmt(Unit unit, DFF d, SootMethod m, DirectedGraph graph) { + if(d.toString().equals("<>")){ + if(unit instanceof JAssignStmt){ + JAssignStmt assign = (JAssignStmt) unit; + Value rightOp = assign.getRightOp(); + if(rightOp instanceof IntConstant){ + return true; + } + } + if(unit instanceof InvokeStmt){ + return true; + } + } + + //keep the stmt which generates the D + if (d.getGeneratedAt() != null && unit.toString().equals(d.getGeneratedAt().toString())) { + return true; + } + //keep for case 1: if v (local) appears in a stmt if (keepForCase1(unit, d, m)) { return true; @@ -94,13 +230,30 @@ private boolean shouldKeepStmt(Unit unit, DFF d, SootMethod m, DirectedGraph graph) { if (stmt instanceof JIfStmt || stmt instanceof JNopStmt || stmt instanceof JGotoStmt || stmt instanceof JReturnStmt || stmt instanceof JReturnVoidStmt || stmt instanceof JIdentityStmt) { return true; } +// if (stmt instanceof JIdentityStmt) { +// JIdentityStmt id = (JIdentityStmt) stmt; +// if (id.getRightOp() instanceof JCaughtExceptionRef) { +// return true; +// } +// } // or if stmt has multiple successors if (graph.getSuccsOf(stmt).size() > 1) { return true; @@ -208,6 +376,38 @@ private boolean keepControlFlowStmts(Unit stmt, DirectedGraph graph) { return false; } + private boolean keepFieldStore(Unit unit) { + if (unit instanceof JAssignStmt) { + Value left = ((JAssignStmt) unit).getLeftOp(); + //V.f = x + if (left instanceof JInstanceFieldRef) { + // TODO: maybe this can be handled similar to aliases of v.m(), but did not work like below + //JInstanceFieldRef fieldRef = (JInstanceFieldRef) left; + //Value base = fieldRef.getBase(); + //if(isTargetDFFOrAlias((Stmt) unit, method, base, sparseCFG.getD())){ + return true; + //} + } + } + return false; + } + + private boolean keepFieldLoad(Unit unit) { + if (unit instanceof JAssignStmt) { + Value left = ((JAssignStmt) unit).getRightOp(); + //V.f = x + if (left instanceof JInstanceFieldRef) { + // TODO: maybe this can be handled similar to aliases of v.m(), but did not work like below + //JInstanceFieldRef fieldRef = (JInstanceFieldRef) left; + //Value base = fieldRef.getBase(); + //if(isTargetDFFOrAlias((Stmt) unit, method, base, sparseCFG.getD())){ + return true; + //} + } + } + return false; + } + private void logCFG(Logger logger, MutableGraph graph, String cfgType, Body body, DFF d) { if (log) { diff --git a/src/main/java/sparse/DefaultSparseCFGBuilderStash.java b/src/main/java/sparse/DefaultSparseCFGBuilderStash.java new file mode 100644 index 0000000..e9bfbdc --- /dev/null +++ b/src/main/java/sparse/DefaultSparseCFGBuilderStash.java @@ -0,0 +1,228 @@ +package sparse; + +import analysis.data.DFF; +import com.google.common.graph.MutableGraph; +import heros.sparse.SparseCFG; +import heros.sparse.SparseCFGBuilder; +import heros.sparse.SparseCFGQueryStat; +import soot.*; +import soot.jimple.*; +import soot.jimple.internal.*; +import soot.toolkits.graph.BriefUnitGraph; +import soot.toolkits.graph.DirectedGraph; + +import java.util.*; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +/** + * Value is the type of DFF + * Specialized for Constant Propagation + */ +public class DefaultSparseCFGBuilderStash implements SparseCFGBuilder { + + private final static Logger LOGGER = Logger.getLogger(CPAJimpleSparseCFGBuilder.class.getName()); + + private boolean enableExceptions; + + private boolean log = false; + + private Set stmsToRemove; + + public DefaultSparseCFGBuilderStash(boolean enableExceptions) { + this.enableExceptions = enableExceptions; + } + + private SootMethod m; + + @Override + public SparseCFG buildSparseCFG(SootMethod m, DFF d, SparseCFGQueryStat queryStat) { + this.m = m; + DirectedGraph rawGraph = new BriefUnitGraph(m.getActiveBody()); + //handle zero +// if (d.toString().equals("<>")) { +// JimpleDefaultSparseCFG cfg = new JimpleDefaultSparseCFG(d, rawGraph, null, rawGraph.size()); +// return cfg; +// } + + Map jumps = sparsify(d, m, rawGraph); + + JimpleDefaultSparseCFG cfg = new JimpleDefaultSparseCFG(d, rawGraph, jumps, rawGraph.size() - stmsToRemove.size()); + + return cfg; + } + + + + private Map sparsify(DFF d, SootMethod m, DirectedGraph graph) { + stmsToRemove = new LinkedHashSet<>(); + Iterator iter = graph.iterator(); + while (iter.hasNext()) { + Unit unit = iter.next(); + if (!stmsToRemove.contains(unit) && !shouldKeepStmt(unit, d, m, graph)) { + stmsToRemove.add(unit); + } + } + Map jumps = new HashMap<>(); + UnitPatchingChain units = m.getActiveBody().getUnits(); + for (Unit unit : stmsToRemove) { + Unit pred = units.getPredOf(unit); + Unit succ = units.getSuccOf(unit); + if (!stmsToRemove.contains(pred)) { + while (stmsToRemove.contains(succ)) { + succ = units.getSuccOf(succ); + } + jumps.put(pred, succ); + } + } + return jumps; + } + + + private boolean shouldKeepStmt(Unit unit, DFF d, SootMethod m, DirectedGraph graph) { + + if(d.toString().equals("<>")){ + if(unit instanceof JAssignStmt){ + JAssignStmt assign = (JAssignStmt) unit; + Value rightOp = assign.getRightOp(); + if(rightOp instanceof IntConstant){ + return true; + } + } + } + + //keep for case 1: if v (local) appears in a stmt + if (keepForCase1(unit, d, m)) { + return true; + } + + // case 3: if stmt accesses T.f (static field) or is a callsite + if (keepForCase3(unit, d)) { + return true; + } + + if (keepControlFlowStmts(unit, graph)) { + return true; + } + + return false; + } + + /** + * // case 1: if d (local) appears in a stmt + * + * @param unit + * @param m + */ + private boolean keepForCase1(Unit unit, DFF d, SootMethod m) { + if (unit instanceof JAssignStmt) { + JAssignStmt stmt = (JAssignStmt) unit; + Value leftOp = stmt.getLeftOp(); + Value rightOp = stmt.getRightOp(); + DFF left = DFF.asDFF(leftOp); + DFF right; + + // handle Casts (Not mentioned) + if (rightOp instanceof JCastExpr) { + JCastExpr cast = (JCastExpr) rightOp; + right = DFF.asDFF(cast.getOp()); + } else { + right = DFF.asDFF(rightOp); + } + + if (d.equals(left) || d.equals(right)) { + if (rightOp instanceof InvokeExpr) { + } + return true; + } else if (rightOp instanceof BinopExpr) { + BinopExpr binop = (BinopExpr) rightOp; + Value lop = binop.getOp1(); + Value rop = binop.getOp2(); + if (DFF.asDFF(lop).equals(d) || DFF.asDFF(rop).equals(d)) { + return true; + } + } else { + // field case (Case 2: handled here) + if (d.getRemainingFields(right) != null) { + return true; + } else if (d.getRemainingFields(left) != null) { + return true; + } + } + } + if (unit instanceof Stmt) { + Stmt stmt = (Stmt) unit; + if (stmt.containsInvokeExpr()) { + InvokeExpr invokeExpr = stmt.getInvokeExpr(); + List args = invokeExpr.getArgs(); + // v as arg + for (Value arg : args) { + DFF argDFF = DFF.asDFF(arg); + if (d.equals(argDFF)) { + return true; + } else if (d.getRemainingFields(argDFF) != null) { + return true; + } + } + // v as base v.m() + if (invokeExpr instanceof JVirtualInvokeExpr) { + Value base = ((JVirtualInvokeExpr) invokeExpr).getBase(); + if (d.equals(DFF.asDFF(base))) { + return true; + } + } + } + } + return false; + } + + private boolean keepForCase3(Unit unit, DFF d) { + if (d.getValue() instanceof StaticFieldRef) { + if (unit instanceof JAssignStmt) { + Value left = ((JAssignStmt) unit).getLeftOp(); + Value right = ((JAssignStmt) unit).getRightOp(); + //V.f = x + if (left instanceof StaticFieldRef) { + if (left.equivTo(d.getValue())) { + return true; + } + } + //x=V.f + if (right instanceof StaticFieldRef) { + if (right.equivTo(d.getValue())) { + return true; + } + } + } + if (unit instanceof Stmt) { + Stmt stmt = (Stmt) unit; + if (stmt.containsInvokeExpr()) { + return true; + } + } + } + return false; + } + + private boolean keepControlFlowStmts(Unit stmt, DirectedGraph graph) { + if (stmt instanceof JIfStmt || stmt instanceof JNopStmt || stmt instanceof JGotoStmt || stmt instanceof JReturnStmt || stmt instanceof JReturnVoidStmt || stmt instanceof JIdentityStmt) { + return true; + } + // or if stmt has multiple successors + if (graph.getSuccsOf(stmt).size() > 1) { + return true; + } + return false; + } + + + private void logCFG(Logger logger, MutableGraph graph, String cfgType, Body body, DFF d) { + if (log) { + logger.info(cfgType + "-" + d.toString() + ":\n" + + graph.nodes().stream() + .map(Objects::toString) + .collect(Collectors.joining(System.lineSeparator())) + "\n" + body.toString()); + } + } + +} diff --git a/src/main/java/sparse/JimpleSparseIDESolver.java b/src/main/java/sparse/JimpleSparseIDESolver.java index fc0a52d..9d8ffdd 100644 --- a/src/main/java/sparse/JimpleSparseIDESolver.java +++ b/src/main/java/sparse/JimpleSparseIDESolver.java @@ -29,7 +29,7 @@ public JimpleSparseIDESolver(IDETabulationProblem pro public void solve(String targetClassName) { super.solve(); - this.dumpResults(targetClassName); + //this.dumpResults(targetClassName); } //private static Map> checkedMethods = new TreeMap<>(); diff --git a/src/test/java/target/constant/Context5.java b/src/test/java/target/constant/Context5.java new file mode 100644 index 0000000..8abe67e --- /dev/null +++ b/src/test/java/target/constant/Context5.java @@ -0,0 +1,23 @@ +package target.constant; + + +public class Context5 { + + + void assign(int a, Field f){ + f.x = a; + f.y = 200; + } + + /** + * assign field in call + */ + public void entryPoint() { + int a = 100; + Field field = new Field(); + assign(a, field); + int b = field.x; + int c = field.y; + } + +} diff --git a/src/test/java/target/constant/Context6.java b/src/test/java/target/constant/Context6.java new file mode 100644 index 0000000..a40a803 --- /dev/null +++ b/src/test/java/target/constant/Context6.java @@ -0,0 +1,20 @@ +package target.constant; + + +public class Context6 { + + private static int a; + + void assign(){ + a = 100; + } + + /** + * assign static in call + */ + public void entryPoint() { + assign(); + int x = a; + } + +} diff --git a/src/test/java/test/constant/ConstantPropagationAnalysisTest.java b/src/test/java/test/constant/ConstantPropagationAnalysisTest.java index dc6ccc6..b4269b2 100644 --- a/src/test/java/test/constant/ConstantPropagationAnalysisTest.java +++ b/src/test/java/test/constant/ConstantPropagationAnalysisTest.java @@ -346,6 +346,33 @@ public void Context4() { checkResults(defaultIDEResult, sparseIDEResult, expected); } + @Test + public void Context5() { + JimpleIDESolver> analysis = executeStaticAnalysis(Context5.class.getName()); + Set> defaultIDEResult = getResult(analysis); + JimpleSparseIDESolver> sparseAnalysis = executeSparseStaticAnalysis(Context5.class.getName()); + Set> sparseIDEResult = getResult(sparseAnalysis); + Set> expected = new HashSet<>(); + expected.add(new Pair("a", 100)); + expected.add(new Pair("field.x", 100)); + expected.add(new Pair("field.y", 200)); + expected.add(new Pair("b", 100)); + expected.add(new Pair("c", 200)); + checkResults(defaultIDEResult, sparseIDEResult, expected); + } + + @Test + public void Context6() { + JimpleIDESolver> analysis = executeStaticAnalysis(Context6.class.getName()); + Set> defaultIDEResult = getResult(analysis); + JimpleSparseIDESolver> sparseAnalysis = executeSparseStaticAnalysis(Context6.class.getName()); + Set> sparseIDEResult = getResult(sparseAnalysis); + Set> expected = new HashSet<>(); + expected.add(new Pair("target.constant.Context6.a", 100)); + expected.add(new Pair("x", 100)); + checkResults(defaultIDEResult, sparseIDEResult, expected); + } + @Test public void Loop() {