Search in sources :

Example 6 with ThrowStmt

use of soot.jimple.ThrowStmt in project soot by Sable.

the class ThrowInstruction method jimplify.

@Override
public void jimplify(DexBody body) {
    Instruction11x throwInstruction = (Instruction11x) instruction;
    ThrowStmt throwStmt = Jimple.v().newThrowStmt(body.getRegisterLocal(throwInstruction.getRegisterA()));
    setUnit(throwStmt);
    addTags(throwStmt);
    body.add(throwStmt);
    if (IDalvikTyper.ENABLE_DVKTYPER) {
        DalvikTyper.v().setType(throwStmt.getOpBox(), RefType.v("java.lang.Throwable"), true);
    }
}
Also used : Instruction11x(org.jf.dexlib2.iface.instruction.formats.Instruction11x) ThrowStmt(soot.jimple.ThrowStmt)

Example 7 with ThrowStmt

use of soot.jimple.ThrowStmt in project soot by Sable.

the class DexNullTransformer method internalTransform.

@Override
protected void internalTransform(final Body body, String phaseName, Map<String, String> options) {
    final DexDefUseAnalysis localDefs = new DexDefUseAnalysis(body);
    AbstractStmtSwitch checkDef = new // Alex: should also end as
    AbstractStmtSwitch() {

        // soon as detected as not
        // used as an object
        @Override
        public void caseAssignStmt(AssignStmt stmt) {
            Value r = stmt.getRightOp();
            if (r instanceof FieldRef) {
                usedAsObject = isObject(((FieldRef) r).getFieldRef().type());
                doBreak = true;
                return;
            } else if (r instanceof ArrayRef) {
                ArrayRef ar = (ArrayRef) r;
                if (ar.getType() instanceof UnknownType) {
                    // isObject
                    usedAsObject = stmt.hasTag("ObjectOpTag");
                // (findArrayType
                // (g,
                // localDefs,
                // localUses,
                // stmt));
                } else {
                    usedAsObject = isObject(ar.getType());
                }
                doBreak = true;
                return;
            } else if (r instanceof StringConstant || r instanceof NewExpr || r instanceof NewArrayExpr) {
                usedAsObject = true;
                doBreak = true;
                return;
            } else if (r instanceof CastExpr) {
                usedAsObject = isObject(((CastExpr) r).getCastType());
                doBreak = true;
                return;
            } else if (r instanceof InvokeExpr) {
                usedAsObject = isObject(((InvokeExpr) r).getType());
                doBreak = true;
                return;
            } else if (r instanceof LengthExpr) {
                usedAsObject = false;
                doBreak = true;
                return;
            // introduces alias
            }
        }

        @Override
        public void caseIdentityStmt(IdentityStmt stmt) {
            if (stmt.getLeftOp() == l) {
                usedAsObject = isObject(stmt.getRightOp().getType());
                doBreak = true;
                return;
            }
        }
    };
    AbstractStmtSwitch checkUse = new AbstractStmtSwitch() {

        private boolean examineInvokeExpr(InvokeExpr e) {
            List<Value> args = e.getArgs();
            List<Type> argTypes = e.getMethodRef().parameterTypes();
            assert args.size() == argTypes.size();
            for (int i = 0; i < args.size(); i++) {
                if (args.get(i) == l && isObject(argTypes.get(i))) {
                    return true;
                }
            }
            // check for base
            SootMethodRef sm = e.getMethodRef();
            if (!sm.isStatic()) {
                if (e instanceof AbstractInvokeExpr) {
                    AbstractInstanceInvokeExpr aiiexpr = (AbstractInstanceInvokeExpr) e;
                    Value b = aiiexpr.getBase();
                    if (b == l) {
                        return true;
                    }
                }
            }
            return false;
        }

        @Override
        public void caseInvokeStmt(InvokeStmt stmt) {
            InvokeExpr e = stmt.getInvokeExpr();
            usedAsObject = examineInvokeExpr(e);
            doBreak = true;
            return;
        }

        @Override
        public void caseAssignStmt(AssignStmt stmt) {
            Value left = stmt.getLeftOp();
            Value r = stmt.getRightOp();
            if (left instanceof ArrayRef) {
                ArrayRef ar = (ArrayRef) left;
                if (ar.getIndex() == l) {
                    doBreak = true;
                    return;
                } else if (ar.getBase() == l) {
                    usedAsObject = true;
                    doBreak = true;
                    return;
                }
            }
            if (left instanceof InstanceFieldRef) {
                InstanceFieldRef ifr = (InstanceFieldRef) left;
                if (ifr.getBase() == l) {
                    usedAsObject = true;
                    doBreak = true;
                    return;
                }
            }
            // used to assign
            if (stmt.getRightOp() == l) {
                Value l = stmt.getLeftOp();
                if (l instanceof StaticFieldRef && isObject(((StaticFieldRef) l).getFieldRef().type())) {
                    usedAsObject = true;
                    doBreak = true;
                    return;
                } else if (l instanceof InstanceFieldRef && isObject(((InstanceFieldRef) l).getFieldRef().type())) {
                    usedAsObject = true;
                    doBreak = true;
                    return;
                } else if (l instanceof ArrayRef) {
                    Type aType = ((ArrayRef) l).getType();
                    if (aType instanceof UnknownType) {
                        usedAsObject = stmt.hasTag(// isObject(
                        "ObjectOpTag");
                    // findArrayType(g,
                    // localDefs,
                    // localUses,
                    // stmt));
                    } else {
                        usedAsObject = isObject(aType);
                    }
                    doBreak = true;
                    return;
                }
            }
            // is used as value (does not exclude assignment)
            if (r instanceof FieldRef) {
                // isObject(((FieldRef)
                usedAsObject = true;
                // r).getFieldRef().type());
                doBreak = true;
                return;
            } else if (r instanceof ArrayRef) {
                ArrayRef ar = (ArrayRef) r;
                if (ar.getBase() == l) {
                    usedAsObject = true;
                } else {
                    // used as index
                    usedAsObject = false;
                }
                doBreak = true;
                return;
            } else if (r instanceof StringConstant || r instanceof NewExpr) {
                throw new RuntimeException("NOT POSSIBLE StringConstant or NewExpr at " + stmt);
            } else if (r instanceof NewArrayExpr) {
                usedAsObject = false;
                doBreak = true;
                return;
            } else if (r instanceof CastExpr) {
                usedAsObject = isObject(((CastExpr) r).getCastType());
                doBreak = true;
                return;
            } else if (r instanceof InvokeExpr) {
                usedAsObject = examineInvokeExpr((InvokeExpr) stmt.getRightOp());
                doBreak = true;
                return;
            } else if (r instanceof LengthExpr) {
                usedAsObject = true;
                doBreak = true;
                return;
            } else if (r instanceof BinopExpr) {
                usedAsObject = false;
                doBreak = true;
                return;
            }
        }

        @Override
        public void caseIdentityStmt(IdentityStmt stmt) {
            if (stmt.getLeftOp() == l)
                throw new RuntimeException("IMPOSSIBLE 0");
        }

        @Override
        public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
            usedAsObject = stmt.getOp() == l;
            doBreak = true;
            return;
        }

        @Override
        public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
            usedAsObject = stmt.getOp() == l;
            doBreak = true;
            return;
        }

        @Override
        public void caseReturnStmt(ReturnStmt stmt) {
            usedAsObject = stmt.getOp() == l && isObject(body.getMethod().getReturnType());
            doBreak = true;
            return;
        }

        @Override
        public void caseThrowStmt(ThrowStmt stmt) {
            usedAsObject = stmt.getOp() == l;
            doBreak = true;
            return;
        }
    };
    for (Local loc : getNullCandidates(body)) {
        usedAsObject = false;
        Set<Unit> defs = localDefs.collectDefinitionsWithAliases(loc);
        // process normally
        doBreak = false;
        for (Unit u : defs) {
            // put correct local in l
            if (u instanceof DefinitionStmt) {
                l = (Local) ((DefinitionStmt) u).getLeftOp();
            } else if (u instanceof IfStmt) {
                throw new RuntimeException("ERROR: def can not be something else than Assign or Identity statement! (def: " + u + " class: " + u.getClass() + "");
            }
            // check defs
            u.apply(checkDef);
            if (doBreak)
                break;
            // check uses
            for (Unit use : localDefs.getUsesOf(l)) {
                use.apply(checkUse);
                if (doBreak)
                    break;
            }
            // for uses
            if (doBreak)
                break;
        }
        // change values
        if (usedAsObject) {
            for (Unit u : defs) {
                replaceWithNull(u);
                Set<Value> defLocals = new HashSet<Value>();
                for (ValueBox vb : u.getDefBoxes()) defLocals.add(vb.getValue());
                Local l = (Local) ((DefinitionStmt) u).getLeftOp();
                for (Unit uuse : localDefs.getUsesOf(l)) {
                    Stmt use = (Stmt) uuse;
                    // If we have a[x] = 0 and a is an object, we may not conclude 0 -> null
                    if (!use.containsArrayRef() || !defLocals.contains(use.getArrayRef().getBase()))
                        replaceWithNull(use);
                }
            }
        }
    // end if
    }
    // Check for inlined zero values
    AbstractStmtSwitch inlinedZeroValues = new AbstractStmtSwitch() {

        final NullConstant nullConstant = NullConstant.v();

        @Override
        public void caseAssignStmt(AssignStmt stmt) {
            // Case a = 0 with a being an object
            if (isObject(stmt.getLeftOp().getType()) && isConstZero(stmt.getRightOp())) {
                stmt.setRightOp(nullConstant);
                return;
            }
            // Case a = (Object) 0
            if (stmt.getRightOp() instanceof CastExpr) {
                CastExpr ce = (CastExpr) stmt.getRightOp();
                if (isObject(ce.getCastType()) && isConstZero(ce.getOp())) {
                    stmt.setRightOp(nullConstant);
                }
            }
            // Case a[0] = 0
            if (stmt.getLeftOp() instanceof ArrayRef && isConstZero(stmt.getRightOp())) {
                ArrayRef ar = (ArrayRef) stmt.getLeftOp();
                if (isObjectArray(ar.getBase(), body) || stmt.hasTag("ObjectOpTag")) {
                    stmt.setRightOp(nullConstant);
                }
            }
        }

        private boolean isConstZero(Value rightOp) {
            if (rightOp instanceof IntConstant && ((IntConstant) rightOp).value == 0)
                return true;
            if (rightOp instanceof LongConstant && ((LongConstant) rightOp).value == 0)
                return true;
            return false;
        }

        @Override
        public void caseReturnStmt(ReturnStmt stmt) {
            if (stmt.getOp() instanceof IntConstant && isObject(body.getMethod().getReturnType())) {
                IntConstant iconst = (IntConstant) stmt.getOp();
                assert iconst.value == 0;
                stmt.setOp(nullConstant);
            }
        }

        @Override
        public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
            if (stmt.getOp() instanceof IntConstant && ((IntConstant) stmt.getOp()).value == 0)
                stmt.setOp(nullConstant);
        }

        @Override
        public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
            if (stmt.getOp() instanceof IntConstant && ((IntConstant) stmt.getOp()).value == 0)
                stmt.setOp(nullConstant);
        }
    };
    final NullConstant nullConstant = NullConstant.v();
    for (Unit u : body.getUnits()) {
        u.apply(inlinedZeroValues);
        if (u instanceof Stmt) {
            Stmt stmt = (Stmt) u;
            if (stmt.containsInvokeExpr()) {
                InvokeExpr invExpr = stmt.getInvokeExpr();
                for (int i = 0; i < invExpr.getArgCount(); i++) if (isObject(invExpr.getMethodRef().parameterType(i)))
                    if (invExpr.getArg(i) instanceof IntConstant) {
                        IntConstant iconst = (IntConstant) invExpr.getArg(i);
                        assert iconst.value == 0;
                        invExpr.setArg(i, nullConstant);
                    }
            }
        }
    }
}
Also used : ExitMonitorStmt(soot.jimple.ExitMonitorStmt) InvokeStmt(soot.jimple.InvokeStmt) AssignStmt(soot.jimple.AssignStmt) Unit(soot.Unit) InvokeStmt(soot.jimple.InvokeStmt) ThrowStmt(soot.jimple.ThrowStmt) IfStmt(soot.jimple.IfStmt) IdentityStmt(soot.jimple.IdentityStmt) EnterMonitorStmt(soot.jimple.EnterMonitorStmt) ReturnStmt(soot.jimple.ReturnStmt) ExitMonitorStmt(soot.jimple.ExitMonitorStmt) Stmt(soot.jimple.Stmt) AssignStmt(soot.jimple.AssignStmt) DefinitionStmt(soot.jimple.DefinitionStmt) ArrayRef(soot.jimple.ArrayRef) AbstractInvokeExpr(soot.jimple.internal.AbstractInvokeExpr) AbstractInstanceInvokeExpr(soot.jimple.internal.AbstractInstanceInvokeExpr) AbstractInvokeExpr(soot.jimple.internal.AbstractInvokeExpr) InvokeExpr(soot.jimple.InvokeExpr) AbstractInstanceInvokeExpr(soot.jimple.internal.AbstractInstanceInvokeExpr) AbstractStmtSwitch(soot.jimple.AbstractStmtSwitch) CastExpr(soot.jimple.CastExpr) InstanceFieldRef(soot.jimple.InstanceFieldRef) IntConstant(soot.jimple.IntConstant) IdentityStmt(soot.jimple.IdentityStmt) EnterMonitorStmt(soot.jimple.EnterMonitorStmt) HashSet(java.util.HashSet) LongConstant(soot.jimple.LongConstant) FieldRef(soot.jimple.FieldRef) InstanceFieldRef(soot.jimple.InstanceFieldRef) StaticFieldRef(soot.jimple.StaticFieldRef) SootMethodRef(soot.SootMethodRef) LengthExpr(soot.jimple.LengthExpr) Local(soot.Local) NullConstant(soot.jimple.NullConstant) StaticFieldRef(soot.jimple.StaticFieldRef) UnknownType(soot.UnknownType) UnknownType(soot.UnknownType) ArrayType(soot.ArrayType) Type(soot.Type) IfStmt(soot.jimple.IfStmt) NewArrayExpr(soot.jimple.NewArrayExpr) ValueBox(soot.ValueBox) Value(soot.Value) NewExpr(soot.jimple.NewExpr) StringConstant(soot.jimple.StringConstant) ReturnStmt(soot.jimple.ReturnStmt) ThrowStmt(soot.jimple.ThrowStmt) DefinitionStmt(soot.jimple.DefinitionStmt) BinopExpr(soot.jimple.BinopExpr)

