Search in sources :

Example 1 with ThrowableSet

use of soot.toolkits.exceptions.ThrowableSet in project soot by Sable.

the class ExceptionalUnitGraph method buildExceptionDests.

/**
 * <p>
 * Utility method used in the construction of
 * {@link soot.toolkits.graph.UnitGraph UnitGraph} variants which include
 * exceptional control flow. It determines which {@link Unit}s may throw
 * exceptions that would be caught by {@link Trap}s within the method.
 * </p>
 *
 * @param throwAnalysis
 *            The source of information about which exceptions each
 *            <code>Unit</code> may throw.
 *
 * @return <code>null</code> if no <code>Unit</code>s in the method throw
 *         any exceptions caught within the method. Otherwise, a {@link Map}
 *         from <code>Unit</code>s to {@link Collection}s of
 *         {@link ExceptionDest}s.
 *
 *         <p>
 *         The returned map has an idiosyncracy which is hidden from most
 *         client code, but which is exposed to subclasses extending
 *         <code>ExceptionalUnitGraph</code>. If a <code>Unit</code> throws
 *         one or more exceptions which are caught within the method, it
 *         will be mapped to a <code>Collection</code> of
 *         <code>ExceptionDest</code>s describing the sets of exceptions
 *         that the <code>Unit</code> might throw to each {@link Trap}. But
 *         if all of a <code>Unit</code>'s exceptions escape the method, it
 *         will be mapped to <code>null</code, rather than to a
 *         <code>Collection</code> containing a single
 *         <code>ExceptionDest</code> with a <code>null</code> trap. (The
 *         special case for <code>Unit</code>s with no caught exceptions
 *         allows <code>buildExceptionDests()</code> to ignore completely
 *         <code>Unit</code>s which are outside the scope of all
 *         <code>Trap</code>s.)
 *         </p>
 */
protected Map<Unit, Collection<ExceptionDest>> buildExceptionDests(ThrowAnalysis throwAnalysis) {
    Chain<Unit> units = body.getUnits();
    Map<Unit, ThrowableSet> unitToUncaughtThrowables = new LinkedHashMap<Unit, ThrowableSet>(units.size());
    Map<Unit, Collection<ExceptionDest>> result = null;
    // Record the caught exceptions.
    for (Trap trap : body.getTraps()) {
        RefType catcher = trap.getException().getType();
        for (Iterator<Unit> unitIt = units.iterator(trap.getBeginUnit(), units.getPredOf(trap.getEndUnit())); unitIt.hasNext(); ) {
            Unit unit = unitIt.next();
            ThrowableSet thrownSet = unitToUncaughtThrowables.get(unit);
            if (thrownSet == null) {
                thrownSet = throwAnalysis.mightThrow(unit);
            }
            ThrowableSet.Pair catchableAs = thrownSet.whichCatchableAs(catcher);
            if (!catchableAs.getCaught().equals(ThrowableSet.Manager.v().EMPTY)) {
                result = addDestToMap(result, unit, trap, catchableAs.getCaught());
                unitToUncaughtThrowables.put(unit, catchableAs.getUncaught());
            } else {
                assert thrownSet.equals(catchableAs.getUncaught()) : "ExceptionalUnitGraph.buildExceptionDests(): catchableAs.caught == EMPTY, but catchableAs.uncaught != thrownSet" + System.getProperty("line.separator") + body.getMethod().getSubSignature() + " Unit: " + unit.toString() + System.getProperty("line.separator") + " catchableAs.getUncaught() == " + catchableAs.getUncaught().toString() + System.getProperty("line.separator") + " thrownSet == " + thrownSet.toString();
            }
        }
    }
    for (Map.Entry<Unit, ThrowableSet> entry : unitToUncaughtThrowables.entrySet()) {
        Unit unit = entry.getKey();
        ThrowableSet escaping = entry.getValue();
        if (escaping != ThrowableSet.Manager.v().EMPTY) {
            result = addDestToMap(result, unit, null, escaping);
        }
    }
    if (result == null) {
        result = Collections.emptyMap();
    }
    return result;
}
Also used : Trap(soot.Trap) Unit(soot.Unit) LinkedHashMap(java.util.LinkedHashMap) RefType(soot.RefType) ThrowableSet(soot.toolkits.exceptions.ThrowableSet) Collection(java.util.Collection) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map)

Example 2 with ThrowableSet

use of soot.toolkits.exceptions.ThrowableSet 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)

Example 3 with ThrowableSet

use of soot.toolkits.exceptions.ThrowableSet in project soot by Sable.

the class ExceptionalBlockGraph method collectDests.

