Skip to content

Commit

Permalink
refactoring changes: 1. for merged objects, we provide a MergedNewExp…
Browse files Browse the repository at this point in the history
…r 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-
  • Loading branch information
Dongjie committed Feb 3, 2022
1 parent e426f3a commit bcf008e
Show file tree
Hide file tree
Showing 54 changed files with 377 additions and 492 deletions.
10 changes: 3 additions & 7 deletions qilin.core/src/qilin/core/CorePTA.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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) {
Expand Down Expand Up @@ -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)) {
Expand Down
18 changes: 14 additions & 4 deletions qilin.core/src/qilin/core/PTA.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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();
Expand Down
15 changes: 1 addition & 14 deletions qilin.core/src/qilin/core/builder/CallGraphBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -40,7 +39,6 @@
public class CallGraphBuilder {
protected final RefType clRunnable = RefType.v("java.lang.Runnable");

protected final Map<VarNode, Collection<Pair<MethodOrMethodContext, Unit>>> receiverToStaticSites;
protected final Map<VarNode, Collection<VirtualCallSite>> receiverToSites;
protected final Map<Type, Map<Unit, Set<SootMethod>>> dispatchCache;
protected final Map<SootMethod, Map<Object, Stmt>> methodToInvokeStmt;
Expand All @@ -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<>();
Expand All @@ -68,11 +65,6 @@ public Collection<MethodOrMethodContext> getReachableMethods() {
return reachMethods;
}

// for Manu's ondemand pta.
public Map<VarNode, Collection<Pair<MethodOrMethodContext, Unit>>> 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<VarNode, Collection<VirtualCallSite>> getReceiverToSitesMap() {
Expand Down Expand Up @@ -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)) {
Expand All @@ -216,11 +208,6 @@ public boolean recordVirtualCallSite(VarNode receiver, VirtualCallSite site) {
return sites.add(site);
}

public void recordStaticCallSite(VarNode receiver, Pair<MethodOrMethodContext, Unit> site) {
Collection<Pair<MethodOrMethodContext, Unit>> 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) {
Expand Down
1 change: 0 additions & 1 deletion qilin.core/src/qilin/core/builder/MethodNodeFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import soot.jimple.internal.JNewArrayExpr;

/**
*
* @author Ondrej Lhotak
*/
public class MethodNodeFactory extends AbstractJimpleValueSwitch<Node> {
Expand Down
20 changes: 20 additions & 0 deletions qilin.core/src/qilin/core/pag/MergedNewExpr.java
Original file line number Diff line number Diff line change
@@ -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<RefType, MergedNewExpr> map = new HashMap<>();

private MergedNewExpr(RefType type) {
super(type);
}

public static MergedNewExpr v(RefType type) {
return map.computeIfAbsent(type, k -> new MergedNewExpr(type));
}

}
87 changes: 8 additions & 79 deletions qilin.core/src/qilin/core/pag/MethodPAG.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -43,6 +42,7 @@ public class MethodPAG {
private final QueueReader<Node> internalReader = internalEdges.reader();
private final Set<SootMethod> clinits = new HashSet<>();
public Collection<Unit> 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.
Expand All @@ -60,10 +60,11 @@ public class MethodPAG {
public final Map<Stmt, List<Trap>> stmt2wrapperedTraps = new HashMap<>();
public final Map<Node, Map<Stmt, List<Trap>>> 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();
}

Expand All @@ -84,87 +85,16 @@ protected void build() {
if (method.getSignature().equals("<org.apache.xerces.parsers.XML11Configuration: boolean getFeature0(java.lang.String)>")) {
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
* <java.lang.System: void arraycopy(java.lang.Object,int,java.lang.Object,int,int)>
* directly to its caller methods.
* */
if (PTAScene.v().arraycopyBuilt.add(method)) {
handleArrayCopy();
}
}
}

private void handleArrayCopy() {
Map<Unit, Collection<Unit>> 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("<java.lang.System: void arraycopy(java.lang.Object,int,java.lang.Object,int,int)>")) {
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) {
Expand All @@ -178,7 +108,6 @@ protected void buildException() {
if (!CoreConfig.v().getPtaConfig().preciseExceptions) {
return;
}
Body body = PTAUtils.getMethodBody(method);
Chain<Trap> traps = body.getTraps();
PatchingChain<Unit> units = body.getUnits();
Set<Unit> inTraps = new HashSet<>();
Expand Down
Loading

0 comments on commit bcf008e

Please sign in to comment.