// 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; }
public static Counterexample ReconstructTrace(Counterexample trace, string currProc, TraceLocation currLocation, Dictionary <string, Tuple <Block, Implementation> > origProg) { // we cannot be starting in the last block Debug.Assert(currLocation.numBlock != trace.Trace.Count - 1); // we cannot be starting in the middle of a block Debug.Assert(currLocation.numInstr == 0); var newTrace = new List <Block>(); var newTraceCallees = new Dictionary <TraceLocation, CalleeCounterexampleInfo>(); Block currOrigBlock = null; Implementation currOrigImpl = null; int currOrigInstr = 0; while (true) { if (currLocation.numInstr == 0 && origProg.ContainsKey(trace.Trace[currLocation.numBlock].Label)) { var origPlace = origProg[trace.Trace[currLocation.numBlock].Label]; if (currOrigImpl != null && currOrigImpl.Name != origPlace.Item2.Name) { // change of proc // First, recurse var calleeTrace = ReconstructTrace(trace, origPlace.Item2.Name, currLocation, origProg); // Find the call to this guy in currOrigBlock while (currOrigInstr < currOrigBlock.Cmds.Count) { var cmd = currOrigBlock.Cmds[currOrigInstr] as CallCmd; if (cmd != null && cmd.callee == origPlace.Item2.Name) { break; } currOrigInstr++; } Debug.Assert(currOrigInstr != currOrigBlock.Cmds.Count); newTraceCallees.Add(new TraceLocation(newTrace.Count - 1, currOrigInstr), new CalleeCounterexampleInfo(calleeTrace, new List <object>())); // we're done break; } currOrigBlock = origPlace.Item1; currOrigImpl = origProg[trace.Trace[currLocation.numBlock].Label].Item2; currOrigInstr = 0; newTrace.Add(currOrigBlock); } if (trace.calleeCounterexamples.ContainsKey(currLocation)) { // find the corresponding call in origBlock var calleeInfo = trace.calleeCounterexamples[currLocation]; var calleeName = trace.getCalledProcName(trace.Trace[currLocation.numBlock].Cmds[currLocation.numInstr]); while (currOrigInstr < currOrigBlock.Cmds.Count) { var cmd = currOrigBlock.Cmds[currOrigInstr] as CallCmd; if (cmd != null && cmd.callee == calleeName) { break; } currOrigInstr++; } Debug.Assert(currOrigInstr != currOrigBlock.Cmds.Count); newTraceCallees.Add(new TraceLocation(newTrace.Count - 1, currOrigInstr), calleeInfo); } // increment location currLocation.numInstr++; if (currLocation.numInstr >= trace.Trace[currLocation.numBlock].Cmds.Count) { currLocation.numBlock++; currLocation.numInstr = 0; } if (currLocation.numBlock == trace.Trace.Count) { break; } } var ret = new AssertCounterexample(newTrace, null, null, trace.Model, trace.MvInfo, trace.Context); ret.calleeCounterexamples = newTraceCallees; return(ret); }