예제 #1
0
 public WorkItemR(Implementation i, string l)
 {
     impl          = i;
     labelBlockMap = BoogieUtil.labelBlockMapping(impl);
     label         = l;
     block         = getBlock(label, labelBlockMap);
     count         = 0;
 }
예제 #2
0
        // Rename basic blocks, local variables
        // Add "havoc locals" at the beginning
        // block return
        private static void RenameImpl(Implementation impl, Dictionary <string, Tuple <Block, Implementation> > origProg)
        {
            var origImpl   = (new FixedDuplicator(true)).VisitImplementation(impl);
            var origBlocks = BoogieUtil.labelBlockMapping(origImpl);

            // create new locals
            var newLocals = new Dictionary <string, Variable>();

            foreach (var l in impl.LocVars.Concat(impl.InParams).Concat(impl.OutParams))
            {
                // substitute even formal variables with LocalVariables. This is fine
                // because we finally just merge all implemnetations together
                var nl = BoogieAstFactory.MkLocal(l.Name + "_" + impl.Name + "_copy", l.TypedIdent.Type);
                newLocals.Add(l.Name, nl);
            }

            // rename locals
            var subst = new VarSubstituter(newLocals, new Dictionary <string, Variable>());

            subst.VisitImplementation(impl);

            // Rename blocks
            foreach (var blk in impl.Blocks)
            {
                var newName = impl.Name + "_" + blk.Label;
                origProg.Add(newName, Tuple.Create(origBlocks[blk.Label], origImpl));
                blk.Label = newName;

                if (blk.TransferCmd is GotoCmd)
                {
                    var gc = blk.TransferCmd as GotoCmd;
                    gc.labelNames = new List <string>(
                        gc.labelNames.Select(lab => impl.Name + "_" + lab));
                }

                if (blk.TransferCmd is ReturnCmd)
                {
                    // block return
                    blk.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
                }
            }

            /*
             * // havoc locals -- not necessary
             * if (newLocals.Count > 0)
             * {
             *  var ies = new List<IdentifierExpr>();
             *  newLocals.Values.Iter(v => ies.Add(Expr.Ident(v)));
             *  impl.Blocks[0].Cmds.Insert(0, new HavocCmd(Token.NoToken, ies));
             * }
             */
        }
