Search in sources :

Example 1 with Edge

use of soot.jimple.toolkits.callgraph.Edge 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;
}
Also used : CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) AllocNode(soot.jimple.spark.pag.AllocNode) PointsToSetInternal(soot.jimple.spark.sets.PointsToSetInternal) SootMethod(soot.SootMethod) ContextVarNode(soot.jimple.spark.pag.ContextVarNode) Unit(soot.Unit) LocalVarNode(soot.jimple.spark.pag.LocalVarNode) Edge(soot.jimple.toolkits.callgraph.Edge) CgEdge(soot.jimple.spark.geom.dataRep.CgEdge)

Example 2 with Edge

use of soot.jimple.toolkits.callgraph.Edge 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;
}
Also used : CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) ChunkedQueue(soot.util.queue.ChunkedQueue) PlainConstraint(soot.jimple.spark.geom.dataRep.PlainConstraint) Stmt(soot.jimple.Stmt) CallGraph(soot.jimple.toolkits.callgraph.CallGraph) SootMethod(soot.SootMethod) Edge(soot.jimple.toolkits.callgraph.Edge) CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) HashSet(java.util.HashSet)

Example 3 with Edge

use of soot.jimple.toolkits.callgraph.Edge 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];
}
Also used : CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) AllocDotField(soot.jimple.spark.pag.AllocDotField) PlainConstraint(soot.jimple.spark.geom.dataRep.PlainConstraint) SparkField(soot.jimple.spark.pag.SparkField) FieldRefNode(soot.jimple.spark.pag.FieldRefNode) ContextVarNode(soot.jimple.spark.pag.ContextVarNode) LocalVarNode(soot.jimple.spark.pag.LocalVarNode) Node(soot.jimple.spark.pag.Node) VarNode(soot.jimple.spark.pag.VarNode) AllocNode(soot.jimple.spark.pag.AllocNode) Stmt(soot.jimple.Stmt) MethodOrMethodContext(soot.MethodOrMethodContext) Pair(soot.toolkits.scalar.Pair) ContextVarNode(soot.jimple.spark.pag.ContextVarNode) LocalVarNode(soot.jimple.spark.pag.LocalVarNode) VarNode(soot.jimple.spark.pag.VarNode) InstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) PlainConstraint(soot.jimple.spark.geom.dataRep.PlainConstraint) RefType(soot.RefType) Type(soot.Type) FieldRefNode(soot.jimple.spark.pag.FieldRefNode) CallGraph(soot.jimple.toolkits.callgraph.CallGraph) AllocNode(soot.jimple.spark.pag.AllocNode) SootMethod(soot.SootMethod) SootField(soot.SootField) Edge(soot.jimple.toolkits.callgraph.Edge) CgEdge(soot.jimple.spark.geom.dataRep.CgEdge)

Example 4 with Edge

use of soot.jimple.toolkits.callgraph.Edge in project soot by Sable.

the class EvalResults method checkCallGraph.

/**
 * Report the virtual callsites resolution result for the user's code.
 */
