use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomPointsTo method callGraphDFS.
/**
* Using Tarjan's algorithm to contract the SCCs.
*/
private void callGraphDFS(int s) {
int t;
CgEdge p;
vis_cg[s] = low_cg[s] = pre_cnt++;
queue_cg.addLast(s);
p = call_graph[s];
while (p != null) {
t = p.t;
if (vis_cg[t] == 0)
callGraphDFS(t);
if (low_cg[t] < low_cg[s])
low_cg[s] = low_cg[t];
p = p.next;
}
if (low_cg[s] < vis_cg[s]) {
scc_size[s] = 1;
return;
}
scc_size[s] = queue_cg.size();
do {
t = queue_cg.getLast();
queue_cg.removeLast();
rep_cg[t] = s;
low_cg[t] += n_func;
} while (s != t);
scc_size[s] -= queue_cg.size();
if (scc_size[s] > max_scc_size) {
max_scc_size = scc_size[s];
max_scc_id = s;
}
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomPointsTo method buildRevCallGraph.
/**
* The reversed call graph might be used by evaluating queries.
*/
private void buildRevCallGraph() {
rev_call_graph = new HashMap<Integer, LinkedList<CgEdge>>();
for (int i = 0; i < n_func; ++i) {
CgEdge p = call_graph[i];
while (p != null) {
LinkedList<CgEdge> list = rev_call_graph.get(p.t);
if (list == null) {
list = new LinkedList<CgEdge>();
rev_call_graph.put(p.t, list);
}
list.add(p);
p = p.next;
}
}
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomPointsTo method reachingObjects.
/*
* Currently, we only accept one call unit context (1CFA).
* For querying K-CFA (K >1), please see GeomQueries.contextsByCallChain
*/
@Override
public PointsToSet reachingObjects(Context c, Local l) {
if (!hasExecuted)
return super.reachingObjects(c, l);
if (hasTransformed || !(c instanceof Unit))
return reachingObjects(l);
LocalVarNode vn = findLocalVarNode(l);
if (vn == null)
return EmptyPointsToSet.v();
// Lookup the context sensitive points-to information for this pointer
IVarAbstraction pn = consG.get(vn);
if (pn == null)
return vn.getP2Set();
pn = pn.getRepresentative();
// Obtain the context sensitive points-to result
SootMethod callee = vn.getMethod();
Edge e = Scene.v().getCallGraph().findEdge((Unit) c, callee);
if (e == null)
return vn.getP2Set();
// Compute the contexts interval
CgEdge myEdge = getInternalEdgeFromSootEdge(e);
if (myEdge == null)
return vn.getP2Set();
long low = myEdge.map_offset;
long high = low + max_context_size_block[myEdge.s];
// Lookup the cache
ContextVarNode cvn = vn.context(c);
if (cvn != null) {
PointsToSetInternal ans = cvn.getP2Set();
if (ans != EmptyPointsToSet.v())
return ans;
} else {
// Create a new context sensitive variable
// The points-to vector is set to empty at start
cvn = makeContextVarNode(vn, c);
}
// Fill
PointsToSetInternal ptset = cvn.makeP2Set();
for (AllocNode an : pn.get_all_points_to_objects()) {
if (pn.pointer_interval_points_to(low, high, an))
ptset.add(an);
}
return ptset;
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomPointsTo method updateCallGraph.
/**
* Remove unreachable call targets at the virtual callsites using the up-to-date points-to information.
*/
private int updateCallGraph() {
int all_virtual_edges = 0, n_obsoleted = 0;
CallGraph cg = Scene.v().getCallGraph();
ChunkedQueue<SootMethod> targetsQueue = new ChunkedQueue<SootMethod>();
QueueReader<SootMethod> targets = targetsQueue.reader();
Set<SootMethod> resolvedMethods = new HashSet<SootMethod>();
// We first update the virtual callsites
for (Iterator<Stmt> csIt = multiCallsites.iterator(); csIt.hasNext(); ) {
Stmt callsite = csIt.next();
Iterator<Edge> edges = cg.edgesOutOf(callsite);
if (!edges.hasNext()) {
csIt.remove();
continue;
}
Edge anyEdge = edges.next();
CgEdge p = edgeMapping.get(anyEdge);
SootMethod src = anyEdge.src();
if (!isReachableMethod(src)) {
// The source method is no longer reachable
// We move this callsite
csIt.remove();
continue;
}
if (!edges.hasNext()) {
// We keep this resolved site for call graph profiling
continue;
}
IVarAbstraction pn = consG.get(p.base_var);
if (pn != null) {
pn = pn.getRepresentative();
// We resolve the call targets with the new points-to result
getCallTargets(pn, src, callsite, targetsQueue);
resolvedMethods.clear();
while (targets.hasNext()) {
resolvedMethods.add(targets.next());
}
// We delete the edges that are proven to be spurious
while (true) {
SootMethod tgt = anyEdge.tgt();
if (!resolvedMethods.contains(tgt) && !anyEdge.kind().isFake()) {
p = edgeMapping.get(anyEdge);
p.is_obsoleted = true;
}
if (!edges.hasNext())
break;
anyEdge = edges.next();
}
}
}
// We delete the spurious edges
for (int i = 1; i < n_func; ++i) {
// New outgoing edge list is pointed to by q
CgEdge p = call_graph[i];
CgEdge q = null;
while (p != null) {
if (vis_cg[i] == 0) {
// If this method is unreachable, we delete all its outgoing edges
p.is_obsoleted = true;
}
if (p.base_var != null) {
++all_virtual_edges;
}
CgEdge temp = p.next;
if (p.is_obsoleted == false) {
p.next = q;
q = p;
} else {
// Update the corresponding SOOT call graph
// ps.println("%%% Remove an call edge: " + p.toString());
cg.removeEdge(p.sootEdge);
// We record this obsoleted edge
// obsoletedEdges.add(p);
++n_obsoleted;
}
p = temp;
}
call_graph[i] = q;
}
ps.printf("%d of %d virtual call edges are proved to be spurious.\n", n_obsoleted, all_virtual_edges);
return n_obsoleted;
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomPointsTo method preprocess.
/**
* Read in the program facts generated by SPARK.
* We also construct our own call graph and pointer variables.
*/
private void preprocess() {
int id;
int s, t;
// Build the call graph
n_func = Scene.v().getReachableMethods().size() + 1;
call_graph = new CgEdge[n_func];
n_calls = 0;
n_reach_spark_user_methods = 0;
id = 1;
QueueReader<MethodOrMethodContext> smList = Scene.v().getReachableMethods().listener();
CallGraph soot_callgraph = Scene.v().getCallGraph();
while (smList.hasNext()) {
final SootMethod func = smList.next().method();
func2int.put(func, id);
int2func.put(id, func);
/*
* We cannot identify all entry methods since some entry methods call themselves.
* In that case, the Soot CallGraph.isEntryMethod() function returns false.
*/
if (soot_callgraph.isEntryMethod(func) || func.isEntryMethod()) {
CgEdge p = new CgEdge(Constants.SUPER_MAIN, id, null, call_graph[Constants.SUPER_MAIN]);
call_graph[Constants.SUPER_MAIN] = p;
n_calls++;
}
if (!func.isJavaLibraryMethod())
++n_reach_spark_user_methods;
id++;
}
// Next, we scan all the call edges and rebuild the call graph in our own vocabulary
QueueReader<Edge> edgeList = Scene.v().getCallGraph().listener();
while (edgeList.hasNext()) {
Edge edge = edgeList.next();
if (edge.isClinit()) {
continue;
}
SootMethod src_func = edge.src();
SootMethod tgt_func = edge.tgt();
s = func2int.get(src_func);
t = func2int.get(tgt_func);
// Create a new call edge in our own format
CgEdge p = new CgEdge(s, t, edge, call_graph[s]);
call_graph[s] = p;
edgeMapping.put(edge, p);
// We collect callsite information
Stmt callsite = edge.srcStmt();
if (edge.isThreadRunCall() || edge.kind().isExecutor() || edge.kind().isAsyncTask()) {
// We don't modify the treatment to the thread run() calls
thread_run_callsites.add(callsite);
} else if (edge.isInstance() && !edge.isSpecial()) {
// We try to refine the virtual callsites (virtual + interface) with multiple call targets
InstanceInvokeExpr expr = (InstanceInvokeExpr) callsite.getInvokeExpr();
if (expr.getMethodRef().getSignature().contains("<java.lang.Thread: void start()>")) {
// It is a thread start function
thread_run_callsites.add(callsite);
} else {
p.base_var = findLocalVarNode(expr.getBase());
if (SootInfo.countCallEdgesForCallsite(callsite, true) > 1 && p.base_var != null) {
multiCallsites.add(callsite);
}
}
}
++n_calls;
}
// We build the wrappers for all the pointers built by SPARK
for (Iterator<VarNode> it = getVarNodeNumberer().iterator(); it.hasNext(); ) {
VarNode vn = it.next();
IVarAbstraction pn = makeInternalNode(vn);
pointers.add(pn);
}
for (Iterator<AllocDotField> it = getAllocDotFieldNodeNumberer().iterator(); it.hasNext(); ) {
AllocDotField adf = it.next();
// Some allocdotfield is invalid, we check and remove them
SparkField field = adf.getField();
if (field instanceof SootField) {
// This is an instance field of a class
Type decType = ((SootField) field).getDeclaringClass().getType();
Type baseType = adf.getBase().getType();
// baseType must be a sub type of decType
if (!castNeverFails(baseType, decType))
continue;
}
IVarAbstraction pn = makeInternalNode(adf);
pointers.add(pn);
}
for (Iterator<AllocNode> it = getAllocNodeNumberer().iterator(); it.hasNext(); ) {
AllocNode obj = it.next();
IVarAbstraction pn = makeInternalNode(obj);
allocations.add(pn);
}
// The address constraints, new obj -> p
for (Object object : allocSources()) {
IVarAbstraction obj = makeInternalNode((AllocNode) object);
Node[] succs = allocLookup((AllocNode) object);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
IVarAbstraction p = makeInternalNode(element0);
cons.expr.setPair(obj, p);
cons.type = Constants.NEW_CONS;
constraints.add(cons);
}
}
// The assign constraints, p -> q
Pair<Node, Node> intercall = new Pair<Node, Node>();
for (Object object : simpleSources()) {
IVarAbstraction p = makeInternalNode((VarNode) object);
Node[] succs = simpleLookup((VarNode) object);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
IVarAbstraction q = makeInternalNode(element0);
cons.expr.setPair(p, q);
cons.type = Constants.ASSIGN_CONS;
intercall.setPair((VarNode) object, element0);
cons.interCallEdges = lookupEdgesForAssignment(intercall);
constraints.add(cons);
}
}
intercall = null;
assign2edges.clear();
// The load constraints, p.f -> q
for (Object object : loadSources()) {
FieldRefNode frn = (FieldRefNode) object;
IVarAbstraction p = makeInternalNode(frn.getBase());
Node[] succs = loadLookup(frn);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
IVarAbstraction q = makeInternalNode(element0);
cons.f = frn.getField();
cons.expr.setPair(p, q);
cons.type = Constants.LOAD_CONS;
constraints.add(cons);
}
}
// The store constraints, p -> q.f
for (Object object : storeSources()) {
IVarAbstraction p = makeInternalNode((VarNode) object);
Node[] succs = storeLookup((VarNode) object);
for (Node element0 : succs) {
PlainConstraint cons = new PlainConstraint();
FieldRefNode frn = (FieldRefNode) element0;
IVarAbstraction q = makeInternalNode(frn.getBase());
cons.f = frn.getField();
cons.expr.setPair(p, q);
cons.type = Constants.STORE_CONS;
constraints.add(cons);
}
}
n_init_constraints = constraints.size();
// Initialize other stuff
low_cg = new int[n_func];
vis_cg = new int[n_func];
rep_cg = new int[n_func];
indeg_cg = new int[n_func];
scc_size = new int[n_func];
block_num = new int[n_func];
context_size = new long[n_func];
max_context_size_block = new long[n_func];
}
Aggregations