예제 #3
0
        // Note: this does not reconstruct the failing assert in trace
        public static void ReconstructImperativeTrace(Counterexample trace, string currProc, Dictionary <string, Implementation> origProg)
        {
            if (trace == null)
            {
                return;
            }

            var originalBlocks = BoogieUtil.labelBlockMapping(origProg[currProc]);

            var newBlocks       = new List <Block>();
            var newCalleeTraces = new Dictionary <TraceLocation, CalleeCounterexampleInfo>();

            for (int numBlock = 0; numBlock < trace.Trace.Count; numBlock++)
            {
                Block b = trace.Trace[numBlock];

                Block ib;
                originalBlocks.TryGetValue(b.Label, out ib);
                if (ib == null)
                {
                    // Such blocks correspond to "itermediate" blocks inserted
                    // by Boogie. We can ignore them. (But note that we should
                    // still check that the counterexample is a valid path in impl
                    // to guard against vagaries of Boogie.)

                    //Log.Out(Log.Normal, "Could not find block " + b.Label);
                    //b.Emit(new TokenTextWriter(Console.Out), 0);
                    for (int numInstr = 0; numInstr < b.Cmds.Count; numInstr++)
                    {
                        if (trace.calleeCounterexamples.ContainsKey(new TraceLocation(numBlock, numInstr)))
                        {
                            throw new InternalError("BoogieVerify: An intermediate block has a procedure call");
                        }
                    }
                }
                else
                {
                    // We have a corresponding block. The number of Commands in b and ib won't match. We
                    // simply use all of the Cmds of ib -- and match the calls manually
                    // TODO: Fix this! It doesn't work when the failing assert is not the last statement
                    // of the block
                    newBlocks.Add(ib);
                    var calleeTraces = new List <Duple <string, CalleeCounterexampleInfo> >();
                    for (int numInstr = 0; numInstr < b.Cmds.Count; numInstr++)
                    {
                        var loc = new TraceLocation(numBlock, numInstr);
                        if (trace.calleeCounterexamples.ContainsKey(loc))
                        {
                            Cmd c           = b.Cmds[numInstr];
                            var calleeName  = trace.getCalledProcName(c);
                            var calleeTrace = trace.calleeCounterexamples[loc].counterexample;
                            ReconstructImperativeTrace(calleeTrace, calleeName, origProg);
                            calleeTraces.Add(
                                new Duple <string, CalleeCounterexampleInfo>(
                                    calleeName,
                                    new CalleeCounterexampleInfo(calleeTrace,
                                                                 trace.calleeCounterexamples[loc].args)
                                    ));
                        }
                    }

                    // Check consistency and map calleeTraces to the actual call instructions
                    var currCount = 0;
                    for (int numInstr = 0; numInstr < ib.Cmds.Count; numInstr++)
                    {
                        Cmd c = ib.Cmds[numInstr];

                        if (!(c is CallCmd))
                        {
                            continue;
                        }

                        var cc = c as CallCmd;

                        // No more calls left to process
                        if (calleeTraces.Count <= currCount)
                        {
                            break;
                        }

                        if (cc.Proc.Name != calleeTraces[currCount].fst)
                        {
                            continue;
                        }

                        // Check if this proc has an implementation
                        //if (!origProg.ContainsKey(cc.Proc.Name))
                        //    continue;

                        // Check if the proc is inlined
                        //if (QKeyValue.FindExprAttribute(cc.Proc.Attributes, "inline") == null)
                        //    continue;

                        // Some thing wrong about the interprocedural trace returned by Boogie if the
                        // following don't match
                        // TODO: Fix when the failing assert is not the last statement of the block
                        //Debug.Assert(cc.Proc.Name == calleeTraces[currCount].fst);

                        newCalleeTraces.Add(new TraceLocation(newBlocks.Count - 1, numInstr), calleeTraces[currCount].snd);
                        currCount++;
                    }
                }
            }
            trace.Trace = newBlocks;
            // reset other info. Safe thing to do unless we know what it is
            trace.calleeCounterexamples = newCalleeTraces;
        }
        // Prints trace by recursively calling itself on calleeTraces. This assumes
        // that info in each of the ErrorTraceInstr is valid.
        // Returns the value of k at the end of the trace
        private static int collectAllEvents(ErrorTrace trace)
        {
            Debug.Assert(trace.Blocks.Count != 0);
            int k = 0, tid = 1;

            Implementation impl         = nameImplMap[trace.procName];
            var            nameBlockMap = BoogieUtil.labelBlockMapping(impl);

            lastCLocation = null;

            var first_block             = true;

            // Walk through trace and impl in lock step
            foreach (var tblk in trace.Blocks)
            {
                Block pblk = nameBlockMap[tblk.blockName];
                fetchInfo(tblk.info, out k, out tid);

                if (first_block)
                {
                    pushWI(tid, new WorkItem(trace.procName, null, null));
                }
                first_block = false;

                updateWI(tid, pblk.tok as Token);
                updateWI(tid, pblk.Label);

                updateCLocation(tid);

                var assertFails = "";
                if (tblk.info is AssertFailInstrInfo)
                {
                    var extra = (tblk.info is RequiresFailInstrInfo) ? ": Requires" :
                                (tblk.info is EnsuresFailInstrInfo) ? ": Ensures" : "";
                    assertFails = "ASSERTION FAILS" + extra;
                }

                events.Add(new Event(k, tid, printStack(tid), getFileName(tid), getLineNo(tid), getColNo(tid), assertFails, true));

                int pcnt = 0;
                int tcnt = 0;
                foreach (var tcmd in tblk.Cmds)
                {
                    fetchInfo(tcmd.info, out k, out tid);
                    updateWI(tid, pblk.Cmds[pcnt].tok as Token);

                    assertFails = "";
                    if (tcmd.info is AssertFailInstrInfo)
                    {
                        var extra = (tcmd.info is RequiresFailInstrInfo) ? ": Requires" :
                                    (tcmd.info is EnsuresFailInstrInfo) ? ": Ensures" : "";
                        assertFails = "ASSERTION FAILS " + (pblk.Cmds[pcnt].ToString()) + " " + extra;
                    }

                    if (tcmd.info is ModelInstrInfo)
                    {
                        assertFails = tcmd.info.ToString();
                        changeVarNames((tcmd.info as ModelInstrInfo).model);
                    }

                    if (tcmd.info is PrintInstrInfo)
                    {
                        assertFails += tcmd.info.ToString();
                    }

                    if (tcmd.isCall())
                    {
                        Debug.Assert(pblk.Cmds[pcnt] is CallCmd);

                        CallInstr cc      = tcmd as CallInstr;
                        string    callstr = string.Format("{0} {1}", cc.asyncCall ? "FORK" : "CALL", (pblk.Cmds[pcnt] as CallCmd).Proc.Name);
                        if (!cc.hasCalledTrace)
                        {
                            callstr = "";
                            if (cc.callee.StartsWith(VerificationPass.recordArgProcPrefix))
                            {
                                var cmd = pblk.Cmds[pcnt] as CallCmd;
                                Debug.Assert(cmd.Ins.Count == 1);
                                var prefix = QKeyValue.FindStringAttribute(cmd.Attributes, "cexpr");
                                if (prefix == null)
                                {
                                    prefix = "v";
                                }
                                prefix += " = ";
                                if (cc.info.hasVar("si_arg"))
                                {
                                    callstr += prefix + cc.info.getVal("si_arg").ToString();
                                }
                            }
                        }

                        var leftOverForReturn = "";
                        if (assertFails != "" && callstr != "")
                        {
                            // This can only be because of a failed requires/ensures
                            leftOverForReturn = assertFails;
                        }
                        else
                        {
                            callstr = callstr + assertFails;
                        }

                        events.Add(new Event(k, tid, printStack(tid), getFileName(tid), getLineNo(tid), getColNo(tid), callstr, true));

                        if (cc.hasCalledTrace)
                        {
                            int oldk = k;
                            k = collectAllEvents(cc.calleeTrace);
                            if (cc.asyncCall)
                            {
                                k = oldk;
                            }

                            if (cc.calleeTrace.returns)
                            {
                                var extra = "";
                                if (!cc.asyncCall)
                                {
                                    extra  = "RETURN from " + (pblk.Cmds[pcnt] as CallCmd).Proc.Name;
                                    extra += " " + leftOverForReturn;
                                }
                                events.Add(new Event(k, tid, printStack(tid), getFileName(tid), getLineNo(tid), getColNo(tid), extra, true));
                            }
                        }
                    }
                    else
                    {
                        events.Add(new Event(k, tid, printStack(tid), getFileName(tid), getLineNo(tid), getColNo(tid), "" + assertFails, true));
                    }

                    pcnt++;
                    tcnt++;
                }
            }
            if (first_block == false)
            {
                popWI(tid);
            }
            return(k);
        }
