public ErrorTrace mapBackTrace(ErrorTrace trace)
        {
            if (!dict.ContainsKey(trace.procName))
            {
                // missing transformations are assumed to be identity
                var ret = new ErrorTrace(getSrcProcName(trace.procName));

                foreach (var blk in trace.Blocks)
                {
                    ret.addBlock(new ErrorTraceBlock(blk.blockName));
                    foreach (var c in blk.Cmds)
                    {
                        if (c.isCall())
                        {
                            CallInstr cc = c as CallInstr;
                            if (cc.calleeTrace != null)
                            {
                                var t = mapBackTrace(cc.calleeTrace);
                                ret.addInstr(new CallInstr(t, cc.asyncCall, cc.info));
                                continue;
                            }
                        }
                        ret.addInstr(c);
                    }
                }

                if (trace.returns)
                {
                    ret.addReturn(trace.raisesException);
                }

                return(ret);
            }
            return(dict[trace.procName].mapBackTrace(trace, this));
        }
        // map back "trace[start, start + to.size - 1]" through this transformation.
        //
        // tinfo is the parent
        // transformation info for the whole program -- it is used for recursively
        // calling the mapBack procedure on callee traces
        public ErrorTraceInstr mapBackTrace(List <ErrorTraceInstr> trace, int start, ModifyTrans tinfo)
        {
            Debug.Assert(start >= 0);
            Debug.Assert(start + to.Count - 1 < trace.Count);

            // Find the "info" for "from". It is obtained from the
            // corresponding instruction, if one is provided. Else
            // we search through "to" to find (any) valid info.
            InstrInfo info = null;

            if (correspondingInstr >= 0)
            {
                info = trace[start + correspondingInstr].info;
            }
            else
            {
                // Default info (invalid)
                info = new InstrInfo();
                for (int i = start; i < start + to.Count; i++)
                {
                    if (trace[i].info.isValid)
                    {
                        info = trace[i].info;
                        break;
                    }
                }
            }

            Debug.Assert(info != null);

            ErrorTraceInstr ret = null;

            if (from.type == InstrTypeEnum.CALL || from.type == InstrTypeEnum.ASYNC)
            {
                // check if the corresponding instruction is also a call
                if (correspondingInstr >= 0 && trace[start + correspondingInstr].isCall())
                {
                    var calleeTrace = (trace[start + correspondingInstr] as CallInstr).calleeTrace;
                    if (calleeTrace != null)
                    {
                        // Recurse on the callee trace
                        calleeTrace = tinfo.mapBackTrace(calleeTrace);
                    }

                    ret = new CallInstr(from.callee, calleeTrace, (from.type == InstrTypeEnum.ASYNC ? true : false), info);
                }
                else
                {
                    // no corresponding callee trace
                    ret = new CallInstr(from.callee, null, (from.type == InstrTypeEnum.ASYNC ? true : false), info);
                }
            }
            else
            {
                ret = new IntraInstr(info);
            }
            Debug.Assert(ret != null);

            return(ret);
        }
Exemplo n.º 3
0
        public ErrorTrace mapBackTrace(ErrorTrace trace)
        {
            Debug.Assert(tinfo.ContainsKey(trace.procName));

            var ret  = new ErrorTrace(trace.procName);
            var info = tinfo[trace.procName];

            foreach (var blk in trace.Blocks)
            {
                var peices = info[blk.blockName];
                Debug.Assert(peices.Count != 0);

                // This is an index into blk.Cmds
                var cnt     = 0;
                var done    = false;
                var lastInf = blk.info;

                for (int i = 0; !done && i < peices.Count; i++)
                {
                    // Do we have enough in blk.Cmds for peices[i]?
                    if (cnt + peices[i].snd - 1 >= blk.Cmds.Count)
                    {
                        done = true;
                    }

                    var eblk = new ErrorTraceBlock(peices[i].fst);
                    eblk.info = lastInf;

                    int j = 0;
                    while (j < peices[i].snd && cnt < blk.Cmds.Count)
                    {
                        var inst = blk.Cmds[cnt];
                        lastInf = inst.info;
                        if (inst is CallInstr)
                        {
                            var cinst = inst as CallInstr;
                            if (cinst.hasCalledTrace)
                            {
                                inst = new CallInstr(cinst.callee, mapBackTrace(cinst.calleeTrace), cinst.asyncCall, cinst.info);
                                if (!(inst as CallInstr).calleeTrace.returns)
                                {
                                    done = true;
                                }
                            }
                        }

                        eblk.addInstr(inst);
                        cnt++;
                        j++;
                    }
                    ret.addBlock(eblk);
                }
            }
            if (trace.returns)
            {
                ret.addReturn();
            }
            return(ret);
        }
Exemplo n.º 4
0
        public ErrorTrace mapBackTraceRecord(ErrorTrace trace)
        {
            var ret = new ErrorTrace(trace.procName);

            foreach (var block in trace.Blocks)
            {
                var nb = new ErrorTraceBlock(block.blockName);
                foreach (var cmd in block.Cmds)
                {
                    if (cmd is CallInstr)
                    {
                        var ccmd = cmd as CallInstr;
                        if (ccmd.callee == recordProcNameInt || ccmd.callee == recordProcNameBool || ccmd.callee.StartsWith(recordProcNameCtor))
                        {
                            Debug.Assert(nb.Cmds.Count != 0);
                            nb.Cmds.Last().info = ccmd.info;
                            continue;
                        }

                        if (ccmd.hasCalledTrace)
                        {
                            var c = new CallInstr(mapBackTraceRecord(ccmd.calleeTrace), ccmd.asyncCall, ccmd.info);
                            nb.addInstr(c);
                        }
                        else
                        {
                            nb.addInstr(ccmd);
                        }
                    }
                    else
                    {
                        nb.addInstr(cmd.Copy());
                    }
                }
                ret.addBlock(nb);
            }

            if (trace.returns)
            {
                ret.addReturn(trace.raisesException);
            }

            return(ret);
        }
        // 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);
        }
Exemplo n.º 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);
        }