summaryrefslogtreecommitdiff
path: root/Source/VCGeneration/ConditionGeneration.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Source/VCGeneration/ConditionGeneration.cs')
-rw-r--r--Source/VCGeneration/ConditionGeneration.cs4026
1 files changed, 2041 insertions, 1985 deletions
diff --git a/Source/VCGeneration/ConditionGeneration.cs b/Source/VCGeneration/ConditionGeneration.cs
index 515ec16d..19438924 100644
--- a/Source/VCGeneration/ConditionGeneration.cs
+++ b/Source/VCGeneration/ConditionGeneration.cs
@@ -1,1985 +1,2041 @@
-//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Linq;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Threading;
-using System.IO;
-using Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-using Microsoft.Boogie.VCExprAST;
-using Set = Microsoft.Boogie.GSet<object>;
-
-namespace Microsoft.Boogie {
-
- public class CalleeCounterexampleInfo {
- public Counterexample counterexample;
- public List<object>/*!>!*/ args;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(args));
- }
-
- public CalleeCounterexampleInfo(Counterexample cex, List<object/*!>!*/> x)
- {
- Contract.Requires(cce.NonNullElements(x));
- counterexample = cex;
- args = x;
- }
- }
-
- public class TraceLocation : IEquatable<TraceLocation>
- {
- public int numBlock;
- public int numInstr;
-
- public TraceLocation(int numBlock, int numInstr)
- {
- this.numBlock = numBlock;
- this.numInstr = numInstr;
- }
-
- public override bool Equals(object obj)
- {
- TraceLocation that = obj as TraceLocation;
- if (that == null) return false;
- return (numBlock == that.numBlock && numInstr == that.numInstr);
- }
-
- public bool Equals(TraceLocation that)
- {
- return (numBlock == that.numBlock && numInstr == that.numInstr);
- }
-
- public override int GetHashCode()
- {
- return numBlock.GetHashCode() ^ 131 * numInstr.GetHashCode();
- }
- }
-
- public abstract class Counterexample {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Trace != null);
- Contract.Invariant(Context != null);
- Contract.Invariant(cce.NonNullElements(relatedInformation));
- Contract.Invariant(cce.NonNullDictionaryAndValues(calleeCounterexamples));
- }
-
- [Peer]
- public List<Block> Trace;
- public Model Model;
- public VC.ModelViewInfo MvInfo;
- public ProverContext Context;
- [Peer]
- public List<string>/*!>!*/ relatedInformation;
- public string OriginalRequestId;
- public string RequestId;
- public abstract byte[] Checksum { get; }
- public byte[] SugaredCmdChecksum;
-
- public Dictionary<TraceLocation, CalleeCounterexampleInfo> calleeCounterexamples;
-
- internal Counterexample(List<Block> trace, Model model, VC.ModelViewInfo mvInfo, ProverContext context) {
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- this.Trace = trace;
- this.Model = model;
- this.MvInfo = mvInfo;
- this.Context = context;
- this.relatedInformation = new List<string>();
- this.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
- }
-
- // Create a shallow copy of the counterexample
- public abstract Counterexample Clone();
-
- public void AddCalleeCounterexample(TraceLocation loc, CalleeCounterexampleInfo cex)
- {
- Contract.Requires(cex != null);
- calleeCounterexamples[loc] = cex;
- }
-
- public void AddCalleeCounterexample(int numBlock, int numInstr, CalleeCounterexampleInfo cex)
- {
- Contract.Requires(cex != null);
- calleeCounterexamples[new TraceLocation(numBlock, numInstr)] = cex;
- }
-
- public void AddCalleeCounterexample(Dictionary<TraceLocation, CalleeCounterexampleInfo> cs)
- {
- Contract.Requires(cce.NonNullDictionaryAndValues(cs));
- foreach (TraceLocation loc in cs.Keys)
- {
- AddCalleeCounterexample(loc, cs[loc]);
- }
- }
-
- // Looks up the Cmd at a given index into the trace
- public Cmd getTraceCmd(TraceLocation loc)
- {
- Debug.Assert(loc.numBlock < Trace.Count);
- Block b = Trace[loc.numBlock];
- Debug.Assert(loc.numInstr < b.Cmds.Count);
- return b.Cmds[loc.numInstr];
- }
-
- // Looks up the name of the called procedure.
- // Asserts that the name exists
- public string getCalledProcName(Cmd cmd)
- {
- // There are two options:
- // 1. cmd is a CallCmd
- // 2. cmd is an AssumeCmd (passified version of a CallCmd)
- if(cmd is CallCmd) {
- return (cmd as CallCmd).Proc.Name;
- }
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- Debug.Assert(assumeCmd != null);
-
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- Debug.Assert(naryExpr != null);
-
- return naryExpr.Fun.FunctionName;
- }
-
- public void Print(int indent, TextWriter tw, Action<Block> blockAction = null) {
- int numBlock = -1;
- string ind = new string(' ', indent);
- foreach (Block b in Trace) {
- Contract.Assert(b != null);
- numBlock++;
- if (b.tok == null) {
- tw.WriteLine("{0}<intermediate block>", ind);
- } else {
- // for ErrorTrace == 1 restrict the output;
- // do not print tokens with -17:-4 as their location because they have been
- // introduced in the translation and do not give any useful feedback to the user
- if (!(CommandLineOptions.Clo.ErrorTrace == 1 && b.tok.line == -17 && b.tok.col == -4)) {
- if (blockAction != null)
- {
- blockAction(b);
- }
-
- tw.WriteLine("{4}{0}({1},{2}): {3}", b.tok.filename, b.tok.line, b.tok.col, b.Label, ind);
-
- for (int numInstr = 0; numInstr < b.Cmds.Count; numInstr++)
- {
- var loc = new TraceLocation(numBlock, numInstr);
- if (calleeCounterexamples.ContainsKey(loc))
- {
- var cmd = getTraceCmd(loc);
- var calleeName = getCalledProcName(cmd);
- if (calleeName.StartsWith(VC.StratifiedVCGen.recordProcName) && CommandLineOptions.Clo.StratifiedInlining > 0)
- {
- Contract.Assert(calleeCounterexamples[loc].args.Count == 1);
- var arg = calleeCounterexamples[loc].args[0];
- tw.WriteLine("{0}value = {1}", ind, arg.ToString());
- }
- else
- {
- tw.WriteLine("{1}Inlined call to procedure {0} begins", calleeName, ind);
- calleeCounterexamples[loc].counterexample.Print(indent + 4, tw);
- tw.WriteLine("{1}Inlined call to procedure {0} ends", calleeName, ind);
- }
- }
- }
- }
- }
- }
- }
-
- public static bool firstModelFile = true;
-
- public bool ModelHasStatesAlready = false;
-
- public void PrintModel(TextWriter tw)
- {
- var filename = CommandLineOptions.Clo.ModelViewFile;
- if (Model == null || filename == null || CommandLineOptions.Clo.StratifiedInlining > 0) return;
-
- if (!ModelHasStatesAlready) {
- PopulateModelWithStates();
- ModelHasStatesAlready = true;
- }
-
- if (filename == "-") {
- Model.Write(tw);
- tw.Flush();
- } else {
- using (var wr = new StreamWriter(filename, !firstModelFile)) {
- firstModelFile = false;
- Model.Write(wr);
- }
- }
- }
-
- void ApplyRedirections(Model m) {
- var mapping = new Dictionary<Model.Element, Model.Element>();
- foreach (var name in new string[] { "U_2_bool", "U_2_int" }) {
- Model.Func f = m.TryGetFunc(name);
- if (f != null && f.Arity == 1) {
- foreach (var ft in f.Apps) mapping[ft.Args[0]] = ft.Result;
- }
- }
- m.Substitute(mapping);
- }
-
- public void PopulateModelWithStates()
- {
- Contract.Requires(Model != null);
-
- Model m = Model;
- ApplyRedirections(m);
-
- var mvstates = m.TryGetFunc("$mv_state");
- if (MvInfo == null || mvstates == null || (mvstates.Arity == 1 && mvstates.Apps.Count() == 0))
- return;
-
- Contract.Assert(mvstates.Arity == 2);
-
- foreach (Variable v in MvInfo.AllVariables) {
- m.InitialState.AddBinding(v.Name, GetModelValue(m, v));
- }
-
- var states = new List<int>();
- foreach (var t in mvstates.Apps)
- states.Add(t.Args[1].AsInt());
-
- states.Sort();
-
- for (int i = 0; i < states.Count; ++i) {
- var s = states[i];
- if (0 <= s && s < MvInfo.CapturePoints.Count) {
- VC.ModelViewInfo.Mapping map = MvInfo.CapturePoints[s];
- var prevInc = i > 0 ? MvInfo.CapturePoints[states[i - 1]].IncarnationMap : new Dictionary<Variable, Expr>();
- var cs = m.MkState(map.Description);
-
- foreach (Variable v in MvInfo.AllVariables) {
- Expr e = map.IncarnationMap.ContainsKey(v) ? map.IncarnationMap[v] : null;
- if (e == null) continue;
-
- Expr prevIncV = prevInc.ContainsKey(v) ? prevInc[v] : null;
- if (prevIncV == e) continue; // skip unchanged variables
-
- Model.Element elt;
-
- if (e is IdentifierExpr) {
- IdentifierExpr ide = (IdentifierExpr)e;
- elt = GetModelValue(m, ide.Decl);
- } else if (e is LiteralExpr) {
- LiteralExpr lit = (LiteralExpr)e;
- elt = m.MkElement(lit.Val.ToString());
- } else {
- elt = m.MkFunc(e.ToString(), 0).GetConstant();
- }
-
- cs.AddBinding(v.Name, elt);
- }
-
- } else {
- Contract.Assume(false);
- }
- }
- }
-
- private Model.Element GetModelValue(Model m, Variable v) {
- Model.Element elt;
- // first, get the unique name
- string uniqueName;
- VCExprVar vvar = Context.BoogieExprTranslator.TryLookupVariable(v);
- if (vvar == null) {
- uniqueName = v.Name;
- } else {
- uniqueName = Context.Lookup(vvar);
- }
-
- var f = m.TryGetFunc(uniqueName);
- if (f == null) {
- f = m.MkFunc(uniqueName, 0);
- }
- elt = f.GetConstant();
- return elt;
- }
-
- public abstract int GetLocation();
- }
-
- public class CounterexampleComparer : IComparer<Counterexample> {
-
- private int Compare(List<Block> bs1, List<Block> bs2)
- {
- if (bs1.Count < bs2.Count)
- {
- return -1;
- }
- else if (bs2.Count < bs1.Count)
- {
- return 1;
- }
-
- for (int i = 0; i < bs1.Count; i++)
- {
- var b1 = bs1[i];
- var b2 = bs2[i];
- if (b1.tok.pos < b2.tok.pos)
- {
- return -1;
- }
- else if (b2.tok.pos < b1.tok.pos)
- {
- return 1;
- }
- }
-
- return 0;
- }
-
- public int Compare(Counterexample c1, Counterexample c2)
- {
- //Contract.Requires(c1 != null);
- //Contract.Requires(c2 != null);
- if (c1.GetLocation() == c2.GetLocation())
- {
- var c = Compare(c1.Trace, c2.Trace);
- if (c != 0)
- {
- return c;
- }
- // TODO(wuestholz): Generalize this to compare all IPotentialErrorNodes of the counterexample.
- var a1 = c1 as AssertCounterexample;
- var a2 = c2 as AssertCounterexample;
- if (a1 != null && a2 != null)
- {
- var s1 = a1.FailingAssert.ErrorData as string;
- var s2 = a2.FailingAssert.ErrorData as string;
- if (s1 != null && s2 != null)
- {
- return s1.CompareTo(s2);
- }
- }
-
- return 0;
- }
- if (c1.GetLocation() > c2.GetLocation())
- {
- return 1;
- }
- return -1;
- }
- }
-
- public class AssertCounterexample : Counterexample {
- [Peer]
- public AssertCmd FailingAssert;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(FailingAssert != null);
- }
-
-
- public AssertCounterexample(List<Block> trace, AssertCmd failingAssert, Model model, VC.ModelViewInfo mvInfo, ProverContext context)
- : base(trace, model, mvInfo, context) {
- Contract.Requires(trace != null);
- Contract.Requires(failingAssert != null);
- Contract.Requires(context != null);
- this.FailingAssert = failingAssert;
- }
-
- public override int GetLocation() {
- return FailingAssert.tok.line * 1000 + FailingAssert.tok.col;
- }
-
- public override byte[] Checksum
- {
- get { return FailingAssert.Checksum; }
- }
-
- public override Counterexample Clone()
- {
- var ret = new AssertCounterexample(Trace, FailingAssert, Model, MvInfo, Context);
- ret.calleeCounterexamples = calleeCounterexamples;
- return ret;
- }
- }
-
- public class CallCounterexample : Counterexample {
- public CallCmd FailingCall;
- public Requires FailingRequires;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(FailingCall != null);
- Contract.Invariant(FailingRequires != null);
- }
-
-
- public CallCounterexample(List<Block> trace, CallCmd failingCall, Requires failingRequires, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum = null)
- : base(trace, model, mvInfo, context) {
- Contract.Requires(!failingRequires.Free);
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- Contract.Requires(failingCall != null);
- Contract.Requires(failingRequires != null);
- this.FailingCall = failingCall;
- this.FailingRequires = failingRequires;
- this.checksum = checksum;
- this.SugaredCmdChecksum = failingCall.Checksum;
- }
-
- public override int GetLocation() {
- return FailingCall.tok.line * 1000 + FailingCall.tok.col;
- }
-
- byte[] checksum;
- public override byte[] Checksum
- {
- get { return checksum; }
- }
-
- public override Counterexample Clone()
- {
- var ret = new CallCounterexample(Trace, FailingCall, FailingRequires, Model, MvInfo, Context, Checksum);
- ret.calleeCounterexamples = calleeCounterexamples;
- return ret;
- }
- }
-
- public class ReturnCounterexample : Counterexample {
- public TransferCmd FailingReturn;
- public Ensures FailingEnsures;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(FailingEnsures != null);
- Contract.Invariant(FailingReturn != null);
- }
-
-
- public ReturnCounterexample(List<Block> trace, TransferCmd failingReturn, Ensures failingEnsures, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum)
- : base(trace, model, mvInfo, context) {
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- Contract.Requires(failingReturn != null);
- Contract.Requires(failingEnsures != null);
- Contract.Requires(!failingEnsures.Free);
- this.FailingReturn = failingReturn;
- this.FailingEnsures = failingEnsures;
- this.checksum = checksum;
- }
-
- public override int GetLocation() {
- return FailingReturn.tok.line * 1000 + FailingReturn.tok.col;
- }
-
- byte[] checksum;
-
- /// <summary>
- /// Returns the checksum of the corresponding assertion.
- /// </summary>
- public override byte[] Checksum
- {
- get
- {
- return checksum;
- }
- }
-
- public override Counterexample Clone()
- {
- var ret = new ReturnCounterexample(Trace, FailingReturn, FailingEnsures, Model, MvInfo, Context, checksum);
- ret.calleeCounterexamples = calleeCounterexamples;
- return ret;
- }
- }
-
- public class VerifierCallback {
- // reason == null means this is genuine counterexample returned by the prover
- // other reason means it's time out/memory out/crash
- public virtual void OnCounterexample(Counterexample ce, string/*?*/ reason) {
- Contract.Requires(ce != null);
- }
-
- // called in case resource is exceeded and we don't have counterexample
- public virtual void OnTimeout(string reason) {
- Contract.Requires(reason != null);
- }
-
- public virtual void OnOutOfMemory(string reason) {
- Contract.Requires(reason != null);
- }
-
- public virtual void OnProgress(string phase, int step, int totalSteps, double progressEstimate) {
- }
-
- public virtual void OnUnreachableCode(Implementation impl) {
- Contract.Requires(impl != null);
- }
-
- public virtual void OnWarning(string msg) {
- Contract.Requires(msg != null);
- switch (CommandLineOptions.Clo.PrintProverWarnings) {
- case CommandLineOptions.ProverWarnings.None:
- break;
- case CommandLineOptions.ProverWarnings.Stdout:
- Console.WriteLine("Prover warning: " + msg);
- break;
- case CommandLineOptions.ProverWarnings.Stderr:
- Console.Error.WriteLine("Prover warning: " + msg);
- break;
- default:
- Contract.Assume(false);
- throw new cce.UnreachableException(); // unexpected case
- }
- }
- }
-}
-
-////////////////////////////////////////////
-
-namespace VC {
- using Bpl = Microsoft.Boogie;
-
- public class VCGenException : Exception {
- public VCGenException(string s)
- : base(s) {
- }
- }
- [ContractClassFor(typeof(ConditionGeneration))]
- public abstract class ConditionGenerationContracts : ConditionGeneration {
- public override Outcome VerifyImplementation(Implementation impl, VerifierCallback callback) {
- Contract.Requires(impl != null);
- Contract.Requires(callback != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
- public ConditionGenerationContracts(Program p, List<Checker> checkers)
- : base(p, checkers) {
- }
- }
-
- [ContractClass(typeof(ConditionGenerationContracts))]
- public abstract class ConditionGeneration : IDisposable {
- protected internal object CheckerCommonState;
-
- public enum Outcome {
- Correct,
- Errors,
- TimedOut,
- OutOfMemory,
- Inconclusive,
- ReachedBound
- }
-
- public static Outcome ProverInterfaceOutcomeToConditionGenerationOutcome(ProverInterface.Outcome outcome) {
- switch (outcome) {
- case ProverInterface.Outcome.Invalid:
- return Outcome.Errors;
- case ProverInterface.Outcome.OutOfMemory:
- return Outcome.OutOfMemory;
- case ProverInterface.Outcome.TimeOut:
- return Outcome.TimedOut;
- case ProverInterface.Outcome.Undetermined:
- return Outcome.Inconclusive;
- case ProverInterface.Outcome.Valid:
- return Outcome.Correct;
- }
- return Outcome.Inconclusive; // unreachable but the stupid compiler does not understand
- }
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(checkers));
- Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Invariant(program != null);
- }
-
- public int CumulativeAssertionCount; // for statistics
-
- protected readonly List<Checker>/*!>!*/ checkers;
-
- private bool _disposed;
-
- protected Implementation currentImplementation;
-
- protected List<Variable> CurrentLocalVariables = null;
-
- // shared across each implementation; created anew for each implementation
- protected Dictionary<Variable, int> variable2SequenceNumber;
- public Dictionary<Incarnation, Absy>/*!>!*/ incarnationOriginMap = new Dictionary<Incarnation, Absy>();
-
- public Program program;
- protected string/*?*/ logFilePath;
- protected bool appendLogFile;
-
- public static List<Model> errorModelList;
-
- public ConditionGeneration(Program p, List<Checker> checkers) {
- Contract.Requires(p != null && checkers != null && cce.NonNullElements(checkers));
- program = p;
- this.checkers = checkers;
- Cores = 1;
- }
-
- /// <summary>
- /// Takes an implementation and constructs a verification condition and sends
- /// it to the theorem prover.
- /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
- /// each counterexample consisting of an array of labels.
- /// </summary>
- /// <param name="impl"></param>
- public Outcome VerifyImplementation(Implementation impl, out List<Counterexample>/*?*/ errors, string requestId = null) {
- Contract.Requires(impl != null);
-
- Contract.Ensures(Contract.ValueAtReturn(out errors) == null || Contract.ForAll(Contract.ValueAtReturn(out errors), i => i != null));
- Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || errors != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- Helpers.ExtraTraceInformation("Starting implementation verification");
-
- CounterexampleCollector collector = new CounterexampleCollector();
- collector.RequestId = requestId;
- Outcome outcome = VerifyImplementation(impl, collector);
- if (outcome == Outcome.Errors || outcome == Outcome.TimedOut || outcome == Outcome.OutOfMemory) {
- errors = collector.examples;
- } else {
- errors = null;
- }
-
- Helpers.ExtraTraceInformation("Finished implementation verification");
- return outcome;
- }
-
- /// <summary>
- /// Takes an implementation and constructs a verification condition and sends
- /// it to the theorem prover.
- /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
- /// each counterexample consisting of an array of labels.
- /// </summary>
- /// <param name="impl"></param>
- public Outcome VerifyImplementation(Implementation impl, out List<Counterexample> errors, out List<Model> errorsModel)
- {
- Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || Contract.ValueAtReturn(out errors) != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- List<Counterexample> errorsOut;
-
- Outcome outcome;
- errorModelList = new List<Model>();
- outcome = VerifyImplementation(impl, out errorsOut);
- errors = errorsOut;
- errorsModel = errorModelList;
-
- return outcome;
- }
-
- public abstract Outcome VerifyImplementation(Implementation impl, VerifierCallback callback);
-
- /////////////////////////////////// Common Methods and Classes //////////////////////////////////////////
-
- #region Methods for injecting pre- and postconditions
- private static void
- ThreadInCodeExpr(Implementation impl,
- Block targetBlock,
- CodeExpr codeExpr,
- bool replaceWithAssert,
- TokenTextWriter debugWriter) {
- Contract.Requires(impl != null);
- Contract.Requires(codeExpr != null);
- Contract.Requires(targetBlock != null);
- // Go through codeExpr and for all blocks that have a "return e"
- // as their transfer command:
- // Replace all "return e" with "assert/assume e"
- // Change the transfer command to "goto targetBlock"
- // Then add all of the blocks in codeExpr to the implementation (at the end)
- foreach (Block b in codeExpr.Blocks) {
- Contract.Assert(b != null);
- ReturnExprCmd rec = b.TransferCmd as ReturnExprCmd;
- if (rec != null) { // otherwise it is a goto command
- if (replaceWithAssert) {
- Ensures ens = new Ensures(rec.tok, false, rec.Expr, null);
- Contract.Assert(ens != null);
- Cmd c = new AssertEnsuresCmd(ens);
- Contract.Assert(c != null);
- b.Cmds.Add(c);
- } else {
- b.Cmds.Add(new AssumeCmd(rec.tok, rec.Expr));
- }
- b.TransferCmd = new GotoCmd(Token.NoToken,
- new List<String> { targetBlock.Label },
- new List<Block> { targetBlock });
- targetBlock.Predecessors.Add(b);
- }
- impl.Blocks.Add(b);
- }
- if (debugWriter != null) {
- codeExpr.Emit(debugWriter, 1, false);
- }
- return;
- }
-
- private static void AddAsPrefix(Block b, List<Cmd> cs) {
- Contract.Requires(b != null);
- Contract.Requires(cs != null);
- List<Cmd> newCommands = new List<Cmd>();
- newCommands.AddRange(cs);
- newCommands.AddRange(b.Cmds);
- b.Cmds = newCommands;
- }
-
-
- /// <summary>
- /// Modifies an implementation by prepending it with startCmds and then, as assume
- /// statements, all preconditions. Insert new blocks as needed, and adjust impl.Blocks[0]
- /// accordingly to make it the new implementation entry block.
- /// </summary>
- /// <param name="impl"></param>
- /// <param name="startCmds"></param>
- protected static void InjectPreconditions(Implementation impl, [Captured] List<Cmd> startCmds) {
- Contract.Requires(impl != null);
- Contract.Requires(startCmds != null);
- Contract.Requires(impl.Proc != null);
-
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective precondition:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- string blockLabel = "PreconditionGeneratedEntry";
-
- Block origStartBlock = impl.Blocks[0];
- Block insertionPoint = new Block(
- new Token(-17, -4), blockLabel, startCmds,
- new GotoCmd(Token.NoToken, new List<String> { origStartBlock.Label }, new List<Block> { origStartBlock }));
-
- impl.Blocks[0] = insertionPoint; // make insertionPoint the start block
- impl.Blocks.Add(origStartBlock); // and put the previous start block at the end of the list
-
- // (free and checked) requires clauses
- foreach (Requires req in impl.Proc.Requires)
- // invariant: insertionPoint.TransferCmd is "goto origStartBlock;", but origStartBlock.Predecessors has not yet been updated
- {
- Contract.Assert(req != null);
- Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
- Cmd c = new AssumeCmd(req.tok, e);
- insertionPoint.Cmds.Add(c);
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- origStartBlock.Predecessors.Add(insertionPoint);
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
- }
- /// <summary>
- /// Modifies an implementation by inserting all postconditions
- /// as assert statements at the end of the implementation
- /// Returns the possibly-new unified exit block of the implementation
- /// </summary>
- /// <param name="impl"></param>
- /// <param name="unifiedExitblock">The unified exit block that has
- /// already been constructed for the implementation (and so
- /// is already an element of impl.Blocks)
- /// </param>
- protected static void InjectPostConditions(Implementation impl, Block unifiedExitBlock, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
- Contract.Requires(impl != null);
- Contract.Requires(unifiedExitBlock != null);
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(impl.Proc != null);
- Contract.Requires(unifiedExitBlock.TransferCmd is ReturnCmd);
-
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective postcondition:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
-
- // (free and checked) ensures clauses
- foreach (Ensures ens in impl.Proc.Ensures) {
- Contract.Assert(ens != null);
- if (!ens.Free) { // skip free ensures clauses
- Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
- Ensures ensCopy = (Ensures)cce.NonNull(ens.Clone());
- ensCopy.Condition = e;
- AssertEnsuresCmd c = new AssertEnsuresCmd(ensCopy);
- c.ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
- unifiedExitBlock.Cmds.Add(c);
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- }
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
- }
-
-
- /// <summary>
- /// Get the pre-condition of an implementation, including the where clauses from the in-parameters.
- /// </summary>
- /// <param name="impl"></param>
- protected static List<Cmd> GetPre(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
-
-
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective precondition:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- List<Cmd> pre = new List<Cmd>();
-
- // (free and checked) requires clauses
- foreach (Requires req in impl.Proc.Requires) {
- Contract.Assert(req != null);
- Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
- Contract.Assert(e != null);
- Cmd c = new AssumeCmd(req.tok, e);
- Contract.Assert(c != null);
- pre.Add(c);
-
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
-
- return pre;
- }
-
- /// <summary>
- /// Get the post-condition of an implementation.
- /// </summary>
- /// <param name="impl"></param>
- protected static List<Cmd> GetPost(Implementation impl) {
-
-
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- Console.WriteLine("Effective postcondition:");
- }
-
- // Construct an Expr for the post-condition
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- List<Cmd> post = new List<Cmd>();
- foreach (Ensures ens in impl.Proc.Ensures) {
- Contract.Assert(ens != null);
- if (!ens.Free) {
- Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
- Contract.Assert(e != null);
- Ensures ensCopy = cce.NonNull((Ensures)ens.Clone());
- ensCopy.Condition = e;
- Cmd c = new AssertEnsuresCmd(ensCopy);
- ((AssertEnsuresCmd)c).ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
- post.Add(c);
-
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- c.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 1);
- }
- }
- }
-
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- Console.WriteLine();
- }
-
- return post;
- }
-
- /// <summary>
- /// Get the where clauses from the in- and out-parameters as
- /// a sequence of assume commands.
- /// As a side effect, this method adds these where clauses to the out parameters.
- /// </summary>
- /// <param name="impl"></param>
- protected static List<Cmd> GetParamWhereClauses(Implementation impl) {
- Contract.Requires(impl != null);
- Contract.Requires(impl.Proc != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
- TokenTextWriter debugWriter = null;
- if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
- debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
- debugWriter.WriteLine("Effective precondition from where-clauses:");
- }
-
- Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
- List<Cmd> whereClauses = new List<Cmd>();
-
- // where clauses of in-parameters
- foreach (Formal f in impl.Proc.InParams) {
- Contract.Assert(f != null);
- if (f.TypedIdent.WhereExpr != null) {
- Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
- Cmd c = new AssumeCmd(f.tok, e);
- whereClauses.Add(c);
-
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- }
-
- // where clauses of out-parameters
- Contract.Assert(impl.OutParams.Count == impl.Proc.OutParams.Count);
- for (int i = 0; i < impl.OutParams.Count; i++) {
- Variable f = cce.NonNull(impl.Proc.OutParams[i]);
- if (f.TypedIdent.WhereExpr != null) {
- Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
- Cmd c = new AssumeCmd(f.tok, e);
- whereClauses.Add(c);
-
- Variable fi = cce.NonNull(impl.OutParams[i]);
- Contract.Assume(fi.TypedIdent.WhereExpr == null);
- fi.TypedIdent.WhereExpr = e;
-
- if (debugWriter != null) {
- c.Emit(debugWriter, 1);
- }
- }
- }
-
- if (debugWriter != null) {
- debugWriter.WriteLine();
- }
-
- return whereClauses;
- }
-
- protected static void RestoreParamWhereClauses(Implementation impl) {
- Contract.Requires(impl != null);
- // We no longer need the where clauses on the out parameters, so we remove them to restore the situation from before VC generation
- foreach (Formal f in impl.OutParams) {
- Contract.Assert(f != null);
- f.TypedIdent.WhereExpr = null;
- }
- }
- #endregion
-
-
- protected Checker FindCheckerFor(int timeout, bool isBlocking = true)
- {
- Contract.Ensures(!isBlocking || Contract.Result<Checker>() != null);
-
- var maxRetries = 3;
- lock (checkers)
- {
- retry:
- // Look for existing checker.
- for (int i = 0; i < checkers.Count; i++)
- {
- var c = checkers[i];
- if (Monitor.TryEnter(c))
- {
- try
- {
- if (c.WillingToHandle(timeout, program))
- {
- c.GetReady();
- return c;
- }
- else if (c.IsIdle || c.IsClosed)
- {
- if (c.IsIdle)
- {
- c.Retarget(program, c.TheoremProver.Context, timeout);
- c.GetReady();
- return c;
- }
- else
- {
- checkers.RemoveAt(i);
- }
- }
- }
- finally
- {
- Monitor.Exit(c);
- }
- }
- }
-
- if (Cores <= checkers.Count)
- {
- if (isBlocking || 0 < maxRetries)
- {
- Monitor.Wait(checkers, 50);
- maxRetries--;
- goto retry;
- }
- else
- {
- return null;
- }
- }
-
- // Create a new checker.
- string log = logFilePath;
- if (log != null && !log.Contains("@PROC@") && checkers.Count > 0)
- {
- log = log + "." + checkers.Count;
- }
- Checker ch = new Checker(this, program, log, appendLogFile, timeout);
- ch.GetReady();
- checkers.Add(ch);
- return ch;
- }
- }
-
-
- virtual public void Close() {
- }
-
-
- public class CounterexampleCollector : VerifierCallback {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(examples));
- }
-
- public string RequestId;
-
- public readonly List<Counterexample>/*!>!*/ examples = new List<Counterexample>();
- public override void OnCounterexample(Counterexample ce, string/*?*/ reason) {
- //Contract.Requires(ce != null);
- if (RequestId != null)
- {
- ce.RequestId = RequestId;
- }
- if (ce.OriginalRequestId == null && 1 < CommandLineOptions.Clo.VerifySnapshots)
- {
- ce.OriginalRequestId = RequestId;
- }
- examples.Add(ce);
- }
-
- public override void OnUnreachableCode(Implementation impl) {
- //Contract.Requires(impl != null);
- System.Console.WriteLine("found unreachable code:");
- EmitImpl(impl, false);
- // TODO report error about next to last in seq
- }
- }
-
- protected static void EmitImpl(Implementation impl, bool printDesugarings) {
- Contract.Requires(impl != null);
- int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
- CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program
- bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings;
- CommandLineOptions.Clo.PrintDesugarings = printDesugarings;
- impl.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0);
- CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting;
- CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
- }
-
-
- protected Block GenerateUnifiedExit(Implementation impl, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
- Contract.Requires(impl != null);
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Contract.Ensures(Contract.Result<Block>().TransferCmd is ReturnCmd);
- Block/*?*/ exitBlock = null;
- #region Create a unified exit block, if there's more than one
- {
- int returnBlocks = 0;
- foreach (Block b in impl.Blocks) {
- if (b.TransferCmd is ReturnCmd) {
- exitBlock = b;
- returnBlocks++;
- }
- }
- if (returnBlocks > 1) {
- string unifiedExitLabel = "GeneratedUnifiedExit";
- Block unifiedExit = new Block(new Token(-17, -4), unifiedExitLabel, new List<Cmd>(), new ReturnCmd(Token.NoToken));
- Contract.Assert(unifiedExit != null);
- foreach (Block b in impl.Blocks) {
- if (b.TransferCmd is ReturnCmd) {
- List<String> labels = new List<String>();
- labels.Add(unifiedExitLabel);
- List<Block> bs = new List<Block>();
- bs.Add(unifiedExit);
- GotoCmd go = new GotoCmd(Token.NoToken, labels, bs);
- gotoCmdOrigins[go] = (ReturnCmd)b.TransferCmd;
- b.TransferCmd = go;
- unifiedExit.Predecessors.Add(b);
- }
- }
-
- exitBlock = unifiedExit;
- impl.Blocks.Add(unifiedExit);
- }
- Contract.Assert(exitBlock != null);
- }
- return exitBlock;
- #endregion
- }
-
- protected static void ResetPredecessors(List<Block> blocks) {
- Contract.Requires(blocks != null);
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- b.Predecessors = new List<Block>();
- }
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- foreach (Block ch in Exits(b)) {
- Contract.Assert(ch != null);
- ch.Predecessors.Add(b);
- }
- }
- }
-
- protected static IEnumerable Exits(Block b) {
- Contract.Requires(b != null);
- GotoCmd g = b.TransferCmd as GotoCmd;
- if (g != null) {
- return cce.NonNull(g.labelTargets);
- }
- return new List<Block>();
- }
-
- protected Variable CreateIncarnation(Variable x, Absy a) {
- Contract.Requires(this.variable2SequenceNumber != null);
- Contract.Requires(this.CurrentLocalVariables != null);
- Contract.Requires(a is Block || a is AssignCmd || a is HavocCmd);
-
- Contract.Requires(x != null);
- Contract.Ensures(Contract.Result<Variable>() != null);
-
- int currentIncarnationNumber =
- variable2SequenceNumber.ContainsKey(x)
- ?
- variable2SequenceNumber[x]
- :
- -1;
- Variable v = new Incarnation(x, currentIncarnationNumber + 1);
- variable2SequenceNumber[x] = currentIncarnationNumber + 1;
- CurrentLocalVariables.Add(v);
- incarnationOriginMap.Add((Incarnation)v, a);
- return v;
- }
-
- /// <summary>
- /// Compute the incarnation map at the beginning of block "b" from the incarnation blocks of the
- /// predecessors of "b".
- ///
- /// The predecessor map b.map for block "b" is defined as follows:
- /// b.map.Domain == Union{Block p in b.predecessors; p.map.Domain}
- /// Forall{Variable v in b.map.Domain;
- /// b.map[v] == (v in Intersection{Block p in b.predecessors; p.map}.Domain
- /// ? b.predecessors[0].map[v]
- /// : new Variable())}
- /// Every variable that b.map maps to a fresh variable requires a fixup in all predecessor blocks.
- /// </summary>
- /// <param name="b"></param>
- /// <param name="block2Incarnation">Gives incarnation maps for b's predecessors.</param>
- /// <returns></returns>
- protected Dictionary<Variable, Expr> ComputeIncarnationMap(Block b, Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation) {
- Contract.Requires(b != null);
- Contract.Requires(block2Incarnation != null);
- Contract.Ensures(Contract.Result<Dictionary<Variable, Expr>>() != null);
-
- if (b.Predecessors.Count == 0) {
- return new Dictionary<Variable, Expr>();
- }
-
- Dictionary<Variable, Expr> incarnationMap = null;
- Set /*Variable*/ fixUps = new Set /*Variable*/ ();
- foreach (Block pred in b.Predecessors) {
- Contract.Assert(pred != null);
- Contract.Assert(block2Incarnation.ContainsKey(pred)); // otherwise, Passive Transformation found a block whose predecessors have not been processed yet
- Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)block2Incarnation[pred];
- Contract.Assert(predMap != null);
- if (incarnationMap == null) {
- incarnationMap = new Dictionary<Variable, Expr>(predMap);
- continue;
- }
-
- ArrayList /*Variable*/ conflicts = new ArrayList /*Variable*/ ();
- foreach (Variable v in incarnationMap.Keys) {
- Contract.Assert(v != null);
- if (!predMap.ContainsKey(v)) {
- // conflict!!
- conflicts.Add(v);
- fixUps.Add(v);
- }
- }
- // Now that we're done with enumeration, we'll do all the removes
- foreach (Variable v in conflicts) {
- Contract.Assert(v != null);
- incarnationMap.Remove(v);
- }
- foreach (Variable v in predMap.Keys) {
- Contract.Assert(v != null);
- if (!incarnationMap.ContainsKey(v)) {
- // v was not in the domain of the predecessors seen so far, so it needs to be fixed up
- fixUps.Add(v);
- } else {
- // v in incarnationMap ==> all pred blocks (up to now) all agree on its incarnation
- if (predMap[v] != incarnationMap[v]) {
- // conflict!!
- incarnationMap.Remove(v);
- fixUps.Add(v);
- }
- }
- }
- }
-
- #region Second, for all variables in the fixups list, introduce a new incarnation and push it back into the preds.
- foreach (Variable v in fixUps) {
- Contract.Assert(v != null);
- if (!b.IsLive(v))
- continue;
- Variable v_prime = CreateIncarnation(v, b);
- IdentifierExpr ie = new IdentifierExpr(v_prime.tok, v_prime);
- Contract.Assert(incarnationMap != null);
- incarnationMap[v] = ie;
- foreach (Block pred in b.Predecessors) {
- Contract.Assert(pred != null);
- #region Create an assume command equating v_prime with its last incarnation in pred
- #region Create an identifier expression for the last incarnation in pred
- Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)cce.NonNull(block2Incarnation[pred]);
-
- Expr pred_incarnation_exp;
- Expr o = predMap.ContainsKey(v) ? predMap[v] : null;
- if (o == null) {
- Variable predIncarnation = v;
- IdentifierExpr ie2 = new IdentifierExpr(predIncarnation.tok, predIncarnation);
- pred_incarnation_exp = ie2;
- } else {
- pred_incarnation_exp = o;
- }
- #endregion
- #region Create an identifier expression for the new incarnation
- IdentifierExpr v_prime_exp = new IdentifierExpr(v_prime.tok, v_prime);
- #endregion
- #region Create the assume command itself
- AssumeCmd ac = new AssumeCmd(v.tok, TypedExprEq(v_prime_exp, pred_incarnation_exp, v_prime.Name.Contains("a##post##")));
- pred.Cmds.Add(ac);
- #endregion
- #endregion
- }
- }
- #endregion
-
- Contract.Assert(incarnationMap != null);
- return incarnationMap;
- }
-
- Dictionary<Variable, Expr> preHavocIncarnationMap = null; // null = the previous command was not an HashCmd. Otherwise, a *copy* of the map before the havoc statement
-
- protected void TurnIntoPassiveBlock(Block b, Dictionary<Variable, Expr> incarnationMap, ModelViewInfo mvInfo, Substitution oldFrameSubst, MutableVariableCollector variableCollector, byte[] currentChecksum = null) {
- Contract.Requires(b != null);
- Contract.Requires(incarnationMap != null);
- Contract.Requires(mvInfo != null);
- Contract.Requires(oldFrameSubst != null);
- #region Walk forward over the commands in this block and convert them to passive commands
-
- List<Cmd> passiveCmds = new List<Cmd>();
- foreach (Cmd c in b.Cmds) {
- Contract.Assert(c != null); // walk forward over the commands because the map gets modified in a forward direction
- ChecksumHelper.ComputeChecksums(c, currentImplementation, variableCollector.UsedVariables, currentChecksum);
- variableCollector.Visit(c);
- currentChecksum = c.Checksum;
- TurnIntoPassiveCmd(c, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, b);
- }
- b.Checksum = currentChecksum;
- b.Cmds = passiveCmds;
-
- if (b.TransferCmd is ReturnExprCmd) {
- ReturnExprCmd rec = (ReturnExprCmd)b.TransferCmd.Clone();
- Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
- rec.Expr = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, rec.Expr);
- b.TransferCmd = rec;
- }
- #endregion
- }
-
- protected Dictionary<Variable, Expr> Convert2PassiveCmd(Implementation impl, ModelViewInfo mvInfo) {
- Contract.Requires(impl != null);
- Contract.Requires(mvInfo != null);
-
- currentImplementation = impl;
-
- var start = DateTime.UtcNow;
-
- Dictionary<Variable, Expr> r = ConvertBlocks2PassiveCmd(impl.Blocks, impl.Proc.Modifies, mvInfo);
-
- var end = DateTime.UtcNow;
-
- if (CommandLineOptions.Clo.TraceCachingForDebugging)
- {
- Console.Out.WriteLine("Turned implementation into passive commands within {0:F0} ms.\n", end.Subtract(start).TotalMilliseconds);
- }
-
- if (CommandLineOptions.Clo.TraceCachingForDebugging)
- {
- using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
- {
- var pd = CommandLineOptions.Clo.PrintDesugarings;
- var pu = CommandLineOptions.Clo.PrintUnstructured;
- CommandLineOptions.Clo.PrintDesugarings = true;
- CommandLineOptions.Clo.PrintUnstructured = 1;
- impl.Emit(tokTxtWr, 0);
- CommandLineOptions.Clo.PrintDesugarings = pd;
- CommandLineOptions.Clo.PrintUnstructured = pu;
- }
- }
-
- currentImplementation = null;
-
- RestoreParamWhereClauses(impl);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify) {
- Console.WriteLine("after conversion to passive commands");
- EmitImpl(impl, true);
- }
- #endregion
-
- return r;
- }
-
- protected Dictionary<Variable, Expr> ConvertBlocks2PassiveCmd(List<Block> blocks, List<IdentifierExpr> modifies, ModelViewInfo mvInfo) {
- Contract.Requires(blocks != null);
- Contract.Requires(modifies != null);
- Contract.Requires(mvInfo != null);
- #region Convert to Passive Commands
-
- #region Topological sort -- need to process in a linearization of the partial order
- Graph<Block> dag = new Graph<Block>();
- dag.AddSource(cce.NonNull(blocks[0])); // there is always at least one node in the graph
- foreach (Block b in blocks) {
- GotoCmd gtc = b.TransferCmd as GotoCmd;
- if (gtc != null) {
- Contract.Assume(gtc.labelTargets != null);
- foreach (Block dest in gtc.labelTargets) {
- Contract.Assert(dest != null);
- dag.AddEdge(b, dest);
- }
- }
- }
-
- IEnumerable sortedNodes;
- if (CommandLineOptions.Clo.ModifyTopologicalSorting) {
- sortedNodes = dag.TopologicalSort(true);
- } else {
- sortedNodes = dag.TopologicalSort();
- }
-
- Contract.Assert(sortedNodes != null);
- #endregion
-
- Substitution oldFrameSubst = ComputeOldExpressionSubstitution(modifies);
-
- // Now we can process the nodes in an order so that we're guaranteed to have
- // processed all of a node's predecessors before we process the node.
- Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation = new Dictionary<Block, Dictionary<Variable, Expr>>();
- Block exitBlock = null;
- Dictionary<Variable, Expr> exitIncarnationMap = null;
- var variableCollectors = new Dictionary<Block, MutableVariableCollector>();
- foreach (Block b in sortedNodes) {
- Contract.Assert(b != null);
- Contract.Assert(!block2Incarnation.ContainsKey(b));
- Dictionary<Variable, Expr> incarnationMap = ComputeIncarnationMap(b, block2Incarnation);
-
- // b.liveVarsBefore has served its purpose in the just-finished call to ComputeIncarnationMap; null it out.
- b.liveVarsBefore = null;
-
- // Decrement the succCount field in each predecessor. Once the field reaches zero in any block,
- // all its successors have been passified. Consequently, its entry in block2Incarnation can be removed.
- byte[] currentChecksum = null;
- var mvc = new MutableVariableCollector();
- variableCollectors[b] = mvc;
- foreach (Block p in b.Predecessors) {
- p.succCount--;
- if (p.Checksum != null)
- {
- // Compute the checksum based on the checksums of the predecessor. The order should not matter.
- currentChecksum = ChecksumHelper.CombineChecksums(p.Checksum, currentChecksum, true);
- }
- mvc.AddUsedVariables(variableCollectors[p].UsedVariables);
- if (p.succCount == 0)
- block2Incarnation.Remove(p);
- }
-
- #region Each block's map needs to be available to successor blocks
- GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
- if (gotoCmd == null) {
- b.succCount = 0;
- }
- else {
- // incarnationMap needs to be added only if there is some successor of b
- b.succCount = gotoCmd.labelNames.Count;
- block2Incarnation.Add(b, incarnationMap);
- }
- #endregion Each block's map needs to be available to successor blocks
-
- TurnIntoPassiveBlock(b, incarnationMap, mvInfo, oldFrameSubst, mvc, currentChecksum);
- exitBlock = b;
- exitIncarnationMap = incarnationMap;
- }
-
- variableCollectors.Clear();
-
- // Verify that exitBlock is indeed the unique exit block
- Contract.Assert(exitBlock != null);
- Contract.Assert(exitBlock.TransferCmd is ReturnCmd);
- #endregion Convert to Passive Commands
-
- return exitIncarnationMap;
- }
-
- /// <summary>
- /// Compute the substitution for old expressions.
- /// </summary>
- protected static Substitution ComputeOldExpressionSubstitution(List<IdentifierExpr> modifies)
- {
- Dictionary<Variable, Expr> oldFrameMap = new Dictionary<Variable, Expr>();
- foreach (IdentifierExpr ie in modifies)
- {
- Contract.Assert(ie != null);
- if (!oldFrameMap.ContainsKey(cce.NonNull(ie.Decl)))
- oldFrameMap.Add(ie.Decl, ie);
- }
- return Substituter.SubstitutionFromHashtable(oldFrameMap);
- }
-
- public enum CachingAction : byte
- {
- DoNothingToAssert,
- MarkAsPartiallyVerified,
- MarkAsFullyVerified,
- RecycleError,
- AssumeNegationOfAssumptionVariable,
- DropAssume
- }
-
- public long[] CachingActionCounts;
-
- void TraceCachingAction(Cmd cmd, CachingAction action)
- {
- if (CommandLineOptions.Clo.TraceCachingForTesting)
- {
- using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
- {
- var loc = cmd.tok != null && cmd.tok != Token.NoToken ? string.Format("{0}({1},{2})", cmd.tok.filename, cmd.tok.line, cmd.tok.col) : "<unknown location>";
- Console.Write("Processing command (at {0}) ", loc);
- cmd.Emit(tokTxtWr, 0);
- Console.Out.WriteLine(" >>> {0}", action);
- }
- }
-
- if (CommandLineOptions.Clo.TraceCachingForBenchmarking && CachingActionCounts != null)
- {
- Interlocked.Increment(ref CachingActionCounts[(int)action]);
- }
- }
-
- /// <summary>
- /// Turn a command into a passive command, and it remembers the previous step, to see if it is a havoc or not. In the case, it remembers the incarnation map BEFORE the havoc
- /// Meanwhile, record any information needed to later reconstruct a model view.
- /// </summary>
- protected void TurnIntoPassiveCmd(Cmd c, Dictionary<Variable, Expr> incarnationMap, Substitution oldFrameSubst, List<Cmd> passiveCmds, ModelViewInfo mvInfo, Block containingBlock) {
- Contract.Requires(c != null);
- Contract.Requires(incarnationMap != null);
- Contract.Requires(oldFrameSubst != null);
- Contract.Requires(passiveCmds != null);
- Contract.Requires(mvInfo != null);
- Contract.Requires(containingBlock != null);
-
- Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
- #region assert/assume P |--> assert/assume P[x := in(x)], out := in
- if (c is PredicateCmd) {
- Contract.Assert(c is AssertCmd || c is AssumeCmd); // otherwise, unexpected PredicateCmd type
-
- PredicateCmd pc = (PredicateCmd)c.Clone();
- Contract.Assert(pc != null);
-
- Expr copy = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, pc.Expr);
- if (CommandLineOptions.Clo.ModelViewFile != null && pc is AssumeCmd) {
- string description = QKeyValue.FindStringAttribute(pc.Attributes, "captureState");
- if (description != null) {
- Expr mv = new NAryExpr(pc.tok, new FunctionCall(ModelViewInfo.MVState_FunctionDef), new List<Expr> { Bpl.Expr.Ident(ModelViewInfo.MVState_ConstantDef), Bpl.Expr.Literal(mvInfo.CapturePoints.Count) });
- copy = Bpl.Expr.And(mv, copy);
- mvInfo.CapturePoints.Add(new ModelViewInfo.Mapping(description, new Dictionary<Variable, Expr>(incarnationMap)));
- }
- }
- Contract.Assert(copy != null);
- var dropCmd = false;
- var relevantAssumpVars = currentImplementation != null ? currentImplementation.RelevantInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
- var relevantDoomedAssumpVars = currentImplementation != null ? currentImplementation.RelevantDoomedInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
- var checksum = pc.Checksum;
- if (pc is AssertCmd) {
- var ac = (AssertCmd)pc;
- ac.OrigExpr = ac.Expr;
- Contract.Assert(ac.IncarnationMap == null);
- ac.IncarnationMap = (Dictionary<Variable, Expr>)cce.NonNull(new Dictionary<Variable, Expr>(incarnationMap));
-
- var subsumption = Wlp.Subsumption(ac);
- if (relevantDoomedAssumpVars.Any())
- {
- TraceCachingAction(pc, CachingAction.DoNothingToAssert);
- }
- else if (currentImplementation != null
- && currentImplementation.HasCachedSnapshot
- && checksum != null
- && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
- && !currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
- {
- if (!currentImplementation.AnyErrorsInCachedSnapshot
- && currentImplementation.InjectedAssumptionVariables.Count == 1
- && relevantAssumpVars.Count == 1)
- {
- TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
- }
- else
- {
- bool isTrue;
- var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
- TraceCachingAction(pc, !isTrue ? CachingAction.MarkAsPartiallyVerified : CachingAction.MarkAsFullyVerified);
- var litExpr = ac.Expr as LiteralExpr;
- if (litExpr == null || !litExpr.IsTrue)
- {
- ac.MarkAsVerifiedUnder(assmVars);
- }
- else
- {
- dropCmd = true;
- }
- }
- }
- else if (currentImplementation != null
- && currentImplementation.HasCachedSnapshot
- && relevantAssumpVars.Count == 0
- && checksum != null
- && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
- && currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
- {
- TraceCachingAction(pc, CachingAction.RecycleError);
- ac.MarkAsVerifiedUnder(Expr.True);
- currentImplementation.AddRecycledFailingAssertion(ac);
- pc.Attributes = new QKeyValue(Token.NoToken, "recycled_failing_assertion", new List<object>(), pc.Attributes);
- }
- else
- {
- TraceCachingAction(pc, CachingAction.DoNothingToAssert);
- }
- }
- else if (pc is AssumeCmd
- && QKeyValue.FindBoolAttribute(pc.Attributes, "precondition_previous_snapshot")
- && pc.SugaredCmdChecksum != null)
- {
- if (!relevantDoomedAssumpVars.Any()
- && currentImplementation.HasCachedSnapshot
- && currentImplementation.IsAssertionChecksumInCachedSnapshot(pc.SugaredCmdChecksum)
- && !currentImplementation.IsErrorChecksumInCachedSnapshot(pc.SugaredCmdChecksum))
- {
- bool isTrue;
- var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
- if (!isTrue)
- {
- copy = LiteralExpr.Imp(assmVars, copy);
- TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
- }
- else
- {
- TraceCachingAction(pc, CachingAction.MarkAsFullyVerified);
- }
- }
- else
- {
- TraceCachingAction(pc, CachingAction.DropAssume);
- dropCmd = true;
- }
- }
- else if (pc is AssumeCmd && QKeyValue.FindBoolAttribute(pc.Attributes, "assumption_variable_initialization"))
- {
- var identExpr = pc.Expr as IdentifierExpr;
- if (identExpr != null && identExpr.Decl != null && !incarnationMap.ContainsKey(identExpr.Decl))
- {
- incarnationMap[identExpr.Decl] = LiteralExpr.True;
- dropCmd = true;
- }
- }
- pc.Expr = copy;
- if (!dropCmd)
- {
- passiveCmds.Add(pc);
- }
- }
- #endregion
- #region x1 := E1, x2 := E2, ... |--> assume x1' = E1[in] & x2' = E2[in], out := in( x |-> x' ) [except as noted below]
- else if (c is AssignCmd) {
- AssignCmd assign = ((AssignCmd)c).AsSimpleAssignCmd; // first remove map assignments
- Contract.Assert(assign != null);
- #region Substitute all variables in E with the current map
- List<Expr> copies = new List<Expr>();
- foreach (Expr e in assign.Rhss) {
- Contract.Assert(e != null);
- copies.Add(Substituter.ApplyReplacingOldExprs(incarnationSubst,
- oldFrameSubst,
- e));
- }
- #endregion
-
- List<Expr/*!>!*/> assumptions = new List<Expr>();
- // it might be too slow to create a new dictionary each time ...
- IDictionary<Variable, Expr> newIncarnationMappings =
- new Dictionary<Variable, Expr>();
-
- for (int i = 0; i < assign.Lhss.Count; ++i) {
- IdentifierExpr lhsIdExpr =
- cce.NonNull((SimpleAssignLhs)assign.Lhss[i]).AssignedVariable;
- Variable lhs = cce.NonNull(lhsIdExpr.Decl);
- Contract.Assert(lhs != null);
- Expr rhs = assign.Rhss[i];
- Contract.Assert(rhs != null);
-
- // don't create incarnations for assignments of literals or single variables.
- if (rhs is LiteralExpr) {
- incarnationMap[lhs] = rhs;
- } else if (rhs is IdentifierExpr) {
- IdentifierExpr ie = (IdentifierExpr)rhs;
- if (incarnationMap.ContainsKey(cce.NonNull(ie.Decl)))
- newIncarnationMappings[lhs] = cce.NonNull((Expr)incarnationMap[ie.Decl]);
- else
- newIncarnationMappings[lhs] = ie;
- } else {
- IdentifierExpr x_prime_exp = null;
- #region Make a new incarnation, x', for variable x, but only if x is *not* already an incarnation
- if (lhs is Incarnation) {
- // incarnations are already written only once, no need to make an incarnation of an incarnation
- x_prime_exp = lhsIdExpr;
- } else {
- Variable v = CreateIncarnation(lhs, c);
- x_prime_exp = new IdentifierExpr(lhsIdExpr.tok, v);
- newIncarnationMappings[lhs] = x_prime_exp;
- }
- #endregion
-
- var nAryExpr = copies[i] as NAryExpr;
- if (nAryExpr != null)
- {
- var binOp = nAryExpr.Fun as BinaryOperator;
- if (binOp != null
- && binOp.Op == BinaryOperator.Opcode.And)
- {
- var arg0 = nAryExpr.Args[0] as LiteralExpr;
- var arg1 = nAryExpr.Args[1] as LiteralExpr;
- if ((arg0 != null && arg0.IsTrue) || (arg1 != null && arg1.IsFalse))
- {
- // Replace the expressions "true && arg1" or "arg0 && false" by "arg1".
- copies[i] = nAryExpr.Args[1];
- }
- }
- }
-
- #region Create an assume command with the new variable
- assumptions.Add(TypedExprEq(x_prime_exp, copies[i], x_prime_exp.Decl != null && x_prime_exp.Decl.Name.Contains("a##post##")));
- #endregion
- }
- }
-
- foreach (KeyValuePair<Variable, Expr> pair in newIncarnationMappings) {
- Contract.Assert(pair.Key != null && pair.Value != null);
- incarnationMap[pair.Key] = pair.Value;
- }
-
- if (assumptions.Count > 0) {
- Expr assumption = assumptions[0];
-
- for (int i = 1; i < assumptions.Count; ++i) {
- Contract.Assert(assumption != null);
- assumption = Expr.And(assumption, assumptions[i]);
- }
- passiveCmds.Add(new AssumeCmd(c.tok, assumption));
- }
-
- if (currentImplementation != null
- && currentImplementation.HasCachedSnapshot
- && !currentImplementation.AnyErrorsInCachedSnapshot
- && currentImplementation.InjectedAssumptionVariables.Count == 1
- && assign.Lhss.Count == 1)
- {
- var identExpr = assign.Lhss[0].AsExpr as IdentifierExpr;
- Expr incarnation;
- if (identExpr != null && identExpr.Decl != null && QKeyValue.FindBoolAttribute(identExpr.Decl.Attributes, "assumption") && incarnationMap.TryGetValue(identExpr.Decl, out incarnation))
- {
- TraceCachingAction(assign, CachingAction.AssumeNegationOfAssumptionVariable);
- passiveCmds.Add(new AssumeCmd(c.tok, Expr.Not(incarnation)));
- }
- }
- }
- #endregion
- #region havoc w |--> assume whereClauses, out := in( w |-> w' )
- else if (c is HavocCmd) {
- if (this.preHavocIncarnationMap == null) // Save a copy of the incarnation map (at the top of a sequence of havoc statements)
- this.preHavocIncarnationMap = new Dictionary<Variable, Expr>(incarnationMap);
-
- HavocCmd hc = (HavocCmd)c;
- Contract.Assert(c != null);
- // If an assumption variable for postconditions is included here, it must have been assigned within a loop.
- // We do not need to havoc it if we have performed a modular proof of the loop (i.e., using only the loop
- // invariant) in the previous snapshot and are therefore not going refer to the assumption variable after
- // the loop. We can achieve this by simply not updating/adding it in the incarnation map.
- List<IdentifierExpr> havocVars = hc.Vars.Where(v => !(QKeyValue.FindBoolAttribute(v.Decl.Attributes, "assumption") && v.Decl.Name.StartsWith("a##post##"))).ToList();
- // First, compute the new incarnations
- foreach (IdentifierExpr ie in havocVars) {
- Contract.Assert(ie != null);
- if (!(ie.Decl is Incarnation)) {
- Variable x = cce.NonNull(ie.Decl);
- Variable x_prime = CreateIncarnation(x, c);
- incarnationMap[x] = new IdentifierExpr(x_prime.tok, x_prime);
- }
- }
- // Then, perform the assume of the where clauses, using the updated incarnations
- Substitution updatedIncarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
- foreach (IdentifierExpr ie in havocVars) {
- Contract.Assert(ie != null);
- if (!(ie.Decl is Incarnation)) {
- Variable x = cce.NonNull(ie.Decl);
- Bpl.Expr w = x.TypedIdent.WhereExpr;
- if (w != null) {
- Expr copy = Substituter.ApplyReplacingOldExprs(updatedIncarnationSubst, oldFrameSubst, w);
- passiveCmds.Add(new AssumeCmd(c.tok, copy));
- }
- }
- }
- }
- #endregion
- else if (c is CommentCmd) {
- // comments are just for debugging and don't affect verification
- } else if (c is SugaredCmd) {
- SugaredCmd sug = (SugaredCmd)c;
- Contract.Assert(sug != null);
- Cmd cmd = sug.Desugaring;
- Contract.Assert(cmd != null);
- TurnIntoPassiveCmd(cmd, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
- } else if (c is StateCmd) {
- this.preHavocIncarnationMap = null; // we do not need to remeber the previous incarnations
- StateCmd st = (StateCmd)c;
- Contract.Assert(st != null);
- // account for any where clauses among the local variables
- foreach (Variable v in st.Locals) {
- Contract.Assert(v != null);
- Expr w = v.TypedIdent.WhereExpr;
- if (w != null) {
- passiveCmds.Add(new AssumeCmd(v.tok, w));
- }
- }
- // do the sub-commands
- foreach (Cmd s in st.Cmds) {
- Contract.Assert(s != null);
- TurnIntoPassiveCmd(s, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
- }
- // remove the local variables from the incarnation map
- foreach (Variable v in st.Locals) {
- Contract.Assert(v != null);
- incarnationMap.Remove(v);
- }
- }
- #region There shouldn't be any other types of commands at this point
- else {
- Debug.Fail("Internal Error: Passive transformation handed a command that is not one of assert,assume,havoc,assign.");
- }
- #endregion
-
-
- #region We remember if we have put an havoc statement into a passive form
-
- if (!(c is HavocCmd))
- this.preHavocIncarnationMap = null;
- // else: it has already been set by the case for the HavocCmd
- #endregion
- }
-
- NAryExpr TypedExprEq(Expr e0, Expr e1, bool doNotResolveOverloading = false) {
- Contract.Requires(e0 != null);
- Contract.Requires(e1 != null);
- NAryExpr e = Expr.Eq(e0, e1);
- var fun = e.Fun as IOverloadedAppliable;
- if (fun != null)
- {
- fun.DoNotResolveOverloading = doNotResolveOverloading;
- }
- e.Type = Bpl.Type.Bool;
- e.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
- return e;
- }
-
- /// <summary>
- /// Creates a new block to add to impl.Blocks, where impl is the implementation that contains
- /// succ. Caller must do the add to impl.Blocks.
- /// </summary>
- protected Block CreateBlockBetween(int predIndex, Block succ) {
- Contract.Requires(0 <= predIndex && predIndex < succ.Predecessors.Count);
-
-
- Contract.Requires(succ != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block pred = cce.NonNull(succ.Predecessors[predIndex]);
-
- string newBlockLabel = pred.Label + "_@2_" + succ.Label;
-
- // successor of newBlock list
- List<String> ls = new List<String>();
- ls.Add(succ.Label);
- List<Block> bs = new List<Block>();
- bs.Add(succ);
-
- Block newBlock = new Block(
- new Token(-17, -4),
- newBlockLabel,
- new List<Cmd>(),
- new GotoCmd(Token.NoToken, ls, bs)
- );
-
- // predecessors of newBlock
- List<Block> ps = new List<Block>();
- ps.Add(pred);
- newBlock.Predecessors = ps;
-
- // fix successors of pred
- #region Change the edge "pred->succ" to "pred->newBlock"
- GotoCmd gtc = (GotoCmd)cce.NonNull(pred.TransferCmd);
- Contract.Assume(gtc.labelTargets != null);
- Contract.Assume(gtc.labelNames != null);
- for (int i = 0, n = gtc.labelTargets.Count; i < n; i++) {
- if (gtc.labelTargets[i] == succ) {
- gtc.labelTargets[i] = newBlock;
- gtc.labelNames[i] = newBlockLabel;
- break;
- }
- }
- #endregion Change the edge "pred->succ" to "pred->newBlock"
-
- // fix predecessors of succ
- succ.Predecessors[predIndex] = newBlock;
-
- return newBlock;
- }
-
- protected void AddBlocksBetween(List<Block> blocks) {
- Contract.Requires(blocks != null);
- #region Introduce empty blocks between join points and their multi-successor predecessors
- List<Block> tweens = new List<Block>();
- foreach (Block b in blocks) {
- int nPreds = b.Predecessors.Count;
- if (nPreds > 1) {
- // b is a join point (i.e., it has more than one predecessor)
- for (int i = 0; i < nPreds; i++) {
- GotoCmd gotocmd = (GotoCmd)(cce.NonNull(b.Predecessors[i]).TransferCmd);
- if (gotocmd.labelNames != null && gotocmd.labelNames.Count > 1) {
- tweens.Add(CreateBlockBetween(i, b));
- }
- }
- }
- }
- blocks.AddRange(tweens); // must wait until iteration is done before changing the list
- #endregion
- }
-
-
- public void Dispose()
- {
- Dispose(true);
- GC.SuppressFinalize(this);
- }
-
- protected virtual void Dispose(bool disposing)
- {
- if (!_disposed)
- {
- if (disposing)
- {
- Close();
- }
- _disposed = true;
- }
- }
-
- public int Cores { get; set; }
- }
-
- public class ModelViewInfo
- {
- public readonly List<Variable> AllVariables = new List<Variable>();
- public readonly List<Mapping> CapturePoints = new List<Mapping>();
- public static readonly Function MVState_FunctionDef = new Function(Token.NoToken, "$mv_state",
- new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true),
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true) },
- new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Bool), false));
- public static readonly Constant MVState_ConstantDef = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "$mv_state_const", Bpl.Type.Int));
-
- public ModelViewInfo(Program program, Implementation impl) {
- Contract.Requires(program != null);
- Contract.Requires(impl != null);
-
- // global variables
- lock (program.TopLevelDeclarations)
- {
- foreach (var v in program.Variables)
- {
- if (!(v is Constant))
- {
- AllVariables.Add(v);
- }
- }
- }
- // implementation parameters
- foreach (Variable p in impl.InParams) {
- AllVariables.Add(p);
- }
- foreach (Variable p in impl.OutParams) {
- AllVariables.Add(p);
- }
- // implementation locals
- foreach (Variable v in impl.LocVars) {
- AllVariables.Add(v);
- }
- }
-
- public ModelViewInfo(CodeExpr codeExpr) {
- Contract.Requires(codeExpr != null);
- // TODO: also need all variables of enclosing scopes (the global variables of the program, the parameters
- // and perhaps locals of the implementation (if any), any enclosing code expressions).
-
- foreach (Variable v in codeExpr.LocVars) {
- AllVariables.Add(v);
- }
- }
-
- public class Mapping
- {
- public readonly string Description;
- public readonly Dictionary<Variable, Expr> IncarnationMap;
- public Mapping(string description, Dictionary<Variable, Expr> incarnationMap) {
- Description = description;
- IncarnationMap = incarnationMap;
- }
- }
- }
-}
+//-----------------------------------------------------------------------------
+//
+// Copyright (C) Microsoft Corporation. All Rights Reserved.
+//
+//-----------------------------------------------------------------------------
+using System;
+using System.Linq;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Threading;
+using System.IO;
+using Microsoft.Boogie;
+using Microsoft.Boogie.GraphUtil;
+using System.Diagnostics.Contracts;
+using Microsoft.Basetypes;
+using Microsoft.Boogie.VCExprAST;
+using Set = Microsoft.Boogie.GSet<object>;
+
+namespace Microsoft.Boogie {
+
+ public class CalleeCounterexampleInfo {
+ public Counterexample counterexample;
+ public List<object>/*!>!*/ args;
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(args));
+ }
+
+ public CalleeCounterexampleInfo(Counterexample cex, List<object/*!>!*/> x)
+ {
+ Contract.Requires(cce.NonNullElements(x));
+ counterexample = cex;
+ args = x;
+ }
+ }
+
+ public class TraceLocation : IEquatable<TraceLocation>
+ {
+ public int numBlock;
+ public int numInstr;
+
+ public TraceLocation(int numBlock, int numInstr)
+ {
+ this.numBlock = numBlock;
+ this.numInstr = numInstr;
+ }
+
+ public override bool Equals(object obj)
+ {
+ TraceLocation that = obj as TraceLocation;
+ if (that == null) return false;
+ return (numBlock == that.numBlock && numInstr == that.numInstr);
+ }
+
+ public bool Equals(TraceLocation that)
+ {
+ return (numBlock == that.numBlock && numInstr == that.numInstr);
+ }
+
+ public override int GetHashCode()
+ {
+ return numBlock.GetHashCode() ^ 131 * numInstr.GetHashCode();
+ }
+ }
+
+ public abstract class Counterexample {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(Trace != null);
+ Contract.Invariant(Context != null);
+ Contract.Invariant(cce.NonNullElements(relatedInformation));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(calleeCounterexamples));
+ }
+
+ [Peer]
+ public List<Block> Trace;
+ public Model Model;
+ public VC.ModelViewInfo MvInfo;
+ public ProverContext Context;
+ [Peer]
+ public List<string>/*!>!*/ relatedInformation;
+ public string OriginalRequestId;
+ public string RequestId;
+ public abstract byte[] Checksum { get; }
+ public byte[] SugaredCmdChecksum;
+ public bool IsAuxiliaryCexForDiagnosingTimeouts;
+
+ public Dictionary<TraceLocation, CalleeCounterexampleInfo> calleeCounterexamples;
+
+ internal Counterexample(List<Block> trace, Model model, VC.ModelViewInfo mvInfo, ProverContext context) {
+ Contract.Requires(trace != null);
+ Contract.Requires(context != null);
+ this.Trace = trace;
+ this.Model = model;
+ this.MvInfo = mvInfo;
+ this.Context = context;
+ this.relatedInformation = new List<string>();
+ this.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
+ }
+
+ // Create a shallow copy of the counterexample
+ public abstract Counterexample Clone();
+
+ public void AddCalleeCounterexample(TraceLocation loc, CalleeCounterexampleInfo cex)
+ {
+ Contract.Requires(cex != null);
+ calleeCounterexamples[loc] = cex;
+ }
+
+ public void AddCalleeCounterexample(int numBlock, int numInstr, CalleeCounterexampleInfo cex)
+ {
+ Contract.Requires(cex != null);
+ calleeCounterexamples[new TraceLocation(numBlock, numInstr)] = cex;
+ }
+
+ public void AddCalleeCounterexample(Dictionary<TraceLocation, CalleeCounterexampleInfo> cs)
+ {
+ Contract.Requires(cce.NonNullDictionaryAndValues(cs));
+ foreach (TraceLocation loc in cs.Keys)
+ {
+ AddCalleeCounterexample(loc, cs[loc]);
+ }
+ }
+
+ // Looks up the Cmd at a given index into the trace
+ public Cmd getTraceCmd(TraceLocation loc)
+ {
+ Debug.Assert(loc.numBlock < Trace.Count);
+ Block b = Trace[loc.numBlock];
+ Debug.Assert(loc.numInstr < b.Cmds.Count);
+ return b.Cmds[loc.numInstr];
+ }
+
+ // Looks up the name of the called procedure.
+ // Asserts that the name exists
+ public string getCalledProcName(Cmd cmd)
+ {
+ // There are two options:
+ // 1. cmd is a CallCmd
+ // 2. cmd is an AssumeCmd (passified version of a CallCmd)
+ if(cmd is CallCmd) {
+ return (cmd as CallCmd).Proc.Name;
+ }
+ AssumeCmd assumeCmd = cmd as AssumeCmd;
+ Debug.Assert(assumeCmd != null);
+
+ NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
+ Debug.Assert(naryExpr != null);
+
+ return naryExpr.Fun.FunctionName;
+ }
+
+ public void Print(int indent, TextWriter tw, Action<Block> blockAction = null) {
+ int numBlock = -1;
+ string ind = new string(' ', indent);
+ foreach (Block b in Trace) {
+ Contract.Assert(b != null);
+ numBlock++;
+ if (b.tok == null) {
+ tw.WriteLine("{0}<intermediate block>", ind);
+ } else {
+ // for ErrorTrace == 1 restrict the output;
+ // do not print tokens with -17:-4 as their location because they have been
+ // introduced in the translation and do not give any useful feedback to the user
+ if (!(CommandLineOptions.Clo.ErrorTrace == 1 && b.tok.line == -17 && b.tok.col == -4)) {
+ if (blockAction != null)
+ {
+ blockAction(b);
+ }
+
+ tw.WriteLine("{4}{0}({1},{2}): {3}", b.tok.filename, b.tok.line, b.tok.col, b.Label, ind);
+
+ for (int numInstr = 0; numInstr < b.Cmds.Count; numInstr++)
+ {
+ var loc = new TraceLocation(numBlock, numInstr);
+ if (calleeCounterexamples.ContainsKey(loc))
+ {
+ var cmd = getTraceCmd(loc);
+ var calleeName = getCalledProcName(cmd);
+ if (calleeName.StartsWith(VC.StratifiedVCGen.recordProcName) && CommandLineOptions.Clo.StratifiedInlining > 0)
+ {
+ Contract.Assert(calleeCounterexamples[loc].args.Count == 1);
+ var arg = calleeCounterexamples[loc].args[0];
+ tw.WriteLine("{0}value = {1}", ind, arg.ToString());
+ }
+ else
+ {
+ tw.WriteLine("{1}Inlined call to procedure {0} begins", calleeName, ind);
+ calleeCounterexamples[loc].counterexample.Print(indent + 4, tw);
+ tw.WriteLine("{1}Inlined call to procedure {0} ends", calleeName, ind);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static bool firstModelFile = true;
+
+ public bool ModelHasStatesAlready = false;
+
+ public void PrintModel(TextWriter tw)
+ {
+ var filename = CommandLineOptions.Clo.ModelViewFile;
+ if (Model == null || filename == null || CommandLineOptions.Clo.StratifiedInlining > 0) return;
+
+ if (!ModelHasStatesAlready) {
+ PopulateModelWithStates();
+ ModelHasStatesAlready = true;
+ }
+
+ if (filename == "-") {
+ Model.Write(tw);
+ tw.Flush();
+ } else {
+ using (var wr = new StreamWriter(filename, !firstModelFile)) {
+ firstModelFile = false;
+ Model.Write(wr);
+ }
+ }
+ }
+
+ void ApplyRedirections(Model m) {
+ var mapping = new Dictionary<Model.Element, Model.Element>();
+ foreach (var name in new string[] { "U_2_bool", "U_2_int" }) {
+ Model.Func f = m.TryGetFunc(name);
+ if (f != null && f.Arity == 1) {
+ foreach (var ft in f.Apps) mapping[ft.Args[0]] = ft.Result;
+ }
+ }
+ m.Substitute(mapping);
+ }
+
+ public void PopulateModelWithStates()
+ {
+ Contract.Requires(Model != null);
+
+ Model m = Model;
+ ApplyRedirections(m);
+
+ var mvstates = m.TryGetFunc("$mv_state");
+ if (MvInfo == null || mvstates == null || (mvstates.Arity == 1 && mvstates.Apps.Count() == 0))
+ return;
+
+ Contract.Assert(mvstates.Arity == 2);
+
+ foreach (Variable v in MvInfo.AllVariables) {
+ m.InitialState.AddBinding(v.Name, GetModelValue(m, v));
+ }
+
+ var states = new List<int>();
+ foreach (var t in mvstates.Apps)
+ states.Add(t.Args[1].AsInt());
+
+ states.Sort();
+
+ for (int i = 0; i < states.Count; ++i) {
+ var s = states[i];
+ if (0 <= s && s < MvInfo.CapturePoints.Count) {
+ VC.ModelViewInfo.Mapping map = MvInfo.CapturePoints[s];
+ var prevInc = i > 0 ? MvInfo.CapturePoints[states[i - 1]].IncarnationMap : new Dictionary<Variable, Expr>();
+ var cs = m.MkState(map.Description);
+
+ foreach (Variable v in MvInfo.AllVariables) {
+ Expr e = map.IncarnationMap.ContainsKey(v) ? map.IncarnationMap[v] : null;
+ if (e == null) continue;
+
+ Expr prevIncV = prevInc.ContainsKey(v) ? prevInc[v] : null;
+ if (prevIncV == e) continue; // skip unchanged variables
+
+ Model.Element elt;
+
+ if (e is IdentifierExpr) {
+ IdentifierExpr ide = (IdentifierExpr)e;
+ elt = GetModelValue(m, ide.Decl);
+ } else if (e is LiteralExpr) {
+ LiteralExpr lit = (LiteralExpr)e;
+ elt = m.MkElement(lit.Val.ToString());
+ } else {
+ elt = m.MkFunc(e.ToString(), 0).GetConstant();
+ }
+
+ cs.AddBinding(v.Name, elt);
+ }
+
+ } else {
+ Contract.Assume(false);
+ }
+ }
+ }
+
+ private Model.Element GetModelValue(Model m, Variable v) {
+ Model.Element elt;
+ // first, get the unique name
+ string uniqueName;
+ VCExprVar vvar = Context.BoogieExprTranslator.TryLookupVariable(v);
+ if (vvar == null) {
+ uniqueName = v.Name;
+ } else {
+ uniqueName = Context.Lookup(vvar);
+ }
+
+ var f = m.TryGetFunc(uniqueName);
+ if (f == null) {
+ f = m.MkFunc(uniqueName, 0);
+ }
+ elt = f.GetConstant();
+ return elt;
+ }
+
+ public abstract int GetLocation();
+ }
+
+ public class CounterexampleComparer : IComparer<Counterexample>, IEqualityComparer<Counterexample> {
+
+ private int Compare(List<Block> bs1, List<Block> bs2)
+ {
+ if (bs1.Count < bs2.Count)
+ {
+ return -1;
+ }
+ else if (bs2.Count < bs1.Count)
+ {
+ return 1;
+ }
+
+ for (int i = 0; i < bs1.Count; i++)
+ {
+ var b1 = bs1[i];
+ var b2 = bs2[i];
+ if (b1.tok.pos < b2.tok.pos)
+ {
+ return -1;
+ }
+ else if (b2.tok.pos < b1.tok.pos)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+ }
+
+ public int Compare(Counterexample c1, Counterexample c2)
+ {
+ //Contract.Requires(c1 != null);
+ //Contract.Requires(c2 != null);
+ if (c1.GetLocation() == c2.GetLocation())
+ {
+ var c = Compare(c1.Trace, c2.Trace);
+ if (c != 0)
+ {
+ return c;
+ }
+ // TODO(wuestholz): Generalize this to compare all IPotentialErrorNodes of the counterexample.
+ var a1 = c1 as AssertCounterexample;
+ var a2 = c2 as AssertCounterexample;
+ if (a1 != null && a2 != null)
+ {
+ var s1 = a1.FailingAssert.ErrorData as string;
+ var s2 = a2.FailingAssert.ErrorData as string;
+ if (s1 != null && s2 != null)
+ {
+ return s1.CompareTo(s2);
+ }
+ }
+
+ return 0;
+ }
+ if (c1.GetLocation() > c2.GetLocation())
+ {
+ return 1;
+ }
+ return -1;
+ }
+
+ public bool Equals(Counterexample x, Counterexample y)
+ {
+ return Compare(x, y) == 0;
+ }
+
+ public int GetHashCode(Counterexample obj)
+ {
+ return 0;
+ }
+ }
+
+ public class AssertCounterexample : Counterexample {
+ [Peer]
+ public AssertCmd FailingAssert;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(FailingAssert != null);
+ }
+
+
+ public AssertCounterexample(List<Block> trace, AssertCmd failingAssert, Model model, VC.ModelViewInfo mvInfo, ProverContext context)
+ : base(trace, model, mvInfo, context) {
+ Contract.Requires(trace != null);
+ Contract.Requires(failingAssert != null);
+ Contract.Requires(context != null);
+ this.FailingAssert = failingAssert;
+ }
+
+ public override int GetLocation() {
+ return FailingAssert.tok.line * 1000 + FailingAssert.tok.col;
+ }
+
+ public override byte[] Checksum
+ {
+ get { return FailingAssert.Checksum; }
+ }
+
+ public override Counterexample Clone()
+ {
+ var ret = new AssertCounterexample(Trace, FailingAssert, Model, MvInfo, Context);
+ ret.calleeCounterexamples = calleeCounterexamples;
+ return ret;
+ }
+ }
+
+ public class CallCounterexample : Counterexample {
+ public CallCmd FailingCall;
+ public Requires FailingRequires;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(FailingCall != null);
+ Contract.Invariant(FailingRequires != null);
+ }
+
+
+ public CallCounterexample(List<Block> trace, CallCmd failingCall, Requires failingRequires, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum = null)
+ : base(trace, model, mvInfo, context) {
+ Contract.Requires(!failingRequires.Free);
+ Contract.Requires(trace != null);
+ Contract.Requires(context != null);
+ Contract.Requires(failingCall != null);
+ Contract.Requires(failingRequires != null);
+ this.FailingCall = failingCall;
+ this.FailingRequires = failingRequires;
+ this.checksum = checksum;
+ this.SugaredCmdChecksum = failingCall.Checksum;
+ }
+
+ public override int GetLocation() {
+ return FailingCall.tok.line * 1000 + FailingCall.tok.col;
+ }
+
+ byte[] checksum;
+ public override byte[] Checksum
+ {
+ get { return checksum; }
+ }
+
+ public override Counterexample Clone()
+ {
+ var ret = new CallCounterexample(Trace, FailingCall, FailingRequires, Model, MvInfo, Context, Checksum);
+ ret.calleeCounterexamples = calleeCounterexamples;
+ return ret;
+ }
+ }
+
+ public class ReturnCounterexample : Counterexample {
+ public TransferCmd FailingReturn;
+ public Ensures FailingEnsures;
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(FailingEnsures != null);
+ Contract.Invariant(FailingReturn != null);
+ }
+
+
+ public ReturnCounterexample(List<Block> trace, TransferCmd failingReturn, Ensures failingEnsures, Model model, VC.ModelViewInfo mvInfo, ProverContext context, byte[] checksum)
+ : base(trace, model, mvInfo, context) {
+ Contract.Requires(trace != null);
+ Contract.Requires(context != null);
+ Contract.Requires(failingReturn != null);
+ Contract.Requires(failingEnsures != null);
+ Contract.Requires(!failingEnsures.Free);
+ this.FailingReturn = failingReturn;
+ this.FailingEnsures = failingEnsures;
+ this.checksum = checksum;
+ }
+
+ public override int GetLocation() {
+ return FailingReturn.tok.line * 1000 + FailingReturn.tok.col;
+ }
+
+ byte[] checksum;
+
+ /// <summary>
+ /// Returns the checksum of the corresponding assertion.
+ /// </summary>
+ public override byte[] Checksum
+ {
+ get
+ {
+ return checksum;
+ }
+ }
+
+ public override Counterexample Clone()
+ {
+ var ret = new ReturnCounterexample(Trace, FailingReturn, FailingEnsures, Model, MvInfo, Context, checksum);
+ ret.calleeCounterexamples = calleeCounterexamples;
+ return ret;
+ }
+ }
+
+ public class VerifierCallback {
+ // reason == null means this is genuine counterexample returned by the prover
+ // other reason means it's time out/memory out/crash
+ public virtual void OnCounterexample(Counterexample ce, string/*?*/ reason) {
+ Contract.Requires(ce != null);
+ }
+
+ // called in case resource is exceeded and we don't have counterexample
+ public virtual void OnTimeout(string reason) {
+ Contract.Requires(reason != null);
+ }
+
+ public virtual void OnOutOfMemory(string reason) {
+ Contract.Requires(reason != null);
+ }
+
+ public virtual void OnProgress(string phase, int step, int totalSteps, double progressEstimate) {
+ }
+
+ public virtual void OnUnreachableCode(Implementation impl) {
+ Contract.Requires(impl != null);
+ }
+
+ public virtual void OnWarning(string msg) {
+ Contract.Requires(msg != null);
+ switch (CommandLineOptions.Clo.PrintProverWarnings) {
+ case CommandLineOptions.ProverWarnings.None:
+ break;
+ case CommandLineOptions.ProverWarnings.Stdout:
+ Console.WriteLine("Prover warning: " + msg);
+ break;
+ case CommandLineOptions.ProverWarnings.Stderr:
+ Console.Error.WriteLine("Prover warning: " + msg);
+ break;
+ default:
+ Contract.Assume(false);
+ throw new cce.UnreachableException(); // unexpected case
+ }
+ }
+ }
+}
+
+////////////////////////////////////////////
+
+namespace VC {
+ using Bpl = Microsoft.Boogie;
+
+ public class VCGenException : Exception {
+ public VCGenException(string s)
+ : base(s) {
+ }
+ }
+ [ContractClassFor(typeof(ConditionGeneration))]
+ public abstract class ConditionGenerationContracts : ConditionGeneration {
+ public override Outcome VerifyImplementation(Implementation impl, VerifierCallback callback) {
+ Contract.Requires(impl != null);
+ Contract.Requires(callback != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ throw new NotImplementedException();
+ }
+ public ConditionGenerationContracts(Program p, List<Checker> checkers)
+ : base(p, checkers) {
+ }
+ }
+
+ [ContractClass(typeof(ConditionGenerationContracts))]
+ public abstract class ConditionGeneration : IDisposable {
+ protected internal object CheckerCommonState;
+
+ public enum Outcome {
+ Correct,
+ Errors,
+ TimedOut,
+ OutOfMemory,
+ Inconclusive,
+ ReachedBound
+ }
+
+ public static Outcome ProverInterfaceOutcomeToConditionGenerationOutcome(ProverInterface.Outcome outcome) {
+ switch (outcome) {
+ case ProverInterface.Outcome.Invalid:
+ return Outcome.Errors;
+ case ProverInterface.Outcome.OutOfMemory:
+ return Outcome.OutOfMemory;
+ case ProverInterface.Outcome.TimeOut:
+ return Outcome.TimedOut;
+ case ProverInterface.Outcome.Undetermined:
+ return Outcome.Inconclusive;
+ case ProverInterface.Outcome.Valid:
+ return Outcome.Correct;
+ }
+ return Outcome.Inconclusive; // unreachable but the stupid compiler does not understand
+ }
+
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(checkers));
+ Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap));
+ Contract.Invariant(program != null);
+ }
+
+ public int CumulativeAssertionCount; // for statistics
+
+ protected readonly List<Checker>/*!>!*/ checkers;
+
+ private bool _disposed;
+
+ protected Implementation currentImplementation;
+
+ protected List<Variable> CurrentLocalVariables = null;
+
+ // shared across each implementation; created anew for each implementation
+ protected Dictionary<Variable, int> variable2SequenceNumber;
+ public Dictionary<Incarnation, Absy>/*!>!*/ incarnationOriginMap = new Dictionary<Incarnation, Absy>();
+
+ public Program program;
+ protected string/*?*/ logFilePath;
+ protected bool appendLogFile;
+
+ public static List<Model> errorModelList;
+
+ public ConditionGeneration(Program p, List<Checker> checkers) {
+ Contract.Requires(p != null && checkers != null && cce.NonNullElements(checkers));
+ program = p;
+ this.checkers = checkers;
+ Cores = 1;
+ }
+
+ /// <summary>
+ /// Takes an implementation and constructs a verification condition and sends
+ /// it to the theorem prover.
+ /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
+ /// each counterexample consisting of an array of labels.
+ /// </summary>
+ /// <param name="impl"></param>
+ public Outcome VerifyImplementation(Implementation impl, out List<Counterexample>/*?*/ errors, string requestId = null) {
+ Contract.Requires(impl != null);
+
+ Contract.Ensures(Contract.ValueAtReturn(out errors) == null || Contract.ForAll(Contract.ValueAtReturn(out errors), i => i != null));
+ Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || errors != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ Helpers.ExtraTraceInformation("Starting implementation verification");
+
+ CounterexampleCollector collector = new CounterexampleCollector();
+ collector.RequestId = requestId;
+ Outcome outcome = VerifyImplementation(impl, collector);
+ if (outcome == Outcome.Errors || outcome == Outcome.TimedOut || outcome == Outcome.OutOfMemory) {
+ errors = collector.examples;
+ } else {
+ errors = null;
+ }
+
+ Helpers.ExtraTraceInformation("Finished implementation verification");
+ return outcome;
+ }
+
+ /// <summary>
+ /// Takes an implementation and constructs a verification condition and sends
+ /// it to the theorem prover.
+ /// Returns null if "impl" is correct. Otherwise, returns a list of counterexamples,
+ /// each counterexample consisting of an array of labels.
+ /// </summary>
+ /// <param name="impl"></param>
+ public Outcome VerifyImplementation(Implementation impl, out List<Counterexample> errors, out List<Model> errorsModel)
+ {
+ Contract.Ensures(Contract.Result<Outcome>() != Outcome.Errors || Contract.ValueAtReturn(out errors) != null);
+ Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
+ List<Counterexample> errorsOut;
+
+ Outcome outcome;
+ errorModelList = new List<Model>();
+ outcome = VerifyImplementation(impl, out errorsOut);
+ errors = errorsOut;
+ errorsModel = errorModelList;
+
+ return outcome;
+ }
+
+ public abstract Outcome VerifyImplementation(Implementation impl, VerifierCallback callback);
+
+ /////////////////////////////////// Common Methods and Classes //////////////////////////////////////////
+
+ #region Methods for injecting pre- and postconditions
+ private static void
+ ThreadInCodeExpr(Implementation impl,
+ Block targetBlock,
+ CodeExpr codeExpr,
+ bool replaceWithAssert,
+ TokenTextWriter debugWriter) {
+ Contract.Requires(impl != null);
+ Contract.Requires(codeExpr != null);
+ Contract.Requires(targetBlock != null);
+ // Go through codeExpr and for all blocks that have a "return e"
+ // as their transfer command:
+ // Replace all "return e" with "assert/assume e"
+ // Change the transfer command to "goto targetBlock"
+ // Then add all of the blocks in codeExpr to the implementation (at the end)
+ foreach (Block b in codeExpr.Blocks) {
+ Contract.Assert(b != null);
+ ReturnExprCmd rec = b.TransferCmd as ReturnExprCmd;
+ if (rec != null) { // otherwise it is a goto command
+ if (replaceWithAssert) {
+ Ensures ens = new Ensures(rec.tok, false, rec.Expr, null);
+ Contract.Assert(ens != null);
+ Cmd c = new AssertEnsuresCmd(ens);
+ Contract.Assert(c != null);
+ b.Cmds.Add(c);
+ } else {
+ b.Cmds.Add(new AssumeCmd(rec.tok, rec.Expr));
+ }
+ b.TransferCmd = new GotoCmd(Token.NoToken,
+ new List<String> { targetBlock.Label },
+ new List<Block> { targetBlock });
+ targetBlock.Predecessors.Add(b);
+ }
+ impl.Blocks.Add(b);
+ }
+ if (debugWriter != null) {
+ codeExpr.Emit(debugWriter, 1, false);
+ }
+ return;
+ }
+
+ private static void AddAsPrefix(Block b, List<Cmd> cs) {
+ Contract.Requires(b != null);
+ Contract.Requires(cs != null);
+ List<Cmd> newCommands = new List<Cmd>();
+ newCommands.AddRange(cs);
+ newCommands.AddRange(b.Cmds);
+ b.Cmds = newCommands;
+ }
+
+
+ /// <summary>
+ /// Modifies an implementation by prepending it with startCmds and then, as assume
+ /// statements, all preconditions. Insert new blocks as needed, and adjust impl.Blocks[0]
+ /// accordingly to make it the new implementation entry block.
+ /// </summary>
+ /// <param name="impl"></param>
+ /// <param name="startCmds"></param>
+ protected static void InjectPreconditions(Implementation impl, [Captured] List<Cmd> startCmds) {
+ Contract.Requires(impl != null);
+ Contract.Requires(startCmds != null);
+ Contract.Requires(impl.Proc != null);
+
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective precondition:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ string blockLabel = "PreconditionGeneratedEntry";
+
+ Block origStartBlock = impl.Blocks[0];
+ Block insertionPoint = new Block(
+ new Token(-17, -4), blockLabel, startCmds,
+ new GotoCmd(Token.NoToken, new List<String> { origStartBlock.Label }, new List<Block> { origStartBlock }));
+
+ impl.Blocks[0] = insertionPoint; // make insertionPoint the start block
+ impl.Blocks.Add(origStartBlock); // and put the previous start block at the end of the list
+
+ // (free and checked) requires clauses
+ foreach (Requires req in impl.Proc.Requires)
+ // invariant: insertionPoint.TransferCmd is "goto origStartBlock;", but origStartBlock.Predecessors has not yet been updated
+ {
+ Contract.Assert(req != null);
+ Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
+ Cmd c = new AssumeCmd(req.tok, e);
+ c.IrrelevantForChecksumComputation = true;
+ insertionPoint.Cmds.Add(c);
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ origStartBlock.Predecessors.Add(insertionPoint);
+
+ if (impl.ExplicitAssumptionAboutCachedPrecondition != null)
+ {
+ insertionPoint.Cmds.Add(impl.ExplicitAssumptionAboutCachedPrecondition);
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+ }
+ /// <summary>
+ /// Modifies an implementation by inserting all postconditions
+ /// as assert statements at the end of the implementation
+ /// Returns the possibly-new unified exit block of the implementation
+ /// </summary>
+ /// <param name="impl"></param>
+ /// <param name="unifiedExitblock">The unified exit block that has
+ /// already been constructed for the implementation (and so
+ /// is already an element of impl.Blocks)
+ /// </param>
+ protected static void InjectPostConditions(Implementation impl, Block unifiedExitBlock, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
+ Contract.Requires(impl != null);
+ Contract.Requires(unifiedExitBlock != null);
+ Contract.Requires(gotoCmdOrigins != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Requires(unifiedExitBlock.TransferCmd is ReturnCmd);
+
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective postcondition:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+
+ // (free and checked) ensures clauses
+ foreach (Ensures ens in impl.Proc.Ensures) {
+ Contract.Assert(ens != null);
+ if (!ens.Free) { // skip free ensures clauses
+ Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
+ Ensures ensCopy = (Ensures)cce.NonNull(ens.Clone());
+ ensCopy.Condition = e;
+ AssertEnsuresCmd c = new AssertEnsuresCmd(ensCopy);
+ c.ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
+ unifiedExitBlock.Cmds.Add(c);
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+ }
+
+
+ /// <summary>
+ /// Get the pre-condition of an implementation, including the where clauses from the in-parameters.
+ /// </summary>
+ /// <param name="impl"></param>
+ protected static List<Cmd> GetPre(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+
+
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective precondition:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ List<Cmd> pre = new List<Cmd>();
+
+ // (free and checked) requires clauses
+ foreach (Requires req in impl.Proc.Requires) {
+ Contract.Assert(req != null);
+ Expr e = Substituter.Apply(formalProcImplSubst, req.Condition);
+ Contract.Assert(e != null);
+ Cmd c = new AssumeCmd(req.tok, e);
+ Contract.Assert(c != null);
+ pre.Add(c);
+
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+
+ return pre;
+ }
+
+ /// <summary>
+ /// Get the post-condition of an implementation.
+ /// </summary>
+ /// <param name="impl"></param>
+ protected static List<Cmd> GetPost(Implementation impl) {
+
+
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ Console.WriteLine("Effective postcondition:");
+ }
+
+ // Construct an Expr for the post-condition
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ List<Cmd> post = new List<Cmd>();
+ foreach (Ensures ens in impl.Proc.Ensures) {
+ Contract.Assert(ens != null);
+ if (!ens.Free) {
+ Expr e = Substituter.Apply(formalProcImplSubst, ens.Condition);
+ Contract.Assert(e != null);
+ Ensures ensCopy = cce.NonNull((Ensures)ens.Clone());
+ ensCopy.Condition = e;
+ Cmd c = new AssertEnsuresCmd(ensCopy);
+ ((AssertEnsuresCmd)c).ErrorDataEnhanced = ensCopy.ErrorDataEnhanced;
+ post.Add(c);
+
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ c.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 1);
+ }
+ }
+ }
+
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ Console.WriteLine();
+ }
+
+ return post;
+ }
+
+ /// <summary>
+ /// Get the where clauses from the in- and out-parameters as
+ /// a sequence of assume commands.
+ /// As a side effect, this method adds these where clauses to the out parameters.
+ /// </summary>
+ /// <param name="impl"></param>
+ protected static List<Cmd> GetParamWhereClauses(Implementation impl) {
+ Contract.Requires(impl != null);
+ Contract.Requires(impl.Proc != null);
+ Contract.Ensures(Contract.Result<List<Cmd>>() != null);
+ TokenTextWriter debugWriter = null;
+ if (CommandLineOptions.Clo.PrintWithUniqueASTIds) {
+ debugWriter = new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false);
+ debugWriter.WriteLine("Effective precondition from where-clauses:");
+ }
+
+ Substitution formalProcImplSubst = Substituter.SubstitutionFromHashtable(impl.GetImplFormalMap());
+ List<Cmd> whereClauses = new List<Cmd>();
+
+ // where clauses of in-parameters
+ foreach (Formal f in impl.Proc.InParams) {
+ Contract.Assert(f != null);
+ if (f.TypedIdent.WhereExpr != null) {
+ Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
+ Cmd c = new AssumeCmd(f.tok, e);
+ whereClauses.Add(c);
+
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ }
+
+ // where clauses of out-parameters
+ Contract.Assert(impl.OutParams.Count == impl.Proc.OutParams.Count);
+ for (int i = 0; i < impl.OutParams.Count; i++) {
+ Variable f = cce.NonNull(impl.Proc.OutParams[i]);
+ if (f.TypedIdent.WhereExpr != null) {
+ Expr e = Substituter.Apply(formalProcImplSubst, f.TypedIdent.WhereExpr);
+ Cmd c = new AssumeCmd(f.tok, e);
+ whereClauses.Add(c);
+
+ Variable fi = cce.NonNull(impl.OutParams[i]);
+ Contract.Assume(fi.TypedIdent.WhereExpr == null);
+ fi.TypedIdent.WhereExpr = e;
+
+ if (debugWriter != null) {
+ c.Emit(debugWriter, 1);
+ }
+ }
+ }
+
+ if (debugWriter != null) {
+ debugWriter.WriteLine();
+ }
+
+ return whereClauses;
+ }
+
+ protected static void RestoreParamWhereClauses(Implementation impl) {
+ Contract.Requires(impl != null);
+ // We no longer need the where clauses on the out parameters, so we remove them to restore the situation from before VC generation
+ foreach (Formal f in impl.OutParams) {
+ Contract.Assert(f != null);
+ f.TypedIdent.WhereExpr = null;
+ }
+ }
+ #endregion
+
+
+ protected Checker FindCheckerFor(int timeout, bool isBlocking = true, int waitTimeinMs = 50, int maxRetries = 3)
+ {
+ Contract.Requires(0 <= waitTimeinMs && 0 <= maxRetries);
+ Contract.Ensures(!isBlocking || Contract.Result<Checker>() != null);
+
+ lock (checkers)
+ {
+ retry:
+ // Look for existing checker.
+ for (int i = 0; i < checkers.Count; i++)
+ {
+ var c = checkers[i];
+ if (Monitor.TryEnter(c))
+ {
+ try
+ {
+ if (c.WillingToHandle(timeout, program))
+ {
+ c.GetReady();
+ return c;
+ }
+ else if (c.IsIdle || c.IsClosed)
+ {
+ if (c.IsIdle)
+ {
+ c.Retarget(program, c.TheoremProver.Context, timeout);
+ c.GetReady();
+ return c;
+ }
+ else
+ {
+ checkers.RemoveAt(i);
+ i--;
+ continue;
+ }
+ }
+ }
+ finally
+ {
+ Monitor.Exit(c);
+ }
+ }
+ }
+
+ if (Cores <= checkers.Count)
+ {
+ if (isBlocking || 0 < maxRetries)
+ {
+ if (0 < waitTimeinMs)
+ {
+ Monitor.Wait(checkers, waitTimeinMs);
+ }
+ maxRetries--;
+ goto retry;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ // Create a new checker.
+ string log = logFilePath;
+ if (log != null && !log.Contains("@PROC@") && checkers.Count > 0)
+ {
+ log = log + "." + checkers.Count;
+ }
+ Checker ch = new Checker(this, program, log, appendLogFile, timeout);
+ ch.GetReady();
+ checkers.Add(ch);
+ return ch;
+ }
+ }
+
+
+ virtual public void Close() {
+ }
+
+
+ public class CounterexampleCollector : VerifierCallback {
+ [ContractInvariantMethod]
+ void ObjectInvariant() {
+ Contract.Invariant(cce.NonNullElements(examples));
+ }
+
+ public string RequestId;
+
+ public readonly List<Counterexample>/*!>!*/ examples = new List<Counterexample>();
+ public override void OnCounterexample(Counterexample ce, string/*?*/ reason) {
+ //Contract.Requires(ce != null);
+ if (RequestId != null)
+ {
+ ce.RequestId = RequestId;
+ }
+ if (ce.OriginalRequestId == null && 1 < CommandLineOptions.Clo.VerifySnapshots)
+ {
+ ce.OriginalRequestId = RequestId;
+ }
+ examples.Add(ce);
+ }
+
+ public override void OnUnreachableCode(Implementation impl) {
+ //Contract.Requires(impl != null);
+ System.Console.WriteLine("found unreachable code:");
+ EmitImpl(impl, false);
+ // TODO report error about next to last in seq
+ }
+ }
+
+ protected static void EmitImpl(Implementation impl, bool printDesugarings) {
+ Contract.Requires(impl != null);
+ int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
+ CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program
+ bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings;
+ CommandLineOptions.Clo.PrintDesugarings = printDesugarings;
+ impl.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0);
+ CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting;
+ CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
+ }
+
+
+ protected Block GenerateUnifiedExit(Implementation impl, Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins) {
+ Contract.Requires(impl != null);
+ Contract.Requires(gotoCmdOrigins != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+
+ Contract.Ensures(Contract.Result<Block>().TransferCmd is ReturnCmd);
+ Block/*?*/ exitBlock = null;
+ #region Create a unified exit block, if there's more than one
+ {
+ int returnBlocks = 0;
+ foreach (Block b in impl.Blocks) {
+ if (b.TransferCmd is ReturnCmd) {
+ exitBlock = b;
+ returnBlocks++;
+ }
+ }
+ if (returnBlocks > 1) {
+ string unifiedExitLabel = "GeneratedUnifiedExit";
+ Block unifiedExit;
+ unifiedExit = new Block(new Token(-17, -4), unifiedExitLabel, new List<Cmd>(), new ReturnCmd(impl.StructuredStmts != null ? impl.StructuredStmts.EndCurly : Token.NoToken));
+ Contract.Assert(unifiedExit != null);
+ foreach (Block b in impl.Blocks) {
+ if (b.TransferCmd is ReturnCmd) {
+ List<String> labels = new List<String>();
+ labels.Add(unifiedExitLabel);
+ List<Block> bs = new List<Block>();
+ bs.Add(unifiedExit);
+ GotoCmd go = new GotoCmd(Token.NoToken, labels, bs);
+ gotoCmdOrigins[go] = (ReturnCmd)b.TransferCmd;
+ b.TransferCmd = go;
+ unifiedExit.Predecessors.Add(b);
+ }
+ }
+
+ exitBlock = unifiedExit;
+ impl.Blocks.Add(unifiedExit);
+ }
+ Contract.Assert(exitBlock != null);
+ }
+ return exitBlock;
+ #endregion
+ }
+
+ protected static void ResetPredecessors(List<Block> blocks) {
+ Contract.Requires(blocks != null);
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ b.Predecessors = new List<Block>();
+ }
+ foreach (Block b in blocks) {
+ Contract.Assert(b != null);
+ foreach (Block ch in Exits(b)) {
+ Contract.Assert(ch != null);
+ ch.Predecessors.Add(b);
+ }
+ }
+ }
+
+ protected static IEnumerable Exits(Block b) {
+ Contract.Requires(b != null);
+ GotoCmd g = b.TransferCmd as GotoCmd;
+ if (g != null) {
+ return cce.NonNull(g.labelTargets);
+ }
+ return new List<Block>();
+ }
+
+ protected Variable CreateIncarnation(Variable x, Absy a) {
+ Contract.Requires(this.variable2SequenceNumber != null);
+ Contract.Requires(this.CurrentLocalVariables != null);
+ Contract.Requires(a is Block || a is AssignCmd || a is HavocCmd);
+
+ Contract.Requires(x != null);
+ Contract.Ensures(Contract.Result<Variable>() != null);
+
+ int currentIncarnationNumber =
+ variable2SequenceNumber.ContainsKey(x)
+ ?
+ variable2SequenceNumber[x]
+ :
+ -1;
+ Variable v = new Incarnation(x, currentIncarnationNumber + 1);
+ variable2SequenceNumber[x] = currentIncarnationNumber + 1;
+ CurrentLocalVariables.Add(v);
+ incarnationOriginMap.Add((Incarnation)v, a);
+ return v;
+ }
+
+ /// <summary>
+ /// Compute the incarnation map at the beginning of block "b" from the incarnation blocks of the
+ /// predecessors of "b".
+ ///
+ /// The predecessor map b.map for block "b" is defined as follows:
+ /// b.map.Domain == Union{Block p in b.predecessors; p.map.Domain}
+ /// Forall{Variable v in b.map.Domain;
+ /// b.map[v] == (v in Intersection{Block p in b.predecessors; p.map}.Domain
+ /// ? b.predecessors[0].map[v]
+ /// : new Variable())}
+ /// Every variable that b.map maps to a fresh variable requires a fixup in all predecessor blocks.
+ /// </summary>
+ /// <param name="b"></param>
+ /// <param name="block2Incarnation">Gives incarnation maps for b's predecessors.</param>
+ /// <returns></returns>
+ protected Dictionary<Variable, Expr> ComputeIncarnationMap(Block b, Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation) {
+ Contract.Requires(b != null);
+ Contract.Requires(block2Incarnation != null);
+ Contract.Ensures(Contract.Result<Dictionary<Variable, Expr>>() != null);
+
+ if (b.Predecessors.Count == 0) {
+ return new Dictionary<Variable, Expr>();
+ }
+
+ Dictionary<Variable, Expr> incarnationMap = null;
+ Set /*Variable*/ fixUps = new Set /*Variable*/ ();
+ foreach (Block pred in b.Predecessors) {
+ Contract.Assert(pred != null);
+ Contract.Assert(block2Incarnation.ContainsKey(pred)); // otherwise, Passive Transformation found a block whose predecessors have not been processed yet
+ Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)block2Incarnation[pred];
+ Contract.Assert(predMap != null);
+ if (incarnationMap == null) {
+ incarnationMap = new Dictionary<Variable, Expr>(predMap);
+ continue;
+ }
+
+ ArrayList /*Variable*/ conflicts = new ArrayList /*Variable*/ ();
+ foreach (Variable v in incarnationMap.Keys) {
+ Contract.Assert(v != null);
+ if (!predMap.ContainsKey(v)) {
+ // conflict!!
+ conflicts.Add(v);
+ fixUps.Add(v);
+ }
+ }
+ // Now that we're done with enumeration, we'll do all the removes
+ foreach (Variable v in conflicts) {
+ Contract.Assert(v != null);
+ incarnationMap.Remove(v);
+ }
+ foreach (Variable v in predMap.Keys) {
+ Contract.Assert(v != null);
+ if (!incarnationMap.ContainsKey(v)) {
+ // v was not in the domain of the predecessors seen so far, so it needs to be fixed up
+ fixUps.Add(v);
+ } else {
+ // v in incarnationMap ==> all pred blocks (up to now) all agree on its incarnation
+ if (predMap[v] != incarnationMap[v]) {
+ // conflict!!
+ incarnationMap.Remove(v);
+ fixUps.Add(v);
+ }
+ }
+ }
+ }
+
+ #region Second, for all variables in the fixups list, introduce a new incarnation and push it back into the preds.
+ foreach (Variable v in fixUps) {
+ Contract.Assert(v != null);
+ if (!b.IsLive(v))
+ continue;
+ Variable v_prime = CreateIncarnation(v, b);
+ IdentifierExpr ie = new IdentifierExpr(v_prime.tok, v_prime);
+ Contract.Assert(incarnationMap != null);
+ incarnationMap[v] = ie;
+ foreach (Block pred in b.Predecessors) {
+ Contract.Assert(pred != null);
+ #region Create an assume command equating v_prime with its last incarnation in pred
+ #region Create an identifier expression for the last incarnation in pred
+ Dictionary<Variable, Expr> predMap = (Dictionary<Variable, Expr>)cce.NonNull(block2Incarnation[pred]);
+
+ Expr pred_incarnation_exp;
+ Expr o = predMap.ContainsKey(v) ? predMap[v] : null;
+ if (o == null) {
+ Variable predIncarnation = v;
+ IdentifierExpr ie2 = new IdentifierExpr(predIncarnation.tok, predIncarnation);
+ pred_incarnation_exp = ie2;
+ } else {
+ pred_incarnation_exp = o;
+ }
+ #endregion
+ #region Create an identifier expression for the new incarnation
+ IdentifierExpr v_prime_exp = new IdentifierExpr(v_prime.tok, v_prime);
+ #endregion
+ #region Create the assume command itself
+ AssumeCmd ac = new AssumeCmd(v.tok, TypedExprEq(v_prime_exp, pred_incarnation_exp, v_prime.Name.Contains("a##cached##")));
+ pred.Cmds.Add(ac);
+ #endregion
+ #endregion
+ }
+ }
+ #endregion
+
+ Contract.Assert(incarnationMap != null);
+ return incarnationMap;
+ }
+
+ Dictionary<Variable, Expr> preHavocIncarnationMap = null; // null = the previous command was not an HashCmd. Otherwise, a *copy* of the map before the havoc statement
+
+ protected void TurnIntoPassiveBlock(Block b, Dictionary<Variable, Expr> incarnationMap, ModelViewInfo mvInfo, Substitution oldFrameSubst, MutableVariableCollector variableCollector, byte[] currentChecksum = null) {
+ Contract.Requires(b != null);
+ Contract.Requires(incarnationMap != null);
+ Contract.Requires(mvInfo != null);
+ Contract.Requires(oldFrameSubst != null);
+ #region Walk forward over the commands in this block and convert them to passive commands
+
+ List<Cmd> passiveCmds = new List<Cmd>();
+ foreach (Cmd c in b.Cmds) {
+ Contract.Assert(c != null); // walk forward over the commands because the map gets modified in a forward direction
+ ChecksumHelper.ComputeChecksums(c, currentImplementation, variableCollector.UsedVariables, currentChecksum);
+ variableCollector.Visit(c);
+ currentChecksum = c.Checksum;
+ TurnIntoPassiveCmd(c, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, b);
+ }
+ b.Checksum = currentChecksum;
+ b.Cmds = passiveCmds;
+
+ if (b.TransferCmd is ReturnExprCmd) {
+ ReturnExprCmd rec = (ReturnExprCmd)b.TransferCmd.Clone();
+ Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
+ rec.Expr = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, rec.Expr);
+ b.TransferCmd = rec;
+ }
+ #endregion
+ }
+
+ protected Dictionary<Variable, Expr> Convert2PassiveCmd(Implementation impl, ModelViewInfo mvInfo) {
+ Contract.Requires(impl != null);
+ Contract.Requires(mvInfo != null);
+
+ currentImplementation = impl;
+
+ var start = DateTime.UtcNow;
+
+ Dictionary<Variable, Expr> r = ConvertBlocks2PassiveCmd(impl.Blocks, impl.Proc.Modifies, mvInfo);
+
+ var end = DateTime.UtcNow;
+
+ if (CommandLineOptions.Clo.TraceCachingForDebugging)
+ {
+ Console.Out.WriteLine("Turned implementation into passive commands within {0:F0} ms.\n", end.Subtract(start).TotalMilliseconds);
+ }
+
+ if (CommandLineOptions.Clo.TraceCachingForDebugging)
+ {
+ using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
+ {
+ var pd = CommandLineOptions.Clo.PrintDesugarings;
+ var pu = CommandLineOptions.Clo.PrintUnstructured;
+ CommandLineOptions.Clo.PrintDesugarings = true;
+ CommandLineOptions.Clo.PrintUnstructured = 1;
+ impl.Emit(tokTxtWr, 0);
+ CommandLineOptions.Clo.PrintDesugarings = pd;
+ CommandLineOptions.Clo.PrintUnstructured = pu;
+ }
+ }
+
+ currentImplementation = null;
+
+ RestoreParamWhereClauses(impl);
+
+ #region Debug Tracing
+ if (CommandLineOptions.Clo.TraceVerify) {
+ Console.WriteLine("after conversion to passive commands");
+ EmitImpl(impl, true);
+ }
+ #endregion
+
+ return r;
+ }
+
+ protected Dictionary<Variable, Expr> ConvertBlocks2PassiveCmd(List<Block> blocks, List<IdentifierExpr> modifies, ModelViewInfo mvInfo) {
+ Contract.Requires(blocks != null);
+ Contract.Requires(modifies != null);
+ Contract.Requires(mvInfo != null);
+ #region Convert to Passive Commands
+
+ #region Topological sort -- need to process in a linearization of the partial order
+ Graph<Block> dag = new Graph<Block>();
+ dag.AddSource(cce.NonNull(blocks[0])); // there is always at least one node in the graph
+ foreach (Block b in blocks) {
+ GotoCmd gtc = b.TransferCmd as GotoCmd;
+ if (gtc != null) {
+ Contract.Assume(gtc.labelTargets != null);
+ foreach (Block dest in gtc.labelTargets) {
+ Contract.Assert(dest != null);
+ dag.AddEdge(b, dest);
+ }
+ }
+ }
+
+ IEnumerable sortedNodes;
+ if (CommandLineOptions.Clo.ModifyTopologicalSorting) {
+ sortedNodes = dag.TopologicalSort(true);
+ } else {
+ sortedNodes = dag.TopologicalSort();
+ }
+
+ Contract.Assert(sortedNodes != null);
+ #endregion
+
+ Substitution oldFrameSubst = ComputeOldExpressionSubstitution(modifies);
+
+ // Now we can process the nodes in an order so that we're guaranteed to have
+ // processed all of a node's predecessors before we process the node.
+ Dictionary<Block, Dictionary<Variable, Expr>> block2Incarnation = new Dictionary<Block, Dictionary<Variable, Expr>>();
+ Block exitBlock = null;
+ Dictionary<Variable, Expr> exitIncarnationMap = null;
+ var variableCollectors = new Dictionary<Block, MutableVariableCollector>();
+ foreach (Block b in sortedNodes) {
+ Contract.Assert(b != null);
+ Contract.Assert(!block2Incarnation.ContainsKey(b));
+ Dictionary<Variable, Expr> incarnationMap = ComputeIncarnationMap(b, block2Incarnation);
+
+ // b.liveVarsBefore has served its purpose in the just-finished call to ComputeIncarnationMap; null it out.
+ b.liveVarsBefore = null;
+
+ // Decrement the succCount field in each predecessor. Once the field reaches zero in any block,
+ // all its successors have been passified. Consequently, its entry in block2Incarnation can be removed.
+ byte[] currentChecksum = null;
+ var mvc = new MutableVariableCollector();
+ variableCollectors[b] = mvc;
+ foreach (Block p in b.Predecessors) {
+ p.succCount--;
+ if (p.Checksum != null)
+ {
+ // Compute the checksum based on the checksums of the predecessor. The order should not matter.
+ currentChecksum = ChecksumHelper.CombineChecksums(p.Checksum, currentChecksum, true);
+ }
+ mvc.AddUsedVariables(variableCollectors[p].UsedVariables);
+ if (p.succCount == 0)
+ block2Incarnation.Remove(p);
+ }
+
+ #region Each block's map needs to be available to successor blocks
+ GotoCmd gotoCmd = b.TransferCmd as GotoCmd;
+ if (gotoCmd == null) {
+ b.succCount = 0;
+ }
+ else {
+ // incarnationMap needs to be added only if there is some successor of b
+ b.succCount = gotoCmd.labelNames.Count;
+ block2Incarnation.Add(b, incarnationMap);
+ }
+ #endregion Each block's map needs to be available to successor blocks
+
+ TurnIntoPassiveBlock(b, incarnationMap, mvInfo, oldFrameSubst, mvc, currentChecksum);
+ exitBlock = b;
+ exitIncarnationMap = incarnationMap;
+ }
+
+ variableCollectors.Clear();
+
+ // Verify that exitBlock is indeed the unique exit block
+ Contract.Assert(exitBlock != null);
+ Contract.Assert(exitBlock.TransferCmd is ReturnCmd);
+ #endregion Convert to Passive Commands
+
+ return exitIncarnationMap;
+ }
+
+ /// <summary>
+ /// Compute the substitution for old expressions.
+ /// </summary>
+ protected static Substitution ComputeOldExpressionSubstitution(List<IdentifierExpr> modifies)
+ {
+ Dictionary<Variable, Expr> oldFrameMap = new Dictionary<Variable, Expr>();
+ foreach (IdentifierExpr ie in modifies)
+ {
+ Contract.Assert(ie != null);
+ if (!oldFrameMap.ContainsKey(cce.NonNull(ie.Decl)))
+ oldFrameMap.Add(ie.Decl, ie);
+ }
+ return Substituter.SubstitutionFromHashtable(oldFrameMap);
+ }
+
+ public enum CachingAction : byte
+ {
+ DoNothingToAssert,
+ MarkAsPartiallyVerified,
+ MarkAsFullyVerified,
+ RecycleError,
+ AssumeNegationOfAssumptionVariable,
+ DropAssume
+ }
+
+ public long[] CachingActionCounts;
+
+ void TraceCachingAction(Cmd cmd, CachingAction action)
+ {
+ if (CommandLineOptions.Clo.TraceCachingForTesting)
+ {
+ using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false))
+ {
+ var loc = cmd.tok != null && cmd.tok != Token.NoToken ? string.Format("{0}({1},{2})", cmd.tok.filename, cmd.tok.line, cmd.tok.col) : "<unknown location>";
+ Console.Write("Processing command (at {0}) ", loc);
+ cmd.Emit(tokTxtWr, 0);
+ Console.Out.WriteLine(" >>> {0}", action);
+ }
+ }
+
+ if (CommandLineOptions.Clo.TraceCachingForBenchmarking && CachingActionCounts != null)
+ {
+ Interlocked.Increment(ref CachingActionCounts[(int)action]);
+ }
+ }
+
+ /// <summary>
+ /// Turn a command into a passive command, and it remembers the previous step, to see if it is a havoc or not. In the case, it remembers the incarnation map BEFORE the havoc
+ /// Meanwhile, record any information needed to later reconstruct a model view.
+ /// </summary>
+ protected void TurnIntoPassiveCmd(Cmd c, Dictionary<Variable, Expr> incarnationMap, Substitution oldFrameSubst, List<Cmd> passiveCmds, ModelViewInfo mvInfo, Block containingBlock) {
+ Contract.Requires(c != null);
+ Contract.Requires(incarnationMap != null);
+ Contract.Requires(oldFrameSubst != null);
+ Contract.Requires(passiveCmds != null);
+ Contract.Requires(mvInfo != null);
+ Contract.Requires(containingBlock != null);
+
+ Substitution incarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
+ #region assert/assume P |--> assert/assume P[x := in(x)], out := in
+ if (c is PredicateCmd) {
+ Contract.Assert(c is AssertCmd || c is AssumeCmd); // otherwise, unexpected PredicateCmd type
+
+ PredicateCmd pc = (PredicateCmd)c.Clone();
+ Contract.Assert(pc != null);
+
+ QKeyValue current = pc.Attributes;
+ while (current != null)
+ {
+ if (current.Key == "minimize" || current.Key == "maximize") {
+ Contract.Assume(current.Params.Count == 1);
+ var param = current.Params[0] as Expr;
+ Contract.Assume(param != null && (param.Type.IsInt || param.Type.IsReal || param.Type.IsBv));
+ current.ClearParams();
+ current.AddParam(Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, param));
+ }
+ if (current.Key == "verified_under") {
+ Contract.Assume(current.Params.Count == 1);
+ var param = current.Params[0] as Expr;
+ Contract.Assume(param != null && param.Type.IsBool);
+ current.ClearParams();
+ current.AddParam(Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, param));
+ }
+ current = current.Next;
+ }
+
+ Expr copy = Substituter.ApplyReplacingOldExprs(incarnationSubst, oldFrameSubst, pc.Expr);
+ if (CommandLineOptions.Clo.ModelViewFile != null && pc is AssumeCmd) {
+ string description = QKeyValue.FindStringAttribute(pc.Attributes, "captureState");
+ if (description != null) {
+ Expr mv = new NAryExpr(pc.tok, new FunctionCall(ModelViewInfo.MVState_FunctionDef), new List<Expr> { Bpl.Expr.Ident(ModelViewInfo.MVState_ConstantDef), Bpl.Expr.Literal(mvInfo.CapturePoints.Count) });
+ copy = Bpl.Expr.And(mv, copy);
+ mvInfo.CapturePoints.Add(new ModelViewInfo.Mapping(description, new Dictionary<Variable, Expr>(incarnationMap)));
+ }
+ }
+ Contract.Assert(copy != null);
+ var dropCmd = false;
+ var relevantAssumpVars = currentImplementation != null ? currentImplementation.RelevantInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
+ var relevantDoomedAssumpVars = currentImplementation != null ? currentImplementation.RelevantDoomedInjectedAssumptionVariables(incarnationMap) : new List<LocalVariable>();
+ var checksum = pc.Checksum;
+ if (pc is AssertCmd) {
+ var ac = (AssertCmd)pc;
+ ac.OrigExpr = ac.Expr;
+ Contract.Assert(ac.IncarnationMap == null);
+ ac.IncarnationMap = (Dictionary<Variable, Expr>)cce.NonNull(new Dictionary<Variable, Expr>(incarnationMap));
+
+ var subsumption = Wlp.Subsumption(ac);
+ if (relevantDoomedAssumpVars.Any())
+ {
+ TraceCachingAction(pc, CachingAction.DoNothingToAssert);
+ }
+ else if (currentImplementation != null
+ && currentImplementation.HasCachedSnapshot
+ && checksum != null
+ && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
+ && !currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
+ {
+ if (!currentImplementation.AnyErrorsInCachedSnapshot
+ && currentImplementation.InjectedAssumptionVariables.Count == 1
+ && relevantAssumpVars.Count == 1)
+ {
+ TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
+ }
+ else
+ {
+ bool isTrue;
+ var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
+ TraceCachingAction(pc, !isTrue ? CachingAction.MarkAsPartiallyVerified : CachingAction.MarkAsFullyVerified);
+ var litExpr = ac.Expr as LiteralExpr;
+ if (litExpr == null || !litExpr.IsTrue)
+ {
+ ac.MarkAsVerifiedUnder(assmVars);
+ }
+ else
+ {
+ dropCmd = true;
+ }
+ }
+ }
+ else if (currentImplementation != null
+ && currentImplementation.HasCachedSnapshot
+ && relevantAssumpVars.Count == 0
+ && checksum != null
+ && currentImplementation.IsAssertionChecksumInCachedSnapshot(checksum)
+ && currentImplementation.IsErrorChecksumInCachedSnapshot(checksum))
+ {
+ TraceCachingAction(pc, CachingAction.RecycleError);
+ ac.MarkAsVerifiedUnder(Expr.True);
+ currentImplementation.AddRecycledFailingAssertion(ac);
+ pc.Attributes = new QKeyValue(Token.NoToken, "recycled_failing_assertion", new List<object>(), pc.Attributes);
+ }
+ else
+ {
+ TraceCachingAction(pc, CachingAction.DoNothingToAssert);
+ }
+ }
+ else if (pc is AssumeCmd
+ && QKeyValue.FindBoolAttribute(pc.Attributes, "precondition_previous_snapshot")
+ && pc.SugaredCmdChecksum != null)
+ {
+ if (!relevantDoomedAssumpVars.Any()
+ && currentImplementation.HasCachedSnapshot
+ && currentImplementation.IsAssertionChecksumInCachedSnapshot(pc.SugaredCmdChecksum)
+ && !currentImplementation.IsErrorChecksumInCachedSnapshot(pc.SugaredCmdChecksum))
+ {
+ bool isTrue;
+ var assmVars = currentImplementation.ConjunctionOfInjectedAssumptionVariables(incarnationMap, out isTrue);
+ if (!isTrue)
+ {
+ copy = LiteralExpr.Imp(assmVars, copy);
+ TraceCachingAction(pc, CachingAction.MarkAsPartiallyVerified);
+ }
+ else
+ {
+ TraceCachingAction(pc, CachingAction.MarkAsFullyVerified);
+ }
+ }
+ else
+ {
+ TraceCachingAction(pc, CachingAction.DropAssume);
+ dropCmd = true;
+ }
+ }
+ else if (pc is AssumeCmd && QKeyValue.FindBoolAttribute(pc.Attributes, "assumption_variable_initialization"))
+ {
+ var identExpr = pc.Expr as IdentifierExpr;
+ if (identExpr != null && identExpr.Decl != null && !incarnationMap.ContainsKey(identExpr.Decl))
+ {
+ incarnationMap[identExpr.Decl] = LiteralExpr.True;
+ dropCmd = true;
+ }
+ }
+ pc.Expr = copy;
+ if (!dropCmd)
+ {
+ passiveCmds.Add(pc);
+ }
+ }
+ #endregion
+ #region x1 := E1, x2 := E2, ... |--> assume x1' = E1[in] & x2' = E2[in], out := in( x |-> x' ) [except as noted below]
+ else if (c is AssignCmd) {
+ AssignCmd assign = ((AssignCmd)c).AsSimpleAssignCmd; // first remove map assignments
+ Contract.Assert(assign != null);
+ #region Substitute all variables in E with the current map
+ List<Expr> copies = new List<Expr>();
+ foreach (Expr e in assign.Rhss) {
+ Contract.Assert(e != null);
+ copies.Add(Substituter.ApplyReplacingOldExprs(incarnationSubst,
+ oldFrameSubst,
+ e));
+ }
+ #endregion
+
+ List<Expr/*!>!*/> assumptions = new List<Expr>();
+ // it might be too slow to create a new dictionary each time ...
+ IDictionary<Variable, Expr> newIncarnationMappings =
+ new Dictionary<Variable, Expr>();
+
+ for (int i = 0; i < assign.Lhss.Count; ++i) {
+ IdentifierExpr lhsIdExpr =
+ cce.NonNull((SimpleAssignLhs)assign.Lhss[i]).AssignedVariable;
+ Variable lhs = cce.NonNull(lhsIdExpr.Decl);
+ Contract.Assert(lhs != null);
+ Expr rhs = assign.Rhss[i];
+ Contract.Assert(rhs != null);
+
+ // don't create incarnations for assignments of literals or single variables.
+ if (rhs is LiteralExpr) {
+ incarnationMap[lhs] = rhs;
+ } else if (rhs is IdentifierExpr) {
+ IdentifierExpr ie = (IdentifierExpr)rhs;
+ if (incarnationMap.ContainsKey(cce.NonNull(ie.Decl)))
+ newIncarnationMappings[lhs] = cce.NonNull((Expr)incarnationMap[ie.Decl]);
+ else
+ newIncarnationMappings[lhs] = ie;
+ } else {
+ IdentifierExpr x_prime_exp = null;
+ #region Make a new incarnation, x', for variable x, but only if x is *not* already an incarnation
+ if (lhs is Incarnation) {
+ // incarnations are already written only once, no need to make an incarnation of an incarnation
+ x_prime_exp = lhsIdExpr;
+ } else {
+ Variable v = CreateIncarnation(lhs, c);
+ x_prime_exp = new IdentifierExpr(lhsIdExpr.tok, v);
+ newIncarnationMappings[lhs] = x_prime_exp;
+ }
+ #endregion
+
+ var nAryExpr = copies[i] as NAryExpr;
+ if (nAryExpr != null)
+ {
+ var binOp = nAryExpr.Fun as BinaryOperator;
+ if (binOp != null
+ && binOp.Op == BinaryOperator.Opcode.And)
+ {
+ var arg0 = nAryExpr.Args[0] as LiteralExpr;
+ var arg1 = nAryExpr.Args[1] as LiteralExpr;
+ if ((arg0 != null && arg0.IsTrue) || (arg1 != null && arg1.IsFalse))
+ {
+ // Replace the expressions "true && arg1" or "arg0 && false" by "arg1".
+ copies[i] = nAryExpr.Args[1];
+ }
+ }
+ }
+
+ #region Create an assume command with the new variable
+ assumptions.Add(TypedExprEq(x_prime_exp, copies[i], x_prime_exp.Decl != null && x_prime_exp.Decl.Name.Contains("a##cached##")));
+ #endregion
+ }
+ }
+
+ foreach (KeyValuePair<Variable, Expr> pair in newIncarnationMappings) {
+ Contract.Assert(pair.Key != null && pair.Value != null);
+ incarnationMap[pair.Key] = pair.Value;
+ }
+
+ if (assumptions.Count > 0) {
+ Expr assumption = assumptions[0];
+
+ for (int i = 1; i < assumptions.Count; ++i) {
+ Contract.Assert(assumption != null);
+ assumption = Expr.And(assumption, assumptions[i]);
+ }
+ passiveCmds.Add(new AssumeCmd(c.tok, assumption));
+ }
+
+ if (currentImplementation != null
+ && currentImplementation.HasCachedSnapshot
+ && !currentImplementation.AnyErrorsInCachedSnapshot
+ && currentImplementation.DoomedInjectedAssumptionVariables.Count == 0
+ && currentImplementation.InjectedAssumptionVariables.Count == 1
+ && assign.Lhss.Count == 1)
+ {
+ var identExpr = assign.Lhss[0].AsExpr as IdentifierExpr;
+ Expr incarnation;
+ if (identExpr != null && identExpr.Decl != null && QKeyValue.FindBoolAttribute(identExpr.Decl.Attributes, "assumption") && incarnationMap.TryGetValue(identExpr.Decl, out incarnation))
+ {
+ TraceCachingAction(assign, CachingAction.AssumeNegationOfAssumptionVariable);
+ passiveCmds.Add(new AssumeCmd(c.tok, Expr.Not(incarnation)));
+ }
+ }
+ }
+ #endregion
+ #region havoc w |--> assume whereClauses, out := in( w |-> w' )
+ else if (c is HavocCmd) {
+ if (this.preHavocIncarnationMap == null) // Save a copy of the incarnation map (at the top of a sequence of havoc statements)
+ this.preHavocIncarnationMap = new Dictionary<Variable, Expr>(incarnationMap);
+
+ HavocCmd hc = (HavocCmd)c;
+ Contract.Assert(c != null);
+ // If an assumption variable for postconditions is included here, it must have been assigned within a loop.
+ // We do not need to havoc it if we have performed a modular proof of the loop (i.e., using only the loop
+ // invariant) in the previous snapshot and, consequently, the corresponding assumption did not affect the
+ // anything after the loop. We can achieve this by simply not updating/adding it in the incarnation map.
+ List<IdentifierExpr> havocVars = hc.Vars.Where(v => !(QKeyValue.FindBoolAttribute(v.Decl.Attributes, "assumption") && v.Decl.Name.StartsWith("a##cached##"))).ToList();
+ // First, compute the new incarnations
+ foreach (IdentifierExpr ie in havocVars) {
+ Contract.Assert(ie != null);
+ if (!(ie.Decl is Incarnation)) {
+ Variable x = cce.NonNull(ie.Decl);
+ Variable x_prime = CreateIncarnation(x, c);
+ incarnationMap[x] = new IdentifierExpr(x_prime.tok, x_prime);
+ }
+ }
+ // Then, perform the assume of the where clauses, using the updated incarnations
+ Substitution updatedIncarnationSubst = Substituter.SubstitutionFromHashtable(incarnationMap);
+ foreach (IdentifierExpr ie in havocVars) {
+ Contract.Assert(ie != null);
+ if (!(ie.Decl is Incarnation)) {
+ Variable x = cce.NonNull(ie.Decl);
+ Bpl.Expr w = x.TypedIdent.WhereExpr;
+ if (w != null) {
+ Expr copy = Substituter.ApplyReplacingOldExprs(updatedIncarnationSubst, oldFrameSubst, w);
+ passiveCmds.Add(new AssumeCmd(c.tok, copy));
+ }
+ }
+ }
+
+ // Add the following assume-statement for each assumption variable 'v', where 'v_post' is the new incarnation and 'v_pre' is the old one:
+ // assume v_post ==> v_pre;
+ foreach (IdentifierExpr ie in havocVars)
+ {
+ if (QKeyValue.FindBoolAttribute(ie.Decl.Attributes, "assumption"))
+ {
+ var preInc = (Expr)(preHavocIncarnationMap[ie.Decl].Clone());
+ var postInc = (Expr)(incarnationMap[ie.Decl].Clone());
+ passiveCmds.Add(new AssumeCmd(c.tok, Expr.Imp(postInc, preInc)));
+ }
+ }
+ }
+ #endregion
+ else if (c is CommentCmd) {
+ // comments are just for debugging and don't affect verification
+ } else if (c is SugaredCmd) {
+ SugaredCmd sug = (SugaredCmd)c;
+ Contract.Assert(sug != null);
+ Cmd cmd = sug.Desugaring;
+ Contract.Assert(cmd != null);
+ TurnIntoPassiveCmd(cmd, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
+ } else if (c is StateCmd) {
+ this.preHavocIncarnationMap = null; // we do not need to remeber the previous incarnations
+ StateCmd st = (StateCmd)c;
+ Contract.Assert(st != null);
+ // account for any where clauses among the local variables
+ foreach (Variable v in st.Locals) {
+ Contract.Assert(v != null);
+ Expr w = v.TypedIdent.WhereExpr;
+ if (w != null) {
+ passiveCmds.Add(new AssumeCmd(v.tok, w));
+ }
+ }
+ // do the sub-commands
+ foreach (Cmd s in st.Cmds) {
+ Contract.Assert(s != null);
+ TurnIntoPassiveCmd(s, incarnationMap, oldFrameSubst, passiveCmds, mvInfo, containingBlock);
+ }
+ // remove the local variables from the incarnation map
+ foreach (Variable v in st.Locals) {
+ Contract.Assert(v != null);
+ incarnationMap.Remove(v);
+ }
+ }
+ #region There shouldn't be any other types of commands at this point
+ else {
+ Debug.Fail("Internal Error: Passive transformation handed a command that is not one of assert,assume,havoc,assign.");
+ }
+ #endregion
+
+
+ #region We remember if we have put an havoc statement into a passive form
+
+ if (!(c is HavocCmd))
+ this.preHavocIncarnationMap = null;
+ // else: it has already been set by the case for the HavocCmd
+ #endregion
+ }
+
+ NAryExpr TypedExprEq(Expr e0, Expr e1, bool doNotResolveOverloading = false) {
+ Contract.Requires(e0 != null);
+ Contract.Requires(e1 != null);
+ NAryExpr e = Expr.Eq(e0, e1);
+ var fun = e.Fun as IOverloadedAppliable;
+ if (fun != null)
+ {
+ fun.DoNotResolveOverloading = doNotResolveOverloading;
+ }
+ e.Type = Bpl.Type.Bool;
+ e.TypeParameters = SimpleTypeParamInstantiation.EMPTY;
+ return e;
+ }
+
+ /// <summary>
+ /// Creates a new block to add to impl.Blocks, where impl is the implementation that contains
+ /// succ. Caller must do the add to impl.Blocks.
+ /// </summary>
+ protected Block CreateBlockBetween(int predIndex, Block succ) {
+ Contract.Requires(0 <= predIndex && predIndex < succ.Predecessors.Count);
+
+
+ Contract.Requires(succ != null);
+ Contract.Ensures(Contract.Result<Block>() != null);
+
+ Block pred = cce.NonNull(succ.Predecessors[predIndex]);
+
+ string newBlockLabel = pred.Label + "_@2_" + succ.Label;
+
+ // successor of newBlock list
+ List<String> ls = new List<String>();
+ ls.Add(succ.Label);
+ List<Block> bs = new List<Block>();
+ bs.Add(succ);
+
+ Block newBlock = new Block(
+ new Token(-17, -4),
+ newBlockLabel,
+ new List<Cmd>(),
+ new GotoCmd(Token.NoToken, ls, bs)
+ );
+
+ // predecessors of newBlock
+ List<Block> ps = new List<Block>();
+ ps.Add(pred);
+ newBlock.Predecessors = ps;
+
+ // fix successors of pred
+ #region Change the edge "pred->succ" to "pred->newBlock"
+ GotoCmd gtc = (GotoCmd)cce.NonNull(pred.TransferCmd);
+ Contract.Assume(gtc.labelTargets != null);
+ Contract.Assume(gtc.labelNames != null);
+ for (int i = 0, n = gtc.labelTargets.Count; i < n; i++) {
+ if (gtc.labelTargets[i] == succ) {
+ gtc.labelTargets[i] = newBlock;
+ gtc.labelNames[i] = newBlockLabel;
+ break;
+ }
+ }
+ #endregion Change the edge "pred->succ" to "pred->newBlock"
+
+ // fix predecessors of succ
+ succ.Predecessors[predIndex] = newBlock;
+
+ return newBlock;
+ }
+
+ protected void AddBlocksBetween(List<Block> blocks) {
+ Contract.Requires(blocks != null);
+ #region Introduce empty blocks between join points and their multi-successor predecessors
+ List<Block> tweens = new List<Block>();
+ foreach (Block b in blocks) {
+ int nPreds = b.Predecessors.Count;
+ if (nPreds > 1) {
+ // b is a join point (i.e., it has more than one predecessor)
+ for (int i = 0; i < nPreds; i++) {
+ GotoCmd gotocmd = (GotoCmd)(cce.NonNull(b.Predecessors[i]).TransferCmd);
+ if (gotocmd.labelNames != null && gotocmd.labelNames.Count > 1) {
+ tweens.Add(CreateBlockBetween(i, b));
+ }
+ }
+ }
+ }
+ blocks.AddRange(tweens); // must wait until iteration is done before changing the list
+ #endregion
+ }
+
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ Close();
+ }
+ _disposed = true;
+ }
+ }
+
+ public int Cores { get; set; }
+ }
+
+ public class ModelViewInfo
+ {
+ public readonly List<Variable> AllVariables = new List<Variable>();
+ public readonly List<Mapping> CapturePoints = new List<Mapping>();
+ public static readonly Function MVState_FunctionDef = new Function(Token.NoToken, "$mv_state",
+ new List<Variable> { new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true),
+ new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Int), true) },
+ new Formal(Token.NoToken, new TypedIdent(Token.NoToken, TypedIdent.NoName, Bpl.Type.Bool), false));
+ public static readonly Constant MVState_ConstantDef = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "$mv_state_const", Bpl.Type.Int));
+
+ public ModelViewInfo(Program program, Implementation impl) {
+ Contract.Requires(program != null);
+ Contract.Requires(impl != null);
+
+ // global variables
+ lock (program.TopLevelDeclarations)
+ {
+ foreach (var v in program.Variables)
+ {
+ if (!(v is Constant))
+ {
+ AllVariables.Add(v);
+ }
+ }
+ }
+ // implementation parameters
+ foreach (Variable p in impl.InParams) {
+ AllVariables.Add(p);
+ }
+ foreach (Variable p in impl.OutParams) {
+ AllVariables.Add(p);
+ }
+ // implementation locals
+ foreach (Variable v in impl.LocVars) {
+ AllVariables.Add(v);
+ }
+ }
+
+ public ModelViewInfo(CodeExpr codeExpr) {
+ Contract.Requires(codeExpr != null);
+ // TODO: also need all variables of enclosing scopes (the global variables of the program, the parameters
+ // and perhaps locals of the implementation (if any), any enclosing code expressions).
+
+ foreach (Variable v in codeExpr.LocVars) {
+ AllVariables.Add(v);
+ }
+ }
+
+ public class Mapping
+ {
+ public readonly string Description;
+ public readonly Dictionary<Variable, Expr> IncarnationMap;
+ public Mapping(string description, Dictionary<Variable, Expr> incarnationMap) {
+ Description = description;
+ IncarnationMap = incarnationMap;
+ }
+ }
+ }
+}