public void checkCallGraph() {
    int[] limits = new int[] { 1, 2, 4, 8 };
    evalRes.total_call_edges = new Histogram(limits);
    CallGraph cg = Scene.v().getCallGraph();
    for (Stmt callsite : ptsProvider.multiCallsites) {
        Iterator<Edge> edges = cg.edgesOutOf(callsite);
        if (!edges.hasNext())
            continue;
        evalRes.n_callsites++;
        // get an edge
        Edge anyEdge = edges.next();
        SootMethod src = anyEdge.src();
        if (!ptsProvider.isReachableMethod(src) || !ptsProvider.isValidMethod(src))
            continue;
        // get the base pointer
        CgEdge p = ptsProvider.getInternalEdgeFromSootEdge(anyEdge);
        LocalVarNode vn = (LocalVarNode) p.base_var;
        // test the call graph
        int edge_cnt = 1;
        while (edges.hasNext()) {
            ++edge_cnt;
            edges.next();
        }
        evalRes.n_geom_call_edges += edge_cnt;
        if (edge_cnt == 1)
            ++evalRes.n_geom_solved_all;
        // test app method
        if (!src.isJavaLibraryMethod()) {
            InvokeExpr ie = callsite.getInvokeExpr();
            if (edge_cnt == 1) {
                ++evalRes.n_geom_solved_app;
                if (ptsProvider.getOpts().verbose()) {
                    outputer.println();
                    outputer.println("<<<<<<<<<   Additional Solved Call   >>>>>>>>>>");
                    outputer.println(src.toString());
                    outputer.println(ie.toString());
                }
            } else {
                // We try to test if this callsite is solvable
                // under some contexts
                Histogram call_edges = new Histogram(limits);
                test_1cfa_call_graph(vn, src, ie.getMethod(), call_edges);
                evalRes.total_call_edges.merge(call_edges);
                call_edges = null;
            }
            evalRes.n_geom_user_edges += edge_cnt;
            evalRes.n_user_callsites++;
        }
    }
    ptsProvider.ps.println();
    ptsProvider.ps.println("--------> Virtual Callsites Evaluation <---------");
    ptsProvider.ps.printf("Total virtual callsites (app code): %d (%d)\n", evalRes.n_callsites, evalRes.n_user_callsites);
    ptsProvider.ps.printf("Total virtual call edges (app code): %d (%d)\n", evalRes.n_geom_call_edges, evalRes.n_geom_user_edges);
    ptsProvider.ps.printf("Virtual callsites additionally solved by geomPTA compared to SPARK (app code) = %d (%d)\n", evalRes.n_geom_solved_all, evalRes.n_geom_solved_app);
    evalRes.total_call_edges.printResult(ptsProvider.ps, "Testing of unsolved callsites on 1-CFA call graph: ");
    if (ptsProvider.getOpts().verbose())
        ptsProvider.outputNotEvaluatedMethods();
}
Also used : CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) Histogram(soot.jimple.spark.geom.utils.Histogram) InvokeExpr(soot.jimple.InvokeExpr) CallGraph(soot.jimple.toolkits.callgraph.CallGraph) SootMethod(soot.SootMethod) Edge(soot.jimple.toolkits.callgraph.Edge) CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) LocalVarNode(soot.jimple.spark.pag.LocalVarNode) Stmt(soot.jimple.Stmt) AssignStmt(soot.jimple.AssignStmt)

Example 5 with Edge

use of soot.jimple.toolkits.callgraph.Edge in project soot by Sable.

the class PtInsNodeGenerator method initFlowGraph.

