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;
}
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;
}
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;
}
Aggregations