/**
 * Utility method which, given a {@link Block} and the
 * {@link ExceptionalUnitGraph} from which it was constructed,
 * returns the {@link ExceptionDest}s representing the exceptions
 * which may be thrown by units in the block.
 *
 * @param block the {@link Block} whose exceptions are to be collected.
 *
 * @param unitGraph the {@link ExceptionalUnitGraph} from which this
 *                  graph is constructed.
 *
 * @param unitToBlock a {@link Map} from the units which are block heads
 *                    or tails to the blocks that they belong to.
 *
 * @return a {@link Collection} of {@link ExceptionDest}s representing
 *           the exceptions that may be thrown by this block, together
 *           with their catchers.
 */
private Collection<ExceptionDest> collectDests(Block block, ExceptionalUnitGraph unitGraph, Map<Unit, Block> unitToBlock) {
    Unit blockHead = block.getHead();
    Unit blockTail = block.getTail();
    ArrayList<ExceptionDest> blocksDests = null;
    ThrowableSet escapingThrowables = ThrowableSet.Manager.v().EMPTY;
    // Don't allocate unless we need it.
    Map<Trap, ThrowableSet> trapToThrowables = null;
    int caughtCount = 0;
    for (Unit unit2 : block) {
        Unit unit = unit2;
        Collection<ExceptionalUnitGraph.ExceptionDest> unitDests = unitGraph.getExceptionDests(unit);
        if (unitDests.size() != 1 && unit != blockHead && unit != blockTail) {
            throw new IllegalStateException("Multiple ExceptionDests associated with a unit which does not begin or end its block.");
        }
        for (soot.toolkits.graph.ExceptionalUnitGraph.ExceptionDest unitDest : unitDests) {
            if (unitDest.getTrap() == null) {
                try {
                    escapingThrowables = escapingThrowables.add(unitDest.getThrowables());
                } catch (ThrowableSet.AlreadyHasExclusionsException e) {
                    if (escapingThrowables != ThrowableSet.Manager.v().EMPTY) {
                        // to add all the escaping type descriptions together.
                        if (blocksDests == null) {
                            blocksDests = new ArrayList<ExceptionDest>(10);
                        }
                        blocksDests.add(new ExceptionDest(null, escapingThrowables, null));
                    }
                    escapingThrowables = unitDest.getThrowables();
                }
            } else {
                if (unit != blockHead && unit != blockTail) {
                    // Assertion failure.
                    throw new IllegalStateException("Unit " + unit.toString() + " is not a block head or tail, yet it throws " + unitDest.getThrowables() + " to " + unitDest.getTrap());
                }
                caughtCount++;
                if (trapToThrowables == null) {
                    trapToThrowables = new HashMap<Trap, ThrowableSet>(unitDests.size() * 2);
                }
                Trap trap = unitDest.getTrap();
                ThrowableSet throwables = trapToThrowables.get(trap);
                if (throwables == null) {
                    throwables = unitDest.getThrowables();
                } else {
                    throwables = throwables.add(unitDest.getThrowables());
                }
                trapToThrowables.put(trap, throwables);
            }
        }
    }
    if (blocksDests == null) {
        blocksDests = new ArrayList<ExceptionDest>(caughtCount + 1);
    } else {
        blocksDests.ensureCapacity(blocksDests.size() + caughtCount);
    }
    if (escapingThrowables != ThrowableSet.Manager.v().EMPTY) {
        ExceptionDest escapingDest = new ExceptionDest(null, escapingThrowables, null);
        blocksDests.add(escapingDest);
    }
    if (trapToThrowables != null) {
        for (Map.Entry<Trap, ThrowableSet> entry : trapToThrowables.entrySet()) {
            Trap trap = entry.getKey();
            Block trapBlock = unitToBlock.get(trap.getHandlerUnit());
            if (trapBlock == null) {
                throw new IllegalStateException("catching unit is not recorded as a block leader.");
            }
            ThrowableSet throwables = entry.getValue();
            ExceptionDest blockDest = new ExceptionDest(trap, throwables, trapBlock);
            blocksDests.add(blockDest);
        }
    }
    return blocksDests;
}
Also used : ArrayList(java.util.ArrayList) Trap(soot.Trap) Unit(soot.Unit) ThrowableSet(soot.toolkits.exceptions.ThrowableSet) Map(java.util.Map) HashMap(java.util.HashMap)

Aggregations

Trap (soot.Trap)3 Unit (soot.Unit)3 ThrowableSet (soot.toolkits.exceptions.ThrowableSet)3 Collection (java.util.Collection)2 Map (java.util.Map)2 RefType (soot.RefType)2 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 LinkedHashMap (java.util.LinkedHashMap)1 LinkedList (java.util.LinkedList)1 ThrowInst (soot.baf.ThrowInst)1 ThrowStmt (soot.jimple.ThrowStmt)1 ArraySet (soot.util.ArraySet)1