private void addToTrace(ErrorTraceInstr inst, InstrLocation loc, ref ErrorTraceBlock curr, ErrorTrace trace)
        {
            if (curr == null)
            {
                curr = new ErrorTraceBlock(loc.blockName);
                Debug.Assert(loc.num == 0);
                curr.addInstr(inst);
                return;
            }

            // curr != null. We need to see if inst should be put inside curr or start a new block?

            if (loc.num == curr.Cmds.Count && loc.blockName == curr.blockName)
            {
                curr.addInstr(inst);
            }
            else
            {
                // start a new block
                Debug.Assert(loc.num == 0);
                trace.addBlock(curr);
                curr = new ErrorTraceBlock(loc.blockName);
                curr.addInstr(inst);
            }
        }
        // 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);
        }
        private ErrorTraceInstr getCorrespondingInst(InstrLocation from, ErrorTraceInstr toInstr, InsertionTrans tinfo)
        {
            if (from.type.type == InstrTypeEnum.CALL || from.type.type == InstrTypeEnum.ASYNC)
            {
                // Get callee trace
                ErrorTrace calleeTrace = null;
                if (toInstr.isCall())
                {
                    calleeTrace = (toInstr as CallInstr).calleeTrace;
                }
                // recursively mapBack the callee trace
                if (calleeTrace != null)
                {
                    calleeTrace = tinfo.mapBackTrace(calleeTrace);
                }

                return(new CallInstr(from.type.callee, calleeTrace, (from.type.type == InstrTypeEnum.ASYNC ? true : false), toInstr.info));
            }
            else
            {
                return(new IntraInstr(toInstr.info));
            }
        }
Beispiel #4
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);
        }