Search in sources :

Example 1 with ThrowInst

use of soot.baf.ThrowInst in project soot by Sable.

the class ExceptionalUnitGraph method buildExceptionalEdges.

/**
 * Method to compute the edges corresponding to exceptional control flow.
 *
 * @param throwAnalysis
 *            the source of information about the exceptions which each
 *            {@link Unit} may throw.
 *
 * @param unitToExceptionDests
 *            A <code>Map</code> from {@link Unit}s to {@link Collection}s
 *            of {@link ExceptionalUnitGraph.ExceptionDest ExceptionDest}s
 *            which represent the handlers that might catch exceptions
 *            thrown by the <code>Unit</code>. This is an ``in parameter''.
 *
 * @param unitToSuccs
 *            A <code>Map</code> from <code>Unit</code>s to {@link List}s of
 *            <code>Unit</code>s. This is an ``out parameter'';
 *            <code>buildExceptionalEdges</code> will add a mapping from
 *            every <code>Unit</code> in the body that may throw an
 *            exception that could be caught by a {@link Trap} in the body
 *            to a list of its exceptional successors.
 *
 * @param unitToPreds
 *            A <code>Map</code> from <code>Unit</code>s to
 *            <code>List</code>s of <code>Unit</code>s. This is an ``out
 *            parameter''; <code>buildExceptionalEdges</code> will add a
 *            mapping from each handler unit that may catch an exception to
 *            the list of <code>Unit</code>s whose exceptions it may catch.
 * @param omitExceptingUnitEdges
 *            Indicates whether to omit exceptional edges from excepting
 *            units which lack side effects
 *
 * @return a {@link Set} of trap <code>Unit</code>s that might catch
 *         exceptions thrown by the first <code>Unit</code> in the
 *         {@link Body} associated with the graph being constructed. Such
 *         trap <code>Unit</code>s may need to be added to the list of heads
 *         (depending on your definition of heads), since they can be the
 *         first <code>Unit</code> in the <code>Body</code> which actually
 *         completes execution.
 */