예제 #5
0
        // Propagate levels
        static void doHwswLevelMatch(Implementation impl)
        {
            var labelBlockMap = BoogieUtil.labelBlockMapping(impl);

            foreach (var blk in impl.Blocks)
            {
                for (int i = 0; i < blk.Cmds.Count; i++)
                {
                    var ccmd = blk.Cmds[i] as CallCmd;
                    if (ccmd == null || (ccmd.callee != levelCall && ccmd.callee != cpuCall))
                    {
                        continue;
                    }

                    if (ccmd.callee == levelCall)
                    {
                        // Get level
                        if (ccmd.Ins.Count != 1)
                        {
                            throw new InternalError("Incorrect hwsw level usage");
                        }
                        if (!(ccmd.Ins[0] is LiteralExpr))
                        {
                            throw new InternalError("Incorrect hwsw level usage");
                        }
                        var level = ((Microsoft.BaseTypes.BigNum)(ccmd.Ins[0] as LiteralExpr).Val).ToInt;
                        // start search
                        var currBlk = blk;
                        var currCmd = i + 1;
                        var done    = false;
                        while (!done)
                        {
                            for (int j = currCmd; j < currBlk.Cmds.Count && !done; j++)
                            {
                                var tc = currBlk.Cmds[j] as CallCmd;
                                if (tc == null || !tc.IsAsync)
                                {
                                    continue;
                                }
                                done = true;
                                // change attribute
                                var parameters = new List <object>(); parameters.Add(Expr.Literal(level));
                                tc.Attributes = new QKeyValue(Token.NoToken, "level", parameters, tc.Attributes);
                            }
                            if (!done)
                            {
                                var gc = currBlk.TransferCmd as GotoCmd;
                                if (gc == null || gc.labelNames.Count != 1)
                                {
                                    throw new InternalError("Incorrect hwsw level usage");
                                }
                                currBlk = labelBlockMap[gc.labelNames[0]];
                                currCmd = 0;
                            }
                        }
                    }
                    else if (ccmd.callee == cpuCall)
                    {
                        // Get level
                        if (ccmd.Ins.Count != 1)
                        {
                            throw new InternalError("Incorrect hwsw cpu usage");
                        }
                        if (!(ccmd.Ins[0] is LiteralExpr))
                        {
                            throw new InternalError("Incorrect hwsw cpu usage");
                        }
                        var level = ((Microsoft.BaseTypes.BigNum)(ccmd.Ins[0] as LiteralExpr).Val).ToInt;
                        // start search
                        var currBlk = blk;
                        var currCmd = i + 1;
                        var done    = false;
                        while (!done)
                        {
                            for (int j = currCmd; j < currBlk.Cmds.Count && !done; j++)
                            {
                                var tc = currBlk.Cmds[j] as CallCmd;
                                if (tc == null || !tc.IsAsync)
                                {
                                    continue;
                                }
                                done = true;
                                // change attribute
                                var parameters = new List <object>(); parameters.Add(Expr.Literal(level));
                                tc.Attributes = new QKeyValue(Token.NoToken, "cpu", parameters, tc.Attributes);
                            }
                            if (!done)
                            {
                                var gc = currBlk.TransferCmd as GotoCmd;
                                if (gc == null || gc.labelNames.Count != 1)
                                {
                                    throw new InternalError("Incorrect hwsw cpu usage");
                                }
                                currBlk = labelBlockMap[gc.labelNames[0]];
                                currCmd = 0;
                            }
                        }
                    }
                }
            }
        }
