use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomPointsTo method markReachableMethods.
/**
* Scan the call graph and mark the reachable methods.
*/
private void markReachableMethods() {
int ans = 0;
CgEdge p;
for (int i = 0; i < n_func; ++i) vis_cg[i] = 0;
queue_cg.clear();
queue_cg.add(Constants.SUPER_MAIN);
vis_cg[Constants.SUPER_MAIN] = 1;
while (queue_cg.size() > 0) {
int s = queue_cg.removeFirst();
p = call_graph[s];
while (p != null) {
int t = p.t;
if (vis_cg[t] == 0) {
queue_cg.add(t);
vis_cg[t] = 1;
++ans;
}
p = p.next;
}
}
n_reach_methods = ans;
// Scan again to remove unreachable methods
ans = 0;
for (int i = 1; i < n_func; ++i) {
SootMethod sm = int2func.get(i);
if (vis_cg[i] == 0) {
func2int.remove(sm);
int2func.remove(i);
} else {
if (!sm.isJavaLibraryMethod())
++ans;
}
}
n_reach_user_methods = ans;
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomPointsTo method encodeContexts.
/**
* Build a call graph, merge the SCCs and name the contexts.
* Also permit clients to decide whether to connect the disjoint parts in the call graph or not.
*/
private void encodeContexts(boolean connectMissedEntries) {
int i, j;
int n_reachable = 0, n_scc_reachable = 0;
int n_full = 0;
long max_contexts = Long.MIN_VALUE;
Random rGen = new Random();
pre_cnt = 1;
max_scc_size = 1;
for (i = 0; i < n_func; ++i) {
vis_cg[i] = 0;
indeg_cg[i] = 0;
max_context_size_block[i] = 0;
}
// We only consider all the methods which are reachable from SUPER_MAIN
queue_cg.clear();
callGraphDFS(Constants.SUPER_MAIN);
if (connectMissedEntries) {
// We also scan rest of the functions
for (i = Constants.SUPER_MAIN + 1; i < n_func; ++i) if (vis_cg[i] == 0)
callGraphDFS(i);
}
// And, we classify the call edges into SCC/non-SCC edges
for (i = 0; i < n_func; ++i) {
if (vis_cg[i] == 0)
continue;
CgEdge p = call_graph[i];
while (p != null) {
// Only count an edge that links two functions in the same SCC
if (rep_cg[i] == rep_cg[p.t]) {
p.scc_edge = true;
} else {
p.scc_edge = false;
++indeg_cg[rep_cg[p.t]];
}
p = p.next;
}
// Do simple statistics
++n_reachable;
if (rep_cg[i] == i)
++n_scc_reachable;
}
if (connectMissedEntries) {
// The functions other than SUPER_MAIN that have zero in-degrees are missed entry methods
for (i = Constants.SUPER_MAIN + 1; i < n_func; ++i) {
int rep_node = rep_cg[i];
if (indeg_cg[rep_node] == 0) {
CgEdge p = new CgEdge(Constants.SUPER_MAIN, i, null, call_graph[Constants.SUPER_MAIN]);
call_graph[Constants.SUPER_MAIN] = p;
n_calls++;
}
}
}
// context sensitive queries
for (i = 0; i < n_func; ++i) if (vis_cg[i] != 0 && rep_cg[i] != i) {
// Any node in a SCC must have at least one outgoing edge
CgEdge p = call_graph[i];
while (p.next != null) p = p.next;
p.next = call_graph[rep_cg[i]];
// Note that, call_graph[i] is not cleared after merging
call_graph[rep_cg[i]] = call_graph[i];
}
// Now, we add all the source nodes to the queue
max_context_size_block[Constants.SUPER_MAIN] = 1;
queue_cg.addLast(Constants.SUPER_MAIN);
while (!queue_cg.isEmpty()) {
i = queue_cg.getFirst();
queue_cg.removeFirst();
CgEdge p = call_graph[i];
while (p != null) {
if (p.scc_edge == false) {
// Consider the representative only
j = rep_cg[p.t];
/*
* We can control how many contexts created for a specified
* function. And, for any call edge, we can manually move
* the mapping interval from caller to callee.
*/
if (Constants.MAX_CONTEXTS - max_context_size_block[i] < max_context_size_block[j]) {
// The are more than 2^63 - 1 execution paths, terrible!
// We have to merge some contexts in order to make the analysis sound!
// The merging starting context is randomly picked
long start = rGen.nextLong();
if (start < 0)
start = -start;
if (start > Constants.MAX_CONTEXTS - max_context_size_block[i]) {
// We use the last max_context_size_block[i] bits for this mapping
start = Constants.MAX_CONTEXTS - max_context_size_block[i];
max_context_size_block[j] = Constants.MAX_CONTEXTS;
} else {
if (max_context_size_block[j] < start + max_context_size_block[i])
// We compensate the difference
max_context_size_block[j] = start + max_context_size_block[i];
}
p.map_offset = start + 1;
} else {
// Accumulate the contexts
p.map_offset = max_context_size_block[j] + 1;
max_context_size_block[j] += max_context_size_block[i];
}
// Add to the worklist
if (--indeg_cg[j] == 0)
queue_cg.addLast(j);
} else {
// 0-CFA modeling for the SCC, the default mode
p.map_offset = 1;
}
p = p.next;
}
if (max_context_size_block[i] > max_contexts)
max_contexts = max_context_size_block[i];
}
// Now we restore the call graph
for (i = n_func - 1; i > -1; --i) {
if (vis_cg[i] == 0)
continue;
if (rep_cg[i] != i) {
// All nodes in the same SCC have the same number of contexts
max_context_size_block[i] = max_context_size_block[rep_cg[i]];
// Put all the call edges back
CgEdge p = call_graph[i];
while (p.next.s == i) // p.next.s may not be i because it would be linked to another scc member
p = p.next;
call_graph[rep_cg[i]] = p.next;
p.next = null;
}
if (max_context_size_block[i] == Constants.MAX_CONTEXTS)
++n_full;
context_size[i] = max_context_size_block[i];
block_num[i] = 1;
}
// The implementation is slightly different from our paper (the non-SCC edges are not moved, they still use their current context mappings)
if (getOpts().geom_blocking()) {
// We don't manipulate the non-SCC edges, because they don't induce problems
for (i = 0; i < n_func; ++i) {
if (vis_cg[i] == 0)
continue;
CgEdge p = call_graph[i];
while (p != null) {
j = p.t;
if (// This is not a self-loop, and a self-loop is treated specially in the initial encoding phase
j != i && p.scc_edge == true) {
// So, we don't distinguish them
if (context_size[j] <= Constants.MAX_CONTEXTS - max_context_size_block[i]) {
p.map_offset = context_size[j] + 1;
context_size[j] += max_context_size_block[i];
++block_num[j];
} else {
// We randomly pick a block for reuse (try best to avoid reusing the first block)
int iBlock = 0;
if (block_num[j] > 1)
iBlock = rGen.nextInt(block_num[j] - 1) + 1;
p.map_offset = iBlock * max_context_size_block[j] + 1;
}
}
p = p.next;
}
}
}
// Print debug info
ps.printf("Reachable Methods = %d, in which #Condensed Nodes = %d, #Full Context Nodes = %d \n", n_reachable - 1, n_scc_reachable - 1, n_full);
ps.printf("Maximum SCC = %d \n", max_scc_size);
ps.printf("The maximum context size = %e\n", (double) max_contexts);
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class EvalResults method test_1cfa_call_graph.
/**
* We assess the quality of building the 1-cfa call graph with the geometric
* points-to result.
*/
private void test_1cfa_call_graph(LocalVarNode vn, SootMethod caller, SootMethod callee_signature, Histogram ce_range) {
long l, r;
IVarAbstraction pn = ptsProvider.findInternalNode(vn);
if (pn == null)
return;
pn = pn.getRepresentative();
Set<SootMethod> tgts = new HashSet<SootMethod>();
Set<AllocNode> set = pn.get_all_points_to_objects();
LinkedList<CgEdge> list = ptsProvider.getCallEdgesInto(ptsProvider.getIDFromSootMethod(caller));
FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy();
for (Iterator<CgEdge> it = list.iterator(); it.hasNext(); ) {
CgEdge p = it.next();
l = p.map_offset;
r = l + ptsProvider.max_context_size_block[p.s];
tgts.clear();
for (AllocNode obj : set) {
if (!pn.pointer_interval_points_to(l, r, obj))
continue;
Type t = obj.getType();
if (t == null)
continue;
else if (t instanceof AnySubType)
t = ((AnySubType) t).getBase();
else if (t instanceof ArrayType)
t = RefType.v("java.lang.Object");
try {
tgts.add(hierarchy.resolveConcreteDispatch(((RefType) t).getSootClass(), callee_signature));
} catch (Exception e) {
}
}
tgts.remove(null);
ce_range.addNumber(tgts.size());
}
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomQueries method prepareIntervalPropagations.
/**
* Only needed by part of the queries.
* Therefore, it is called on demand.
*/
private void prepareIntervalPropagations() {
if (prop_initialized)
return;
// We layout the nodes hierarchically by topological sorting
// The topological labels are used for speeding up reachability
top_rank = new int[n_func];
Arrays.fill(top_rank, 0);
topQ = new LinkedList<Integer>();
topQ.add(Constants.SUPER_MAIN);
while (!topQ.isEmpty()) {
int s = topQ.poll();
CgEdge p = call_graph[s];
while (p != null) {
int t = p.t;
int rep_t = rep_cg[t];
int w = top_rank[s] + 1;
if (top_rank[rep_t] < w)
top_rank[rep_t] = w;
if (--in_degree[rep_t] == 0)
topQ.add(rep_t);
p = p.next;
}
}
// Prepare for querying artifacts
contextsForMethods = new ContextsCollector[n_func];
for (int i = 0; i < n_func; ++i) {
ContextsCollector cc = new ContextsCollector();
cc.setBudget(Parameters.qryBudgetSize);
contextsForMethods[i] = cc;
}
prop_initialized = true;
}
use of soot.jimple.spark.geom.dataRep.CgEdge in project soot by Sable.
the class GeomQueries method propagateIntervals.
/**
* Compute the mapping from interval [L, R) of method start to the intervals of method target.
* Return true if the mapping is feasible.
*
* @param start
* @param L
* @param R
* @param target
* @return
*/
protected boolean propagateIntervals(int start, long L, long R, int target) {
// We first identify the subgraph, where all edges in the subgraph lead to the target
if (!dfsScanSubgraph(start, target))
return false;
// Now we prepare for iteration
int rep_start = rep_cg[start];
int rep_target = rep_cg[target];
ContextsCollector targetContexts = contextsForMethods[target];
if (rep_start == rep_target) {
// Fast path for the special case
transferInSCC(start, target, L, R, targetContexts);
} else {
// We start traversal from the representative method
transferInSCC(start, rep_start, L, R, contextsForMethods[rep_start]);
// Start topsort
topQ.clear();
topQ.add(rep_start);
while (!topQ.isEmpty()) {
// Every function in the queue is representative function
int s = topQ.poll();
ContextsCollector sContexts = contextsForMethods[s];
// Loop over the edges
CgEdge p = call_graph[s];
while (p != null) {
int t = p.t;
int rep_t = rep_cg[t];
if (in_degree[rep_t] != 0) {
// This node has a path to target
ContextsCollector reptContexts = contextsForMethods[rep_t];
long block_size = max_context_size_block[s];
for (SimpleInterval si : sContexts.bars) {
// Compute the offset within the block for si
long in_block_offset = (si.L - 1) % block_size;
long newL = p.map_offset + in_block_offset;
long newR = si.R - si.L + newL;
if (rep_t == rep_target) {
// t and target are in the same SCC
// We directly transfer this context interval to target
transferInSCC(t, target, newL, newR, targetContexts);
} else {
// We transfer this interval to its SCC representative
// It might be t == rep_t
transferInSCC(t, rep_t, newL, newR, reptContexts);
}
}
if (--in_degree[rep_t] == 0 && rep_t != rep_target) {
topQ.add(rep_t);
}
}
p = p.next;
}
sContexts.clear();
}
}
return true;
}
Aggregations