protected Set<Unit> buildExceptionalEdges(ThrowAnalysis throwAnalysis, Map<Unit, Collection<ExceptionDest>> unitToExceptionDests, Map<Unit, List<Unit>> unitToSuccs, Map<Unit, List<Unit>> unitToPreds, boolean omitExceptingUnitEdges) {
    Set<Unit> trapsThatAreHeads = new ArraySet<Unit>();
    Unit entryPoint = unitChain.getFirst();
    for (Entry<Unit, Collection<ExceptionDest>> entry : unitToExceptionDests.entrySet()) {
        Unit thrower = entry.getKey();
        List<Unit> throwersPreds = getUnexceptionalPredsOf(thrower);
        Collection<ExceptionDest> dests = entry.getValue();
        // We need to recognize:
        // - caught exceptions for which we must add edges from the
        // thrower's predecessors to the catcher:
        // - all exceptions of non-throw instructions;
        // - implicit exceptions of throw instructions.
        // 
        // - caught exceptions where we must add edges from the
        // thrower itself to the catcher:
        // - any exception of non-throw instructions if
        // omitExceptingUnitEdges is not set.
        // - any exception of non-throw instructions with side effects.
        // - explicit exceptions of throw instructions
        // - implicit exceptions of throw instructions if
        // omitExceptingUnitEdges is not set.
        // - implicit exceptions of throw instructions with possible
        // side effects (this is only possible for the grimp
        // IR, where the throw's argument may be an
        // expression---probably a NewInvokeExpr---which
        // might have executed partially before the
        // exception arose).
        // 
        // Note that a throw instruction may be capable of throwing a given
        // Throwable type both implicitly and explicitly.
        // 
        // We track these situations using predThrowables and
        // selfThrowables. Essentially predThrowables is the set
        // of Throwable types to whose catchers there should be
        // edges from predecessors of the thrower, while
        // selfThrowables is the set of Throwable types to whose
        // catchers there should be edges from the thrower itself,
        // but we we take some short cuts to avoid calling
        // ThrowableSet.catchableAs() when we can avoid it.
        boolean alwaysAddSelfEdges = ((!omitExceptingUnitEdges) || mightHaveSideEffects(thrower));
        ThrowableSet predThrowables = null;
        ThrowableSet selfThrowables = null;
        if (thrower instanceof ThrowInst) {
            ThrowInst throwInst = (ThrowInst) thrower;
            predThrowables = throwAnalysis.mightThrowImplicitly(throwInst);
            selfThrowables = throwAnalysis.mightThrowExplicitly(throwInst);
        } else if (thrower instanceof ThrowStmt) {
            ThrowStmt throwStmt = (ThrowStmt) thrower;
            predThrowables = throwAnalysis.mightThrowImplicitly(throwStmt);
            selfThrowables = throwAnalysis.mightThrowExplicitly(throwStmt);
        }
        for (ExceptionDest dest : dests) {
            if (dest.getTrap() != null) {
                Unit catcher = dest.getTrap().getHandlerUnit();
                RefType trapsType = dest.getTrap().getException().getType();
                if (predThrowables == null || predThrowables.catchableAs(trapsType)) {
                    // catcher.
                    if (thrower == entryPoint) {
                        trapsThatAreHeads.add(catcher);
                    }
                    for (Unit pred : throwersPreds) {
                        addEdge(unitToSuccs, unitToPreds, pred, catcher);
                    }
                }
                if (alwaysAddSelfEdges || (selfThrowables != null && selfThrowables.catchableAs(trapsType))) {
                    addEdge(unitToSuccs, unitToPreds, thrower, catcher);
                }
            }
        }
    }
    // worklist containing CFG edges that lead to such a handler.
    class CFGEdge {

        // If null, represents an edge to the handler
        Unit head;

        // from the fictitious "predecessor" of the
        // very first unit in the chain. I.e., tail
        // is a handler which might be reached as a
        // result of an exception thrown by the
        // first Unit in the Body.
        Unit tail;

        CFGEdge(Unit head, Unit tail) {
            if (tail == null)
                throw new RuntimeException("invalid CFGEdge(" + (head == null ? "null" : head.toString()) + ',' + "null" + ')');
            this.head = head;
            this.tail = tail;
        }

        @Override
        public boolean equals(Object rhs) {
            if (rhs == this) {
                return true;
            }
            if (!(rhs instanceof CFGEdge)) {
                return false;
            }
            CFGEdge rhsEdge = (CFGEdge) rhs;
            return ((this.head == rhsEdge.head) && (this.tail == rhsEdge.tail));
        }

        @Override
        public int hashCode() {
            // Following Joshua Bloch's recipe in "Effective Java", Item 8:
            int result = 17;
            result = 37 * result + this.head.hashCode();
            result = 37 * result + this.tail.hashCode();
            return result;
        }
    }
    LinkedList<CFGEdge> workList = new LinkedList<CFGEdge>();
    for (Trap trap : body.getTraps()) {
        Unit handlerStart = trap.getHandlerUnit();
        if (mightThrowToIntraproceduralCatcher(handlerStart)) {
            List<Unit> handlerPreds = getUnexceptionalPredsOf(handlerStart);
            for (Unit pred : handlerPreds) {
                workList.addLast(new CFGEdge(pred, handlerStart));
            }
            handlerPreds = getExceptionalPredsOf(handlerStart);
            for (Unit pred : handlerPreds) {
                workList.addLast(new CFGEdge(pred, handlerStart));
            }
            if (trapsThatAreHeads.contains(handlerStart)) {
                workList.addLast(new CFGEdge(null, handlerStart));
            }
        }
    }
    // the handler's exception.
    while (workList.size() > 0) {
        CFGEdge edgeToThrower = workList.removeFirst();
        Unit pred = edgeToThrower.head;
        Unit thrower = edgeToThrower.tail;
        Collection<ExceptionDest> throwerDests = getExceptionDests(thrower);
        for (ExceptionDest dest : throwerDests) {
            if (dest.getTrap() != null) {
                Unit handlerStart = dest.getTrap().getHandlerUnit();
                boolean edgeAdded = false;
                if (pred == null) {
                    if (!trapsThatAreHeads.contains(handlerStart)) {
                        trapsThatAreHeads.add(handlerStart);
                        edgeAdded = true;
                    }
                } else {
                    if (!getExceptionalSuccsOf(pred).contains(handlerStart)) {
                        addEdge(unitToSuccs, unitToPreds, pred, handlerStart);
                        edgeAdded = true;
                    }
                }
                if (edgeAdded && mightThrowToIntraproceduralCatcher(handlerStart)) {
                    workList.addLast(new CFGEdge(pred, handlerStart));
                }
            }
        }
    }
    return trapsThatAreHeads;
}
Also used : ThrowInst(soot.baf.ThrowInst) ArraySet(soot.util.ArraySet) Trap(soot.Trap) Unit(soot.Unit) LinkedList(java.util.LinkedList) RefType(soot.RefType) ThrowableSet(soot.toolkits.exceptions.ThrowableSet) Collection(java.util.Collection) ThrowStmt(soot.jimple.ThrowStmt)

Aggregations

Collection (java.util.Collection)1 LinkedList (java.util.LinkedList)1 RefType (soot.RefType)1 Trap (soot.Trap)1 Unit (soot.Unit)1 ThrowInst (soot.baf.ThrowInst)1 ThrowStmt (soot.jimple.ThrowStmt)1 ThrowableSet (soot.toolkits.exceptions.ThrowableSet)1 ArraySet (soot.util.ArraySet)1