From bcf008ed06eab4d3dec1c046f57656b599f737b1 Mon Sep 17 00:00:00 2001 From: Dongjie Date: Thu, 3 Feb 2022 11:42:36 +1100 Subject: [PATCH] refactoring changes: 1. for merged objects, we provide a MergedNewExpr for each type. 2. MethodPAG directly include a Jimple body of the method. 3. add add a BasePTA between CorePTA and the concrete PTAs. 4. we move test from qilin.microben to qilin.pta and provide a build.xml to build microben using JDK 8- --- qilin.core/src/qilin/core/CorePTA.java | 10 +- qilin.core/src/qilin/core/PTA.java | 18 +- .../qilin/core/builder/CallGraphBuilder.java | 15 +- .../qilin/core/builder/MethodNodeFactory.java | 1 - .../src/qilin/core/pag/MergedNewExpr.java | 20 ++ qilin.core/src/qilin/core/pag/MethodPAG.java | 87 +---- qilin.core/src/qilin/core/pag/PAG.java | 86 ++++- .../qilin/core/pag/StringConstantNode.java | 2 +- qilin.core/src/qilin/core/solver/Solver.java | 11 +- .../src/qilin/core/solver/Solver.java.bak | 324 ------------------ .../parm/heapabst/HeuristicAbstractor.java | 3 +- qilin.core/src/qilin/stat/BenchmarkStat.java | 3 - qilin.microben/README.md | 6 + qilin.microben/build.gradle | 9 +- qilin.microben/build.xml | 18 + qilin.pta/build.gradle | 11 + .../src/qilin/pta/toolkits/bean/oag/OAG.java | 10 +- .../src/qilin/pta/toolkits/turner/Turner.java | 10 +- .../zipper/pta/WrapperedPointsToAnalysis.java | 8 +- qilin.pta/src/qilin/pta/tools/BasePTA.java | 24 ++ qilin.pta/src/qilin/pta/tools/BeanPTA.java | 2 +- .../src/qilin/pta/tools/CallSiteSensPTA.java | 2 +- .../src/qilin/pta/tools/DataDrivenPTA.java | 2 +- .../qilin/pta/tools/HybridObjectSensPTA.java | 2 +- .../qilin/pta/tools/HybridTypeSensPTA.java | 2 +- qilin.pta/src/qilin/pta/tools/MahjongPTA.java | 2 +- .../src/qilin/pta/tools/ObjectSensPTA.java | 2 +- .../pta/tools/PartialCallSiteSensPTA.java | 4 +- .../qilin/pta/tools/PartialObjSensPTA.java | 7 +- qilin.pta/src/qilin/pta/tools/Spark.java | 3 +- .../src/qilin/pta/tools/TunnelingPTA.java | 3 +- .../src/qilin/pta/tools/TypeSensPTA.java | 2 +- qilin.pta/src/qilin/pta/tools/ZipperPTA.java | 7 +- .../test}/qilin/test/FlowSensTests.java | 0 qilin.pta/test/qilin/test/SummaryTests.java | 145 ++++++++ .../test}/qilin/test/context/CFATests.java | 0 .../qilin/test/context/CollectionsTests.java | 0 .../test}/qilin/test/context/HybTests.java | 0 .../test}/qilin/test/context/OBJTests.java | 0 .../test}/qilin/test/context/TypeTests.java | 0 .../test}/qilin/test/core/ArrayTests.java | 0 .../test}/qilin/test/core/AssignTests.java | 0 .../test}/qilin/test/core/CallTests.java | 0 .../test}/qilin/test/core/ClinitTests.java | 0 .../test}/qilin/test/core/ExceptionTests.java | 0 .../test}/qilin/test/core/FieldTests.java | 0 .../test}/qilin/test/core/GlobalTests.java | 0 .../test}/qilin/test/core/NativeTests.java | 0 .../test}/qilin/test/core/ReflogTests.java | 0 .../test}/qilin/test/util/AliasAssertion.java | 0 .../qilin/test/util/AssertionsParser.java | 0 .../test}/qilin/test/util/IAssertion.java | 0 .../test}/qilin/test/util/JunitTests.java | 7 +- .../src/qilin/util/queue/UniqueQueue.java | 1 + 54 files changed, 377 insertions(+), 492 deletions(-) create mode 100644 qilin.core/src/qilin/core/pag/MergedNewExpr.java delete mode 100644 qilin.core/src/qilin/core/solver/Solver.java.bak create mode 100644 qilin.microben/README.md create mode 100644 qilin.microben/build.xml create mode 100644 qilin.pta/src/qilin/pta/tools/BasePTA.java rename {qilin.microben/src => qilin.pta/test}/qilin/test/FlowSensTests.java (100%) create mode 100644 qilin.pta/test/qilin/test/SummaryTests.java rename {qilin.microben/src => qilin.pta/test}/qilin/test/context/CFATests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/context/CollectionsTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/context/HybTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/context/OBJTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/context/TypeTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/ArrayTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/AssignTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/CallTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/ClinitTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/ExceptionTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/FieldTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/GlobalTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/NativeTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/core/ReflogTests.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/util/AliasAssertion.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/util/AssertionsParser.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/util/IAssertion.java (100%) rename {qilin.microben/src => qilin.pta/test}/qilin/test/util/JunitTests.java (90%) diff --git a/qilin.core/src/qilin/core/CorePTA.java b/qilin.core/src/qilin/core/CorePTA.java index 36b21a8..4b53a41 100644 --- a/qilin.core/src/qilin/core/CorePTA.java +++ b/qilin.core/src/qilin/core/CorePTA.java @@ -23,13 +23,12 @@ import qilin.core.sets.PointsToSet; import qilin.core.sets.PointsToSetInternal; import qilin.core.solver.Propagator; -import qilin.core.solver.Solver; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.HeapAbstractor; import qilin.parm.select.CtxSelector; import soot.*; -import java.util.*; +import java.util.Collections; /* * This represents a parameterized PTA which could be concreted to many pointer analyses. @@ -54,9 +53,7 @@ public HeapAbstractor heapAbstractor() { return heapAbst; } - public Propagator getPropagator() { - return new Solver(this); - } + public abstract Propagator getPropagator(); @Override public Context createCalleeCtx(MethodOrMethodContext caller, AllocNode receiverNode, CallSite callSite, SootMethod target) { @@ -229,8 +226,7 @@ public PointsToSet reachingObjects(SootField f) { public PointsToSet reachingObjectsInternal(PointsToSet s, final SparkField f) { PointsToSetInternal bases = (PointsToSetInternal) s; - final PointsToSetInternal ret = setFactory.newSet((f instanceof SootField) ? ((SootField) f).getType() : null, - pag); + final PointsToSetInternal ret = setFactory.newSet((f instanceof SootField) ? ((SootField) f).getType() : null, pag); for (ContextField contextField : pag.getContextFieldVarNodeMap().getOrDefault(f, Collections.emptyMap()).values()) { AllocNode base = contextField.getBase(); if (bases.contains(base)) { diff --git a/qilin.core/src/qilin/core/PTA.java b/qilin.core/src/qilin/core/PTA.java index 60ebed9..1d1f3a4 100644 --- a/qilin.core/src/qilin/core/PTA.java +++ b/qilin.core/src/qilin/core/PTA.java @@ -33,10 +33,16 @@ import qilin.parm.heapabst.HeapAbstractor; import qilin.stat.PTAEvaluator; import qilin.util.PTAUtils; -import soot.*; +import soot.Context; +import soot.MethodOrMethodContext; +import soot.RefType; +import soot.SootMethod; import soot.jimple.toolkits.callgraph.CallGraph; -import java.util.*; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; public abstract class PTA implements PointsToAnalysis { private static final Logger logger = LoggerFactory.getLogger(PTA.class); @@ -50,8 +56,8 @@ public abstract class PTA implements PointsToAnalysis { protected PTAEvaluator evaluator; public PTA() { - this.pag = new PAG(this); - this.cgb = new CallGraphBuilder(this); + this.pag = createPAG(); + this.cgb = createCallGraphBuilder(); this.eh = new ExceptionHandler(this); this.evaluator = new PTAEvaluator(this); AllocNode rootBase = new AllocNode(pag, "ROOT", RefType.v("java.lang.Object"), null); @@ -61,6 +67,10 @@ public PTA() { this.setFactory = DoublePointsToSet.getFactory(newF, oldF); } + protected abstract PAG createPAG(); + + protected abstract CallGraphBuilder createCallGraphBuilder(); + public void pureRun() { for (int i = 0; i < 5; i++) { System.gc(); diff --git a/qilin.core/src/qilin/core/builder/CallGraphBuilder.java b/qilin.core/src/qilin/core/builder/CallGraphBuilder.java index c1e573e..30d7251 100644 --- a/qilin.core/src/qilin/core/builder/CallGraphBuilder.java +++ b/qilin.core/src/qilin/core/builder/CallGraphBuilder.java @@ -25,7 +25,6 @@ import qilin.core.pag.*; import qilin.core.sets.P2SetVisitor; import qilin.core.sets.PointsToSetInternal; -import qilin.util.Pair; import soot.*; import soot.jimple.*; import soot.jimple.internal.JInvokeStmt; @@ -40,7 +39,6 @@ public class CallGraphBuilder { protected final RefType clRunnable = RefType.v("java.lang.Runnable"); - protected final Map>> receiverToStaticSites; protected final Map> receiverToSites; protected final Map>> dispatchCache; protected final Map> methodToInvokeStmt; @@ -55,7 +53,6 @@ public CallGraphBuilder(PTA pta) { this.pta = pta; this.pag = pta.getPag(); PTAScene.v().setCallGraph(new CallGraph()); - receiverToStaticSites = new HashMap<>(PTAScene.v().getLocalNumberer().size()); receiverToSites = new HashMap<>(PTAScene.v().getLocalNumberer().size()); dispatchCache = new HashMap<>(); methodToInvokeStmt = new HashMap<>(); @@ -68,11 +65,6 @@ public Collection getReachableMethods() { return reachMethods; } - // for Manu's ondemand pta. - public Map>> getReceiverToStaticSitesMap() { - return receiverToStaticSites; - } - // initialize the receiver to sites map with the number of locals * an // estimate for the number of contexts per methods public Map> getReceiverToSitesMap() { @@ -201,7 +193,7 @@ public void addStaticEdge(MethodOrMethodContext caller, Unit callStmt, SootMetho handleCallEdge(new Edge(caller, callStmt, callee, kind)); } - private void handleCallEdge(Edge edge) { + protected void handleCallEdge(Edge edge) { if (calledges.add(edge)) { MethodOrMethodContext callee = edge.getTgt(); if (reachMethods.add(callee)) { @@ -216,11 +208,6 @@ public boolean recordVirtualCallSite(VarNode receiver, VirtualCallSite site) { return sites.add(site); } - public void recordStaticCallSite(VarNode receiver, Pair site) { - Collection> sites = receiverToStaticSites.computeIfAbsent(receiver, k -> new HashSet<>()); - sites.add(site); - } - public void virtualCallDispatch(PointsToSetInternal p2set, VirtualCallSite site) { p2set.forall(new P2SetVisitor() { public void visit(Node n) { diff --git a/qilin.core/src/qilin/core/builder/MethodNodeFactory.java b/qilin.core/src/qilin/core/builder/MethodNodeFactory.java index 39db673..fc249a5 100644 --- a/qilin.core/src/qilin/core/builder/MethodNodeFactory.java +++ b/qilin.core/src/qilin/core/builder/MethodNodeFactory.java @@ -29,7 +29,6 @@ import soot.jimple.internal.JNewArrayExpr; /** - * * @author Ondrej Lhotak */ public class MethodNodeFactory extends AbstractJimpleValueSwitch { diff --git a/qilin.core/src/qilin/core/pag/MergedNewExpr.java b/qilin.core/src/qilin/core/pag/MergedNewExpr.java new file mode 100644 index 0000000..15ec2cf --- /dev/null +++ b/qilin.core/src/qilin/core/pag/MergedNewExpr.java @@ -0,0 +1,20 @@ +package qilin.core.pag; + +import soot.RefType; +import soot.jimple.internal.JNewExpr; + +import java.util.HashMap; +import java.util.Map; + +public class MergedNewExpr extends JNewExpr { + private static final Map map = new HashMap<>(); + + private MergedNewExpr(RefType type) { + super(type); + } + + public static MergedNewExpr v(RefType type) { + return map.computeIfAbsent(type, k -> new MergedNewExpr(type)); + } + +} diff --git a/qilin.core/src/qilin/core/pag/MethodPAG.java b/qilin.core/src/qilin/core/pag/MethodPAG.java index c85315b..8a3c204 100644 --- a/qilin.core/src/qilin/core/pag/MethodPAG.java +++ b/qilin.core/src/qilin/core/pag/MethodPAG.java @@ -19,14 +19,13 @@ package qilin.core.pag; import qilin.CoreConfig; -import qilin.core.PTAScene; import qilin.core.builder.MethodNodeFactory; import qilin.util.PTAUtils; import soot.*; -import soot.jimple.*; -import soot.jimple.internal.JArrayRef; -import soot.jimple.internal.JAssignStmt; -import soot.jimple.internal.JimpleLocal; +import soot.jimple.Jimple; +import soot.jimple.StaticFieldRef; +import soot.jimple.Stmt; +import soot.jimple.ThrowStmt; import soot.util.Chain; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; @@ -43,6 +42,7 @@ public class MethodPAG { private final QueueReader internalReader = internalEdges.reader(); private final Set clinits = new HashSet<>(); public Collection invokeStmts = new HashSet<>(); + public Body body; /** * Since now the exception analysis is handled on-the-fly, we should record the * exception edges explicitly for Eagle and Turner. @@ -60,10 +60,11 @@ public class MethodPAG { public final Map> stmt2wrapperedTraps = new HashMap<>(); public final Map>> node2wrapperedTraps = new HashMap<>(); - public MethodPAG(PAG pag, SootMethod m) { + public MethodPAG(PAG pag, SootMethod m, Body body) { this.pag = pag; this.method = m; this.nodeFactory = new MethodNodeFactory(pag, this); + this.body = body; build(); } @@ -84,87 +85,16 @@ protected void build() { if (method.getSignature().equals("")) { return; } - buildReflective(); - buildNative(); buildException(); buildNormal(); addMiscEdges(); } - protected void buildReflective() { - if (method.isConcrete()) { - pag.reflectionModel.buildReflection(method); - } - } - - protected void buildNative() { - if (method.isNative()) { - pag.nativeDriver.buildNative(method); - } else { - // we will revert these back in the future. - /* - * To keep same with Doop, we move the simulation of - * - * directly to its caller methods. - * */ - if (PTAScene.v().arraycopyBuilt.add(method)) { - handleArrayCopy(); - } - } - } - - private void handleArrayCopy() { - Map> newUnits = new HashMap<>(); - Body body = PTAUtils.getMethodBody(method); - for (Unit unit : body.getUnits()) { - Stmt s = (Stmt) unit; - if (s.containsInvokeExpr()) { - InvokeExpr invokeExpr = s.getInvokeExpr(); - if (invokeExpr instanceof StaticInvokeExpr sie) { - SootMethod sm = sie.getMethod(); - String sig = sm.getSignature(); - if (sig.equals("")) { - Value srcArr = sie.getArg(0); - if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { - continue; - } - Type objType = RefType.v("java.lang.Object"); - if (srcArr.getType() == objType) { - Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); - body.getLocals().add(localSrc); - newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr)); - srcArr = localSrc; - } - Value dstArr = sie.getArg(2); - if (PTAUtils.isPrimitiveArrayType(dstArr.getType())) { - continue; - } - if (dstArr.getType() == objType) { - Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); - body.getLocals().add(localDst); - newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr)); - dstArr = localDst; - } - Value src = new JArrayRef(srcArr, IntConstant.v(0)); - Value dst = new JArrayRef(dstArr, IntConstant.v(0)); - Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), RefType.v("java.lang.Object")); - body.getLocals().add(local); - newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(local, src)); - newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(dst, local)); - } - } - } - } - for (Unit unit : newUnits.keySet()) { - body.getUnits().insertAfter(newUnits.get(unit), unit); - } - } - protected void buildNormal() { if (method.isStatic()) { PTAUtils.clinitsOf(method.getDeclaringClass()).forEach(this::addTriggeredClinit); } - for (Unit unit : PTAUtils.getMethodBody(method).getUnits()) { + for (Unit unit : body.getUnits()) { try { nodeFactory.handleStmt((Stmt) unit); } catch (Exception e) { @@ -178,7 +108,6 @@ protected void buildException() { if (!CoreConfig.v().getPtaConfig().preciseExceptions) { return; } - Body body = PTAUtils.getMethodBody(method); Chain traps = body.getTraps(); PatchingChain units = body.getUnits(); Set inTraps = new HashSet<>(); diff --git a/qilin.core/src/qilin/core/pag/PAG.java b/qilin.core/src/qilin/core/pag/PAG.java index 71a1074..e8fd757 100644 --- a/qilin.core/src/qilin/core/pag/PAG.java +++ b/qilin.core/src/qilin/core/pag/PAG.java @@ -27,10 +27,12 @@ import qilin.core.reflection.ReflectionModel; import qilin.core.reflection.TamiflexModel; import qilin.parm.heapabst.HeapAbstractor; +import qilin.util.PTAUtils; import soot.*; -import soot.jimple.ClassConstant; -import soot.jimple.Stmt; -import soot.jimple.StringConstant; +import soot.jimple.*; +import soot.jimple.internal.JArrayRef; +import soot.jimple.internal.JAssignStmt; +import soot.jimple.internal.JimpleLocal; import soot.util.ArrayNumberer; import soot.util.queue.ChunkedQueue; import soot.util.queue.QueueReader; @@ -49,7 +51,7 @@ public class PAG { protected final Map> contextAllocNodeMap; protected final Map> contextMethodMap; protected final Map> addedContexts; - protected final Map> contextFieldMap; + protected final Map> contextFieldMap; // ========================= ir to Node ============================================== protected final Map valToAllocNode; @@ -185,7 +187,75 @@ public PTA getPta() { } public MethodPAG getMethodPAG(SootMethod m) { - return methodToPag.computeIfAbsent(m, k -> new MethodPAG(this, m)); + Body body = PTAUtils.getMethodBody(m); + if (m.isConcrete()) { + reflectionModel.buildReflection(m); + } + if (m.isNative()) { + nativeDriver.buildNative(m); + } else { + // we will revert these back in the future. + /* + * To keep same with Doop, we move the simulation of + * + * directly to its caller methods. + * */ + if (PTAScene.v().arraycopyBuilt.add(m)) { + handleArrayCopy(m); + } + } + return methodToPag.computeIfAbsent(m, k -> new MethodPAG(this, m, body)); + } + + private void handleArrayCopy(SootMethod method) { + Map> newUnits = new HashMap<>(); + Body body = PTAUtils.getMethodBody(method); + for (Unit unit : body.getUnits()) { + Stmt s = (Stmt) unit; + if (s.containsInvokeExpr()) { + InvokeExpr invokeExpr = s.getInvokeExpr(); + if (invokeExpr instanceof StaticInvokeExpr sie) { + SootMethod sm = sie.getMethod(); + String sig = sm.getSignature(); + if (sig.equals("")) { + Value srcArr = sie.getArg(0); + if (PTAUtils.isPrimitiveArrayType(srcArr.getType())) { + continue; + } + Type objType = RefType.v("java.lang.Object"); + if (srcArr.getType() == objType) { + Local localSrc = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); + body.getLocals().add(localSrc); + newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localSrc, srcArr)); + srcArr = localSrc; + } + Value dstArr = sie.getArg(2); + if (PTAUtils.isPrimitiveArrayType(dstArr.getType())) { + continue; + } + if (dstArr.getType() == objType) { + Local localDst = new JimpleLocal("intermediate/" + body.getLocalCount(), ArrayType.v(objType, 1)); + body.getLocals().add(localDst); + newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(localDst, dstArr)); + dstArr = localDst; + } + Value src = new JArrayRef(srcArr, IntConstant.v(0)); + Value dst = new JArrayRef(dstArr, IntConstant.v(0)); + Local local = new JimpleLocal("nativeArrayCopy" + body.getLocalCount(), RefType.v("java.lang.Object")); + body.getLocals().add(local); + newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(local, src)); + newUnits.computeIfAbsent(unit, k -> new HashSet<>()).add(new JAssignStmt(dst, local)); + } + } + } + } + for (Unit unit : newUnits.keySet()) { + body.getUnits().insertAfter(newUnits.get(unit), unit); + } + } + + public boolean containsMethodPAG(SootMethod m) { + return methodToPag.containsKey(m); } public Collection getContextFields() { @@ -204,14 +274,14 @@ public Map> getContextMethodMap( return contextMethodMap; } - public Map> getContextFieldVarNodeMap() { + public Map> getContextFieldVarNodeMap() { return contextFieldMap; } public ContextField makeContextField(Context context, FieldValNode fieldValNode) { SparkField field = fieldValNode.getField(); - Map ctx2field = contextFieldMap.computeIfAbsent(field, k -> new HashMap<>()); - return ctx2field.computeIfAbsent(context, k -> new ContextField(this, context, field)); + Map field2odotf = contextFieldMap.computeIfAbsent(context, k -> new HashMap<>()); + return field2odotf.computeIfAbsent(field, k -> new ContextField(this, context, field)); } public Collection getVarNodes(Local local) { diff --git a/qilin.core/src/qilin/core/pag/StringConstantNode.java b/qilin.core/src/qilin/core/pag/StringConstantNode.java index 8c62f93..e0b9aa7 100644 --- a/qilin.core/src/qilin/core/pag/StringConstantNode.java +++ b/qilin.core/src/qilin/core/pag/StringConstantNode.java @@ -28,7 +28,7 @@ */ public class StringConstantNode extends ConstantNode { StringConstantNode(PAG pag, StringConstant sc) { - super(pag, sc.value, RefType.v("java.lang.String"), null); + super(pag, sc, RefType.v("java.lang.String"), null); } public String toString() { diff --git a/qilin.core/src/qilin/core/solver/Solver.java b/qilin.core/src/qilin/core/solver/Solver.java index 92812c9..085ee64 100644 --- a/qilin.core/src/qilin/core/solver/Solver.java +++ b/qilin.core/src/qilin/core/solver/Solver.java @@ -134,7 +134,6 @@ private void recordCallStmts(MethodOrMethodContext m, Collection units) { if (tgt != null) { // static invoke or dynamic invoke VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); recNode = (VarNode) pta.parameterize(recNode, m.context()); - cgb.recordStaticCallSite(recNode, new Pair<>(m, s)); if (ie instanceof DynamicInvokeExpr) { // !TODO dynamicInvoke is provided in JDK after Java 7. // currently, PTA does not handle dynamicInvokeExpr. @@ -242,11 +241,13 @@ public void visit(Node n) { private void activateConstraints(QueueReader newCalls, QueueReader newRMs, QueueReader newThrows, QueueReader addedEdges) { while (newCalls.hasNext()) { - final VirtualCallSite site = newCalls.next(); - final VarNode receiver = site.recNode(); - cgb.virtualCallDispatch(receiver.getP2Set().getOldSet(), site); + while (newCalls.hasNext()) { + final VirtualCallSite site = newCalls.next(); + final VarNode receiver = site.recNode(); + cgb.virtualCallDispatch(receiver.getP2Set().getOldSet(), site); + } + processStmts(newRMs); // may produce new calls, thus an out-loop is a must. } - processStmts(newRMs); while (newThrows.hasNext()) { final ExceptionThrowSite ets = newThrows.next(); diff --git a/qilin.core/src/qilin/core/solver/Solver.java.bak b/qilin.core/src/qilin/core/solver/Solver.java.bak deleted file mode 100644 index 7395397..0000000 --- a/qilin.core/src/qilin/core/solver/Solver.java.bak +++ /dev/null @@ -1,324 +0,0 @@ -/* Qilin - a Java Pointer Analysis Framework - * Copyright (C) 2021-2030 Qilin developers - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3.0 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - */ - -package qilin.core.solver; - -import qilin.CoreConfig; -import qilin.core.PTA; -import qilin.core.PTAScene; -import qilin.core.builder.CallGraphBuilder; -import qilin.core.builder.ExceptionHandler; -import qilin.core.builder.MethodNodeFactory; -import qilin.core.pag.*; -import qilin.core.sets.HybridPointsToSet; -import qilin.core.sets.P2SetVisitor; -import qilin.core.sets.PointsToSetInternal; -import qilin.util.PTAUtils; -import qilin.util.Pair; -import soot.*; -import soot.jimple.*; -import soot.jimple.toolkits.callgraph.Edge; -import soot.options.Options; -import soot.util.NumberedString; -import soot.util.queue.ChunkedQueue; -import soot.util.queue.QueueReader; - -import java.util.*; - -public final class Solver extends Propagator { - private final TreeSet valNodeWorkList = new TreeSet<>(); - private final PAG pag; - private final PTA pta; - private final CallGraphBuilder cgb; - private final ExceptionHandler eh; - private final ChunkedQueue throwSiteQueue = new ChunkedQueue<>(); - private final ChunkedQueue virtualCallSiteQueue = new ChunkedQueue<>(); - private final PointsToSetInternal mset; - private ValNode curr; - - public Solver(PTA pta) { - this.cgb = pta.getCgb(); - this.pag = pta.getPag(); - this.eh = pta.getExceptionHandler(); - this.pta = pta; - this.mset = HybridPointsToSet.getFactory().newSet(RefType.v("java.lang.Object"), pag); - } - - @Override - public void propagate() { - final QueueReader newRMs = cgb.reachMethodsReader(); - final QueueReader newPAGEdges = pag.edgeReader(); - final QueueReader newThrows = throwSiteQueue.reader(); - final QueueReader newCalls = virtualCallSiteQueue.reader(); - cgb.initReachableMethods(); - processStmts(newRMs); - pag.getAlloc().forEach((a, set) -> set.forEach(v -> propagatePTS(v, a))); - while (!valNodeWorkList.isEmpty()) { - curr = valNodeWorkList.pollFirst(); - this.mset.clear(); - if (curr instanceof VarNode mSrc) { - // Step 1: Resolving Indirect Constraints. - handleStoreAndLoadOnBase(mSrc); - handleVirtualCallAndExceptionDispatching(); - // Step 2: Collecting New Constraints. - processStmts(newRMs); - // Step 3: Activating New Constraints. - activateConstraints(newCalls, newThrows, newPAGEdges); - } - /* - * Note, handling assign edges must be after handleVirtualAndExceptionDispatching(). - * Because we must ensure all newly added edges from curr be updated with new values in pts(curr). - * */ - // Step 4: Resolving Direct Constraints. - final PointsToSetInternal pts = curr.getP2Set(); - final PointsToSetInternal newset = pts.getNewSet(); - pag.simpleLookup(curr).forEach(to -> handleAssignEdge(newset, to)); - curr.getP2Set().flushNew(); - propagatePTS(curr, mset); - } - } - - public void processStmts(Iterator newRMs) { - while (newRMs.hasNext()) { - MethodOrMethodContext momc = newRMs.next(); - SootMethod method = momc.method(); - if (method.isPhantom()) { - continue; - } - MethodPAG mpag = pag.getMethodPAG(method); - addToPAG(mpag, momc.context()); - // !FIXME in a context-sensitive pointer analysis, clinits in a method maybe added multiple times. - if (CoreConfig.v().getPtaConfig().clinitMode == CoreConfig.ClinitMode.ONFLY) { - // add find in the method to reachableMethods. - Iterator it = mpag.triggeredClinits(); - while (it.hasNext()) { - SootMethod sm = it.next(); - cgb.injectCallEdge(sm.getDeclaringClass().getType(), pta.parameterize(sm, pta.emptyContext()), Kind.CLINIT); - } - } - recordCallStmts(momc, mpag.invokeStmts); - recordThrowStmts(momc, mpag.stmt2wrapperedTraps.keySet()); - } - } - - private void recordCallStmts(MethodOrMethodContext m, Collection units) { - for (final Unit u : units) { - final Stmt s = (Stmt) u; - if (s.containsInvokeExpr()) { - InvokeExpr ie = s.getInvokeExpr(); - if (ie instanceof InstanceInvokeExpr iie) { - Local receiver = (Local) iie.getBase(); - VarNode recNode = cgb.getReceiverVarNode(receiver, m); - NumberedString subSig = iie.getMethodRef().getSubSignature(); - VirtualCallSite virtualCallSite = new VirtualCallSite(recNode, s, m, iie, subSig, Edge.ieToKind(iie)); - if (cgb.recordVirtualCallSite(recNode, virtualCallSite)) { - virtualCallSiteQueue.add(virtualCallSite); - } - } else { - SootMethod tgt = ie.getMethod(); - if (tgt != null) { // static invoke or dynamic invoke - VarNode recNode = pag.getMethodPAG(m.method()).nodeFactory().caseThis(); - recNode = (VarNode) pta.parameterize(recNode, m.context()); - cgb.recordStaticCallSite(recNode, new Pair<>(m, s)); - if (ie instanceof DynamicInvokeExpr) { - // !TODO dynamicInvoke is provided in JDK after Java 7. - // currently, PTA does not handle dynamicInvokeExpr. - } else { - cgb.addStaticEdge(m, s, tgt, Edge.ieToKind(ie)); - } - } else if (!Options.v().ignore_resolution_errors()) { - throw new InternalError("Unresolved target " + ie.getMethod() - + ". Resolution error should have occured earlier."); - } - } - } - } - } - - private void recordThrowStmts(MethodOrMethodContext m, Collection stmts) { - for (final Stmt stmt : stmts) { - SootMethod sm = m.method(); - MethodPAG mpag = pag.getMethodPAG(sm); - MethodNodeFactory nodeFactory = mpag.nodeFactory(); - Node src; - if (stmt.containsInvokeExpr()) { - src = pag.makeInvokeStmtThrowVarNode(stmt, sm); - } else { - assert stmt instanceof ThrowStmt; - ThrowStmt ts = (ThrowStmt) stmt; - src = nodeFactory.getNode(ts.getOp()); - } - VarNode throwNode = (VarNode) pta.parameterize(src, m.context()); - ExceptionThrowSite throwSite = new ExceptionThrowSite(throwNode, stmt, m); - if (eh.addThrowSite(throwNode, throwSite)) { - throwSiteQueue.add(throwSite); - } - } - } - - private void addToPAG(MethodPAG mpag, Context cxt) { - Set contexts = pag.getMethod2ContextsMap().computeIfAbsent(mpag, k1 -> new HashSet<>()); - if (!contexts.add(cxt)) { - return; - } - for (QueueReader reader = mpag.getInternalReader().clone(); reader.hasNext(); ) { - Node from = reader.next(); - Node to = reader.next(); - from = pta.parameterize(from, cxt); - to = pta.parameterize(to, cxt); - if (from instanceof AllocNode) { - handleImplicitCallToFinalizerRegister((AllocNode) from); - } - pag.addEdge(from, to); - } - } - - // handle implicit calls to java.lang.ref.Finalizer.register by the JVM. - // please refer to library/finalization.logic in doop. - private void handleImplicitCallToFinalizerRegister(AllocNode heap) { - if (PTAUtils.supportFinalize(heap)) { - SootMethod rm = PTAScene.v().getMethod(""); - MethodPAG tgtmpag = pag.getMethodPAG(rm); - MethodNodeFactory tgtnf = tgtmpag.nodeFactory(); - Node parm = tgtnf.caseParm(0); - Context calleeCtx = pta.emptyContext(); - AllocNode baseHeap = heap.base(); - parm = pta.parameterize(parm, calleeCtx); - pag.addEdge(heap, parm); - cgb.injectCallEdge(baseHeap, pta.parameterize(rm, calleeCtx), Kind.STATIC); - } - } - - private void handleStoreAndLoadOnBase(VarNode base) { - for (final FieldRefNode fr : base.getAllFieldRefs()) { - final FieldValNode fvn = pag.makeFieldValNode(fr.getField()); - for (final VarNode v : pag.storeInvLookup(fr)) { - handleStoreEdge(base.getP2Set().getNewSet(), fvn, v); - } - for (final VarNode to : pag.loadLookup(fr)) { - handleLoadEdge(base.getP2Set().getNewSet(), fvn, to); - } - } - } - - private void handleStoreEdge(PointsToSetInternal baseHeaps, FieldValNode fvn, ValNode from) { - baseHeaps.forall(new P2SetVisitor() { - public void visit(Node n) { - if (disallowStoreOrLoadOn((AllocNode) n)) { - return; - } - final ValNode oDotF = (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); - pag.addEdge(from, oDotF); - } - }); - } - - private void handleLoadEdge(PointsToSetInternal baseHeaps, FieldValNode fvn, ValNode to) { - baseHeaps.forall(new P2SetVisitor() { - public void visit(Node n) { - if (disallowStoreOrLoadOn((AllocNode) n)) { - return; - } - final ValNode oDotF = (ValNode) pta.parameterize(fvn, PTAUtils.plusplusOp((AllocNode) n)); - pag.addEdge(oDotF, to); - } - }); - } - - private void handleVirtualCallAndExceptionDispatching() { - final PointsToSetInternal newP2Set = curr.getP2Set().getNewSet(); - Collection sites = cgb.callSitesLookUp((VarNode) curr); - Collection throwSites = eh.throwSitesLookUp((VarNode) curr); - for (ExceptionThrowSite site : throwSites) { - eh.exceptionDispatch(newP2Set, site); - } - for (VirtualCallSite site : sites) { - cgb.virtualCallDispatch(newP2Set, site); - } - } - - private void activateConstraints(QueueReader newCalls, QueueReader newThrows, QueueReader addedEdges) { - while (newCalls.hasNext()) { - final VirtualCallSite site = newCalls.next(); - final VarNode receiver = site.recNode(); - cgb.virtualCallDispatch(receiver.getP2Set().getOldSet(), site); - } - - while (newThrows.hasNext()) { - final ExceptionThrowSite ets = newThrows.next(); - final VarNode throwNode = ets.getThrowNode(); - eh.exceptionDispatch(throwNode.getP2Set().getOldSet(), ets); - } - /* - * there are some actual parameter to formal parameter edges whose source nodes are not in the worklist. - * For this case, we should use the following loop to update the target nodes and insert the - * target nodes into the worklist if nesseary. - * */ - while (addedEdges.hasNext()) { - final Node addedSrc = addedEdges.next(); - final Node addedTgt = addedEdges.next(); - if (addedSrc instanceof VarNode && addedTgt instanceof VarNode - || addedSrc instanceof ContextField || addedTgt instanceof ContextField - ) { // x = y; x = o.f; o.f = y; - final ValNode srcv = (ValNode) addedSrc; - final ValNode tgtv = (ValNode) addedTgt; - handleAssignEdge(srcv.getP2Set().getOldSet(), tgtv); - } else if (addedSrc instanceof final FieldRefNode srcfrn) { // b = a.f - final FieldValNode fvn = pag.makeFieldValNode(srcfrn.getField()); - handleLoadEdge(srcfrn.getBase().getP2Set().getOldSet(), fvn, (ValNode) addedTgt); - } else if (addedTgt instanceof final FieldRefNode tgtfrn) { // a.f = b; - final FieldValNode fvn = pag.makeFieldValNode(tgtfrn.getField()); - handleStoreEdge(tgtfrn.getBase().getP2Set().getOldSet(), fvn, (ValNode) addedSrc); - } else if (addedSrc instanceof AllocNode) { // alloc x = new T; - propagatePTS((VarNode) addedTgt, (AllocNode) addedSrc); - } - } - } - - /* - * Note that assign edges have three kinds of forms in PAG: - * x = y; x = o.f; o.f = y; - */ - private void handleAssignEdge(PointsToSetInternal fromHeaps, ValNode to) { - if (to == curr) { - mset.addAll(fromHeaps, null); - } else { - propagatePTS(to, fromHeaps); - } - } - - private void propagatePTS(final ValNode pointer, PointsToSetInternal other) { - final PointsToSetInternal addTo = pointer.makeP2Set(); - if (addTo.addAll(other, null)) { - valNodeWorkList.add(pointer); - } - } - - private void propagatePTS(final ValNode pointer, AllocNode heap) { - if (pointer.makeP2Set().add(heap)) { - valNodeWorkList.add(pointer); - } - } - - // we do not allow store to and load from constant heap/empty array. - private boolean disallowStoreOrLoadOn(AllocNode heap) { - AllocNode base = heap.base(); - // return base instanceof StringConstantNode || PTAUtils.isEmptyArray(base); - return PTAUtils.isEmptyArray(base); - } -} diff --git a/qilin.core/src/qilin/parm/heapabst/HeuristicAbstractor.java b/qilin.core/src/qilin/parm/heapabst/HeuristicAbstractor.java index 5166fdf..f02da86 100644 --- a/qilin.core/src/qilin/parm/heapabst/HeuristicAbstractor.java +++ b/qilin.core/src/qilin/parm/heapabst/HeuristicAbstractor.java @@ -19,6 +19,7 @@ package qilin.parm.heapabst; import qilin.core.pag.AllocNode; +import qilin.core.pag.MergedNewExpr; import qilin.core.pag.PAG; import qilin.util.PTAUtils; import soot.RefType; @@ -41,7 +42,7 @@ public HeuristicAbstractor(PAG pag) { @Override public AllocNode abstractHeap(Object newExpr, Type type, SootMethod m) { if (mergedTypes.contains(type) || (PTAUtils.isThrowable(type) && mergedTypes.add(type))) { - return pag.makeAllocNode("new " + type, type, null); + return pag.makeAllocNode(MergedNewExpr.v((RefType) type), type, null); } else { return pag.makeAllocNode(newExpr, type, m); } diff --git a/qilin.core/src/qilin/stat/BenchmarkStat.java b/qilin.core/src/qilin/stat/BenchmarkStat.java index f2fc7a6..f8fb91b 100644 --- a/qilin.core/src/qilin/stat/BenchmarkStat.java +++ b/qilin.core/src/qilin/stat/BenchmarkStat.java @@ -21,12 +21,9 @@ import qilin.CoreConfig; import qilin.core.PTA; import qilin.core.PTAScene; -import soot.MethodOrMethodContext; import soot.SootClass; import soot.SootMethod; -import soot.util.queue.QueueReader; -import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; diff --git a/qilin.microben/README.md b/qilin.microben/README.md new file mode 100644 index 0000000..b6f0bcb --- /dev/null +++ b/qilin.microben/README.md @@ -0,0 +1,6 @@ +# Qilin's Micro Benchmarks + +## Build + +To build the test cases in this project, please use `ant` command. +The javac version must be `<= 1.8`. \ No newline at end of file diff --git a/qilin.microben/build.gradle b/qilin.microben/build.gradle index 0ea2a0b..7608cf2 100644 --- a/qilin.microben/build.gradle +++ b/qilin.microben/build.gradle @@ -8,13 +8,6 @@ version '1.0-SNAPSHOT' repositories { mavenCentral() } -sourceSets.test { +sourceSets.main { java.srcDirs = ['src'] -} -test { - useJUnit() - maxHeapSize = '30G' -} -dependencies { - implementation(project(':qilin.pta')) } \ No newline at end of file diff --git a/qilin.microben/build.xml b/qilin.microben/build.xml new file mode 100644 index 0000000..8566ded --- /dev/null +++ b/qilin.microben/build.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/qilin.pta/build.gradle b/qilin.pta/build.gradle index 40725f3..6a5e2c1 100644 --- a/qilin.pta/build.gradle +++ b/qilin.pta/build.gradle @@ -6,6 +6,10 @@ sourceSets.main { java.srcDirs = ['src'] } +sourceSets.test { + java.srcDirs = ['test'] +} + repositories { maven { url "https://repo1.maven.org/maven2/" } flatDir { @@ -13,6 +17,13 @@ repositories { } } +sourceCompatibility = 16 + +test { + useJUnit() + maxHeapSize = '30G' +} + dependencies { api(project(':qilin.core')) // https://mvnrepository.com/artifact/commons-cli/commons-cli diff --git a/qilin.pta/src/qilin/pta/toolkits/bean/oag/OAG.java b/qilin.pta/src/qilin/pta/toolkits/bean/oag/OAG.java index cf318fa..4fe8fff 100644 --- a/qilin.pta/src/qilin/pta/toolkits/bean/oag/OAG.java +++ b/qilin.pta/src/qilin/pta/toolkits/bean/oag/OAG.java @@ -189,11 +189,11 @@ private void computeTailNodes() { } /* - * utilities - * */ + * utilities + * */ public void dumpToDot() { Vector vec = constructOAGDotString(); - for(int idx = 0; idx < vec.size(); ++idx) { + for (int idx = 0; idx < vec.size(); ++idx) { String fileName = "a" + idx + ".dot"; try { FileOutputStream fos = new FileOutputStream(fileName); @@ -221,11 +221,11 @@ private int getNodeID(Object node) { private Vector constructOAGDotString() { Vector vector = new Vector<>(); - rootNodes().stream().filter(x -> !tailNodes().contains(x)).forEach( root -> { + rootNodes().stream().filter(x -> !tailNodes().contains(x)).forEach(root -> { Set reachs = computeReachableNodes(root); StringBuilder dumpString = new StringBuilder(); dumpString.append("digraph G {\n"); - for(Node x : reachs) { + for (Node x : reachs) { x.getSuccs().forEach(y -> { dumpString.append(addEdgeString(x, y)); }); diff --git a/qilin.pta/src/qilin/pta/toolkits/turner/Turner.java b/qilin.pta/src/qilin/pta/toolkits/turner/Turner.java index 47c2eb6..6822b1b 100644 --- a/qilin.pta/src/qilin/pta/toolkits/turner/Turner.java +++ b/qilin.pta/src/qilin/pta/toolkits/turner/Turner.java @@ -198,8 +198,8 @@ private void mystat(SCCMergedGraph scccg) { int sccCntGtW = 0; int maxScc = 0; double avgScc = 0.0; - double avgSccGtW = 0.0; - for(MergedNode scc: scccg.allNodes()) { + double avgSccGtW = 0.0; + for (MergedNode scc : scccg.allNodes()) { int sccSize = scc.getContent().size(); if (sccSize > maxScc) { maxScc = sccSize; @@ -213,9 +213,9 @@ private void mystat(SCCMergedGraph scccg) { avgScc /= sccCnt; avgSccGtW /= sccCntGtW; int[] dist = new int[maxScc + 1]; - for(MergedNode scc: scccg.allNodes()) { + for (MergedNode scc : scccg.allNodes()) { int sccSize = scc.getContent().size(); - dist[sccSize] ++; + dist[sccSize]++; } System.out.println("#scc count:" + sccCnt); System.out.println("#scc count (exclude singleton):" + sccCntGtW); @@ -223,7 +223,7 @@ private void mystat(SCCMergedGraph scccg) { System.out.println("Average scc size(exclude singleton):" + avgSccGtW); System.out.println("Maximum scc size:" + maxScc); System.out.println("Scc size distribution (size, count):"); - for(int i = 0; i <= maxScc; ++i) { + for (int i = 0; i <= maxScc; ++i) { if (dist[i] > 0) { System.out.println(i + "," + dist[i]); } diff --git a/qilin.pta/src/qilin/pta/toolkits/zipper/pta/WrapperedPointsToAnalysis.java b/qilin.pta/src/qilin/pta/toolkits/zipper/pta/WrapperedPointsToAnalysis.java index 8072048..078b649 100644 --- a/qilin.pta/src/qilin/pta/toolkits/zipper/pta/WrapperedPointsToAnalysis.java +++ b/qilin.pta/src/qilin/pta/toolkits/zipper/pta/WrapperedPointsToAnalysis.java @@ -351,7 +351,7 @@ public VarNode assignedVarOf(final AllocNode obj) { private void computeAllocatedObjects() { this.allocatedHeaps = new HashMap<>(); - for(AllocNode alloc : prePTA.getPag().getAllocNodeNumberer()) { + for (AllocNode alloc : prePTA.getPag().getAllocNodeNumberer()) { if (alloc.getMethod() == null) {//TODO special objects? continue; } @@ -367,7 +367,7 @@ private void buildCallees() { final Map callIn = new HashMap<>(); final Map callBase = new HashMap<>(); - for(final MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (final MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod sig = momc.method(); prePTA.getPag().getMethodPAG(sig).invokeStmts.forEach(s -> { callIn.put(s, sig); @@ -418,7 +418,7 @@ private void buildMethodsInvokedOnObjects() { private void buildVarDeclaringMethods() { this.var2declaringMethod = new HashMap<>(); this.declaringMethod2var = new HashMap<>(); - for(ValNode valnode : prePTA.getPag().getValNodeNumberer()) { + for (ValNode valnode : prePTA.getPag().getValNodeNumberer()) { if (!(valnode instanceof LocalVarNode lvn)) { continue; } @@ -430,7 +430,7 @@ private void buildVarDeclaringMethods() { private void buildObjectAssignedVariables() { this.objAssignedTo = new HashMap<>(); - for(final MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (final MethodOrMethodContext momc : prePTA.getReachableMethods()) { MethodPAG mpag = prePTA.getPag().getMethodPAG(momc.method()); QueueReader reader = mpag.getInternalReader().clone(); while (reader.hasNext()) { diff --git a/qilin.pta/src/qilin/pta/tools/BasePTA.java b/qilin.pta/src/qilin/pta/tools/BasePTA.java new file mode 100644 index 0000000..75ff1a6 --- /dev/null +++ b/qilin.pta/src/qilin/pta/tools/BasePTA.java @@ -0,0 +1,24 @@ +package qilin.pta.tools; + +import qilin.core.CorePTA; +import qilin.core.builder.CallGraphBuilder; +import qilin.core.pag.PAG; +import qilin.core.solver.Propagator; +import qilin.core.solver.Solver; + +public class BasePTA extends CorePTA { + @Override + protected PAG createPAG() { + return new PAG(this); + } + + @Override + protected CallGraphBuilder createCallGraphBuilder() { + return new CallGraphBuilder(this); + } + + @Override + public Propagator getPropagator() { + return new Solver(this); + } +} diff --git a/qilin.pta/src/qilin/pta/tools/BeanPTA.java b/qilin.pta/src/qilin/pta/tools/BeanPTA.java index 1e7ae81..8a16131 100644 --- a/qilin.pta/src/qilin/pta/tools/BeanPTA.java +++ b/qilin.pta/src/qilin/pta/tools/BeanPTA.java @@ -36,7 +36,7 @@ /* * refer to "Making k-Object-Sensitive Pointer Analysis More Precise with Still k-Limiting" (SAS'16) * */ -public class BeanPTA extends CorePTA { +public class BeanPTA extends BasePTA { private final CorePTA prePTA; // currently, we only support k = 2 and hk = 1; // [current heap, [allocator heap, [heap ctx, new ctx]]] only for B-2obj; diff --git a/qilin.pta/src/qilin/pta/tools/CallSiteSensPTA.java b/qilin.pta/src/qilin/pta/tools/CallSiteSensPTA.java index 164ca2b..854095b 100644 --- a/qilin.pta/src/qilin/pta/tools/CallSiteSensPTA.java +++ b/qilin.pta/src/qilin/pta/tools/CallSiteSensPTA.java @@ -32,7 +32,7 @@ * refer to "Two approaches to interprocedural data flow analysis" (PFA 1981) * */ -public class CallSiteSensPTA extends CorePTA { +public class CallSiteSensPTA extends BasePTA { public CallSiteSensPTA(int k, int hk) { this.ctxCons = new CallsiteCtxConstructor(); diff --git a/qilin.pta/src/qilin/pta/tools/DataDrivenPTA.java b/qilin.pta/src/qilin/pta/tools/DataDrivenPTA.java index f1eb954..f4fc913 100644 --- a/qilin.pta/src/qilin/pta/tools/DataDrivenPTA.java +++ b/qilin.pta/src/qilin/pta/tools/DataDrivenPTA.java @@ -37,7 +37,7 @@ * as claimed in the paper. Maybe we should retrain the formulas in our framework. * */ -public class DataDrivenPTA extends CorePTA { +public class DataDrivenPTA extends BasePTA { public DataDrivenPTA(CtxConstructor ctxCons) { this.ctxCons = ctxCons; diff --git a/qilin.pta/src/qilin/pta/tools/HybridObjectSensPTA.java b/qilin.pta/src/qilin/pta/tools/HybridObjectSensPTA.java index a38a9ed..bc5277a 100644 --- a/qilin.pta/src/qilin/pta/tools/HybridObjectSensPTA.java +++ b/qilin.pta/src/qilin/pta/tools/HybridObjectSensPTA.java @@ -31,7 +31,7 @@ /** * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) */ -public class HybridObjectSensPTA extends CorePTA { +public class HybridObjectSensPTA extends BasePTA { public HybridObjectSensPTA(int k, int hk) { this.ctxCons = new HybObjCtxConstructor(); diff --git a/qilin.pta/src/qilin/pta/tools/HybridTypeSensPTA.java b/qilin.pta/src/qilin/pta/tools/HybridTypeSensPTA.java index 8806b3a..deb26c6 100644 --- a/qilin.pta/src/qilin/pta/tools/HybridTypeSensPTA.java +++ b/qilin.pta/src/qilin/pta/tools/HybridTypeSensPTA.java @@ -32,7 +32,7 @@ * refer to "Hybrid Context-Sensitivity for Points-To Analysis" (PLDI'13) */ -public class HybridTypeSensPTA extends CorePTA { +public class HybridTypeSensPTA extends BasePTA { public HybridTypeSensPTA(int k, int hk) { this.ctxCons = new HybTypeCtxConstructor(); diff --git a/qilin.pta/src/qilin/pta/tools/MahjongPTA.java b/qilin.pta/src/qilin/pta/tools/MahjongPTA.java index 6539630..54ddef8 100644 --- a/qilin.pta/src/qilin/pta/tools/MahjongPTA.java +++ b/qilin.pta/src/qilin/pta/tools/MahjongPTA.java @@ -38,7 +38,7 @@ /* * refer to "Efficient and Precise Points-to Analysis: Modeling the Heap by Merging Equivalent Automata" (PLDI'17) * */ -public class MahjongPTA extends CorePTA { +public class MahjongPTA extends BasePTA { protected final Map heapModelMap = new HashMap<>(); public Set mergedHeap = new HashSet<>(); public Set csHeap = new HashSet<>(); diff --git a/qilin.pta/src/qilin/pta/tools/ObjectSensPTA.java b/qilin.pta/src/qilin/pta/tools/ObjectSensPTA.java index e0552b6..df2d137 100644 --- a/qilin.pta/src/qilin/pta/tools/ObjectSensPTA.java +++ b/qilin.pta/src/qilin/pta/tools/ObjectSensPTA.java @@ -31,7 +31,7 @@ /* * refer to "Parameterized object sensitivity for points-to analysis for Java" (TSE'05) * */ -public class ObjectSensPTA extends CorePTA { +public class ObjectSensPTA extends BasePTA { public ObjectSensPTA(int k, int hk) { this.ctxCons = new ObjCtxConstructor(); CtxSelector us = new UniformSelector(k, hk); diff --git a/qilin.pta/src/qilin/pta/tools/PartialCallSiteSensPTA.java b/qilin.pta/src/qilin/pta/tools/PartialCallSiteSensPTA.java index 5212191..a659a02 100644 --- a/qilin.pta/src/qilin/pta/tools/PartialCallSiteSensPTA.java +++ b/qilin.pta/src/qilin/pta/tools/PartialCallSiteSensPTA.java @@ -38,7 +38,7 @@ import java.util.Map; import java.util.Set; -public abstract class PartialCallSiteSensPTA extends CorePTA { +public abstract class PartialCallSiteSensPTA extends BasePTA { protected Set csnodes = new HashSet<>(); protected Set csmethods = new HashSet<>(); protected CorePTA prePTA; @@ -118,7 +118,7 @@ protected void select() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for(MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); if (method.isPhantom()) { diff --git a/qilin.pta/src/qilin/pta/tools/PartialObjSensPTA.java b/qilin.pta/src/qilin/pta/tools/PartialObjSensPTA.java index 6f7d412..b92f45f 100644 --- a/qilin.pta/src/qilin/pta/tools/PartialObjSensPTA.java +++ b/qilin.pta/src/qilin/pta/tools/PartialObjSensPTA.java @@ -18,7 +18,6 @@ package qilin.pta.tools; -import qilin.core.CorePTA; import qilin.core.pag.*; import qilin.parm.ctxcons.ObjCtxConstructor; import qilin.parm.heapabst.AllocSiteAbstractor; @@ -38,10 +37,10 @@ import java.util.Map; import java.util.Set; -public abstract class PartialObjSensPTA extends CorePTA { +public abstract class PartialObjSensPTA extends BasePTA { protected Set csnodes = new HashSet<>(); protected Set csmethods = new HashSet<>(); - protected CorePTA prePTA; + protected BasePTA prePTA; protected PAG prePAG; // just for stats @@ -118,7 +117,7 @@ protected void select() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1], totalN = new int[1]; - for(MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); if (method.isPhantom()) { diff --git a/qilin.pta/src/qilin/pta/tools/Spark.java b/qilin.pta/src/qilin/pta/tools/Spark.java index cdd6871..6f8de9d 100644 --- a/qilin.pta/src/qilin/pta/tools/Spark.java +++ b/qilin.pta/src/qilin/pta/tools/Spark.java @@ -19,6 +19,7 @@ package qilin.pta.tools; import qilin.core.CorePTA; +import qilin.core.pag.PAG; import qilin.parm.ctxcons.InsensCtxConstructor; import qilin.parm.heapabst.AllocSiteAbstractor; import qilin.parm.heapabst.HeuristicAbstractor; @@ -28,7 +29,7 @@ /* * refer to "Scaling Java Points-To Analysis using SPARK" (CC'03) * */ -public class Spark extends CorePTA { +public class Spark extends BasePTA { public Spark() { this.ctxCons = new InsensCtxConstructor(); this.ctxSel = new InsenSelector(); diff --git a/qilin.pta/src/qilin/pta/tools/TunnelingPTA.java b/qilin.pta/src/qilin/pta/tools/TunnelingPTA.java index 55163d6..5523720 100644 --- a/qilin.pta/src/qilin/pta/tools/TunnelingPTA.java +++ b/qilin.pta/src/qilin/pta/tools/TunnelingPTA.java @@ -19,6 +19,7 @@ package qilin.pta.tools; import qilin.core.CorePTA; +import qilin.core.pag.PAG; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.AllocSiteAbstractor; import qilin.parm.heapabst.HeuristicAbstractor; @@ -34,7 +35,7 @@ * Context Tunneling" (OOPSLA 2018). We reuse the trained formula from the paper. However, our evaluation does * not show the claimed effectiveness. Maybe we should train the benchmarks to get new formulas? * */ -public class TunnelingPTA extends CorePTA { +public class TunnelingPTA extends BasePTA { public TunnelingPTA(CtxConstructor ctxCons, int k, int hk) { this.ctxCons = new TunnelingConstructor(ctxCons); CtxSelector us = new UniformSelector(k, hk); diff --git a/qilin.pta/src/qilin/pta/tools/TypeSensPTA.java b/qilin.pta/src/qilin/pta/tools/TypeSensPTA.java index ebc31bb..f0cfea4 100644 --- a/qilin.pta/src/qilin/pta/tools/TypeSensPTA.java +++ b/qilin.pta/src/qilin/pta/tools/TypeSensPTA.java @@ -31,7 +31,7 @@ /* * refer to "Pick Your Contexts Well: Understanding Object-Sensitivity" (PLDI'11) * */ -public class TypeSensPTA extends CorePTA { +public class TypeSensPTA extends BasePTA { public TypeSensPTA(int k, int hk) { this.ctxCons = new TypeCtxConstructor(); diff --git a/qilin.pta/src/qilin/pta/tools/ZipperPTA.java b/qilin.pta/src/qilin/pta/tools/ZipperPTA.java index c7965fd..b114d4f 100644 --- a/qilin.pta/src/qilin/pta/tools/ZipperPTA.java +++ b/qilin.pta/src/qilin/pta/tools/ZipperPTA.java @@ -18,7 +18,6 @@ package qilin.pta.tools; -import qilin.core.CorePTA; import qilin.core.pag.*; import qilin.parm.ctxcons.CtxConstructor; import qilin.parm.heapabst.AllocSiteAbstractor; @@ -41,8 +40,8 @@ * refer to "Precision-Guided Context Sensitivity for Pointer Analysis" (OOPSLA'18) * and "A Principled Approach to Selective Context Sensitivity for Pointer Analysis" (TOPLAS'20) * */ -public class ZipperPTA extends CorePTA { - private final CorePTA prePTA; +public class ZipperPTA extends BasePTA { + private final BasePTA prePTA; private final Set PCMs = new HashSet<>(); /* @@ -87,7 +86,7 @@ public void run() { protected void extraStats() { int[] RM = new int[1], PCN = new int[1], NPCN = new int[1]; int[] totalN = new int[1]; - for(MethodOrMethodContext momc : prePTA.getReachableMethods()) { + for (MethodOrMethodContext momc : prePTA.getReachableMethods()) { SootMethod method = momc.method(); Set nodes = new HashSet<>(); diff --git a/qilin.microben/src/qilin/test/FlowSensTests.java b/qilin.pta/test/qilin/test/FlowSensTests.java similarity index 100% rename from qilin.microben/src/qilin/test/FlowSensTests.java rename to qilin.pta/test/qilin/test/FlowSensTests.java diff --git a/qilin.pta/test/qilin/test/SummaryTests.java b/qilin.pta/test/qilin/test/SummaryTests.java new file mode 100644 index 0000000..891c36c --- /dev/null +++ b/qilin.pta/test/qilin/test/SummaryTests.java @@ -0,0 +1,145 @@ +package qilin.test; + +import driver.Main; +import org.junit.Test; +import qilin.test.util.JunitTests; + +public class SummaryTests extends JunitTests { + + @Override + public String[] generateArguments(String mainClass) { + return generateArguments(mainClass, "sum-insens"); + } + + @Test + public void testArrays() { + String[] args = generateArguments("qilin.microben.summary.Array"); + checkAssertions(Main.run(args)); + } + +// @Test +// public void testBug() { +// String[] args = generateArguments("qilin.microben.summary.Bug"); +// checkAssertions(Main.run(args)); +// } + + @Test + public void testCallback() { + String[] args = generateArguments("qilin.microben.summary.Callback"); + checkAssertions(Main.run(args)); + } + + @Test + public void testCast() { + String[] args = generateArguments("qilin.microben.summary.Cast"); + checkAssertions(Main.run(args)); + } + + @Test + public void testCommonAlloc() { + String[] args = generateArguments("qilin.microben.summary.CommonAlloc"); + checkAssertions(Main.run(args)); + } + + @Test + public void testCommonCall() { + String[] args = generateArguments("qilin.microben.summary.CommonCall"); + checkAssertions(Main.run(args)); + } + + @Test + public void testConstant() { + String[] args = generateArguments("qilin.microben.summary.Constant"); + checkAssertions(Main.run(args)); + } + + @Test + public void testCSAlloc() { + String[] args = generateArguments("qilin.microben.summary.CSAlloc"); + checkAssertions(Main.run(args)); + } + + @Test + public void testDynamic() { + String[] args = generateArguments("qilin.microben.summary.Dynamic"); + checkAssertions(Main.run(args)); + } + + @Test + public void testException() { + String[] args = generateArguments("qilin.microben.summary.Exception"); + checkAssertions(Main.run(args)); + } + + @Test + public void testGetter() { + String[] args = generateArguments("qilin.microben.summary.Getter"); + checkAssertions(Main.run(args)); + } + + @Test + public void testGlobal() { + String[] args = generateArguments("qilin.microben.summary.Global"); + checkAssertions(Main.run(args)); + } + + @Test + public void testId() { + String[] args = generateArguments("qilin.microben.summary.Id"); + checkAssertions(Main.run(args)); + } + + @Test + public void testId2() { + String[] args = generateArguments("qilin.microben.summary.Id2"); + checkAssertions(Main.run(args)); + } + + @Test + public void testId_V() { + String[] args = generateArguments("qilin.microben.summary.Id_V"); + checkAssertions(Main.run(args)); + } + + @Test + public void testInnerVirtual() { + String[] args = generateArguments("qilin.microben.summary.InnerVirtual"); + checkAssertions(Main.run(args)); + } + + @Test + public void testLoadCycle() { + String[] args = generateArguments("qilin.microben.summary.LoadCycle"); + checkAssertions(Main.run(args)); + } + + @Test + public void testMerged() { + String[] args = generateArguments("qilin.microben.summary.Merged"); + checkAssertions(Main.run(args)); + } + + @Test + public void testMultiArray() { + String[] args = generateArguments("qilin.microben.summary.MultiArray"); + checkAssertions(Main.run(args)); + } + + @Test + public void testPartialDynamic() { + String[] args = generateArguments("qilin.microben.summary.PartialDynamic"); + checkAssertions(Main.run(args)); + } + + @Test + public void testReturnCycle() { + String[] args = generateArguments("qilin.microben.summary.ReturnCycle"); + checkAssertions(Main.run(args)); + } + + @Test + public void testSetter() { + String[] args = generateArguments("qilin.microben.summary.Setter"); + checkAssertions(Main.run(args)); + } +} diff --git a/qilin.microben/src/qilin/test/context/CFATests.java b/qilin.pta/test/qilin/test/context/CFATests.java similarity index 100% rename from qilin.microben/src/qilin/test/context/CFATests.java rename to qilin.pta/test/qilin/test/context/CFATests.java diff --git a/qilin.microben/src/qilin/test/context/CollectionsTests.java b/qilin.pta/test/qilin/test/context/CollectionsTests.java similarity index 100% rename from qilin.microben/src/qilin/test/context/CollectionsTests.java rename to qilin.pta/test/qilin/test/context/CollectionsTests.java diff --git a/qilin.microben/src/qilin/test/context/HybTests.java b/qilin.pta/test/qilin/test/context/HybTests.java similarity index 100% rename from qilin.microben/src/qilin/test/context/HybTests.java rename to qilin.pta/test/qilin/test/context/HybTests.java diff --git a/qilin.microben/src/qilin/test/context/OBJTests.java b/qilin.pta/test/qilin/test/context/OBJTests.java similarity index 100% rename from qilin.microben/src/qilin/test/context/OBJTests.java rename to qilin.pta/test/qilin/test/context/OBJTests.java diff --git a/qilin.microben/src/qilin/test/context/TypeTests.java b/qilin.pta/test/qilin/test/context/TypeTests.java similarity index 100% rename from qilin.microben/src/qilin/test/context/TypeTests.java rename to qilin.pta/test/qilin/test/context/TypeTests.java diff --git a/qilin.microben/src/qilin/test/core/ArrayTests.java b/qilin.pta/test/qilin/test/core/ArrayTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/ArrayTests.java rename to qilin.pta/test/qilin/test/core/ArrayTests.java diff --git a/qilin.microben/src/qilin/test/core/AssignTests.java b/qilin.pta/test/qilin/test/core/AssignTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/AssignTests.java rename to qilin.pta/test/qilin/test/core/AssignTests.java diff --git a/qilin.microben/src/qilin/test/core/CallTests.java b/qilin.pta/test/qilin/test/core/CallTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/CallTests.java rename to qilin.pta/test/qilin/test/core/CallTests.java diff --git a/qilin.microben/src/qilin/test/core/ClinitTests.java b/qilin.pta/test/qilin/test/core/ClinitTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/ClinitTests.java rename to qilin.pta/test/qilin/test/core/ClinitTests.java diff --git a/qilin.microben/src/qilin/test/core/ExceptionTests.java b/qilin.pta/test/qilin/test/core/ExceptionTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/ExceptionTests.java rename to qilin.pta/test/qilin/test/core/ExceptionTests.java diff --git a/qilin.microben/src/qilin/test/core/FieldTests.java b/qilin.pta/test/qilin/test/core/FieldTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/FieldTests.java rename to qilin.pta/test/qilin/test/core/FieldTests.java diff --git a/qilin.microben/src/qilin/test/core/GlobalTests.java b/qilin.pta/test/qilin/test/core/GlobalTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/GlobalTests.java rename to qilin.pta/test/qilin/test/core/GlobalTests.java diff --git a/qilin.microben/src/qilin/test/core/NativeTests.java b/qilin.pta/test/qilin/test/core/NativeTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/NativeTests.java rename to qilin.pta/test/qilin/test/core/NativeTests.java diff --git a/qilin.microben/src/qilin/test/core/ReflogTests.java b/qilin.pta/test/qilin/test/core/ReflogTests.java similarity index 100% rename from qilin.microben/src/qilin/test/core/ReflogTests.java rename to qilin.pta/test/qilin/test/core/ReflogTests.java diff --git a/qilin.microben/src/qilin/test/util/AliasAssertion.java b/qilin.pta/test/qilin/test/util/AliasAssertion.java similarity index 100% rename from qilin.microben/src/qilin/test/util/AliasAssertion.java rename to qilin.pta/test/qilin/test/util/AliasAssertion.java diff --git a/qilin.microben/src/qilin/test/util/AssertionsParser.java b/qilin.pta/test/qilin/test/util/AssertionsParser.java similarity index 100% rename from qilin.microben/src/qilin/test/util/AssertionsParser.java rename to qilin.pta/test/qilin/test/util/AssertionsParser.java diff --git a/qilin.microben/src/qilin/test/util/IAssertion.java b/qilin.pta/test/qilin/test/util/IAssertion.java similarity index 100% rename from qilin.microben/src/qilin/test/util/IAssertion.java rename to qilin.pta/test/qilin/test/util/IAssertion.java diff --git a/qilin.microben/src/qilin/test/util/JunitTests.java b/qilin.pta/test/qilin/test/util/JunitTests.java similarity index 90% rename from qilin.microben/src/qilin/test/util/JunitTests.java rename to qilin.pta/test/qilin/test/util/JunitTests.java index f1adb3b..f2e823f 100644 --- a/qilin.microben/src/qilin/test/util/JunitTests.java +++ b/qilin.pta/test/qilin/test/util/JunitTests.java @@ -35,10 +35,11 @@ public abstract class JunitTests { @BeforeClass public static void setUp() throws IOException { - File currentDir = new File("."); - File testDir = new File(currentDir, "build" + File.separator + "classes" + File.separator + "java" + File.separator + "test"); + File rootDir = new File("../"); + File testDir = new File(rootDir, "qilin.microben" + File.separator + "classes"); appPath = testDir.getCanonicalPath(); - File refLogDir = new File(currentDir, "src" + File.separator + "qilin" + File.separator + "microben" + File.separator + "core" + File.separator + "reflog"); + System.out.println(appPath); + File refLogDir = new File(rootDir, "src" + File.separator + "qilin" + File.separator + "microben" + File.separator + "core" + File.separator + "reflog"); refLogPath = refLogDir.getCanonicalPath(); File jreFile = new File(".." + File.separator + "artifact" + File.separator + "pta" + File.separator + "lib" + File.separator + "jre" + File.separator + "jre1.6.0_45"); diff --git a/qilin.util/src/qilin/util/queue/UniqueQueue.java b/qilin.util/src/qilin/util/queue/UniqueQueue.java index c146fbe..3aaa689 100644 --- a/qilin.util/src/qilin/util/queue/UniqueQueue.java +++ b/qilin.util/src/qilin/util/queue/UniqueQueue.java @@ -28,6 +28,7 @@ public UniqueQueue() { this.set = new HashSet<>(); this.queue = new LinkedList<>(); } + @Override public boolean add(T t) { if (set.contains(t)) {