Skip to content

Commit

Permalink
add missing reflog files; add SimplifiedEvaluator; refactor code
Browse files Browse the repository at this point in the history
  • Loading branch information
Dongjie committed Aug 8, 2022
1 parent cfdcf45 commit 30c9316
Show file tree
Hide file tree
Showing 60 changed files with 1,081 additions and 1,446 deletions.
1 change: 0 additions & 1 deletion docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ <h2>
<p>Dongjie He, Jingbo Lu, and Jingling Xue <a href ="">Qilin: A New Framework for Supporting Fine-Grained Context-Sensitivity in Java Pointer Analysis</a>, 36th European Conference on Object-Oriented Programming (ECOOP'22)</p>
<p>Dongjie He, Jingbo Lu, Yaoqing Gao, and Jingling Xue <a href ="https://doi.org/10.1109/TSE.2022.3162236">Selecting Context-Sensitivity Modularly for Accelerating Object-Sensitive Pointer Analysis</a>, IEEE Transactions on Software Engineering (TSE'22)</p>
<p>Dongjie He, Jingbo Lu, and Jingling Xue <a href ="https://doi.org/10.1109/ASE51524.2021.9678880">Context Debloating for Object-Sensitive Pointer Analysis</a>, 36th IEEE/ACM International Conference on Automated Software Engineering (ASE'21)</p>
<p>Jingbo Lu, Dongjie He, and Jingling Xue <a href ="https://doi.org/10.1007/978-3-030-88806-0_13">Selective Context-Sensitivity for k-CFA with CFL-Reachability</a>, 28th International Static Analysis Symposium (SAS'21)</p>
<p>Dongjie He, Jingbo Lu, Yaoqing Gao, and Jingling Xue <a href ="https://doi.org/10.4230/LIPIcs.ECOOP.2021.16">Accelerating Object-Sensitive Pointer Analysis by Exploiting Object Containment and Reachability</a>, 35th European Conference on Object-Oriented Programming (ECOOP'21)</p>
<p>Jingbo Lu, Dongjie He, and Jingling Xue <a href ="https://doi.org/10.1145/3450492">Eagle: CFL-Reachability-based Precision-Preserving Acceleration of Object-Sensitive Pointer Analysis</a>, ACM Transactions on Software Engineering and Methodology (TOSEM 2021)</p>
<p>Jingbo Lu and Jingling Xue <a href="https://doi.org/10.1145/3360574">Precision-Preserving Yet Fast Object-Sensitive Pointer Analysis with Partial Context Sensitivity</a>. ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages, and Applications (OOPSLA'19) </p>
Expand Down
2 changes: 1 addition & 1 deletion qilin.core/src/qilin/core/solver/Solver.java
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,7 @@ protected void propagatePTS(final ValNode pointer, PointsToSetInternal other) {
P2SetVisitor p2SetVisitor = new P2SetVisitor() {
@Override
public void visit(Node n) {
if(addTo.add(n)) {
if (addTo.add(n)) {
returnValue = true;
}
}
Expand Down
192 changes: 192 additions & 0 deletions qilin.core/src/qilin/stat/SimplifiedEvaluator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package qilin.stat;

import qilin.core.PTA;
import qilin.core.builder.FakeMainFactory;
import qilin.core.builder.MethodNodeFactory;
import qilin.core.pag.*;
import qilin.core.sets.P2SetVisitor;
import qilin.core.sets.PointsToSetInternal;
import qilin.util.PTAUtils;
import qilin.util.Stopwatch;
import soot.*;
import soot.jimple.*;
import soot.jimple.toolkits.callgraph.CallGraph;
import soot.jimple.toolkits.callgraph.Edge;

import java.util.*;

public class SimplifiedEvaluator implements IEvaluator {
protected final PTA pta;
protected final Exporter exporter;
protected Stopwatch stopwatch;

public SimplifiedEvaluator(PTA pta) {
this.pta = pta;
exporter = new Exporter();
}

@Override
public void begin() {
stopwatch = Stopwatch.newAndStart("PTA evaluator");
}

@Override
public void end() {
stopwatch.stop();
exporter.collectMetric("Time (sec):", String.valueOf(((double) stopwatch.elapsed())));
exporter.collectMetric("#Reachable Method (CI):", String.valueOf(pta.getNakedReachableMethods().size() - 1));
CallGraph ciCallGraph = pta.getCallGraph();
exporter.collectMetric("#Call Edge(CI):", String.valueOf(ciCallGraph.size() - FakeMainFactory.implicitCallEdges));

CallGraph callGraph = pta.getCallGraph();

// loop over all reachable method's statement to find casts, local
// references, virtual call sites
Set<SootMethod> reachableMethods = new HashSet<>();
for (MethodOrMethodContext momc : pta.getCgb().getReachableMethods()) {
final SootMethod sm = momc.method();
reachableMethods.add(sm);
}
int totalPolyCalls = 0;
int totalCastsMayFail = 0;
for (SootMethod sm : reachableMethods) {
// All the statements in the method
for (Unit unit : PTAUtils.getMethodBody(sm).getUnits()) {
Stmt st = (Stmt) unit;
// virtual calls
if (st.containsInvokeExpr()) {
InvokeExpr ie = st.getInvokeExpr();
if (!(ie instanceof StaticInvokeExpr)) {
// Virtual, Special or Instance
// have to check target soot method, cannot just
// count edges
Set<SootMethod> targets = new HashSet<>();
for (Iterator<Edge> it = callGraph.edgesOutOf(st); it.hasNext(); )
targets.add(it.next().tgt());
if (targets.size() > 1) {
totalPolyCalls++;
}
}
} else if (st instanceof AssignStmt) {
Value rhs = ((AssignStmt) st).getRightOp();
Value lhs = ((AssignStmt) st).getLeftOp();
if (rhs instanceof CastExpr && lhs.getType() instanceof RefLikeType) {
final Type targetType = ((CastExpr) rhs).getCastType();
Value v = ((CastExpr) rhs).getOp();
if (!(v instanceof Local)) {
continue;
}
boolean fails = false;
Set<Node> pts = new HashSet<>();
((PointsToSetInternal) pta.reachingObjects((Local) v)).mapToCIPointsToSet().forall(new P2SetVisitor() {
@Override
public void visit(Node n) {
pts.add(n);
}
});
for (Node n : pts) {
if (fails) {
break;
}
fails = !PTAUtils.castNeverFails(n.getType(), targetType);
}
if (fails) {
totalCastsMayFail++;
}
}
}
}
}
exporter.collectMetric("#May Fail Cast (Total):", String.valueOf(totalCastsMayFail));
exporter.collectMetric("#Virtual Call Site(Polymorphic):", String.valueOf(totalPolyCalls));

ptsStat();
}

private void ptsStat() {
int ptsCntNoNative = 0;
int varCntNoNative = 0;
// locals exclude Exceptions
for (Local local : pta.getPag().getLocalPointers()) {
try {
LocalVarNode lvn = pta.getPag().findLocalVarNode(local);
if (local.toString().contains("intermediate/")) {
continue;
}
mLocalVarNodes.add(lvn);
} catch (Exception e) {
e.printStackTrace();
}
}

// stat avg pts.
for (SootMethod sm : pta.getNakedReachableMethods()) {
MethodPAG mpag = pta.getPag().getMethodPAG(sm);
MethodNodeFactory mnf = mpag.nodeFactory();
if (!sm.isStatic()) {
mLocalVarNodes.add((LocalVarNode) mnf.caseThis());
}
for (int i = 0; i < sm.getParameterCount(); ++i) {
Type mType = sm.getParameterType(i);
if (mType instanceof RefLikeType) {
mLocalVarNodes.add((LocalVarNode) mnf.caseParm(i));
}
}
}
Set<LocalVarNode> tmp = new HashSet<>();
for (LocalVarNode lvn : mLocalVarNodes) {
SootMethod sm = lvn.getMethod();
if (PTAUtils.isFakeMainMethod(sm)) {
tmp.add(lvn);
continue;
}
PointsToSetInternal cpts = (PointsToSetInternal) pta.reachingObjects(lvn);
final Set<Object> callocSites = getPointsToNewExpr(cpts);
if (callocSites.size() > 0) {
if (!handledNatives.contains(sm.toString())) {
ptsCntNoNative += callocSites.size();
varCntNoNative++;
}
} else {
tmp.add(lvn);
}
}
mLocalVarNodes.removeAll(tmp);

exporter.collectMetric("#Avg Points-to Target without Native Var(CI):", String.valueOf(((double) ptsCntNoNative) / (varCntNoNative)));
}

private final Set<String> handledNatives = Set.of(
"<org.apache.xerces.parsers.XML11Configuration: boolean getFeature0(java.lang.String)>",
"<java.lang.ref.Finalizer: void invokeFinalizeMethod(java.lang.Object)>",
"<java.lang.Thread: java.lang.Thread currentThread()>",
"<java.lang.Thread: void start0()>",
"<java.lang.Object: java.lang.Object clone()>",
"<java.lang.System: void setIn0(java.io.InputStream)>",
"<java.lang.System: void setOut0(java.io.PrintStream)>",
"<java.lang.System: void setErr0(java.io.PrintStream)>",
"<java.io.FileSystem: java.io.FileSystem getFileSystem()>",
"<java.io.UnixFileSystem: java.lang.String[] list(java.io.File)>",
"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction)>",
"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)>",
"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction)>",
"<java.security.AccessController: java.lang.Object doPrivileged(java.security.PrivilegedExceptionAction,java.security.AccessControlContext)>"
);

private final Set<LocalVarNode> mLocalVarNodes = new HashSet<>();

protected Set<Object> getPointsToNewExpr(PointsToSetInternal pts) {
final Set<Object> allocSites = new HashSet<>();
pts.forall(new P2SetVisitor() {
public void visit(Node n) {
allocSites.add(((AllocNode) n).getNewExpr());
}
});
return allocSites;
}

@Override
public String toString() {
return exporter.report();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Array.newInstance;int[];qilin.microben.core.reflog.ArrayNewInstance.main;9;;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Class.forName;qilin.microben.core.reflog.ClassForName;qilin.microben.core.reflog.ClassForName.main;9;;
Class.forName;qilin.microben.core.reflog.ClassForName;qilin.microben.core.reflog.ClassForName.main;11;;
Class.forName;java.lang.Object;qilin.microben.core.reflog.ClassForName.main;13;;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Class.forName;qilin.microben.core.reflog.ClassForName1;qilin.microben.core.reflog.ClassForName1.main;9;;
Class.forName;qilin.microben.core.reflog.ClassForName1;qilin.microben.core.reflog.ClassForName1.main;11;;
Class.forName;java.lang.Object;qilin.microben.core.reflog.ClassForName1.main;13;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Class.newInstance;qilin.microben.core.reflog.ClassNewInstance;qilin.microben.core.reflog.ClassNewInstance.main;10;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Constructor.newInstance;<qilin.microben.core.reflog.ConstructorNewInstance: void <init>(java.lang.Object)>;qilin.microben.core.reflog.ConstructorNewInstance.main;17;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Field.get*;<javax.xml.xpath.XPathConstants: javax.xml.namespace.QName STRING>;qilin.microben.core.reflog.DoopRefBug.main;15;;
1 change: 1 addition & 0 deletions qilin.microben/src/qilin/microben/core/reflog/FieldGet.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Field.get*;<qilin.microben.core.reflog.FieldGet: java.lang.Object f>;qilin.microben.core.reflog.FieldGet.main;12;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Field.get*;<qilin.microben.core.reflog.FieldGetStatic: java.lang.Object f>;qilin.microben.core.reflog.FieldGetStatic.main;11;;
2 changes: 2 additions & 0 deletions qilin.microben/src/qilin/microben/core/reflog/FieldSet.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Field.set*;<qilin.microben.core.reflog.FieldSet: java.lang.Object f>;qilin.microben.core.reflog.FieldSet.main;13;;
Field.set*;<qilin.microben.core.reflog.FieldSet: java.lang.Object f>;qilin.microben.core.reflog.FieldSet.main;14;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Field.set*;<qilin.microben.core.reflog.FieldSetStatic: java.lang.Object f>;qilin.microben.core.reflog.FieldSetStatic.main;10;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Method.invoke;<qilin.microben.core.reflog.MethodInvoke: java.lang.Object id(java.lang.Object)>;qilin.microben.core.reflog.MethodInvoke.main;8;;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Method.invoke;<qilin.microben.core.reflog.MethodInvokeStatic: java.lang.Object id(java.lang.Object)>;qilin.microben.core.reflog.MethodInvokeStatic.main;15;;
6 changes: 6 additions & 0 deletions qilin.pta/src/qilin/pta/StagedPTA.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
* This class gives a structure for such kinds of analyses.
* */
public abstract class StagedPTA extends BasePTA {
protected BasePTA prePTA;

public BasePTA getPrePTA() {
return this.prePTA;
}

protected abstract void preAnalysis();

protected void mainAnalysis() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@
* <https://www.gnu.org/licenses/lgpl-3.0.en.html>.
*/

package qilin.pta.toolkits.bean.main;
package qilin.pta.toolkits.bean;

import qilin.core.PTA;
import qilin.core.context.ContextElements;
import qilin.core.pag.AllocNode;
import qilin.pta.toolkits.bean.oag.OAG;
import qilin.pta.toolkits.bean.oag.context.ContextSelector;
import qilin.pta.toolkits.bean.oag.context.RepresentativeContextSelector;
import qilin.pta.toolkits.common.OAG;
import qilin.util.ANSIColor;
import qilin.util.Pair;
import qilin.util.Stopwatch;
Expand Down Expand Up @@ -60,8 +58,7 @@ public static void run(PTA pta, Map<Object, Map<Object, Map<Object, Object>>> be
* Should be generalized for k >= 3.
* */
private static void writeContext(ContextSelector cs, OAG oag, Map<Object, Map<Object, Map<Object, Object>>> beanNexCtxMap) {
oag.allNodes().forEach(node -> {
AllocNode allocator = node.getHeap();
oag.allNodes().forEach(allocator -> {
Set<ContextElements> ctxs = cs.contextsOf(allocator);
for (ContextElements ctx : ctxs) {
AllocNode allocHctx = (AllocNode) ctx.get(0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package qilin.pta.toolkits.bean.oag.context;
package qilin.pta.toolkits.bean;

import qilin.core.context.ContextElements;
import qilin.core.pag.AllocNode;
import qilin.pta.toolkits.bean.oag.OAG;
import qilin.pta.toolkits.common.OAG;
import qilin.util.Pair;

import java.util.HashMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package qilin.pta.toolkits.bean.oag.context;
package qilin.pta.toolkits.bean;

import qilin.core.context.ContextElements;
import qilin.core.pag.AllocNode;
import qilin.parm.ctxcons.CtxConstructor;
import qilin.pta.toolkits.bean.oag.Node;
import qilin.pta.toolkits.bean.oag.OAG;
import qilin.pta.toolkits.common.OAG;
import qilin.util.Triple;

import java.util.*;
Expand All @@ -45,27 +44,26 @@ protected void selectContext(OAG oag) {
mergeContextMap(selectContext(oag, node));
});
oag.allNodes().forEach(node -> {
if (!contextMap.containsKey(node.getHeap())) {
if (!contextMap.containsKey(node)) {
mergeContextMap(selectContext(oag, node));
}
});
}

private Map<AllocNode, Set<ContextElements>> selectContext(OAG oag, Node dest) {
private Map<AllocNode, Set<ContextElements>> selectContext(OAG oag, AllocNode dest) {
Map<AllocNode, Set<ContextElements>> tempContextMap = new HashMap<>();
Queue<Triple<Node, ContextElements, Boolean>> worklist = new LinkedList<>();
Queue<Triple<AllocNode, ContextElements, Boolean>> worklist = new LinkedList<>();
initialWorkList(worklist, oag, dest);
while (!worklist.isEmpty()) {
Triple<Node, ContextElements, Boolean> triple = worklist.poll();
Node node = triple.getFirst();
Triple<AllocNode, ContextElements, Boolean> triple = worklist.poll();
AllocNode heap = triple.getFirst();
ContextElements ctx = triple.getSecond();
boolean split = triple.getThird();
AllocNode heap = node.getHeap();
if (!tempContextMap.containsKey(heap)) {
tempContextMap.put(heap, new HashSet<>());
}
if (tempContextMap.get(heap).add(ctx)) {
Set<Node> reachSuccs = selectReachNodes(oag.getSuccsOf(node), dest, oag);
Set<AllocNode> reachSuccs = selectReachNodes(oag.getSuccsOf(heap), dest, oag);
final boolean isFork = reachSuccs.size() > 1;
reachSuccs.forEach(succ -> {
final boolean isJoinSucc = oag.getInDegreeOf(succ) > 1;
Expand All @@ -82,7 +80,7 @@ private Map<AllocNode, Set<ContextElements>> selectContext(OAG oag, Node dest) {
}
Set<ContextElements> ctxs = tempContextMap.get(succ);
if (ctxs == null || !ctxs.contains(newCtx)) {
addAllocation(ctx, heap, newCtx, succ.getHeap());
addAllocation(ctx, heap, newCtx, succ);
worklist.add(new Triple<>(succ, newCtx, succSplit));
}
});
Expand All @@ -109,16 +107,16 @@ private void mergeContextMap(Map<AllocNode, Set<ContextElements>> anoContextMap)
* @param oag
* @return
*/
private Set<Node> selectReachNodes(Set<Node> nodes, Node dest, OAG oag) {
private Set<AllocNode> selectReachNodes(Collection<AllocNode> nodes, AllocNode dest, OAG oag) {
return nodes.stream().filter(node -> oag.reaches(node, dest)).collect(Collectors.toSet());
}

private void initialWorkList(Queue<Triple<Node, ContextElements, Boolean>> worklist, OAG oag, Node node) {
Set<Node> reachRoots = selectReachNodes(oag.rootNodes(), node, oag);
private void initialWorkList(Queue<Triple<AllocNode, ContextElements, Boolean>> worklist, OAG oag, AllocNode node) {
Set<AllocNode> reachRoots = selectReachNodes(oag.rootNodes(), node, oag);
boolean split = reachRoots.size() > 1;
ContextElements emptyCtx = (ContextElements) CtxConstructor.emptyContext;
reachRoots.forEach(root ->
worklist.add(new Triple<>(root, ContextElements.newContext(emptyCtx, root.getHeap(), depth), split)));
worklist.add(new Triple<>(root, ContextElements.newContext(emptyCtx, root, depth), split)));
}

}
Loading

0 comments on commit 30c9316

Please sign in to comment.