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