Example 8 with ThrowStmt

use of soot.jimple.ThrowStmt in project soot by Sable.

the class IFDSUninitializedVariables method createFlowFunctionsFactory.

@Override
public FlowFunctions<Unit, Local, SootMethod> createFlowFunctionsFactory() {
    return new FlowFunctions<Unit, Local, SootMethod>() {

        @Override
        public FlowFunction<Local> getNormalFlowFunction(Unit curr, Unit succ) {
            final SootMethod m = interproceduralCFG().getMethodOf(curr);
            if (Scene.v().getEntryPoints().contains(m) && interproceduralCFG().isStartPoint(curr)) {
                return new FlowFunction<Local>() {

                    @Override
                    public Set<Local> computeTargets(Local source) {
                        if (source == zeroValue()) {
                            Set<Local> res = new LinkedHashSet<Local>();
                            res.addAll(m.getActiveBody().getLocals());
                            for (int i = 0; i < m.getParameterCount(); i++) res.remove(m.getActiveBody().getParameterLocal(i));
                            return res;
                        }
                        return Collections.emptySet();
                    }
                };
            }
            if (curr instanceof DefinitionStmt) {
                final DefinitionStmt definition = (DefinitionStmt) curr;
                final Value leftOp = definition.getLeftOp();
                if (leftOp instanceof Local) {
                    final Local leftOpLocal = (Local) leftOp;
                    return new FlowFunction<Local>() {

                        @Override
                        public Set<Local> computeTargets(final Local source) {
                            List<ValueBox> useBoxes = definition.getUseBoxes();
                            for (ValueBox valueBox : useBoxes) {
                                if (valueBox.getValue().equivTo(source)) {
                                    LinkedHashSet<Local> res = new LinkedHashSet<Local>();
                                    res.add(source);
                                    res.add(leftOpLocal);
                                    return res;
                                }
                            }
                            if (leftOp.equivTo(source))
                                return Collections.emptySet();
                            return Collections.singleton(source);
                        }
                    };
                }
            }
            return Identity.v();
        }

        @Override
        public FlowFunction<Local> getCallFlowFunction(Unit callStmt, final SootMethod destinationMethod) {
            Stmt stmt = (Stmt) callStmt;
            InvokeExpr invokeExpr = stmt.getInvokeExpr();
            final List<Value> args = invokeExpr.getArgs();
            final List<Local> localArguments = new ArrayList<Local>();
            for (Value value : args) if (value instanceof Local)
                localArguments.add((Local) value);
            return new FlowFunction<Local>() {

                @Override
                public Set<Local> computeTargets(final Local source) {
                    // Do not map parameters for <clinit> edges
                    if (destinationMethod.getName().equals("<clinit>") || destinationMethod.getSubSignature().equals("void run()"))
                        return Collections.emptySet();
                    for (Local localArgument : localArguments) {
                        if (source.equivTo(localArgument)) {
                            return Collections.<Local>singleton(destinationMethod.getActiveBody().getParameterLocal(args.indexOf(localArgument)));
                        }
                    }
                    if (source == zeroValue()) {
                        // gen all locals that are not parameter locals
                        Collection<Local> locals = destinationMethod.getActiveBody().getLocals();
                        LinkedHashSet<Local> uninitializedLocals = new LinkedHashSet<Local>(locals);
                        for (int i = 0; i < destinationMethod.getParameterCount(); i++) {
                            uninitializedLocals.remove(destinationMethod.getActiveBody().getParameterLocal(i));
                        }
                        return uninitializedLocals;
                    }
                    return Collections.emptySet();
                }
            };
        }

        @Override
        public FlowFunction<Local> getReturnFlowFunction(final Unit callSite, SootMethod calleeMethod, final Unit exitStmt, Unit returnSite) {
            if (callSite instanceof DefinitionStmt) {
                final DefinitionStmt definition = (DefinitionStmt) callSite;
                if (definition.getLeftOp() instanceof Local) {
                    final Local leftOpLocal = (Local) definition.getLeftOp();
                    if (exitStmt instanceof ReturnStmt) {
                        final ReturnStmt returnStmt = (ReturnStmt) exitStmt;
                        return new FlowFunction<Local>() {

                            @Override
                            public Set<Local> computeTargets(Local source) {
                                if (returnStmt.getOp().equivTo(source))
                                    return Collections.singleton(leftOpLocal);
                                return Collections.emptySet();
                            }
                        };
                    } else if (exitStmt instanceof ThrowStmt) {
                        // if we throw an exception, LHS of call is undefined
                        return new FlowFunction<Local>() {

                            @Override
                            public Set<Local> computeTargets(final Local source) {
                                if (source == zeroValue())
                                    return Collections.singleton(leftOpLocal);
                                else
                                    return Collections.emptySet();
                            }
                        };
                    }
                }
            }
            return KillAll.v();
        }

        @Override
        public FlowFunction<Local> getCallToReturnFlowFunction(Unit callSite, Unit returnSite) {
            if (callSite instanceof DefinitionStmt) {
                DefinitionStmt definition = (DefinitionStmt) callSite;
                if (definition.getLeftOp() instanceof Local) {
                    final Local leftOpLocal = (Local) definition.getLeftOp();
                    return new Kill<Local>(leftOpLocal);
                }
            }
            return Identity.v();
        }
    };
}
Also used : LinkedHashSet(java.util.LinkedHashSet) LinkedHashSet(java.util.LinkedHashSet) Set(java.util.Set) ArrayList(java.util.ArrayList) Unit(soot.Unit) FlowFunctions(heros.FlowFunctions) ThrowStmt(soot.jimple.ThrowStmt) ReturnStmt(soot.jimple.ReturnStmt) Stmt(soot.jimple.Stmt) DefinitionStmt(soot.jimple.DefinitionStmt) InvokeExpr(soot.jimple.InvokeExpr) Kill(heros.flowfunc.Kill) FlowFunction(heros.FlowFunction) JimpleLocal(soot.jimple.internal.JimpleLocal) Local(soot.Local) ValueBox(soot.ValueBox) Value(soot.Value) SootMethod(soot.SootMethod) DefinitionStmt(soot.jimple.DefinitionStmt) ReturnStmt(soot.jimple.ReturnStmt) ThrowStmt(soot.jimple.ThrowStmt)