@Override
public void initFlowGraph(GeomPointsTo ptAnalyzer) {
    int k;
    int n_legal_cons;
    int nf1, nf2;
    int code;
    CgEdge q;
    IVarAbstraction my_lhs, my_rhs;
    // Visit all the simple constraints
    n_legal_cons = 0;
    for (PlainConstraint cons : ptAnalyzer.constraints) {
        if (!cons.isActive)
            continue;
        my_lhs = cons.getLHS().getRepresentative();
        my_rhs = cons.getRHS().getRepresentative();
        nf1 = ptAnalyzer.getMethodIDFromPtr(my_lhs);
        nf2 = ptAnalyzer.getMethodIDFromPtr(my_rhs);
        // Test how many globals are in this constraint
        code = ((nf1 == Constants.SUPER_MAIN ? 1 : 0) << 1) | (nf2 == Constants.SUPER_MAIN ? 1 : 0);
        switch(cons.type) {
            case Constants.NEW_CONS:
                // We directly add the objects to the points-to set
                my_rhs.add_points_to_3((AllocNode) my_lhs.getWrappedNode(), nf2 == Constants.SUPER_MAIN ? 0 : 1, nf1 == Constants.SUPER_MAIN ? 0 : 1, nf2 == Constants.SUPER_MAIN ? ptAnalyzer.context_size[nf1] : ptAnalyzer.context_size[nf2]);
                // Enqueue to the worklist
                ptAnalyzer.getWorklist().push(my_rhs);
                break;
            case Constants.ASSIGN_CONS:
                // The core part of any context sensitive algorithms
                if (cons.interCallEdges != null) {
                    // Inter-procedural assignment
                    for (Iterator<Edge> it = cons.interCallEdges.iterator(); it.hasNext(); ) {
                        Edge sEdge = it.next();
                        q = ptAnalyzer.getInternalEdgeFromSootEdge(sEdge);
                        if (q.is_obsoleted == true) {
                            continue;
                        }
                        if (nf2 == q.t) {
                            // The receiver is a local, while the sender is perhaps not
                            if (nf1 == Constants.SUPER_MAIN) {
                                my_lhs.add_simple_constraint_3(my_rhs, 0, q.map_offset, ptAnalyzer.max_context_size_block[q.s]);
                            } else {
                                // We should treat the self recursive calls specially
                                if (q.s == q.t) {
                                    my_lhs.add_simple_constraint_3(my_rhs, 1, 1, ptAnalyzer.context_size[nf1]);
                                } else {
                                    for (k = 0; k < ptAnalyzer.block_num[nf1]; ++k) {
                                        my_lhs.add_simple_constraint_3(my_rhs, k * ptAnalyzer.max_context_size_block[nf1] + 1, q.map_offset, ptAnalyzer.max_context_size_block[nf1]);
                                    }
                                }
                            }
                        } else {
                            if (q.s == q.t) {
                                my_lhs.add_simple_constraint_3(my_rhs, 1, 1, ptAnalyzer.context_size[nf2]);
                            } else {
                                for (k = 0; k < ptAnalyzer.block_num[nf2]; ++k) {
                                    my_lhs.add_simple_constraint_3(my_rhs, q.map_offset, k * ptAnalyzer.max_context_size_block[nf2] + 1, ptAnalyzer.max_context_size_block[nf2]);
                                }
                            }
                        }
                    }
                } else {
                    // Intraprocedural
                    // And, assignment involves global variable goes here. By
                    // definition, global variables belong to SUPER_MAIN.
                    // By the Jimple IR, not both sides are global variables
                    my_lhs.add_simple_constraint_3(my_rhs, nf1 == Constants.SUPER_MAIN ? 0 : 1, nf2 == Constants.SUPER_MAIN ? 0 : 1, nf1 == Constants.SUPER_MAIN ? ptAnalyzer.context_size[nf2] : ptAnalyzer.context_size[nf1]);
                }
                break;
            case Constants.LOAD_CONS:
                // lhs is always a local
                // rhs = lhs.f
                cons.code = full_convertor[code];
                cons.otherSide = my_rhs;
                my_lhs.put_complex_constraint(cons);
                break;
            case Constants.STORE_CONS:
                // rhs is always a local
                // rhs.f = lhs
                cons.code = full_convertor[code];
                cons.otherSide = my_lhs;
                my_rhs.put_complex_constraint(cons);
                break;
            default:
                throw new RuntimeException("Invalid node type");
        }
        ++n_legal_cons;
    }
    ptAnalyzer.ps.printf("Only %d (%.1f%%) constraints are needed for this run.\n", n_legal_cons, ((double) n_legal_cons / ptAnalyzer.n_init_constraints) * 100);
}
Also used : CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) PlainConstraint(soot.jimple.spark.geom.dataRep.PlainConstraint) IVarAbstraction(soot.jimple.spark.geom.geomPA.IVarAbstraction) CgEdge(soot.jimple.spark.geom.dataRep.CgEdge) Edge(soot.jimple.toolkits.callgraph.Edge) PlainConstraint(soot.jimple.spark.geom.dataRep.PlainConstraint)

Aggregations

Edge (soot.jimple.toolkits.callgraph.Edge)15 CgEdge (soot.jimple.spark.geom.dataRep.CgEdge)8 SootMethod (soot.SootMethod)7 CallGraph (soot.jimple.toolkits.callgraph.CallGraph)7 PlainConstraint (soot.jimple.spark.geom.dataRep.PlainConstraint)5 Stmt (soot.jimple.Stmt)4 LocalVarNode (soot.jimple.spark.pag.LocalVarNode)4 IVarAbstraction (soot.jimple.spark.geom.geomPA.IVarAbstraction)3 SootClass (soot.SootClass)2 Unit (soot.Unit)2 InstanceInvokeExpr (soot.jimple.InstanceInvokeExpr)2 InvokeExpr (soot.jimple.InvokeExpr)2 AllocNode (soot.jimple.spark.pag.AllocNode)2 ContextVarNode (soot.jimple.spark.pag.ContextVarNode)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 Iterator (java.util.Iterator)1 LinkedList (java.util.LinkedList)1 List (java.util.List)1