예제 #6
0
        private string addTraceRec(ErrorTrace trace)
        {
            Debug.Assert(trace.Blocks.Count != 0);

            // First, construct the procedure declaration: only a name change required
            string    newName = getNewName(trace.procName);
            Procedure proc    = nameToProc[trace.procName];

            output.AddTopLevelDeclaration(
                new Procedure(Token.NoToken, newName, proc.TypeParameters, proc.InParams,
                              proc.OutParams, proc.Requires, proc.Modifies, proc.Ensures,
                              proc.Attributes));

            // Now to peice together the commands from the implementation. We keep around
            // multiple blocks to make sure that trace mapping works out.
            var traceBlocks = new List <Block>();

            Implementation impl = nameToImpl[trace.procName];

            var labelToBlock = BoogieUtil.labelBlockMapping(impl);

            // These two need not agree. This happens when impl.Block[0] has
            // no commands.
            // Debug.Assert(impl.Blocks[0].Label == trace.Blocks[0].blockName);
            Debug.Assert(reachableViaEmptyBlocks(impl.Blocks[0].Label, labelToBlock).Contains(trace.Blocks[0].blockName));

            for (int i = 0, n = trace.Blocks.Count; i < n; i++)
            {
                Block curr = labelToBlock[trace.Blocks[i].blockName];

                Block traceBlock = new Block();
                traceBlock.Cmds  = new List <Cmd>();
                traceBlock.Label = addIntToString(trace.Blocks[i].blockName, i); // (The "i" is to deal with loops)
                if (i != n - 1)
                {
                    traceBlock.TransferCmd = BoogieAstFactory.MkGotoCmd(addIntToString(trace.Blocks[i + 1].blockName, i + 1));
                }
                else
                {
                    traceBlock.TransferCmd = new ReturnCmd(Token.NoToken);
                }
                tinfo.addTrans(newName, trace.Blocks[i].blockName, traceBlock.Label);

                #region Check consistency
                Debug.Assert(curr.Cmds.Count >= trace.Blocks[i].Cmds.Count);
                if (trace.Blocks[i].Cmds.Count != curr.Cmds.Count)
                {
                    Debug.Assert((i == n - 1));
                }

                if (curr.TransferCmd is ReturnCmd)
                {
                    Debug.Assert(i == n - 1);
                }
                else if (curr.TransferCmd is GotoCmd)
                {
                    List <String> targets = (curr.TransferCmd as GotoCmd).labelNames;
                    // one of these targets should be the next label
                    if (i != n - 1)
                    {
                        Debug.Assert(reachableViaEmptyBlocks(targets, labelToBlock).Contains(trace.Blocks[i + 1].blockName));
                    }
                }
                else
                {
                    throw new InternalError("Unknown transfer command");
                }
                #endregion

                // Index into trace.Blocks[i].Cmds
                int instrCount = -1;

                foreach (Cmd c in curr.Cmds)
                {
                    instrCount++;
                    if (instrCount == trace.Blocks[i].Cmds.Count)
                    {
                        break;
                    }

                    ErrorTraceInstr curr_instr = trace.Blocks[i].Cmds[instrCount];
                    if (curr_instr.info.isValid)
                    {
                        traceBlock.Cmds.Add(InstrumentationConfig.getFixedContextProc(curr_instr.info.executionContext));
                        newFixedContextProcs.Add(curr_instr.info.executionContext);
                    }

                    // Don't keep "fix context value" procs from the input program
                    if (InstrumentationConfig.getFixedContextValue(c) != -1)
                    {
                        traceBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.True));
                        addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds);
                        continue;
                    }

                    // Don't keep "fix raise exception" procs from the input program
                    if (InstrumentationConfig.isFixedRaiseExceptionProc(c))
                    {
                        traceBlock.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.True));
                        addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds);
                        continue;
                    }

                    if (addConcretization && c is HavocCmd && curr_instr.info != null && curr_instr.info.hasIntVar("si_arg") &&
                        (c as HavocCmd).Vars.Count > 0 && (c as HavocCmd).Vars[0].Decl.TypedIdent.Type.IsInt)
                    {
                        // concretize havoc-ed variable
                        var val = curr_instr.info.getIntVal("si_arg");
                        traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqConst((c as HavocCmd).Vars[0].Decl, val));
                        addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds);
                        continue;
                    }

                    if (!(c is CallCmd))
                    {
                        if (convertNonFailingAssertsToAssumes && c is AssertCmd && !(curr_instr.info is AssertFailInstrInfo))
                        {
                            traceBlock.Cmds.Add(new AssumeCmd(c.tok, (c as AssertCmd).Expr, (c as AssertCmd).Attributes));
                        }
                        else
                        {
                            traceBlock.Cmds.Add(c);
                        }
                        Debug.Assert(!curr_instr.isCall());
                        addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds);

                        continue;
                    }
                    Debug.Assert(curr_instr.isCall());

                    CallCmd   cc         = c as CallCmd;
                    CallInstr call_instr = curr_instr as CallInstr;

                    if (!nameToImpl.ContainsKey(cc.Proc.Name) || !call_instr.hasCalledTrace)
                    {
                        // This is a call to a procedure without implementation; skip;
                        calledProcsNoImpl.Add(cc.Proc.Name);
                        traceBlock.Cmds.Add(c);
                        Debug.Assert(!call_instr.hasCalledTrace);
                        if (addConcretization && cc.Outs.Count == 1 && call_instr.info.hasVar("si_arg"))
                        {
                            if (!addConcretizationAsConstants)
                            {
                                if (call_instr.info.hasBoolVar("si_arg"))
                                {
                                    traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqConst(cc.Outs[0].Decl, call_instr.info.getBoolVal("si_arg")));
                                }
                                else if (call_instr.info.hasIntVar("si_arg"))
                                {
                                    traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqConst(cc.Outs[0].Decl, call_instr.info.getIntVal("si_arg")));
                                }
                                else
                                {
                                    Debug.Assert(false);
                                }
                            }
                            else
                            {
                                // create a constant that is equal to this literal, then use the constant
                                // for concretization

                                // do we use a specific name for the constant?
                                var constantName = QKeyValue.FindStringAttribute(cc.Attributes, ConcretizeConstantNameAttr);
                                if (constantName == null)
                                {
                                    constantName = "";
                                }

                                var constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
                                                                                          string.Format("alloc_{0}__{1}", constantName, const_counter), cc.Outs[0].Decl.TypedIdent.Type), false);
                                const_counter++;

                                traceBlock.Cmds.Add(BoogieAstFactory.MkVarEqVar(cc.Outs[0].Decl, constant));
                                output.AddTopLevelDeclaration(constant);

                                if (call_instr.info.hasIntVar("si_arg"))
                                {
                                    output.AddTopLevelDeclaration(new Axiom(Token.NoToken, Expr.Eq(Expr.Ident(constant), Expr.Literal(call_instr.info.getIntVal("si_arg")))));
                                }
                                else if (call_instr.info.hasVar("si_arg") && cc.Outs[0].Decl.TypedIdent.Type.IsCtor)
                                {
                                    uvalueToConstants.InitAndAdd(call_instr.info.getVal("si_arg").ToString(), constant);
                                }

                                var id = QKeyValue.FindIntAttribute(cc.Attributes, ConcretizeCallIdAttr, -1);
                                concretizeConstantToCall.Add(constant.Name, id);
                            }
                        }
                        addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds);
                        continue;
                    }

                    Debug.Assert(call_instr.calleeTrace.procName == cc.Proc.Name);
                    var callee = addTraceRec(call_instr.calleeTrace);

                    var newcmd = new CallCmd(Token.NoToken, callee, cc.Ins, cc.Outs, cc.Attributes, cc.IsAsync);
                    traceBlock.Cmds.Add(newcmd);
                    addedTrans(newName, curr.Label, instrCount, c, traceBlock.Label, traceBlock.Cmds);
                }
                traceBlocks.Add(traceBlock);
            }

            Debug.Assert(traceBlocks.Count != 0);
            if (trace.raisesException)
            {
                var exitblk = traceBlocks.Last();
                exitblk.Cmds.Add(InstrumentationConfig.getFixedRaiseExceptionProc());
                addRaiseExceptionProcDecl = true;
            }

            // Add the implementation to output
            //var block = new Block(Token.NoToken, trace.Blocks[0].blockName, traceCmdSeq, new ReturnCmd(Token.NoToken));
            //List<Block> blocks = new List<Block>();
            //blocks.Add(block);

            //tinfo.addTrans(newName, trace.Blocks[0].blockName, trace.Blocks[0].blockName);
            tinfo.addProcNameTrans(trace.procName, newName);

            output.AddTopLevelDeclaration(
                new Implementation(Token.NoToken, newName, impl.TypeParameters,
                                   impl.InParams, impl.OutParams, impl.LocVars, traceBlocks,
                                   QKeyValue.FindStringAttribute(impl.Attributes, "origRTname") == null ?
                                   new QKeyValue(Token.NoToken, "origRTname", new List <object> {
                impl.Name
            }, impl.Attributes)
                    : impl.Attributes));

            return(newName);
        }