Example 9 with ThrowStmt

use of soot.jimple.ThrowStmt in project soot by Sable.

the class ExceptionChecker method internalTransform.

@Override
protected void internalTransform(Body b, String phaseName, Map options) {
    Iterator it = b.getUnits().iterator();
    while (it.hasNext()) {
        Stmt s = (Stmt) it.next();
        if (s instanceof ThrowStmt) {
            ThrowStmt ts = (ThrowStmt) s;
            checkThrow(b, ts);
        } else if (s instanceof InvokeStmt) {
            InvokeStmt is = (InvokeStmt) s;
            checkInvoke(b, is);
        } else if ((s instanceof AssignStmt) && (((AssignStmt) s).getRightOp() instanceof InvokeExpr)) {
            InvokeExpr ie = (InvokeExpr) ((AssignStmt) s).getRightOp();
            checkInvokeExpr(b, ie, s);
        }
    }
}
Also used : InstanceInvokeExpr(soot.jimple.InstanceInvokeExpr) InterfaceInvokeExpr(soot.jimple.InterfaceInvokeExpr) InvokeExpr(soot.jimple.InvokeExpr) InvokeStmt(soot.jimple.InvokeStmt) AssignStmt(soot.jimple.AssignStmt) Iterator(java.util.Iterator) ThrowStmt(soot.jimple.ThrowStmt) Stmt(soot.jimple.Stmt) InvokeStmt(soot.jimple.InvokeStmt) ThrowStmt(soot.jimple.ThrowStmt) AssignStmt(soot.jimple.AssignStmt)

Example 10 with ThrowStmt

use of soot.jimple.ThrowStmt 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

ThrowStmt (soot.jimple.ThrowStmt)14 Local (soot.Local)8 Unit (soot.Unit)8 InvokeExpr (soot.jimple.InvokeExpr)8 ReturnStmt (soot.jimple.ReturnStmt)8 Value (soot.Value)7 InvokeStmt (soot.jimple.InvokeStmt)7 Type (soot.Type)6 AssignStmt (soot.jimple.AssignStmt)6 IdentityStmt (soot.jimple.IdentityStmt)6 IfStmt (soot.jimple.IfStmt)6 RefType (soot.RefType)5 DefinitionStmt (soot.jimple.DefinitionStmt)5 EnterMonitorStmt (soot.jimple.EnterMonitorStmt)5 ExitMonitorStmt (soot.jimple.ExitMonitorStmt)5 ArrayList (java.util.ArrayList)4 ArrayType (soot.ArrayType)4 UnknownType (soot.UnknownType)4 ValueBox (soot.ValueBox)4 ArrayRef (soot.jimple.ArrayRef)4