Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
qilin.pta.toolkits.eagle.Eagle Maven / Gradle / Ivy
/* 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.pta.toolkits.eagle;
import java.util.*;
import java.util.stream.Collectors;
import qilin.core.PTA;
import qilin.core.PointsToAnalysis;
import qilin.core.builder.MethodNodeFactory;
import qilin.core.builder.callgraph.Edge;
import qilin.core.builder.callgraph.OnFlyCallGraph;
import qilin.core.pag.*;
import qilin.core.sets.PointsToSet;
import qilin.util.PTAUtils;
import qilin.util.Util;
import qilin.util.queue.QueueReader;
import qilin.util.queue.UniqueQueue;
import sootup.core.jimple.basic.Local;
import sootup.core.jimple.basic.Value;
import sootup.core.jimple.common.constant.NullConstant;
import sootup.core.jimple.common.expr.AbstractInstanceInvokeExpr;
import sootup.core.jimple.common.expr.AbstractInvokeExpr;
import sootup.core.jimple.common.stmt.JAssignStmt;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootMethod;
import sootup.core.types.ReferenceType;
// implementation of Eagle (OOPSLA'19).
public class Eagle {
protected Map> sparkNode2BNode = new HashMap<>();
// fields for storage
public Set allocs = new HashSet<>();
public Set allocIs = new HashSet<>();
public Map> outEdges = new HashMap<>();
protected Map> balancedOutEdges = new HashMap<>();
private int new_count = 0;
private int assign_count = 0;
protected int store_count = 0;
private int load_count = 0;
private int balance_count = 0;
private int hstore_count = 0;
private int hload_count = 0;
private int total_nodes_count = 0;
private int total_edges_count = 0;
public void dumpCount() {
System.out.println("#NEW:" + new_count);
System.out.println("#ASSIGN:" + assign_count);
System.out.println("#STORE:" + store_count);
System.out.println("#LOAD:" + load_count);
System.out.println("#HSTORE:" + hstore_count);
System.out.println("#HLOAD:" + hload_count);
System.out.println("#BALANCE:" + balance_count);
}
public Collection extends BNode> getNodes() {
return sparkNode2BNode.values().stream()
.flatMap(subMap -> subMap.values().stream())
.collect(Collectors.toSet());
}
public Collection getSparkNodes() {
return sparkNode2BNode.values().stream()
.flatMap(subMap -> subMap.values().stream())
.map(gn -> gn.sparkNode)
.collect(Collectors.toSet());
}
public BNode getBNode(Object origin, Boolean forward) {
Map subMap = sparkNode2BNode.computeIfAbsent(origin, k -> new HashMap<>());
if (subMap.containsKey(forward)) {
return subMap.get(forward);
} else {
BNode ret = new BNode(origin, forward);
subMap.put(forward, ret);
total_nodes_count++;
return ret;
}
}
protected void addNormalEdge(BNode from, BNode to) {
Set m = outEdges.computeIfAbsent(from, k -> new HashSet<>());
m.add(to);
total_edges_count++;
}
public boolean addBalancedEdge(BNode from, BNode to) {
boolean ret = Util.addToMap(balancedOutEdges, from, to);
balance_count++;
total_edges_count++;
return ret;
}
public void addNewEdge(AllocNode from, LocalVarNode to) {
BNode fromE = getBNode(from, true), toE = getBNode(to, true);
addNormalEdge(fromE, toE);
BNode toEI = getBNode(to, false), fromEI = getBNode(from, false);
addNormalEdge(toEI, fromEI);
new_count++;
allocs.add(fromE);
allocIs.add(fromEI);
}
public void addAssignEdge(LocalVarNode from, LocalVarNode to) {
BNode fromE = getBNode(from, true), toE = getBNode(to, true);
addNormalEdge(fromE, toE);
BNode toEI = getBNode(to, false), fromEI = getBNode(from, false);
addNormalEdge(toEI, fromEI);
assign_count++;
}
public void addStoreEdge(LocalVarNode from, LocalVarNode base) {
BNode fromE = getBNode(from, true), baseEI = getBNode(base, false);
addNormalEdge(fromE, baseEI);
BNode baseE = getBNode(base, true), fromEI = getBNode(from, false);
addNormalEdge(baseE, fromEI);
store_count++;
}
public void addLoadEdge(LocalVarNode base, LocalVarNode to) {
BNode baseE = getBNode(base, true), toE = getBNode(to, true);
addNormalEdge(baseE, toE);
BNode toEI = getBNode(to, false), baseEI = getBNode(base, false);
addNormalEdge(toEI, baseEI);
load_count++;
}
public void addHstoreEdge(Object from, AllocNode baseObj) {
BNode fromE = getBNode(from, true), baseObjE = getBNode(baseObj, true);
addNormalEdge(fromE, baseObjE);
BNode baseObjEI = getBNode(baseObj, false), fromEI = getBNode(from, false);
addNormalEdge(baseObjEI, fromEI);
allocIs.add(baseObjEI);
allocs.add(baseObjE);
hstore_count++;
}
public void addHloadEdge(AllocNode baseObj, Object to) {
BNode baseObjEI = getBNode(baseObj, false), toE = getBNode(to, true);
addNormalEdge(baseObjEI, toE);
BNode toEI = getBNode(to, false), baseObjE = getBNode(baseObj, true);
addNormalEdge(toEI, baseObjE);
allocIs.add(baseObjEI);
allocs.add(baseObjE);
hload_count++;
}
public int totalEdgesCount() {
return total_edges_count;
}
public int totalNodesCount() {
return total_nodes_count;
}
public Set getAllOutEdges(BNode node) {
Set ret = new HashSet<>(getOutEdges(node));
if (balancedOutEdges.containsKey(node)) {
ret.addAll(balancedOutEdges.get(node));
}
return ret;
}
public Collection getOutEdges(BNode node) {
return outEdges.getOrDefault(node, Collections.emptySet());
}
public boolean reachValidReceiverObject(BNode from, BNode to) {
BNode fromEI = getBNode(to.sparkNode, false);
if (from.sparkNode instanceof Field || from.sparkNode instanceof ArrayElement) {
return getOutEdges(fromEI).contains(from);
}
return true;
}
// eagle propagate
protected boolean enterCS(BNode node) {
return node.entryCS();
}
public Map contxtLengthAnalysis() {
Queue workList = new UniqueQueue<>();
Set matchedObjects = new HashSet<>();
// start from all "parameter/field" node
for (BNode heapNode : allocIs) {
for (BNode dst : getOutEdges(heapNode)) {
dst.cs = true;
workList.add(dst);
}
}
while (!workList.isEmpty()) {
BNode node = workList.poll();
for (BNode dst : getAllOutEdges(node)) {
if (dst.isHeapPlus() && !node.isHeapMinus()) {
if (reachValidReceiverObject(node, dst)) {
if (matchedObjects.add(dst.sparkNode)) { // add balanced edges
BNode fromEI = getBNode(dst.sparkNode, false);
addBalancedEdge(fromEI, dst, workList);
}
}
} else {
if (enterCS(dst)) {
workList.add(dst);
}
}
}
}
Map ret = new HashMap<>();
getSparkNodes()
.forEach(
sparkNode -> {
BNode node = getBNode(sparkNode, true);
BNode nodeInv = getBNode(sparkNode, false);
ret.put(sparkNode, node.cs && nodeInv.cs ? 1 : 0);
});
return ret;
}
protected void addBalancedEdge(BNode from, BNode to, Queue workList) {
if (addBalancedEdge(from, to)) {
if (from.cs) {
workList.add(from); // add src of the balanced edges to worklist
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////
protected void addParamEdges(
AllocNode o,
LocalVarNode thisRef,
LocalVarNode[] parms,
LocalVarNode mret,
LocalVarNode mThrow) {
this.addHloadEdge(o, thisRef);
for (VarNode parm : parms) {
if (parm != null) {
this.addHloadEdge(o, parm);
}
}
if (mret != null) {
this.addHstoreEdge(mret, o);
}
if (mThrow != null) {
this.addHstoreEdge(mThrow, o);
}
}
public void buildGraph(PTA prePTA) {
PAG prePAG = prePTA.getPag();
// calculate points-to set for "This" pointer in each static method.
Map> pts = PTAUtils.calcStaticThisPTS(prePTA);
OnFlyCallGraph callGraph = prePTA.getCallGraph();
for (SootMethod method : prePTA.getNakedReachableMethods()) {
if (!PTAUtils.hasBody(method)) {
continue;
}
MethodPAG srcmpag = prePAG.getMethodPAG(method);
MethodNodeFactory srcnf = srcmpag.nodeFactory();
LocalVarNode thisRef = (LocalVarNode) srcnf.caseThis();
// add local edges
if (PTAUtils.isFakeMainMethod(method)) {
// special treatment for fake main
this.addNewEdge(prePTA.getRootNode(), thisRef);
}
QueueReader reader = srcmpag.getInternalReader().clone();
while (reader.hasNext()) {
Node from = reader.next(), to = reader.next();
if (from instanceof LocalVarNode) {
if (to instanceof LocalVarNode)
this.addAssignEdge((LocalVarNode) from, (LocalVarNode) to);
else if (to instanceof FieldRefNode) {
FieldRefNode fr = (FieldRefNode) to;
this.addStoreEdge((LocalVarNode) from, (LocalVarNode) fr.getBase());
} // local-global
} else if (from instanceof AllocNode) {
if (to instanceof LocalVarNode) {
this.addNewEdge((AllocNode) from, (LocalVarNode) to);
} // GlobalVarNode
} else if (from instanceof FieldRefNode) {
FieldRefNode fr = (FieldRefNode) from;
this.addLoadEdge((LocalVarNode) fr.getBase(), (LocalVarNode) to);
} // global-local
}
// add exception edges that added dynamically during the pre-analysis.
srcmpag
.getExceptionEdges()
.forEach(
(k, vs) -> {
for (Node v : vs) {
this.addAssignEdge((LocalVarNode) k, (LocalVarNode) v);
}
});
// add para edges
int numParms = method.getParameterCount();
LocalVarNode[] parms = new LocalVarNode[numParms];
for (int i = 0; i < numParms; i++) {
if (method.getParameterType(i) instanceof ReferenceType) {
parms[i] = (LocalVarNode) srcnf.caseParm(i);
}
}
LocalVarNode mret =
method.getReturnType() instanceof ReferenceType ? (LocalVarNode) srcnf.caseRet() : null;
LocalVarNode throwFinal =
prePAG.findLocalVarNode(
method,
new Parm(method, PointsToAnalysis.THROW_NODE),
PTAUtils.getClassType("java.lang.Throwable"));
if (method.isStatic()) {
pts.getOrDefault(thisRef, Collections.emptySet())
.forEach(
a -> {
addParamEdges(a, thisRef, parms, mret, throwFinal);
});
} else {
PointsToSet thisPts = prePTA.reachingObjects(thisRef).toCIPointsToSet();
for (Iterator it = thisPts.iterator(); it.hasNext(); ) {
AllocNode n = it.next();
addParamEdges(n, thisRef, parms, mret, throwFinal);
}
}
// add invoke edges
for (final Stmt s : srcmpag.getInvokeStmts()) {
AbstractInvokeExpr ie = s.getInvokeExpr();
int numArgs = ie.getArgCount();
Value[] args = new Value[numArgs];
for (int i = 0; i < numArgs; i++) {
Value arg = ie.getArg(i);
if (!(arg.getType() instanceof ReferenceType) || arg instanceof NullConstant) continue;
args[i] = arg;
}
LocalVarNode retDest = null;
if (s instanceof JAssignStmt) {
Value dest = ((JAssignStmt) s).getLeftOp();
if (dest.getType() instanceof ReferenceType) {
retDest = prePAG.findLocalVarNode(method, dest, dest.getType());
}
}
LocalVarNode receiver;
if (ie instanceof AbstractInstanceInvokeExpr) {
AbstractInstanceInvokeExpr iie = (AbstractInstanceInvokeExpr) ie;
Local base = iie.getBase();
receiver = prePAG.findLocalVarNode(method, base, base.getType());
} else {
// static call
receiver = thisRef;
}
for (Iterator it = callGraph.edgesOutOf(s); it.hasNext(); ) {
Edge e = it.next();
SootMethod tgtmtd = e.tgt();
for (int i = 0; i < numArgs; i++) {
if (args[i] == null || !(tgtmtd.getParameterType(i) instanceof ReferenceType)) continue;
ValNode argNode = prePAG.findValNode(args[i], method);
if (argNode instanceof LocalVarNode) {
this.addStoreEdge((LocalVarNode) argNode, receiver);
}
}
if (retDest != null && tgtmtd.getReturnType() instanceof ReferenceType) {
this.addLoadEdge(receiver, retDest);
}
LocalVarNode stmtThrowNode = srcnf.makeInvokeStmtThrowVarNode(s, method);
this.addLoadEdge(receiver, stmtThrowNode);
this.addStoreEdge(receiver, receiver); // do not move this out of loop
}
}
}
// add field edges
prePAG
.getContextFields()
.forEach(
contextField -> {
AllocNode base = contextField.getBase();
SparkField field = contextField.getField();
if (!prePAG.simpleInvLookup(contextField).isEmpty()) {
this.addHloadEdge(base, field);
}
if (!prePAG.simpleLookup(contextField).isEmpty()) {
this.addHstoreEdge(field, base);
}
});
}
}