예제 #7
0
        // Short-circuit the chain of returns produced by raiseException
        public void optimizeRaiseExceptionInstrumentation(CBAProgram program)
        {
            var procMap  = BoogieUtil.nameImplMapping(program);
            var mainImpl = procMap[program.mainProcName];

            var labelBlockMap = BoogieUtil.labelBlockMapping(mainImpl);

            // For each block, check if the first statement is "assume raiseException"
            foreach (var blk in mainImpl.Blocks)
            {
                if (blk.Cmds.Count == 0)
                {
                    continue;
                }

                var cmd = blk.Cmds[0];

                if (!(cmd is AssumeCmd))
                {
                    continue;
                }

                var expr = (cmd as AssumeCmd).Expr;
                if (expr is IdentifierExpr)
                {
                    var v = (expr as IdentifierExpr).Decl;
                    if (v.Name != "raiseException")
                    {
                        continue;
                    }
                }
                else
                {
                    continue;
                }

                // Yup, its "assume raiseException" -- follow the chain of gotos through empty blocks
                var lab = getSingleSucc(blk.TransferCmd);
                if (lab == null)
                {
                    continue;
                }

                var b        = labelBlockMap[lab];
                var chainLen = 0;

                /* Heuristic, possibly unsound: some blocks have a single statement that contains
                 * an assignment for the return value. Note that once raiseException has been raised,
                 * no return value is needed.
                 */
                while (b.Cmds.Count <= 1)
                {
                    var next = getSingleSucc(b.TransferCmd);
                    if (next == null)
                    {
                        break;
                    }
                    lab = next;
                    b   = labelBlockMap[lab];
                    chainLen++;
                }

                blk.TransferCmd = BoogieAstFactory.MkGotoCmd(lab);

                if (chainLen != 0)
                {
                    Log.WriteLine(Log.Debug, "raiseException chain shortened by " + chainLen.ToString());
                }
            }
        }