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