diff options
author | Rustan Leino <leino@microsoft.com> | 2015-08-28 13:40:37 -0700 |
---|---|---|
committer | Rustan Leino <leino@microsoft.com> | 2015-08-28 13:40:37 -0700 |
commit | 35332e25e899424ee1714eea8d451c79563154aa (patch) | |
tree | 55cebc386a00a906c4feb130e6236f5dca6f98e8 /Source/VCGeneration | |
parent | 21f1cfff139759d9b9f91ed800da2158daca8ed4 (diff) | |
parent | 713e870a0dd2241869685e95bf31702a4f74cfff (diff) |
Merge branch 'master' of https://github.com/boogie-org/boogie
Conflicts:
Source/Core/CommandLineOptions.cs
Source/ExecutionEngine/ExecutionEngine.cs
Source/ExecutionEngine/VerificationResultCache.cs
Source/VCGeneration/VC.cs
Test/snapshots/runtest.snapshot
Test/snapshots/runtest.snapshot.expect
Diffstat (limited to 'Source/VCGeneration')
-rw-r--r-- | Source/VCGeneration/Check.cs | 1377 | ||||
-rw-r--r-- | Source/VCGeneration/ConditionGeneration.cs | 4018 | ||||
-rw-r--r-- | Source/VCGeneration/Context.cs | 512 | ||||
-rw-r--r-- | Source/VCGeneration/ExprExtensions.cs | 706 | ||||
-rw-r--r-- | Source/VCGeneration/FixedpointVC.cs | 4480 | ||||
-rw-r--r-- | Source/VCGeneration/OrderingAxioms.cs | 676 | ||||
-rw-r--r-- | Source/VCGeneration/RPFP.cs | 1218 | ||||
-rw-r--r-- | Source/VCGeneration/StratifiedVC.cs | 5809 | ||||
-rw-r--r-- | Source/VCGeneration/VC.cs | 7870 | ||||
-rw-r--r-- | Source/VCGeneration/VCGeneration.csproj | 446 | ||||
-rw-r--r-- | Source/VCGeneration/Wlp.cs | 510 | ||||
-rw-r--r-- | Source/VCGeneration/cce.cs | 210 |
12 files changed, 13923 insertions, 13909 deletions
diff --git a/Source/VCGeneration/Check.cs b/Source/VCGeneration/Check.cs index 33baf798..3c3b5cae 100644 --- a/Source/VCGeneration/Check.cs +++ b/Source/VCGeneration/Check.cs @@ -1,688 +1,689 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Linq;
-using System.Collections;
-using System.Collections.Generic;
-using System.Threading;
-using System.IO;
-using System.Text.RegularExpressions;
-using System.Diagnostics;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.AbstractInterpretation;
-using Microsoft.Boogie.VCExprAST;
-using Microsoft.Basetypes;
-using System.Threading.Tasks;
-
-namespace Microsoft.Boogie {
-
- enum CheckerStatus
- {
- Idle,
- Ready,
- Busy,
- Closed
- }
-
- /// <summary>
- /// Interface to the theorem prover specialized to Boogie.
- ///
- /// This class creates the appropriate background axioms. There
- /// should be one instance per BoogiePL program.
- /// </summary>
- public sealed class Checker {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(gen != null);
- Contract.Invariant(thmProver != null);
- }
-
- private readonly VCExpressionGenerator gen;
-
- private ProverInterface thmProver;
- private int timeout;
-
- // state for the async interface
- private volatile ProverInterface.Outcome outcome;
- private volatile bool hasOutput;
- private volatile UnexpectedProverOutputException outputExn;
- private DateTime proverStart;
- private TimeSpan proverRunTime;
- private volatile ProverInterface.ErrorHandler handler;
- private volatile CheckerStatus status;
- public volatile Program Program;
-
- public void GetReady()
- {
- Contract.Requires(IsIdle);
-
- status = CheckerStatus.Ready;
- }
-
- public void GoBackToIdle()
- {
- Contract.Requires(IsBusy);
-
- status = CheckerStatus.Idle;
- }
-
- public Task ProverTask { get; set; }
-
- public bool WillingToHandle(int timeout, Program prog) {
- return status == CheckerStatus.Idle && timeout == this.timeout && (prog == null || Program == prog);
- }
-
- public VCExpressionGenerator VCExprGen {
- get {
- Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
- return this.gen;
- }
- }
- public ProverInterface TheoremProver {
- get {
- Contract.Ensures(Contract.Result<ProverInterface>() != null);
- return this.thmProver;
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////////
- // We share context information for the same program between different Checkers
-
- private struct ContextCacheKey {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(program != null);
- }
-
- public readonly Program program;
-
- public ContextCacheKey(Program prog) {
- Contract.Requires(prog != null);
- this.program = prog;
- }
-
- [Pure]
- [Reads(ReadsAttribute.Reads.Nothing)]
- public override bool Equals(object that) {
- if (that is ContextCacheKey) {
- ContextCacheKey thatKey = (ContextCacheKey)that;
- return this.program.Equals(thatKey.program);
- }
- return false;
- }
-
- [Pure]
- public override int GetHashCode() {
- return this.program.GetHashCode();
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////////
-
- /// <summary>
- /// Constructor. Initialize a checker with the program and log file.
- /// Optionally, use prover context provided by parameter "ctx".
- /// </summary>
- public Checker(VC.ConditionGeneration vcgen, Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, ProverContext ctx = null) {
- Contract.Requires(vcgen != null);
- Contract.Requires(prog != null);
- this.timeout = timeout;
- this.Program = prog;
-
- ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions();
-
- if (logFilePath != null) {
- options.LogFilename = logFilePath;
- if (appendLogFile)
- options.AppendLogFile = appendLogFile;
- }
-
- if (timeout > 0) {
- options.TimeLimit = timeout * 1000;
- }
-
- options.Parse(CommandLineOptions.Clo.ProverOptions);
-
- ContextCacheKey key = new ContextCacheKey(prog);
- ProverInterface prover;
-
- if (vcgen.CheckerCommonState == null) {
- vcgen.CheckerCommonState = new Dictionary<ContextCacheKey, ProverContext>();
- }
- IDictionary<ContextCacheKey, ProverContext>/*!>!*/ cachedContexts = (IDictionary<ContextCacheKey, ProverContext/*!*/>)vcgen.CheckerCommonState;
-
- if (ctx == null && cachedContexts.TryGetValue(key, out ctx))
- {
- ctx = (ProverContext)cce.NonNull(ctx).Clone();
- prover = (ProverInterface)
- CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
- } else {
- if (ctx == null) ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options);
-
- Setup(prog, ctx);
-
- // we first generate the prover and then store a clone of the
- // context in the cache, so that the prover can setup stuff in
- // the context to be cached
- prover = (ProverInterface)
- CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
- cachedContexts.Add(key, cce.NonNull((ProverContext)ctx.Clone()));
- }
-
- this.thmProver = prover;
- this.gen = prover.VCExprGen;
- }
-
- public void Retarget(Program prog, ProverContext ctx, int timeout = 0)
- {
- lock (this)
- {
- hasOutput = default(bool);
- outcome = default(ProverInterface.Outcome);
- outputExn = default(UnexpectedProverOutputException);
- handler = default(ProverInterface.ErrorHandler);
- TheoremProver.FullReset(gen);
- ctx.Reset();
- Setup(prog, ctx);
- this.timeout = timeout;
- SetTimeout();
- }
- }
-
- public void RetargetWithoutReset(Program prog, ProverContext ctx)
- {
- ctx.Clear();
- Setup(prog, ctx);
- }
-
-
- public void SetTimeout()
- {
- if (0 < timeout)
- {
- TheoremProver.SetTimeOut(timeout * 1000);
- }
- else
- {
- TheoremProver.SetTimeOut(0);
- }
- }
-
- /// <summary>
- /// Set up the context.
- /// </summary>
- private void Setup(Program prog, ProverContext ctx)
- {
- Program = prog;
- // TODO(wuestholz): Is this lock necessary?
- lock (Program.TopLevelDeclarations)
- {
- foreach (Declaration decl in Program.TopLevelDeclarations)
- {
- Contract.Assert(decl != null);
- var typeDecl = decl as TypeCtorDecl;
- var constDecl = decl as Constant;
- var funDecl = decl as Function;
- var axiomDecl = decl as Axiom;
- var glVarDecl = decl as GlobalVariable;
- if (typeDecl != null)
- {
- ctx.DeclareType(typeDecl, null);
- }
- else if (constDecl != null)
- {
- ctx.DeclareConstant(constDecl, constDecl.Unique, null);
- }
- else if (funDecl != null)
- {
- ctx.DeclareFunction(funDecl, null);
- }
- else if (axiomDecl != null)
- {
- ctx.AddAxiom(axiomDecl, null);
- }
- else if (glVarDecl != null)
- {
- ctx.DeclareGlobalVariable(glVarDecl, null);
- }
- }
- }
- }
-
- /// <summary>
- /// Clean-up.
- /// </summary>
- public void Close() {
- thmProver.Close();
- status = CheckerStatus.Closed;
- }
-
- /// <summary>
- /// Push a Verification Condition as an Axiom
- /// (Required for Doomed Program Point detection)
- /// </summary>
- public void PushVCExpr(VCExpr vc) {
- Contract.Requires(vc != null);
- //thmProver.Context.AddAxiom(vc);
- thmProver.PushVCExpression(vc);
- }
-
- public bool IsBusy {
- get {
- return status == CheckerStatus.Busy;
- }
- }
-
- public bool IsReady
- {
- get
- {
- return status == CheckerStatus.Ready;
- }
- }
-
- public bool IsClosed {
- get {
- return status == CheckerStatus.Closed;
- }
- }
-
- public bool IsIdle
- {
- get
- {
- return status == CheckerStatus.Idle;
- }
- }
-
- public bool HasOutput {
- get {
- return hasOutput;
- }
- }
-
- public TimeSpan ProverRunTime {
- get {
- return proverRunTime;
- }
- }
-
- private void WaitForOutput(object dummy) {
- lock (this)
- {
- try
- {
- outcome = thmProver.CheckOutcome(cce.NonNull(handler));
- }
- catch (UnexpectedProverOutputException e)
- {
- outputExn = e;
- }
-
- switch (outcome)
- {
- case ProverInterface.Outcome.Valid:
- thmProver.LogComment("Valid");
- break;
- case ProverInterface.Outcome.Invalid:
- thmProver.LogComment("Invalid");
- break;
- case ProverInterface.Outcome.TimeOut:
- thmProver.LogComment("Timed out");
- break;
- case ProverInterface.Outcome.OutOfMemory:
- thmProver.LogComment("Out of memory");
- break;
- case ProverInterface.Outcome.Undetermined:
- thmProver.LogComment("Undetermined");
- break;
- }
-
- hasOutput = true;
- proverRunTime = DateTime.UtcNow - proverStart;
- }
- }
-
- public void BeginCheck(string descriptiveName, VCExpr vc, ProverInterface.ErrorHandler handler) {
- Contract.Requires(descriptiveName != null);
- Contract.Requires(vc != null);
- Contract.Requires(handler != null);
- Contract.Requires(IsReady);
-
- status = CheckerStatus.Busy;
- hasOutput = false;
- outputExn = null;
- this.handler = handler;
-
- thmProver.Reset(gen);
- SetTimeout();
- proverStart = DateTime.UtcNow;
- thmProver.BeginCheck(descriptiveName, vc, handler);
- // gen.ClearSharedFormulas(); PR: don't know yet what to do with this guy
-
- ProverTask = Task.Factory.StartNew(() => { WaitForOutput(null); }, TaskCreationOptions.LongRunning);
- }
-
- public ProverInterface.Outcome ReadOutcome() {
- Contract.Requires(IsBusy);
- Contract.Requires(HasOutput);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- hasOutput = false;
-
- if (outputExn != null) {
- throw outputExn;
- }
-
- return outcome;
- }
- }
-
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
-
- public abstract class ProverInterface {
- public static ProverInterface CreateProver(Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, int taskID = -1) {
- Contract.Requires(prog != null);
-
- ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions();
-
- if (logFilePath != null) {
- options.LogFilename = logFilePath;
- if (appendLogFile)
- options.AppendLogFile = appendLogFile;
- }
-
- if (timeout > 0) {
- options.TimeLimit = timeout * 1000;
- }
-
- if (taskID >= 0) {
- options.Parse(CommandLineOptions.Clo.Cho[taskID].ProverOptions);
- } else {
- options.Parse(CommandLineOptions.Clo.ProverOptions);
- }
-
- ProverContext ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options);
-
- // set up the context
- foreach (Declaration decl in prog.TopLevelDeclarations) {
- Contract.Assert(decl != null);
- TypeCtorDecl t = decl as TypeCtorDecl;
- if (t != null) {
- ctx.DeclareType(t, null);
- }
- }
- foreach (Declaration decl in prog.TopLevelDeclarations) {
- Contract.Assert(decl != null);
- Constant c = decl as Constant;
- if (c != null) {
- ctx.DeclareConstant(c, c.Unique, null);
- }
- else {
- Function f = decl as Function;
- if (f != null) {
- ctx.DeclareFunction(f, null);
- }
- }
- }
- foreach (var ax in prog.Axioms) {
- ctx.AddAxiom(ax, null);
- }
- foreach (Declaration decl in prog.TopLevelDeclarations) {
- Contract.Assert(decl != null);
- GlobalVariable v = decl as GlobalVariable;
- if (v != null) {
- ctx.DeclareGlobalVariable(v, null);
- }
- }
-
- return (ProverInterface)CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx);
- }
-
- public enum Outcome {
- Valid,
- Invalid,
- TimeOut,
- OutOfMemory,
- Undetermined
- }
- public class ErrorHandler {
- // Used in CheckOutcomeCore
- public virtual int StartingProcId()
- {
- return 0;
- }
-
- public virtual void OnModel(IList<string> labels, Model model, Outcome proverOutcome) {
- Contract.Requires(cce.NonNullElements(labels));
- }
-
- public virtual void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) {
- Contract.Requires(message != null);
- }
-
- public virtual void OnProverWarning(string message)
- {
- Contract.Requires(message != null);
- switch (CommandLineOptions.Clo.PrintProverWarnings) {
- case CommandLineOptions.ProverWarnings.None:
- break;
- case CommandLineOptions.ProverWarnings.Stdout:
- Console.WriteLine("Prover warning: " + message);
- break;
- case CommandLineOptions.ProverWarnings.Stderr:
- Console.Error.WriteLine("Prover warning: " + message);
- break;
- default:
- Contract.Assume(false);
- throw new cce.UnreachableException(); // unexpected case
- }
- }
-
- public virtual Absy Label2Absy(string label) {
- Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- throw new System.NotImplementedException();
- }
- }
- public abstract void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler);
-
- public virtual Outcome CheckRPFP(string descriptiveName, RPFP vc, ErrorHandler handler,
- out RPFP.Node cex,
- Dictionary<int, Dictionary<string, string>> varSubst, Dictionary<string,int> extra_bound = null)
- {
- throw new System.NotImplementedException();
- }
- [NoDefaultContract]
- public abstract Outcome CheckOutcome(ErrorHandler handler, int taskID = -1);
- public virtual string[] CalculatePath(int controlFlowConstant) {
- throw new System.NotImplementedException();
- }
- public virtual void LogComment(string comment) {
- Contract.Requires(comment != null);
- }
- public virtual void Close() {
- }
-
- public abstract void Reset(VCExpressionGenerator gen);
-
- public abstract void FullReset(VCExpressionGenerator gen);
-
- /// <summary>
- /// MSchaef: Allows to Push a VCExpression as Axiom on the prover stack (beta)
- /// for now it is only implemented by ProcessTheoremProver and still requires some
- /// testing
- /// </summary>
- public virtual void PushVCExpression(VCExpr vc) {
- Contract.Requires(vc != null);
- throw new NotImplementedException();
- }
- public virtual string VCExpressionToString(VCExpr vc) {
- Contract.Requires(vc != null);
- Contract.Ensures(Contract.Result<string>() != null);
- throw new NotImplementedException();
- }
- public virtual void Pop() {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
- public virtual int NumAxiomsPushed() {
- throw new NotImplementedException();
- }
- public virtual int FlushAxiomsToTheoremProver() {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
-
- // (assert vc)
- public virtual void Assert(VCExpr vc, bool polarity)
- {
- throw new NotImplementedException();
- }
-
- // (assert implicit-axioms)
- public virtual void AssertAxioms()
- {
- throw new NotImplementedException();
- }
-
- // (check-sat)
- public virtual void Check()
- {
- throw new NotImplementedException();
- }
-
- // (check-sat + get-unsat-core + checkOutcome)
- public virtual Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore, ErrorHandler handler)
- {
- throw new NotImplementedException();
- }
-
- public virtual Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions, out List<int> unsatisfiedSoftAssumptions, ErrorHandler handler) {
- throw new NotImplementedException();
- }
-
- public virtual Outcome CheckOutcomeCore(ErrorHandler handler, int taskID = -1)
- {
- throw new NotImplementedException();
- }
-
- // (push 1)
- public virtual void Push()
- {
- throw new NotImplementedException();
- }
-
- // Set theorem prover timeout for the next "check-sat"
- public virtual void SetTimeOut(int ms)
- { }
-
- public abstract ProverContext Context {
- get;
- }
-
- public abstract VCExpressionGenerator VCExprGen {
- get;
- }
-
- public virtual void DefineMacro(Macro fun, VCExpr vc) {
- throw new NotImplementedException();
- }
-
- public class VCExprEvaluationException : Exception
- {
-
- }
-
- public virtual object Evaluate(VCExpr expr)
- {
- throw new NotImplementedException();
- }
-
- //////////////////////
- // For interpolation queries
- //////////////////////
-
- // Assert vc tagged with a name
- public virtual void AssertNamed(VCExpr vc, bool polarity, string name)
- {
- throw new NotImplementedException();
- }
-
- // Returns Interpolant(A,B)
- public virtual VCExpr ComputeInterpolant(VCExpr A, VCExpr B)
- {
- throw new NotImplementedException();
- }
-
- // Returns for each l, Interpolant(root + (leaves - l), l)
- // Preconditions:
- // leaves cannot have subformulas with same variable names
- // Both root and leaves should have been previously named via AssertNamed
- public virtual List<VCExpr> GetTreeInterpolant(List<string> root, List<string> leaves)
- {
- throw new NotImplementedException();
- }
-
- }
-
- public class ProverInterfaceContracts : ProverInterface {
- public override ProverContext Context {
- get {
- Contract.Ensures(Contract.Result<ProverContext>() != null);
-
- throw new NotImplementedException();
- }
- }
- public override VCExpressionGenerator VCExprGen {
- get {
- Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
-
- throw new NotImplementedException();
- }
- }
- public override void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler) {/*Contract.Requires(descriptiveName != null);*/
- //Contract.Requires(vc != null);
- //Contract.Requires(handler != null);
- throw new NotImplementedException();
- }
- [NoDefaultContract]
- public override Outcome CheckOutcome(ErrorHandler handler, int taskID = -1) {
- //Contract.Requires(handler != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- throw new NotImplementedException();
- }
-
- public override void Reset(VCExpressionGenerator gen)
- {
- throw new NotImplementedException();
- }
-
- public override void FullReset(VCExpressionGenerator gen)
- {
- throw new NotImplementedException();
- }
- }
-
- public class ProverException : Exception {
- public ProverException(string s)
- : base(s) {
- }
- }
- public class UnexpectedProverOutputException : ProverException {
- public UnexpectedProverOutputException(string s)
- : base(s) {
- }
- }
- public class ProverDiedException : UnexpectedProverOutputException {
- public ProverDiedException()
- : base("Prover died with no further output, perhaps it ran out of memory or was killed.") {
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Linq; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.IO; +using System.Text.RegularExpressions; +using System.Diagnostics; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.AbstractInterpretation; +using Microsoft.Boogie.VCExprAST; +using Microsoft.Basetypes; +using System.Threading.Tasks; + +namespace Microsoft.Boogie { + + enum CheckerStatus + { + Idle, + Ready, + Busy, + Closed + } + + /// <summary> + /// Interface to the theorem prover specialized to Boogie. + /// + /// This class creates the appropriate background axioms. There + /// should be one instance per BoogiePL program. + /// </summary> + public sealed class Checker { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(gen != null); + Contract.Invariant(thmProver != null); + } + + private readonly VCExpressionGenerator gen; + + private ProverInterface thmProver; + private int timeout; + + // state for the async interface + private volatile ProverInterface.Outcome outcome; + private volatile bool hasOutput; + private volatile UnexpectedProverOutputException outputExn; + private DateTime proverStart; + private TimeSpan proverRunTime; + private volatile ProverInterface.ErrorHandler handler; + private volatile CheckerStatus status; + public volatile Program Program; + + public void GetReady() + { + Contract.Requires(IsIdle); + + status = CheckerStatus.Ready; + } + + public void GoBackToIdle() + { + Contract.Requires(IsBusy); + + status = CheckerStatus.Idle; + } + + public Task ProverTask { get; set; } + + public bool WillingToHandle(int timeout, Program prog) { + return status == CheckerStatus.Idle && timeout == this.timeout && (prog == null || Program == prog); + } + + public VCExpressionGenerator VCExprGen { + get { + Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null); + return this.gen; + } + } + public ProverInterface TheoremProver { + get { + Contract.Ensures(Contract.Result<ProverInterface>() != null); + return this.thmProver; + } + } + + ///////////////////////////////////////////////////////////////////////////////// + // We share context information for the same program between different Checkers + + private struct ContextCacheKey { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(program != null); + } + + public readonly Program program; + + public ContextCacheKey(Program prog) { + Contract.Requires(prog != null); + this.program = prog; + } + + [Pure] + [Reads(ReadsAttribute.Reads.Nothing)] + public override bool Equals(object that) { + if (that is ContextCacheKey) { + ContextCacheKey thatKey = (ContextCacheKey)that; + return this.program.Equals(thatKey.program); + } + return false; + } + + [Pure] + public override int GetHashCode() { + return this.program.GetHashCode(); + } + } + + ///////////////////////////////////////////////////////////////////////////////// + + /// <summary> + /// Constructor. Initialize a checker with the program and log file. + /// Optionally, use prover context provided by parameter "ctx". + /// </summary> + public Checker(VC.ConditionGeneration vcgen, Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, ProverContext ctx = null) { + Contract.Requires(vcgen != null); + Contract.Requires(prog != null); + this.timeout = timeout; + this.Program = prog; + + ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions(); + + if (logFilePath != null) { + options.LogFilename = logFilePath; + if (appendLogFile) + options.AppendLogFile = appendLogFile; + } + + if (timeout > 0) { + options.TimeLimit = timeout * 1000; + } + + options.Parse(CommandLineOptions.Clo.ProverOptions); + + ContextCacheKey key = new ContextCacheKey(prog); + ProverInterface prover; + + if (vcgen.CheckerCommonState == null) { + vcgen.CheckerCommonState = new Dictionary<ContextCacheKey, ProverContext>(); + } + IDictionary<ContextCacheKey, ProverContext>/*!>!*/ cachedContexts = (IDictionary<ContextCacheKey, ProverContext/*!*/>)vcgen.CheckerCommonState; + + if (ctx == null && cachedContexts.TryGetValue(key, out ctx)) + { + ctx = (ProverContext)cce.NonNull(ctx).Clone(); + prover = (ProverInterface) + CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx); + } else { + if (ctx == null) ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options); + + Setup(prog, ctx); + + // we first generate the prover and then store a clone of the + // context in the cache, so that the prover can setup stuff in + // the context to be cached + prover = (ProverInterface) + CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx); + cachedContexts.Add(key, cce.NonNull((ProverContext)ctx.Clone())); + } + + this.thmProver = prover; + this.gen = prover.VCExprGen; + } + + public void Retarget(Program prog, ProverContext ctx, int timeout = 0) + { + lock (this) + { + hasOutput = default(bool); + outcome = default(ProverInterface.Outcome); + outputExn = default(UnexpectedProverOutputException); + handler = default(ProverInterface.ErrorHandler); + TheoremProver.FullReset(gen); + ctx.Reset(); + Setup(prog, ctx); + this.timeout = timeout; + SetTimeout(); + } + } + + public void RetargetWithoutReset(Program prog, ProverContext ctx) + { + ctx.Clear(); + Setup(prog, ctx); + } + + + public void SetTimeout() + { + if (0 < timeout) + { + TheoremProver.SetTimeOut(timeout * 1000); + } + else + { + TheoremProver.SetTimeOut(0); + } + } + + /// <summary> + /// Set up the context. + /// </summary> + private void Setup(Program prog, ProverContext ctx) + { + Program = prog; + // TODO(wuestholz): Is this lock necessary? + lock (Program.TopLevelDeclarations) + { + foreach (Declaration decl in Program.TopLevelDeclarations) + { + Contract.Assert(decl != null); + var typeDecl = decl as TypeCtorDecl; + var constDecl = decl as Constant; + var funDecl = decl as Function; + var axiomDecl = decl as Axiom; + var glVarDecl = decl as GlobalVariable; + if (typeDecl != null) + { + ctx.DeclareType(typeDecl, null); + } + else if (constDecl != null) + { + ctx.DeclareConstant(constDecl, constDecl.Unique, null); + } + else if (funDecl != null) + { + ctx.DeclareFunction(funDecl, null); + } + else if (axiomDecl != null) + { + ctx.AddAxiom(axiomDecl, null); + } + else if (glVarDecl != null) + { + ctx.DeclareGlobalVariable(glVarDecl, null); + } + } + } + } + + /// <summary> + /// Clean-up. + /// </summary> + public void Close() { + thmProver.Close(); + status = CheckerStatus.Closed; + } + + /// <summary> + /// Push a Verification Condition as an Axiom + /// (Required for Doomed Program Point detection) + /// </summary> + public void PushVCExpr(VCExpr vc) { + Contract.Requires(vc != null); + //thmProver.Context.AddAxiom(vc); + thmProver.PushVCExpression(vc); + } + + public bool IsBusy { + get { + return status == CheckerStatus.Busy; + } + } + + public bool IsReady + { + get + { + return status == CheckerStatus.Ready; + } + } + + public bool IsClosed { + get { + return status == CheckerStatus.Closed; + } + } + + public bool IsIdle + { + get + { + return status == CheckerStatus.Idle; + } + } + + public bool HasOutput { + get { + return hasOutput; + } + } + + public TimeSpan ProverRunTime { + get { + return proverRunTime; + } + } + + private void WaitForOutput(object dummy) { + lock (this) + { + try + { + outcome = thmProver.CheckOutcome(cce.NonNull(handler)); + } + catch (UnexpectedProverOutputException e) + { + outputExn = e; + } + + switch (outcome) + { + case ProverInterface.Outcome.Valid: + thmProver.LogComment("Valid"); + break; + case ProverInterface.Outcome.Invalid: + thmProver.LogComment("Invalid"); + break; + case ProverInterface.Outcome.TimeOut: + thmProver.LogComment("Timed out"); + break; + case ProverInterface.Outcome.OutOfMemory: + thmProver.LogComment("Out of memory"); + break; + case ProverInterface.Outcome.Undetermined: + thmProver.LogComment("Undetermined"); + break; + } + + hasOutput = true; + proverRunTime = DateTime.UtcNow - proverStart; + } + } + + public void BeginCheck(string descriptiveName, VCExpr vc, ProverInterface.ErrorHandler handler) { + Contract.Requires(descriptiveName != null); + Contract.Requires(vc != null); + Contract.Requires(handler != null); + Contract.Requires(IsReady); + + status = CheckerStatus.Busy; + hasOutput = false; + outputExn = null; + this.handler = handler; + + thmProver.Reset(gen); + SetTimeout(); + proverStart = DateTime.UtcNow; + thmProver.BeginCheck(descriptiveName, vc, handler); + // gen.ClearSharedFormulas(); PR: don't know yet what to do with this guy + + ProverTask = Task.Factory.StartNew(() => { WaitForOutput(null); }, TaskCreationOptions.LongRunning); + } + + public ProverInterface.Outcome ReadOutcome() { + Contract.Requires(IsBusy); + Contract.Requires(HasOutput); + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + + hasOutput = false; + + if (outputExn != null) { + throw outputExn; + } + + return outcome; + } + } + + // ----------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- + + public abstract class ProverInterface { + public static ProverInterface CreateProver(Program prog, string/*?*/ logFilePath, bool appendLogFile, int timeout, int taskID = -1) { + Contract.Requires(prog != null); + + ProverOptions options = cce.NonNull(CommandLineOptions.Clo.TheProverFactory).BlankProverOptions(); + + if (logFilePath != null) { + options.LogFilename = logFilePath; + if (appendLogFile) + options.AppendLogFile = appendLogFile; + } + + if (timeout > 0) { + options.TimeLimit = timeout * 1000; + } + + if (taskID >= 0) { + options.Parse(CommandLineOptions.Clo.Cho[taskID].ProverOptions); + } else { + options.Parse(CommandLineOptions.Clo.ProverOptions); + } + + ProverContext ctx = (ProverContext)CommandLineOptions.Clo.TheProverFactory.NewProverContext(options); + + // set up the context + foreach (Declaration decl in prog.TopLevelDeclarations) { + Contract.Assert(decl != null); + TypeCtorDecl t = decl as TypeCtorDecl; + if (t != null) { + ctx.DeclareType(t, null); + } + } + foreach (Declaration decl in prog.TopLevelDeclarations) { + Contract.Assert(decl != null); + Constant c = decl as Constant; + if (c != null) { + ctx.DeclareConstant(c, c.Unique, null); + } + else { + Function f = decl as Function; + if (f != null) { + ctx.DeclareFunction(f, null); + } + } + } + foreach (var ax in prog.Axioms) { + ctx.AddAxiom(ax, null); + } + foreach (Declaration decl in prog.TopLevelDeclarations) { + Contract.Assert(decl != null); + GlobalVariable v = decl as GlobalVariable; + if (v != null) { + ctx.DeclareGlobalVariable(v, null); + } + } + + return (ProverInterface)CommandLineOptions.Clo.TheProverFactory.SpawnProver(options, ctx); + } + + public enum Outcome { + Valid, + Invalid, + TimeOut, + OutOfMemory, + Undetermined, + Bounded + } + public class ErrorHandler { + // Used in CheckOutcomeCore + public virtual int StartingProcId() + { + return 0; + } + + public virtual void OnModel(IList<string> labels, Model model, Outcome proverOutcome) { + Contract.Requires(cce.NonNullElements(labels)); + } + + public virtual void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) { + Contract.Requires(message != null); + } + + public virtual void OnProverWarning(string message) + { + Contract.Requires(message != null); + switch (CommandLineOptions.Clo.PrintProverWarnings) { + case CommandLineOptions.ProverWarnings.None: + break; + case CommandLineOptions.ProverWarnings.Stdout: + Console.WriteLine("Prover warning: " + message); + break; + case CommandLineOptions.ProverWarnings.Stderr: + Console.Error.WriteLine("Prover warning: " + message); + break; + default: + Contract.Assume(false); + throw new cce.UnreachableException(); // unexpected case + } + } + + public virtual Absy Label2Absy(string label) { + Contract.Requires(label != null); + Contract.Ensures(Contract.Result<Absy>() != null); + + throw new System.NotImplementedException(); + } + } + public abstract void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler); + + public virtual Outcome CheckRPFP(string descriptiveName, RPFP vc, ErrorHandler handler, + out RPFP.Node cex, + Dictionary<int, Dictionary<string, string>> varSubst, Dictionary<string,int> extra_bound = null) + { + throw new System.NotImplementedException(); + } + [NoDefaultContract] + public abstract Outcome CheckOutcome(ErrorHandler handler, int taskID = -1); + public virtual string[] CalculatePath(int controlFlowConstant) { + throw new System.NotImplementedException(); + } + public virtual void LogComment(string comment) { + Contract.Requires(comment != null); + } + public virtual void Close() { + } + + public abstract void Reset(VCExpressionGenerator gen); + + public abstract void FullReset(VCExpressionGenerator gen); + + /// <summary> + /// MSchaef: Allows to Push a VCExpression as Axiom on the prover stack (beta) + /// for now it is only implemented by ProcessTheoremProver and still requires some + /// testing + /// </summary> + public virtual void PushVCExpression(VCExpr vc) { + Contract.Requires(vc != null); + throw new NotImplementedException(); + } + public virtual string VCExpressionToString(VCExpr vc) { + Contract.Requires(vc != null); + Contract.Ensures(Contract.Result<string>() != null); + throw new NotImplementedException(); + } + public virtual void Pop() { + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + throw new NotImplementedException(); + } + public virtual int NumAxiomsPushed() { + throw new NotImplementedException(); + } + public virtual int FlushAxiomsToTheoremProver() { + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + throw new NotImplementedException(); + } + + // (assert vc) + public virtual void Assert(VCExpr vc, bool polarity) + { + throw new NotImplementedException(); + } + + // (assert implicit-axioms) + public virtual void AssertAxioms() + { + throw new NotImplementedException(); + } + + // (check-sat) + public virtual void Check() + { + throw new NotImplementedException(); + } + + // (check-sat + get-unsat-core + checkOutcome) + public virtual Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore, ErrorHandler handler) + { + throw new NotImplementedException(); + } + + public virtual Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions, out List<int> unsatisfiedSoftAssumptions, ErrorHandler handler) { + throw new NotImplementedException(); + } + + public virtual Outcome CheckOutcomeCore(ErrorHandler handler, int taskID = -1) + { + throw new NotImplementedException(); + } + + // (push 1) + public virtual void Push() + { + throw new NotImplementedException(); + } + + // Set theorem prover timeout for the next "check-sat" + public virtual void SetTimeOut(int ms) + { } + + public abstract ProverContext Context { + get; + } + + public abstract VCExpressionGenerator VCExprGen { + get; + } + + public virtual void DefineMacro(Macro fun, VCExpr vc) { + throw new NotImplementedException(); + } + + public class VCExprEvaluationException : Exception + { + + } + + public virtual object Evaluate(VCExpr expr) + { + throw new NotImplementedException(); + } + + ////////////////////// + // For interpolation queries + ////////////////////// + + // Assert vc tagged with a name + public virtual void AssertNamed(VCExpr vc, bool polarity, string name) + { + throw new NotImplementedException(); + } + + // Returns Interpolant(A,B) + public virtual VCExpr ComputeInterpolant(VCExpr A, VCExpr B) + { + throw new NotImplementedException(); + } + + // Returns for each l, Interpolant(root + (leaves - l), l) + // Preconditions: + // leaves cannot have subformulas with same variable names + // Both root and leaves should have been previously named via AssertNamed + public virtual List<VCExpr> GetTreeInterpolant(List<string> root, List<string> leaves) + { + throw new NotImplementedException(); + } + + } + + public class ProverInterfaceContracts : ProverInterface { + public override ProverContext Context { + get { + Contract.Ensures(Contract.Result<ProverContext>() != null); + + throw new NotImplementedException(); + } + } + public override VCExpressionGenerator VCExprGen { + get { + Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null); + + throw new NotImplementedException(); + } + } + public override void BeginCheck(string descriptiveName, VCExpr vc, ErrorHandler handler) {/*Contract.Requires(descriptiveName != null);*/ + //Contract.Requires(vc != null); + //Contract.Requires(handler != null); + throw new NotImplementedException(); + } + [NoDefaultContract] + public override Outcome CheckOutcome(ErrorHandler handler, int taskID = -1) { + //Contract.Requires(handler != null); + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + throw new NotImplementedException(); + } + + public override void Reset(VCExpressionGenerator gen) + { + throw new NotImplementedException(); + } + + public override void FullReset(VCExpressionGenerator gen) + { + throw new NotImplementedException(); + } + } + + public class ProverException : Exception { + public ProverException(string s) + : base(s) { + } + } + public class UnexpectedProverOutputException : ProverException { + public UnexpectedProverOutputException(string s) + : base(s) { + } + } + public class ProverDiedException : UnexpectedProverOutputException { + public ProverDiedException() + : base("Prover died with no further output, perhaps it ran out of memory or was killed.") { + } + } +} diff --git a/Source/VCGeneration/ConditionGeneration.cs b/Source/VCGeneration/ConditionGeneration.cs index 8d6606b6..1f010757 100644 --- a/Source/VCGeneration/ConditionGeneration.cs +++ b/Source/VCGeneration/ConditionGeneration.cs @@ -1,2009 +1,2009 @@ -//-----------------------------------------------------------------------------
-//
-// 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);
- 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 = 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##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);
-
- 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;
- }
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// 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); + 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 = 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##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); + + 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; + } + } + } +} diff --git a/Source/VCGeneration/Context.cs b/Source/VCGeneration/Context.cs index ddc34976..3bd14e6b 100644 --- a/Source/VCGeneration/Context.cs +++ b/Source/VCGeneration/Context.cs @@ -1,256 +1,256 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.VCExprAST;
-
-namespace Microsoft.Boogie
-{
- /// <summary>
- /// The methods of this class are called in the following order:
- /// DeclareType*
- /// (DeclareConstant DeclareFunction)*
- /// AddAxiom*
- /// DeclareGlobalVariable*
- /// At this time, all "attributes" are passed in as null.
- /// </summary>
- [ContractClass(typeof(ProverContextContracts))]
- public abstract class ProverContext : ICloneable {
- public int TimoutDiagnosticsCount { get; set; }
- public readonly Dictionary<int, Tuple<AssertCmd, TransferCmd>> TimeoutDiagnosticIDToAssertion = new Dictionary<int, Tuple<AssertCmd, TransferCmd>>();
- protected virtual void ProcessDeclaration(Declaration decl) {Contract.Requires(decl != null);}
- public virtual void DeclareType(TypeCtorDecl t, string attributes) {Contract.Requires(t != null); ProcessDeclaration(t); }
- public virtual void DeclareConstant(Constant c, bool uniq, string attributes) {Contract.Requires(c != null); ProcessDeclaration(c); }
- public virtual void DeclareFunction(Function f, string attributes) {Contract.Requires(f != null); ProcessDeclaration(f); }
- public virtual void AddAxiom(Axiom a, string attributes) {Contract.Requires(a != null); ProcessDeclaration(a); }
- public virtual void DeclareGlobalVariable(GlobalVariable v, string attributes) {Contract.Requires(v != null); ProcessDeclaration(v); }
- public abstract void AddAxiom(VCExpr vc);
- public abstract string Lookup(VCExprVar var);
- public abstract VCExpressionGenerator ExprGen { get; }
- public abstract Boogie2VCExprTranslator BoogieExprTranslator { get; }
- public abstract VCGenerationOptions VCGenOptions { get; }
- public abstract object Clone();
- public abstract void Reset();
- public abstract void Clear();
- }
-
-[ContractClassFor(typeof(ProverContext))]
-public abstract class ProverContextContracts:ProverContext{
- public override void AddAxiom(VCExpr vc) {
- }
- public override void AddAxiom(Axiom a, string attributes)
-{
-}
- public override VCExpressionGenerator ExprGen
-{
- get { Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
- throw new NotImplementedException(); }
-}
- public override Boogie2VCExprTranslator BoogieExprTranslator
-{
- get { Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null);
- throw new NotImplementedException(); }
-}
- public override VCGenerationOptions VCGenOptions
-{
- get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null);
- throw new NotImplementedException(); }
-}
- public override object Clone()
-{
- Contract.Ensures(Contract.Result<object>() != null);
- throw new NotImplementedException();
-}
-}
-
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
- // -----------------------------------------------------------------------------------------------
-
- /// <summary>
- /// This ProverContext subclass is intended for use with untyped provers that do not require names
- /// to be declared before use. It constructs its context from unique constants and given axioms.
- /// </summary>
- public class DeclFreeProverContext : ProverContext {
- protected VCExpressionGenerator gen;
- protected VCGenerationOptions genOptions;
- protected Boogie2VCExprTranslator translator;
-
- protected OrderingAxiomBuilder orderingAxiomBuilder;
-
- protected List<Variable> distincts;
- protected List<VCExpr> axiomConjuncts;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(gen != null);
- Contract.Invariant(genOptions != null);
- Contract.Invariant(translator != null);
- Contract.Invariant(orderingAxiomBuilder != null);
- Contract.Invariant(cce.NonNullElements(distincts));
- Contract.Invariant(cce.NonNullElements(axiomConjuncts));
- }
-
- public VCExprTranslator/*?*/ exprTranslator;
-
- public DeclFreeProverContext(VCExpressionGenerator gen,
- VCGenerationOptions genOptions) {
- Contract.Requires(gen != null);
- Contract.Requires(genOptions != null);
- this.gen = gen;
- this.genOptions = genOptions;
- Boogie2VCExprTranslator t = new Boogie2VCExprTranslator (gen, genOptions);
- this.translator = t;
-
- SetupOrderingAxiomBuilder(gen, t);
-
- distincts = new List<Variable>();
- axiomConjuncts = new List<VCExpr>();
-
- exprTranslator = null;
- }
-
- private void SetupOrderingAxiomBuilder(VCExpressionGenerator gen, Boogie2VCExprTranslator t)
- {
- OrderingAxiomBuilder oab = new OrderingAxiomBuilder(gen, t);
- Contract.Assert(oab != null);
- oab.Setup();
- this.orderingAxiomBuilder = oab;
- }
-
- public override void Reset()
- {
- SetupOrderingAxiomBuilder(gen, translator);
- distincts = new List<Variable>();
- axiomConjuncts = new List<VCExpr>();
- }
-
- public override void Clear()
- {
- distincts = new List<Variable>();
- axiomConjuncts = new List<VCExpr>();
- }
-
- protected DeclFreeProverContext(DeclFreeProverContext ctxt) {
- Contract.Requires(ctxt != null);
- this.gen = ctxt.gen;
- this.genOptions = ctxt.genOptions;
- Boogie2VCExprTranslator t = (Boogie2VCExprTranslator)ctxt.translator.Clone();
- Contract.Assert(t != null);
- this.translator = t;
- this.orderingAxiomBuilder = new OrderingAxiomBuilder(ctxt.gen, t, ctxt.orderingAxiomBuilder);
-
- StringBuilder cmds = new StringBuilder ();
-
- distincts = new List<Variable>(ctxt.distincts);
- axiomConjuncts = new List<VCExpr>(ctxt.axiomConjuncts);
-
- if (ctxt.exprTranslator == null)
- exprTranslator = null;
- else
- exprTranslator = (VCExprTranslator)cce.NonNull(ctxt.exprTranslator.Clone());
- }
-
- public override object Clone() {
- Contract.Ensures(Contract.Result<object>() != null);
-
- return new DeclFreeProverContext(this);
- }
-
- public override void DeclareFunction(Function f, string attributes) {//Contract.Requires(f != null);
- base.ProcessDeclaration(f);
- }
-
- public override void DeclareConstant(Constant c, bool uniq, string attributes) {//Contract.Requires(c != null);
- base.DeclareConstant(c, uniq, attributes);
- orderingAxiomBuilder.AddConstant(c);
-
- // TODO: make separate distinct lists for names coming from different types
- // e.g., one for strings, one for ints, one for program types.
- if (uniq){
- distincts.Add(c);
- }
- }
-
- public override void AddAxiom(Axiom ax, string attributes) {//Contract.Requires(ax != null);
- base.AddAxiom(ax, attributes);
-
- axiomConjuncts.Add(translator.Translate(ax.Expr));
- }
-
- public override void AddAxiom(VCExpr vc)
- {//Contract.Requires(vc != null);
- axiomConjuncts.Add(vc);
- }
-
- public VCExpr Axioms {
- get {Contract.Ensures(Contract.Result<VCExpr>() != null);
- VCExpr axioms = gen.NAry(VCExpressionGenerator.AndOp, axiomConjuncts);
- List<VCExpr>/*!>!*/ distinctVars = new List<VCExpr> ();
- foreach (Variable v in distincts){
- Contract.Assert(v != null);
- distinctVars.Add(translator.LookupVariable(v));}
- axioms = gen.AndSimp(gen.Distinct(distinctVars), axioms);
- if (CommandLineOptions.Clo.TypeEncodingMethod != CommandLineOptions.TypeEncoding.Monomorphic)
- axioms = gen.AndSimp(orderingAxiomBuilder.Axioms, axioms);
- return axioms;
- }
- }
-
- public override string Lookup(VCExprVar var)
- {
- return exprTranslator.Lookup(var);
- }
-
- public override VCExpressionGenerator ExprGen { get {Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null);
-
- return gen;
- } }
- public override Boogie2VCExprTranslator BoogieExprTranslator { get {Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null);
-
- return translator;
- } }
- public override VCGenerationOptions VCGenOptions { get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null);
-
- return genOptions;
- } }
- }
-
- // Translator from VCExpressions to strings, which are implemented
- // by the various provers
- [ContractClass(typeof(VCExprTranslatorContracts))]
- public abstract class VCExprTranslator : ICloneable {
- public abstract string translate(VCExpr expr, int polarity);
- public abstract string Lookup(VCExprVar var);
- public abstract Object Clone();
- }
-
- [ContractClassFor(typeof(VCExprTranslator))]
-
- public abstract class VCExprTranslatorContracts : VCExprTranslator {
- public override object Clone() {
- Contract.Ensures(Contract.Result<object>() != null);
- throw new NotImplementedException();
- }
- public override string Lookup(VCExprVar var) {
- Contract.Requires(var != null);
- Contract.Ensures(Contract.Result<string>() != null);
-
- throw new NotImplementedException();
- }
- public override string translate(VCExpr expr, int polarity) {
-
- Contract.Requires(expr != null);
-
- Contract.Ensures(Contract.Result<string>() != null);
-
- throw new NotImplementedException();
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.VCExprAST; + +namespace Microsoft.Boogie +{ + /// <summary> + /// The methods of this class are called in the following order: + /// DeclareType* + /// (DeclareConstant DeclareFunction)* + /// AddAxiom* + /// DeclareGlobalVariable* + /// At this time, all "attributes" are passed in as null. + /// </summary> + [ContractClass(typeof(ProverContextContracts))] + public abstract class ProverContext : ICloneable { + public int TimoutDiagnosticsCount { get; set; } + public readonly Dictionary<int, Tuple<AssertCmd, TransferCmd>> TimeoutDiagnosticIDToAssertion = new Dictionary<int, Tuple<AssertCmd, TransferCmd>>(); + protected virtual void ProcessDeclaration(Declaration decl) {Contract.Requires(decl != null);} + public virtual void DeclareType(TypeCtorDecl t, string attributes) {Contract.Requires(t != null); ProcessDeclaration(t); } + public virtual void DeclareConstant(Constant c, bool uniq, string attributes) {Contract.Requires(c != null); ProcessDeclaration(c); } + public virtual void DeclareFunction(Function f, string attributes) {Contract.Requires(f != null); ProcessDeclaration(f); } + public virtual void AddAxiom(Axiom a, string attributes) {Contract.Requires(a != null); ProcessDeclaration(a); } + public virtual void DeclareGlobalVariable(GlobalVariable v, string attributes) {Contract.Requires(v != null); ProcessDeclaration(v); } + public abstract void AddAxiom(VCExpr vc); + public abstract string Lookup(VCExprVar var); + public abstract VCExpressionGenerator ExprGen { get; } + public abstract Boogie2VCExprTranslator BoogieExprTranslator { get; } + public abstract VCGenerationOptions VCGenOptions { get; } + public abstract object Clone(); + public abstract void Reset(); + public abstract void Clear(); + } + +[ContractClassFor(typeof(ProverContext))] +public abstract class ProverContextContracts:ProverContext{ + public override void AddAxiom(VCExpr vc) { + } + public override void AddAxiom(Axiom a, string attributes) +{ +} + public override VCExpressionGenerator ExprGen +{ + get { Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null); + throw new NotImplementedException(); } +} + public override Boogie2VCExprTranslator BoogieExprTranslator +{ + get { Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null); + throw new NotImplementedException(); } +} + public override VCGenerationOptions VCGenOptions +{ + get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null); + throw new NotImplementedException(); } +} + public override object Clone() +{ + Contract.Ensures(Contract.Result<object>() != null); + throw new NotImplementedException(); +} +} + + // ----------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- + // ----------------------------------------------------------------------------------------------- + + /// <summary> + /// This ProverContext subclass is intended for use with untyped provers that do not require names + /// to be declared before use. It constructs its context from unique constants and given axioms. + /// </summary> + public class DeclFreeProverContext : ProverContext { + protected VCExpressionGenerator gen; + protected VCGenerationOptions genOptions; + protected Boogie2VCExprTranslator translator; + + protected OrderingAxiomBuilder orderingAxiomBuilder; + + protected List<Variable> distincts; + protected List<VCExpr> axiomConjuncts; + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(gen != null); + Contract.Invariant(genOptions != null); + Contract.Invariant(translator != null); + Contract.Invariant(orderingAxiomBuilder != null); + Contract.Invariant(cce.NonNullElements(distincts)); + Contract.Invariant(cce.NonNullElements(axiomConjuncts)); + } + + public VCExprTranslator/*?*/ exprTranslator; + + public DeclFreeProverContext(VCExpressionGenerator gen, + VCGenerationOptions genOptions) { + Contract.Requires(gen != null); + Contract.Requires(genOptions != null); + this.gen = gen; + this.genOptions = genOptions; + Boogie2VCExprTranslator t = new Boogie2VCExprTranslator (gen, genOptions); + this.translator = t; + + SetupOrderingAxiomBuilder(gen, t); + + distincts = new List<Variable>(); + axiomConjuncts = new List<VCExpr>(); + + exprTranslator = null; + } + + private void SetupOrderingAxiomBuilder(VCExpressionGenerator gen, Boogie2VCExprTranslator t) + { + OrderingAxiomBuilder oab = new OrderingAxiomBuilder(gen, t); + Contract.Assert(oab != null); + oab.Setup(); + this.orderingAxiomBuilder = oab; + } + + public override void Reset() + { + SetupOrderingAxiomBuilder(gen, translator); + distincts = new List<Variable>(); + axiomConjuncts = new List<VCExpr>(); + } + + public override void Clear() + { + distincts = new List<Variable>(); + axiomConjuncts = new List<VCExpr>(); + } + + protected DeclFreeProverContext(DeclFreeProverContext ctxt) { + Contract.Requires(ctxt != null); + this.gen = ctxt.gen; + this.genOptions = ctxt.genOptions; + Boogie2VCExprTranslator t = (Boogie2VCExprTranslator)ctxt.translator.Clone(); + Contract.Assert(t != null); + this.translator = t; + this.orderingAxiomBuilder = new OrderingAxiomBuilder(ctxt.gen, t, ctxt.orderingAxiomBuilder); + + StringBuilder cmds = new StringBuilder (); + + distincts = new List<Variable>(ctxt.distincts); + axiomConjuncts = new List<VCExpr>(ctxt.axiomConjuncts); + + if (ctxt.exprTranslator == null) + exprTranslator = null; + else + exprTranslator = (VCExprTranslator)cce.NonNull(ctxt.exprTranslator.Clone()); + } + + public override object Clone() { + Contract.Ensures(Contract.Result<object>() != null); + + return new DeclFreeProverContext(this); + } + + public override void DeclareFunction(Function f, string attributes) {//Contract.Requires(f != null); + base.ProcessDeclaration(f); + } + + public override void DeclareConstant(Constant c, bool uniq, string attributes) {//Contract.Requires(c != null); + base.DeclareConstant(c, uniq, attributes); + orderingAxiomBuilder.AddConstant(c); + + // TODO: make separate distinct lists for names coming from different types + // e.g., one for strings, one for ints, one for program types. + if (uniq){ + distincts.Add(c); + } + } + + public override void AddAxiom(Axiom ax, string attributes) {//Contract.Requires(ax != null); + base.AddAxiom(ax, attributes); + + axiomConjuncts.Add(translator.Translate(ax.Expr)); + } + + public override void AddAxiom(VCExpr vc) + {//Contract.Requires(vc != null); + axiomConjuncts.Add(vc); + } + + public VCExpr Axioms { + get {Contract.Ensures(Contract.Result<VCExpr>() != null); + VCExpr axioms = gen.NAry(VCExpressionGenerator.AndOp, axiomConjuncts); + List<VCExpr>/*!>!*/ distinctVars = new List<VCExpr> (); + foreach (Variable v in distincts){ + Contract.Assert(v != null); + distinctVars.Add(translator.LookupVariable(v));} + axioms = gen.AndSimp(gen.Distinct(distinctVars), axioms); + if (CommandLineOptions.Clo.TypeEncodingMethod != CommandLineOptions.TypeEncoding.Monomorphic) + axioms = gen.AndSimp(orderingAxiomBuilder.Axioms, axioms); + return axioms; + } + } + + public override string Lookup(VCExprVar var) + { + return exprTranslator.Lookup(var); + } + + public override VCExpressionGenerator ExprGen { get {Contract.Ensures(Contract.Result<VCExpressionGenerator>() != null); + + return gen; + } } + public override Boogie2VCExprTranslator BoogieExprTranslator { get {Contract.Ensures(Contract.Result<Boogie2VCExprTranslator>() != null); + + return translator; + } } + public override VCGenerationOptions VCGenOptions { get {Contract.Ensures(Contract.Result<VCGenerationOptions>() != null); + + return genOptions; + } } + } + + // Translator from VCExpressions to strings, which are implemented + // by the various provers + [ContractClass(typeof(VCExprTranslatorContracts))] + public abstract class VCExprTranslator : ICloneable { + public abstract string translate(VCExpr expr, int polarity); + public abstract string Lookup(VCExprVar var); + public abstract Object Clone(); + } + + [ContractClassFor(typeof(VCExprTranslator))] + + public abstract class VCExprTranslatorContracts : VCExprTranslator { + public override object Clone() { + Contract.Ensures(Contract.Result<object>() != null); + throw new NotImplementedException(); + } + public override string Lookup(VCExprVar var) { + Contract.Requires(var != null); + Contract.Ensures(Contract.Result<string>() != null); + + throw new NotImplementedException(); + } + public override string translate(VCExpr expr, int polarity) { + + Contract.Requires(expr != null); + + Contract.Ensures(Contract.Result<string>() != null); + + throw new NotImplementedException(); + } + } +} diff --git a/Source/VCGeneration/ExprExtensions.cs b/Source/VCGeneration/ExprExtensions.cs index 2bdb4af7..5e0dcf8e 100644 --- a/Source/VCGeneration/ExprExtensions.cs +++ b/Source/VCGeneration/ExprExtensions.cs @@ -1,353 +1,353 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using Term = Microsoft.Boogie.VCExprAST.VCExpr;
-using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
-using Sort = Microsoft.Boogie.Type;
-using Microsoft.Boogie.VCExprAST;
-
-
-/** This namespace contains some extensions to allow VCExpr to provide the
- * interface needed by RPFP and FixedpointVC. */
-
-namespace Microsoft.Boogie.ExprExtensions
-{
- class ReferenceComparer<T> : IEqualityComparer<T> where T : class
- {
- private static ReferenceComparer<T> m_instance;
-
- public static ReferenceComparer<T> Instance
- {
- get
- {
- return m_instance ?? (m_instance = new ReferenceComparer<T>());
- }
- }
-
- public bool Equals(T x, T y)
- {
- return ReferenceEquals(x, y);
- }
-
- public int GetHashCode(T obj)
- {
- return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj);
- }
- }
-
- public class TermDict<T> : Dictionary<Term, T>
- {
- public TermDict() : base(ReferenceComparer<Term>.Instance) { }
- }
-
-
-
- public enum TermKind { App, Other };
-
- public enum DeclKind { Uninterpreted, And, Implies, Label, Other };
-
- public static class MyExtensions
- {
- public static Term[] GetAppArgs(this Term t)
- {
- Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
- return tn.ToArray();
- }
-
- public static FuncDecl GetAppDecl(this Term t)
- {
- Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
- return tn.Op;
- }
-
- public static string GetDeclName(this FuncDecl f)
- {
- return (f as VCExprBoogieFunctionOp).Func.Name; //TODO
- }
-
- public static DeclKind GetKind(this FuncDecl f)
- {
- if (f is VCExprBoogieFunctionOp)
- return DeclKind.Uninterpreted;
- if (f == VCExpressionGenerator.AndOp)
- return DeclKind.And;
- if (f == VCExpressionGenerator.ImpliesOp)
- return DeclKind.Implies;
- if (f is VCExprLabelOp)
- return DeclKind.Label;
- return DeclKind.Other;
- }
-
- public static bool IsLabel(this Term t)
- {
- return (t is VCExprNAry) && (GetAppDecl(t) is VCExprLabelOp);
- }
-
- public static string LabelName(this Term t)
- {
- return (GetAppDecl(t) as VCExprLabelOp).label;
- }
-
- public static Sort GetSort(this Term t)
- {
- return t.Type;
- }
-
- public static TermKind GetKind(this Term t)
- {
- if (t is Microsoft.Boogie.VCExprAST.VCExprNAry)
- return TermKind.App;
- return TermKind.Other;
- }
-
- public static bool IsFunctionApp(this Term t)
- {
- return t.GetKind() == TermKind.App && t.GetAppDecl().GetKind() == DeclKind.Uninterpreted;
- }
-
- public static bool IsFalse(this Term t)
- {
- return t == VCExpressionGenerator.False;
- }
-
- public static Term VCExprToTerm(this Microsoft.Boogie.ProverContext ctx, VCExpr e, LineariserOptions lin){
- return e;
- }
-
- }
-
- public class Context : Microsoft.Boogie.VCExpressionGenerator
- {
- public Term MkTrue()
- {
- return VCExpressionGenerator.True;
- }
-
- public Term MkFalse()
- {
- return VCExpressionGenerator.False;
- }
-
-
- public List<Term> axioms = new List<Term>();
-
- public void AddAxiom(Term ax)
- {
- axioms.Add(ax);
- }
-
- public void RemoveAxiom(Term ax)
- {
- axioms.Remove(ax);
- }
-
- public FuncDecl MkFuncDecl(string name, FuncDecl f)
- {
- Function h = (f as VCExprBoogieFunctionOp).Func;
- Function g = new Function(Token.NoToken, name, h.InParams, h.OutParams[0]);
- return BoogieFunctionOp(g);
- }
-
- public FuncDecl MkFuncDecl(string name, Sort rng)
- {
- Function g = new Function(Token.NoToken, name, new List<Variable>(), new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "dummy",rng)));
- return BoogieFunctionOp(g);
- }
-
- public Term MkApp(FuncDecl f, Term[] args)
- {
- return Function(f, args);
- }
-
- public Term MkApp(FuncDecl f, Term[] args, Type[]/*!*/ typeArguments)
- {
- return Function(f, args, typeArguments);
- }
-
- public Term MkApp(FuncDecl f, Term arg)
- {
- return Function(f, arg);
- }
-
- public Term CloneApp(Term t, Term[] args)
- {
- var f = t.GetAppDecl();
- var typeArgs = (t as VCExprNAry).TypeArguments;
- if (typeArgs != null && typeArgs.Count > 0)
- {
- return MkApp(f, args, typeArgs.ToArray());
- }
- else
- {
- return MkApp(f, args);
- }
- }
-
- public Term MkAnd(Term[] args)
- {
- if (args.Length == 0) return True;
- Term res = args[0];
- for (int i = 1; i < args.Length; i++)
- res = And(res, args[i]);
- return res;
- }
-
- public Term MkAnd(Term arg1, Term arg2)
- {
- return And(arg1, arg2);
- }
-
-
- public Term MkNot(Term arg1)
- {
- return Not(arg1);
- }
-
- public Term MkImplies(Term arg1, Term arg2)
- {
- return Implies(arg1, arg2);
- }
-
- public Term MkEq(Term arg1, Term arg2)
- {
- return Eq(arg1, arg2);
- }
-
- public Sort MkBoolSort()
- {
- return Type.Bool;
- }
-
- public Term MkConst(string name, Sort sort)
- {
- return Variable(name, sort);
- }
-
- public Term MkForall(Term[] bounds, Term body)
- {
- if (bounds.Length == 0)
- return body;
- List<VCExprVar> vbs = new List<VCExprVar>();
- foreach(var v in bounds)
- vbs.Add(v as VCExprVar);
- return Forall(vbs,new List<VCTrigger>(), body);
- }
-
- public Term MkExists(Term[] bounds, Term body)
- {
- if (bounds.Length == 0)
- return body;
- List<VCExprVar> vbs = new List<VCExprVar>();
- foreach (var v in bounds)
- vbs.Add(v as VCExprVar);
- return Exists(vbs, new List<VCTrigger>(), body);
- }
-
- private class Letifier
- {
- private class counter
- {
- public int cnt = 0;
- }
- TermDict<counter> refcnt = new TermDict<counter>();
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- TermDict< VCExprVar> bindingMap = new TermDict< VCExprVar>();
- int letcnt = 0;
- Context ctx;
-
- public Letifier(Context _ctx) { ctx = _ctx; }
-
- private void RefCnt(Term t)
- {
- counter cnt;
- if (!refcnt.TryGetValue(t, out cnt))
- {
- cnt = new counter();
- refcnt.Add(t, cnt);
- }
- cnt.cnt++;
- if (cnt.cnt == 1)
- {
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var args = t.GetAppArgs();
- foreach (var arg in args)
- RefCnt(arg);
- }
- else if (t is VCExprQuantifier)
- {
- RefCnt((t as VCExprQuantifier).Body);
- }
- }
- }
-
- private Term Doit(Term t)
- {
- VCExprVar v;
- if (bindingMap.TryGetValue(t, out v))
- {
- return v;
- }
- Term res = null;
- var kind = t.GetKind();
- bool letok = false;
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- args = args.Select(x => Doit(x)).ToArray();
- res = ctx.MkApp(f, args);
- letok = true;
- }
- else if (t is VCExprQuantifier)
- {
- var q = t as VCExprQuantifier;
- var newbody = ctx.Letify(q.Body);
- if (q.Quan == Quantifier.ALL)
- res = ctx.Forall(q.BoundVars, q.Triggers, newbody);
- else
- res = ctx.Exists(q.BoundVars, q.Triggers, newbody);
- letok = true;
- }
- else res = t;
- if (letok && refcnt[t].cnt > 1)
- {
- VCExprVar lv = ctx.MkConst("fpvc$" + Convert.ToString(letcnt), t.GetSort()) as VCExprVar;
- VCExprLetBinding b = ctx.LetBinding(lv, res);
- bindings.Add(b);
- bindingMap.Add(t, lv);
- res = lv;
- letcnt++;
- }
- return res;
- }
-
- public Term Letify(Term t)
- {
- RefCnt(t);
- Term res = Doit(t);
- if (bindings.Count > 0)
- res = ctx.Let(bindings, res);
- return res;
- }
-
- }
-
- public Term Letify(Term t)
- {
- var thing = new Letifier(this);
- return thing.Letify(t);
- }
-
- };
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Term = Microsoft.Boogie.VCExprAST.VCExpr; +using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp; +using Sort = Microsoft.Boogie.Type; +using Microsoft.Boogie.VCExprAST; + + +/** This namespace contains some extensions to allow VCExpr to provide the + * interface needed by RPFP and FixedpointVC. */ + +namespace Microsoft.Boogie.ExprExtensions +{ + class ReferenceComparer<T> : IEqualityComparer<T> where T : class + { + private static ReferenceComparer<T> m_instance; + + public static ReferenceComparer<T> Instance + { + get + { + return m_instance ?? (m_instance = new ReferenceComparer<T>()); + } + } + + public bool Equals(T x, T y) + { + return ReferenceEquals(x, y); + } + + public int GetHashCode(T obj) + { + return System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(obj); + } + } + + public class TermDict<T> : Dictionary<Term, T> + { + public TermDict() : base(ReferenceComparer<Term>.Instance) { } + } + + + + public enum TermKind { App, Other }; + + public enum DeclKind { Uninterpreted, And, Implies, Label, Other }; + + public static class MyExtensions + { + public static Term[] GetAppArgs(this Term t) + { + Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry; + return tn.ToArray(); + } + + public static FuncDecl GetAppDecl(this Term t) + { + Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry; + return tn.Op; + } + + public static string GetDeclName(this FuncDecl f) + { + return (f as VCExprBoogieFunctionOp).Func.Name; //TODO + } + + public static DeclKind GetKind(this FuncDecl f) + { + if (f is VCExprBoogieFunctionOp) + return DeclKind.Uninterpreted; + if (f == VCExpressionGenerator.AndOp) + return DeclKind.And; + if (f == VCExpressionGenerator.ImpliesOp) + return DeclKind.Implies; + if (f is VCExprLabelOp) + return DeclKind.Label; + return DeclKind.Other; + } + + public static bool IsLabel(this Term t) + { + return (t is VCExprNAry) && (GetAppDecl(t) is VCExprLabelOp); + } + + public static string LabelName(this Term t) + { + return (GetAppDecl(t) as VCExprLabelOp).label; + } + + public static Sort GetSort(this Term t) + { + return t.Type; + } + + public static TermKind GetKind(this Term t) + { + if (t is Microsoft.Boogie.VCExprAST.VCExprNAry) + return TermKind.App; + return TermKind.Other; + } + + public static bool IsFunctionApp(this Term t) + { + return t.GetKind() == TermKind.App && t.GetAppDecl().GetKind() == DeclKind.Uninterpreted; + } + + public static bool IsFalse(this Term t) + { + return t == VCExpressionGenerator.False; + } + + public static Term VCExprToTerm(this Microsoft.Boogie.ProverContext ctx, VCExpr e, LineariserOptions lin){ + return e; + } + + } + + public class Context : Microsoft.Boogie.VCExpressionGenerator + { + public Term MkTrue() + { + return VCExpressionGenerator.True; + } + + public Term MkFalse() + { + return VCExpressionGenerator.False; + } + + + public List<Term> axioms = new List<Term>(); + + public void AddAxiom(Term ax) + { + axioms.Add(ax); + } + + public void RemoveAxiom(Term ax) + { + axioms.Remove(ax); + } + + public FuncDecl MkFuncDecl(string name, FuncDecl f) + { + Function h = (f as VCExprBoogieFunctionOp).Func; + Function g = new Function(Token.NoToken, name, h.InParams, h.OutParams[0]); + return BoogieFunctionOp(g); + } + + public FuncDecl MkFuncDecl(string name, Sort rng) + { + Function g = new Function(Token.NoToken, name, new List<Variable>(), new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "dummy",rng))); + return BoogieFunctionOp(g); + } + + public Term MkApp(FuncDecl f, Term[] args) + { + return Function(f, args); + } + + public Term MkApp(FuncDecl f, Term[] args, Type[]/*!*/ typeArguments) + { + return Function(f, args, typeArguments); + } + + public Term MkApp(FuncDecl f, Term arg) + { + return Function(f, arg); + } + + public Term CloneApp(Term t, Term[] args) + { + var f = t.GetAppDecl(); + var typeArgs = (t as VCExprNAry).TypeArguments; + if (typeArgs != null && typeArgs.Count > 0) + { + return MkApp(f, args, typeArgs.ToArray()); + } + else + { + return MkApp(f, args); + } + } + + public Term MkAnd(Term[] args) + { + if (args.Length == 0) return True; + Term res = args[0]; + for (int i = 1; i < args.Length; i++) + res = And(res, args[i]); + return res; + } + + public Term MkAnd(Term arg1, Term arg2) + { + return And(arg1, arg2); + } + + + public Term MkNot(Term arg1) + { + return Not(arg1); + } + + public Term MkImplies(Term arg1, Term arg2) + { + return Implies(arg1, arg2); + } + + public Term MkEq(Term arg1, Term arg2) + { + return Eq(arg1, arg2); + } + + public Sort MkBoolSort() + { + return Type.Bool; + } + + public Term MkConst(string name, Sort sort) + { + return Variable(name, sort); + } + + public Term MkForall(Term[] bounds, Term body) + { + if (bounds.Length == 0) + return body; + List<VCExprVar> vbs = new List<VCExprVar>(); + foreach(var v in bounds) + vbs.Add(v as VCExprVar); + return Forall(vbs,new List<VCTrigger>(), body); + } + + public Term MkExists(Term[] bounds, Term body) + { + if (bounds.Length == 0) + return body; + List<VCExprVar> vbs = new List<VCExprVar>(); + foreach (var v in bounds) + vbs.Add(v as VCExprVar); + return Exists(vbs, new List<VCTrigger>(), body); + } + + private class Letifier + { + private class counter + { + public int cnt = 0; + } + TermDict<counter> refcnt = new TermDict<counter>(); + List<VCExprLetBinding> bindings = new List<VCExprLetBinding>(); + TermDict< VCExprVar> bindingMap = new TermDict< VCExprVar>(); + int letcnt = 0; + Context ctx; + + public Letifier(Context _ctx) { ctx = _ctx; } + + private void RefCnt(Term t) + { + counter cnt; + if (!refcnt.TryGetValue(t, out cnt)) + { + cnt = new counter(); + refcnt.Add(t, cnt); + } + cnt.cnt++; + if (cnt.cnt == 1) + { + var kind = t.GetKind(); + if (kind == TermKind.App) + { + var args = t.GetAppArgs(); + foreach (var arg in args) + RefCnt(arg); + } + else if (t is VCExprQuantifier) + { + RefCnt((t as VCExprQuantifier).Body); + } + } + } + + private Term Doit(Term t) + { + VCExprVar v; + if (bindingMap.TryGetValue(t, out v)) + { + return v; + } + Term res = null; + var kind = t.GetKind(); + bool letok = false; + if (kind == TermKind.App) + { + var f = t.GetAppDecl(); + var args = t.GetAppArgs(); + args = args.Select(x => Doit(x)).ToArray(); + res = ctx.MkApp(f, args); + letok = true; + } + else if (t is VCExprQuantifier) + { + var q = t as VCExprQuantifier; + var newbody = ctx.Letify(q.Body); + if (q.Quan == Quantifier.ALL) + res = ctx.Forall(q.BoundVars, q.Triggers, newbody); + else + res = ctx.Exists(q.BoundVars, q.Triggers, newbody); + letok = true; + } + else res = t; + if (letok && refcnt[t].cnt > 1) + { + VCExprVar lv = ctx.MkConst("fpvc$" + Convert.ToString(letcnt), t.GetSort()) as VCExprVar; + VCExprLetBinding b = ctx.LetBinding(lv, res); + bindings.Add(b); + bindingMap.Add(t, lv); + res = lv; + letcnt++; + } + return res; + } + + public Term Letify(Term t) + { + RefCnt(t); + Term res = Doit(t); + if (bindings.Count > 0) + res = ctx.Let(bindings, res); + return res; + } + + } + + public Term Letify(Term t) + { + var thing = new Letifier(this); + return thing.Letify(t); + } + + }; +} diff --git a/Source/VCGeneration/FixedpointVC.cs b/Source/VCGeneration/FixedpointVC.cs index 5c698633..c636ea2b 100644 --- a/Source/VCGeneration/FixedpointVC.cs +++ b/Source/VCGeneration/FixedpointVC.cs @@ -1,2235 +1,2245 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.IO;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie;
-using Microsoft.Boogie.VCExprAST;
-
-
-using Term = Microsoft.Boogie.VCExprAST.VCExpr;
-using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
-using Sort = Microsoft.Boogie.Type;
-using Microsoft.Boogie.ExprExtensions;
-
-
-namespace Microsoft.Boogie
-{
- public class FixedpointVC : VC.VCGen
- {
-
- public class AnnotationInfo
- {
- public enum AnnotationType { LoopInvariant, ProcedureSummary };
- public string filename;
- public int lineno;
- public string[] argnames;
- public AnnotationType type;
- };
-
- static bool NoLabels = false;
-
- // options
- bool largeblock = false;
-
- public bool SetOption(string option, string value)
- {
- if (option == "LargeBlock")
- {
- largeblock = true;
- return true;
- }
- return false;
- }
-
- Context ctx;
- RPFP rpfp;
- // Program program;
- Microsoft.Boogie.ProverContext boogieContext;
- Microsoft.Boogie.VCExpressionGenerator gen;
- public readonly static string recordProcName = "boogie_si_record"; // TODO: this really needed?
- private Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo
- = new Dictionary<string, StratifiedInliningInfo>();
- Checker checker;
- // Microsoft.Boogie.Z3.Z3InstanceOptions options = new Microsoft.Boogie.Z3.Z3InstanceOptions(); // TODO: what?
- LineariserOptions linOptions;
- Dictionary<FuncDecl, StratifiedInliningInfo> relationToProc = new Dictionary<FuncDecl, StratifiedInliningInfo>();
- Dictionary<string, Term> labels = new Dictionary<string, Term> ();
- List<Term> DualityVCs = new List<Term>();
- Dictionary<string, bool> summaries = new Dictionary<string, bool>();
- Dictionary<Block, List<Block>> edgesCut = new Dictionary<Block, List<Block>>();
- string main_proc_name = "main";
- Dictionary<string, int> extraRecBound = null;
-
-
- public enum Mode { Corral, OldCorral, Boogie};
- public enum AnnotationStyle { Flat, Procedure, Call };
-
- Mode mode;
- AnnotationStyle style;
-
- private static Checker old_checker = null;
-
- public static void CleanUp()
- {
- if (old_checker != null)
- {
- old_checker.Close();
- old_checker = null;
- }
- }
-
- public FixedpointVC( Program _program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Dictionary<string,int> _extraRecBound = null)
- : base(_program, logFilePath, appendLogFile, checkers)
- {
- switch (CommandLineOptions.Clo.FixedPointMode)
- {
- case CommandLineOptions.FixedPointInferenceMode.Corral:
- mode = Mode.Corral;
- style = AnnotationStyle.Procedure;
- break;
- case CommandLineOptions.FixedPointInferenceMode.OldCorral:
- mode = Mode.OldCorral;
- style = AnnotationStyle.Procedure;
- break;
- case CommandLineOptions.FixedPointInferenceMode.Flat:
- mode = Mode.Boogie;
- style = AnnotationStyle.Flat;
- break;
- case CommandLineOptions.FixedPointInferenceMode.Procedure:
- mode = Mode.Boogie;
- style = AnnotationStyle.Procedure;
- break;
- case CommandLineOptions.FixedPointInferenceMode.Call:
- mode = Mode.Boogie;
- style = AnnotationStyle.Call;
- break;
- }
- ctx = new Context(); // TODO is this right?
- rpfp = new RPFP(RPFP.CreateLogicSolver(ctx));
- program = _program;
- gen = ctx;
- if(old_checker == null)
- checker = new Checker(this, program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime, null);
- else {
- checker = old_checker;
- checker.RetargetWithoutReset(program,checker.TheoremProver.Context);
- }
- old_checker = checker;
- boogieContext = checker.TheoremProver.Context;
- linOptions = null; // new Microsoft.Boogie.Z3.Z3LineariserOptions(false, options, new List<VCExprVar>());
- extraRecBound = _extraRecBound;
- }
-
- Dictionary<string, AnnotationInfo> annotationInfo = new Dictionary<string, AnnotationInfo>();
-
- public void AnnotateLoops(Implementation impl, ProverContext ctxt)
- {
- Contract.Requires(impl != null);
-
- CurrentLocalVariables = impl.LocVars;
- variable2SequenceNumber = new Dictionary<Variable, int>();
- incarnationOriginMap = new Dictionary<Incarnation, Absy>();
-
- ResetPredecessors(impl.Blocks);
-
- #region Create the graph by adding the source node and each edge
- GraphUtil.Graph<Block> g = Program.GraphFromImpl(impl);
- #endregion
-
- //Graph<Block> g = program.ProcessLoops(impl);
-
- g.ComputeLoops(); // this is the call that does all of the processing
- if (!g.Reducible)
- {
- throw new System.Exception("Irreducible flow graphs are unsupported.");
- }
-
- #region add a symbolic annoation to every loop head
- foreach (Block header in cce.NonNull(g.Headers))
- AnnotateBlock(impl, ctxt, header);
- #endregion
- }
-
- private void AnnotateCallSites(Implementation impl, ProverContext ctxt, Dictionary<string, bool> impls){
- foreach (var b in impl.Blocks)
- {
- foreach (var cmd in b.Cmds)
- {
- if (cmd is CallCmd)
- {
- string name = (cmd as CallCmd).callee;
- if(impls.ContainsKey(name))
- goto annotate;
- }
- }
- continue;
- annotate:
- AnnotateBlock(impl, ctxt, b);
- }
- }
-
-
- private void AnnotateBlock(Implementation impl, ProverContext ctxt, Block header)
- {
- Contract.Assert(header != null);
-
- string name = impl.Name + "_" + header.Label + "_invar";
- if (annotationInfo.ContainsKey(name))
- return;
-
- // collect the variables needed in the invariant
- List<Expr> exprs = new List<Expr>();
- List<Variable> vars = new List<Variable>();
- List<string> names = new List<string>();
-
- if (style == AnnotationStyle.Flat)
- {
- // in flat mode, all live globals should be in live set
-#if false
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- names.Add(v.ToString());
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
-#endif
- foreach (Variable v in /* impl.LocVars */ header.liveVarsBefore)
- {
- if (!(v is BoundVariable))
- {
- vars.Add(v);
- names.Add(v.ToString());
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- }
- }
- else
- {
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- names.Add("@old_" + v.ToString());
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (IdentifierExpr ie in impl.Proc.Modifies)
- {
- if (ie.Decl == null)
- continue;
- vars.Add(ie.Decl);
- names.Add(ie.Decl.ToString());
- exprs.Add(ie);
- }
- foreach (Variable v in impl.Proc.InParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- names.Add("@old_" + v.ToString());
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (Variable v in impl.LocVars)
- {
- vars.Add(v);
- names.Add(v.ToString());
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- }
-
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- var function = new Function(Token.NoToken, name, vars, returnVar);
- ctxt.DeclareFunction(function, "");
-
- Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
- var invarAssertion = new AssertCmd(Token.NoToken, invarExpr);
- List<Cmd> newCmds = new List<Cmd>();
- newCmds.Add(invarAssertion);
-
- // make a record in annotationInfo;
- var info = new AnnotationInfo();
- info.filename = header.tok.filename;
- info.lineno = header.Line;
- info.argnames = names.ToArray();
- info.type = AnnotationInfo.AnnotationType.LoopInvariant;
- annotationInfo.Add(name, info);
- // get file and line info from havoc, if there is...
- if (header.Cmds.Count > 0)
- {
- PredicateCmd bif = header.Cmds[0] as PredicateCmd;
- if (bif != null)
- {
- string foo = QKeyValue.FindStringAttribute(bif.Attributes, "sourcefile");
- if (foo != null)
- info.filename = foo;
- int bar = QKeyValue.FindIntAttribute(bif.Attributes, "sourceline", -1);
- if (bar != -1)
- info.lineno = bar;
- }
- }
- var thing = header;
- foreach (Cmd c in header.Cmds)
- {
- newCmds.Add(c);
- }
- header.Cmds = newCmds;
- }
-
-#if true
- public void AnnotateProcRequires(Procedure proc, Implementation impl, ProverContext ctxt)
- {
- Contract.Requires(impl != null);
-
- CurrentLocalVariables = impl.LocVars;
-
- // collect the variables needed in the invariant
- List<Expr> exprs = new List<Expr>();
- List<Variable> vars = new List<Variable>();
- List<string> names = new List<string>();
-
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- names.Add(v.Name);
- }
- foreach (Variable v in proc.InParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- names.Add(v.Name);
- }
- string name = impl.Name + "_precond";
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- var function = new Function(Token.NoToken, name, vars, returnVar);
- ctxt.DeclareFunction(function, "");
-
- Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
-
- proc.Requires.Add(new Requires(Token.NoToken, false, invarExpr, "", null));
-
- var info = new AnnotationInfo();
- info.filename = proc.tok.filename;
- info.lineno = proc.Line;
- info.argnames = names.ToArray();
- info.type = AnnotationInfo.AnnotationType.LoopInvariant;
- annotationInfo.Add(name, info);
- }
-
- public void AnnotateProcEnsures(Procedure proc, Implementation impl, ProverContext ctxt)
- {
- Contract.Requires(impl != null);
-
- CurrentLocalVariables = impl.LocVars;
-
- // collect the variables needed in the invariant
- List<Expr> exprs = new List<Expr>();
- List<Variable> vars = new List<Variable>();
- List<string> names = new List<string>();
-
- foreach (Variable v in program.GlobalVariables)
- {
- vars.Add(v);
- exprs.Add(new OldExpr(Token.NoToken,new IdentifierExpr(Token.NoToken, v)));
- names.Add(v.Name);
- }
- foreach (Variable v in proc.InParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- names.Add(v.Name);
- }
- foreach (IdentifierExpr ie in proc.Modifies)
- {
- if (ie.Decl == null)
- continue;
- vars.Add(ie.Decl);
- exprs.Add(ie);
- names.Add(ie.Decl.Name + "_out");
- }
- foreach (Variable v in proc.OutParams)
- {
- Contract.Assert(v != null);
- vars.Add(v);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- names.Add(v.Name);
- }
- string name = impl.Name + "_summary";
- summaries.Add(name, true);
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- var function = new Function(Token.NoToken, name, vars, returnVar);
- ctxt.DeclareFunction(function, "");
-
- Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
-
- proc.Ensures.Add(new Ensures(Token.NoToken, false, invarExpr, "", null));
-
- var info = new AnnotationInfo();
- info.filename = proc.tok.filename;
- info.lineno = proc.Line;
- info.argnames = names.ToArray();
- info.type = AnnotationInfo.AnnotationType.ProcedureSummary;
- annotationInfo.Add(name, info);
- }
-#endif
-
- void MarkAllFunctionImplementationsInline()
- {
- foreach (var func in program.Functions)
- {
- if (func.Body == null && func.DefinitionAxiom != null)
- {
- var def = func.DefinitionAxiom.Expr as QuantifierExpr;
- var bod = def.Body as NAryExpr;
- func.Body = bod.Args[1];
- func.DefinitionAxiom = null;
- }
- if (func.Body != null)
- if (func.FindExprAttribute("inline") == null)
- func.AddAttribute("inline", Expr.Literal(100));
- }
- }
-
- void InlineAll()
- {
- foreach (var impl in program.Implementations)
- {
- impl.OriginalBlocks = impl.Blocks;
- impl.OriginalLocVars = impl.LocVars;
- if(impl.Name != main_proc_name)
- if(impl.FindExprAttribute("inline") == null)
- impl.AddAttribute("inline", Expr.Literal(100));
- }
- foreach (var impl in program.Implementations)
- {
- if (!impl.SkipVerification)
- {
- Inliner.ProcessImplementation(program, impl);
- }
- }
- foreach (var impl in program.Implementations)
- {
- impl.OriginalBlocks = null;
- impl.OriginalLocVars = null;
- }
- }
-
- public class LazyInliningInfo
- {
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(impl != null);
- Contract.Invariant(function != null);
- Contract.Invariant(controlFlowVariable != null);
- Contract.Invariant(assertExpr != null);
- Contract.Invariant(cce.NonNullElements(interfaceVars));
- Contract.Invariant(incarnationOriginMap == null || cce.NonNullDictionaryAndValues(incarnationOriginMap));
- }
-
- public Implementation impl;
- public int uniqueId;
- public Function function;
- public Variable controlFlowVariable;
- public List<Variable> interfaceVars;
- public List<List<Variable>> interfaceVarCopies;
- public Expr assertExpr;
- public VCExpr vcexpr;
- public List<VCExprVar> privateVars;
- public Dictionary<Incarnation, Absy> incarnationOriginMap;
- public Hashtable /*Variable->Expr*/ exitIncarnationMap;
- public Hashtable /*GotoCmd->returnCmd*/ gotoCmdOrigins;
- public Dictionary<int, Absy> label2absy;
- public VC.ModelViewInfo mvInfo;
-
- public Dictionary<Block, VCExprVar> reachVars;
- public List<VCExprLetBinding> reachVarBindings;
- public Variable inputErrorVariable;
- public Variable outputErrorVariable;
-
-
-
- public LazyInliningInfo(Implementation impl, Program program, ProverContext ctxt, int uniqueId, GlobalVariable errorVariable)
- {
- Contract.Requires(impl != null);
- Contract.Requires(program != null);
- Procedure proc = cce.NonNull(impl.Proc);
-
- this.impl = impl;
- this.uniqueId = uniqueId;
- this.controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "cfc", Microsoft.Boogie.Type.Int));
- impl.LocVars.Add(controlFlowVariable);
-
- List<Variable> interfaceVars = new List<Variable>();
- Expr assertExpr = new LiteralExpr(Token.NoToken, true);
- Contract.Assert(assertExpr != null);
- foreach (Variable v in program.GlobalVariables)
- {
- Contract.Assert(v != null);
- interfaceVars.Add(v);
- if (v.Name == "error")
- inputErrorVariable = v;
- }
- // InParams must be obtained from impl and not proc
- foreach (Variable v in impl.InParams)
- {
- Contract.Assert(v != null);
- interfaceVars.Add(v);
- }
- // OutParams must be obtained from impl and not proc
- foreach (Variable v in impl.OutParams)
- {
- Contract.Assert(v != null);
- Constant c = new Constant(Token.NoToken,
- new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- interfaceVars.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertExpr = Expr.And(assertExpr, eqExpr);
- }
- if (errorVariable != null)
- {
- proc.Modifies.Add(new IdentifierExpr(Token.NoToken, errorVariable));
- }
- foreach (IdentifierExpr e in proc.Modifies)
- {
- Contract.Assert(e != null);
- if (e.Decl == null)
- continue;
- Variable v = e.Decl;
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- interfaceVars.Add(c);
- if (v.Name == "error")
- {
- outputErrorVariable = c;
- continue;
- }
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertExpr = Expr.And(assertExpr, eqExpr);
- }
-
- this.interfaceVars = interfaceVars;
- this.assertExpr = Expr.Not(assertExpr);
- List<Variable> functionInterfaceVars = new List<Variable>();
- foreach (Variable v in interfaceVars)
- {
- Contract.Assert(v != null);
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, v.Name, v.TypedIdent.Type), true));
- }
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
- this.function = new Function(Token.NoToken, proc.Name, functionInterfaceVars, returnVar);
- ctxt.DeclareFunction(this.function, "");
-
- interfaceVarCopies = new List<List<Variable>>();
- int temp = 0;
- for (int i = 0; i < /* CommandLineOptions.Clo.ProcedureCopyBound */ 0; i++)
- {
- interfaceVarCopies.Add(new List<Variable>());
- foreach (Variable v in interfaceVars)
- {
- Constant constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, v.Name + temp++, v.TypedIdent.Type));
- interfaceVarCopies[i].Add(constant);
- //program.AddTopLevelDeclaration(constant);
- }
- }
- }
- }
-
- public class StratifiedInliningInfo : LazyInliningInfo
- {
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(cce.NonNullElements(privateVars));
- Contract.Invariant(cce.NonNullElements(interfaceExprVars));
- Contract.Invariant(cce.NonNullElements(interfaceExprVars));
- }
-
- // public StratifiedVCGenBase vcgen;
- //public Implementation impl;
- //public Program program;
- //public ProverContext ctxt;
- //public int uniqueid;
- //public Function function;
- //public Variable controlFlowVariable;
- //public Expr assertExpr;
- //public VCExpr vcexpr;
- //public List<VCExprVar> interfaceExprVars;
- //public List<VCExprVar> privateExprVars;
- //public Dictionary<int, Absy> label2absy;
- //public VC.ModelViewInfo mvInfo;
- //public Dictionary<Block, List<CallSite>> callSites;
- //public Dictionary<Block, List<CallSite>> recordProcCallSites;
- //public IEnumerable<Block> sortedBlocks;
- //public bool initialized { get; private set; }
-
-
- public List<VCExprVar> interfaceExprVars;
- // public List<VCExprVar> privateVars;
- public VCExpr funcExpr;
- public VCExpr falseExpr;
- public RPFP.Transformer F;
- public RPFP.Node node;
- public RPFP.Edge edge;
- public bool isMain = false;
- public Dictionary<Absy, string> label2absyInv;
- public ProverContext ctxt;
- public Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/();
- public List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
-
- public StratifiedInliningInfo(Implementation _impl, Program _program, ProverContext _ctxt, int _uniqueid)
- : base(_impl,_program,_ctxt,_uniqueid,null){
- Contract.Requires(_impl != null);
- Contract.Requires(_program != null);
- privateVars = new List<VCExprVar>();
- interfaceExprVars = new List<VCExprVar>();
- ctxt = _ctxt;
- }
-
- }
-
- protected override void addExitAssert(string implName, Block exitBlock)
- {
- if (implName2StratifiedInliningInfo != null
- && implName2StratifiedInliningInfo.ContainsKey(implName)
- && !implName2StratifiedInliningInfo[implName].isMain)
- {
- if (mode == Mode.Boogie) return;
- Expr assertExpr = implName2StratifiedInliningInfo[implName].assertExpr;
- Contract.Assert(assertExpr != null);
- exitBlock.Cmds.Add(new AssertCmd(Token.NoToken, assertExpr));
- }
- }
-
-#if false
- protected override void storeIncarnationMaps(string implName, Hashtable exitIncarnationMap)
- {
- if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName))
- {
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[implName];
- Contract.Assert(info != null);
- info.exitIncarnationMap = exitIncarnationMap;
- info.incarnationOriginMap = this.incarnationOriginMap;
- }
- }
-#endif
-
- public void GenerateVCsForStratifiedInlining()
- {
- Contract.Requires(program != null);
- foreach (var impl in program.Implementations)
- {
- Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy");
-
- Procedure proc = cce.NonNull(impl.Proc);
-
- {
- StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId());
- implName2StratifiedInliningInfo[impl.Name] = info;
- // We don't need controlFlowVariable for stratified Inlining
- //impl.LocVars.Add(info.controlFlowVariable);
- List<Expr> exprs = new List<Expr>();
-
- if (mode != Mode.Boogie && QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- {
- proc.Ensures.Add(new Ensures(Token.NoToken, true, Microsoft.Boogie.Expr.False, "", null));
- info.assertExpr = Microsoft.Boogie.Expr.False;
- // info.isMain = true;
- }
- else if (mode == Mode.Corral || proc.FindExprAttribute("inline") != null || proc is LoopProcedure)
- {
- foreach (Variable v in program.GlobalVariables)
- {
- Contract.Assert(v != null);
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (Variable v in proc.InParams)
- {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (Variable v in proc.OutParams)
- {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (IdentifierExpr ie in proc.Modifies)
- {
- Contract.Assert(ie != null);
- if (ie.Decl == null)
- continue;
- exprs.Add(ie);
- }
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs);
-#if true
- if(mode == Mode.Corral || mode == Mode.OldCorral)
- proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null)));
-#endif
- }
- else // not marked "inline" must be main
- {
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs);
- info.isMain = true;
- }
- }
- }
-
- if (mode == Mode.Boogie) return;
-
- foreach (var proc in program.Procedures)
- {
- if (!proc.Name.StartsWith(recordProcName)) continue;
- Contract.Assert(proc.InParams.Count == 1);
-
- // Make a new function
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
-
- // Get record type
- var argtype = proc.InParams[0].TypedIdent.Type;
-
- var ins = new List<Variable>();
- ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true));
-
- var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar);
- boogieContext.DeclareFunction(recordFunc, "");
-
- var exprs = new List<Expr>();
- exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0]));
-
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs);
- proc.Ensures.Add(new Ensures(true, freePostExpr));
- }
- }
-
- private void FixedPointToSpecs(){
-
- if(mode != Mode.Corral || CommandLineOptions.Clo.PrintFixedPoint == null)
- return; // not implemented for other annotation modes yet
-
- var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintFixedPoint, /*pretty=*/ false);
- Dictionary<string, RPFP.Node> pmap = new Dictionary<string,RPFP.Node> ();
-
- foreach (var node in rpfp.nodes)
- pmap.Add ((node.Name as VCExprBoogieFunctionOp).Func.Name, node);
-
- foreach (var impl in program.Implementations)
- {
- Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy");
-
- Procedure proc = cce.NonNull(impl.Proc);
-
- {
- StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId());
- implName2StratifiedInliningInfo[impl.Name] = info;
- // We don't need controlFlowVariable for stratified Inlining
- //impl.LocVars.Add(info.controlFlowVariable);
- List<Expr> exprs = new List<Expr>();
-
- {
- if (pmap.ContainsKey(impl.Name))
- {
- RPFP.Node node = pmap[impl.Name];
- var annot = node.Annotation;
- EmitProcSpec(twr, proc, info, annot);
- }
- }
- }
- }
- twr.Close ();
- }
-
- private void EmitProcSpec(TokenTextWriter twr, Procedure proc, StratifiedInliningInfo info, RPFP.Transformer annot)
- {
- // last ensures clause will be the symbolic one
- if (!info.isMain)
- {
- var ens = proc.Ensures[proc.Ensures.Count - 1];
- if (ens.Condition != Expr.False) // this is main
- {
- var postExpr = ens.Condition as NAryExpr;
- var args = postExpr.Args;
-
- var ind = annot.IndParams;
- var bound = new Dictionary<VCExpr, Expr>();
- for (int i = 0; i < args.Count; i++)
- {
- bound[ind[i]] = args[i];
- }
- var new_ens_cond = VCExprToExpr(annot.Formula, bound);
- if (new_ens_cond != Expr.True)
- {
- var new_ens = new Ensures(false, new_ens_cond);
- var enslist = new List<Ensures>();
- enslist.Add(new_ens);
- var new_proc = new Procedure(proc.tok, proc.Name, proc.TypeParameters, proc.InParams,
- proc.OutParams, new List<Requires>(), new List<IdentifierExpr>(), enslist);
- new_proc.Emit(twr, 0);
- }
- }
- }
- }
-
- static int ConjectureFileCounter = 0;
-
- private void ConjecturesToSpecs()
- {
-
- if (mode != Mode.Corral || CommandLineOptions.Clo.PrintConjectures == null)
- return; // not implemented for other annotation modes yet
-
- var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintConjectures + "." + ConjectureFileCounter.ToString(), /*pretty=*/ false);
- ConjectureFileCounter++;
-
- foreach (var c in rpfp.conjectures)
- {
- var name = c.node.Name.GetDeclName();
- if (implName2StratifiedInliningInfo.ContainsKey(name))
- {
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[c.node.Name.GetDeclName()];
- Implementation impl = info.impl;
- Procedure proc = impl.Proc;
- EmitProcSpec(twr, proc, info, c.bound);
- }
- }
-
- twr.Close ();
- }
-
- private Term ExtractSmallerVCsRec(TermDict< Term> memo, Term t, List<Term> small, Term lbl = null)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- if (f.GetKind() == DeclKind.Implies){
- var lhs = t.GetAppArgs()[0];
- if(lhs.GetKind() == TermKind.App){
- var r = lhs.GetAppDecl();
- if (r.GetKind() == DeclKind.And)
- {
- Term q = t.GetAppArgs()[1];
- var lhsargs = lhs.GetAppArgs();
- for (int i = lhsargs.Length-1; i >= 0; --i)
- {
- q = ctx.MkImplies(lhsargs[i], q);
- }
- res = ExtractSmallerVCsRec(memo, q, small,lbl);
- goto done;
- }
- if (r.GetKind() == DeclKind.Label)
- {
- var arg = lhs;
- arg = lhs.GetAppArgs()[0];
- if (!(arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted))
- goto normal;
- if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant))
- goto normal;
- var sm = ctx.MkImplies(lhs, ExtractSmallerVCsRec(memo, t.GetAppArgs()[1], small));
- if (lbl != null)
- sm = ctx.MkImplies(lbl, sm);
- small.Add(sm);
- res = ctx.MkTrue();
- goto done;
- }
- if (r.GetKind() == DeclKind.Uninterpreted)
- {
- var arg = lhs;
- if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant))
- goto normal;
- var sm = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small));
- if (lbl != null)
- sm = ctx.MkImplies(lbl, sm);
- small.Add(sm);
- res = ctx.MkTrue();
- goto done;
- }
- }
- normal:
- Term newlbl = null;
- if (lhs.IsLabel() && lhs.GetAppArgs()[0] == ctx.MkTrue())
- newlbl = lhs;
- res = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small,newlbl));
- }
- else if (f.GetKind() == DeclKind.And)
- {
- res = ctx.MkApp(f,t.GetAppArgs().Select(x => ExtractSmallerVCsRec(memo, x, small)).ToArray());
- }
- else
- res = t;
- }
- else
- res = t;
- done:
- memo.Add(t, res);
- return res;
- }
-
- private void ExtractSmallerVCs(Term t, List<Term> small){
- TermDict< Term> memo = new TermDict< Term>();
- Term top = ExtractSmallerVCsRec(memo, t, small);
- small.Add(top);
- }
-
- private Dictionary<FuncDecl, int> goalNumbering = new Dictionary<FuncDecl, int>();
-
- private Term NormalizeGoal(Term goal, FuncDecl label)
- {
- var f = goal.GetAppDecl();
- var args = goal.GetAppArgs();
- int number;
- if (!goalNumbering.TryGetValue(f, out number))
- {
- number = goalNumbering.Count;
- goalNumbering.Add(f, number);
- }
- Term[] tvars = new Term[args.Length];
- Term[] eqns = new Term[args.Length];
- AnnotationInfo info = null;
- annotationInfo.TryGetValue(f.GetDeclName(), out info);
- for (int i = 0; i < args.Length; i++)
- {
- string pname = (info == null) ? i.ToString() : info.argnames[i];
- tvars[i] = ctx.MkConst("@a" + number.ToString() + "_" + pname, args[i].GetSort());
- eqns[i] = ctx.MkEq(tvars[i], args[i]);
- }
- return ctx.MkImplies(ctx.MkAnd(eqns), ctx.MkApp(label, ctx.MkApp(f, tvars)));
- }
-
- private Term MergeGoalsRec(TermDict< Term> memo, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- if (f.GetKind() == DeclKind.Implies)
- {
- res = ctx.MkImplies(args[0], MergeGoalsRec(memo, args[1]));
- goto done;
- }
- else if (f.GetKind() == DeclKind.And)
- {
- args = args.Select(x => MergeGoalsRec(memo, x)).ToArray();
- res = ctx.MkApp(f, args);
- goto done;
- }
- else if (f.GetKind() == DeclKind.Label)
- {
- var arg = t.GetAppArgs()[0];
- var r = arg.GetAppDecl();
- if (r.GetKind() == DeclKind.Uninterpreted)
- {
- res = NormalizeGoal(arg, f);
- goto done;
- }
- }
- }
- res = t;
- done:
- memo.Add(t, res);
- return res;
- }
-
- private Term MergeGoals(Term t)
- {
- TermDict< Term> memo = new TermDict< Term>();
- return MergeGoalsRec(memo, t);
- }
-
- private Term CollectGoalsRec(TermDict< Term> memo, Term t, List<Term> goals, List<Term> cruft)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- if (f.GetKind() == DeclKind.Implies)
- {
- CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft);
- goto done;
- }
- else if (f.GetKind() == DeclKind.And)
- {
- foreach (var arg in t.GetAppArgs())
- {
- CollectGoalsRec(memo, arg, goals, cruft);
- }
- goto done;
- }
- else if (f.GetKind() == DeclKind.Label)
- {
- var arg = t.GetAppArgs()[0];
- if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted)
- {
- var r = arg.GetAppDecl();
- if (memo.TryGetValue(arg, out res))
- goto done;
- if (!annotationInfo.ContainsKey(r.GetDeclName()) && !arg.GetAppDecl().GetDeclName().StartsWith("_solve_"))
- goto done;
- goals.Add(arg);
- memo.Add(arg, arg);
- goto done;
- }
- else
- return CollectGoalsRec(memo, arg, goals, cruft);
- }
- else if (f.GetKind() == DeclKind.Uninterpreted)
- {
- string name = f.GetDeclName();
- if (name.StartsWith("_solve_"))
- {
- if (memo.TryGetValue(t, out res))
- goto done;
- goals.Add(t);
- memo.Add(t, t);
- return t;
- }
- }
- }
- // else the goal must be cruft
- cruft.Add(t);
- done:
- res = t; // just to return something
- memo.Add(t, res);
- return res;
- }
-
- private void CollectGoals(Term t, List<Term> goals, List<Term> cruft)
- {
- TermDict< Term> memo = new TermDict< Term>();
- CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft);
- }
-
- private Term SubstRec(TermDict< Term> memo, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- // var f = t.GetAppDecl();
- var args = t.GetAppArgs().Select(x => SubstRec(memo, x)).ToArray();
- res = ctx.CloneApp(t, args);
- }
- else res = t;
- memo.Add(t, res);
- return res;
- }
-
- private Term SubstRecGoals(TermDict< Term> memo, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- if (f.GetKind() == DeclKind.Implies){
- res = SubstRecGoals(memo, args[1]);
- if (res != ctx.MkTrue())
- res = ctx.MkImplies(args[0],res);
- goto done;
- }
- else if (f.GetKind() == DeclKind.And)
- {
- args = args.Select(x => SubstRecGoals(memo, x)).ToArray();
- args = args.Where(x => x != ctx.MkTrue()).ToArray();
- res = ctx.MkAnd(args);
- goto done;
- }
- else if (f.GetKind() == DeclKind.Label)
- {
- var arg = t.GetAppArgs()[0];
- if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted)
- {
- var r = arg.GetAppDecl();
- if (memo.TryGetValue(arg, out res))
- {
- if(res != ctx.MkTrue())
- res = ctx.MkApp(f, res);
- goto done;
- }
- }
- else
- {
- res = ctx.MkApp(f, SubstRecGoals(memo, arg));
- goto done;
- }
-
- }
- // what's left could be cruft!
- if (memo.TryGetValue(t, out res))
- {
- goto done;
- }
- }
- res = t;
- done:
- memo.Add(t, res);
- return res;
- }
-
- private void FactorVCs(Term t, List<Term> vcs)
- {
- List<Term> small = new List<Term>();
- ExtractSmallerVCs(t, small);
- foreach (var smm in small)
- {
- List<Term> goals = new List<Term>();
- List<Term> cruft = new List<Term>();
- var sm = largeblock ? MergeGoals(smm) : smm;
- CollectGoals(sm, goals,cruft);
- foreach (var goal in goals)
- {
- TermDict< Term> memo = new TermDict< Term>();
- foreach (var othergoal in goals)
- memo.Add(othergoal, othergoal.Equals(goal) ? ctx.MkFalse() : ctx.MkTrue());
- foreach (var thing in cruft)
- memo.Add(thing, ctx.MkTrue());
- var vc = SubstRecGoals(memo, sm);
- vc = ctx.MkImplies(ctx.MkNot(vc), goal);
- vcs.Add(vc);
- }
- {
- TermDict< Term> memo = new TermDict< Term>();
- foreach (var othergoal in goals)
- memo.Add(othergoal, ctx.MkTrue());
- var vc = SubstRecGoals(memo, sm);
- if (vc != ctx.MkTrue())
- {
- vc = ctx.MkImplies(ctx.MkNot(vc), ctx.MkFalse());
- vcs.Add(vc);
- }
- }
- }
- }
-
-
-
- private void GenerateVCForStratifiedInlining(Program program, StratifiedInliningInfo info, Checker checker)
- {
- Contract.Requires(program != null);
- Contract.Requires(info != null);
- Contract.Requires(checker != null);
- Contract.Requires(info.impl != null);
- Contract.Requires(info.impl.Proc != null);
-
-
-
- Implementation impl = info.impl;
- if (mode == Mode.Boogie && style == AnnotationStyle.Flat && impl.Name != main_proc_name)
- return;
- Contract.Assert(impl != null);
- ConvertCFG2DAG(impl,edgesCut);
- VC.ModelViewInfo mvInfo;
- PassifyImpl(impl, out mvInfo);
- Dictionary<int, Absy> label2absy = null;
- VCExpressionGenerator gen = checker.VCExprGen;
- Contract.Assert(gen != null);
- VCExpr vcexpr;
- if(NoLabels){
- // int assertionCount = 0;
- VCExpr startCorrect = null; /* VC.VCGen.LetVC(cce.NonNull(impl.Blocks[0]), null, null, info.blockVariables, info.bindings,
- info.ctxt, out assertionCount); */
- vcexpr = gen.Let(info.bindings, startCorrect);
- }
- else vcexpr = GenerateVC(impl, null /* info.controlFlowVariable */, out label2absy, info.ctxt);
- if(mode != Mode.Boogie)
- vcexpr = gen.Not(vcexpr);
- Contract.Assert(vcexpr != null);
- info.label2absy = label2absy;
- info.mvInfo = mvInfo;
- List<VCExpr> interfaceExprs = new List<VCExpr>();
-
- if (true /* was: !info.isMain */)
- {
- Boogie2VCExprTranslator translator = checker.TheoremProver.Context.BoogieExprTranslator;
- Contract.Assert(translator != null);
- info.privateVars = new List<VCExprVar>();
- foreach (Variable v in impl.LocVars)
- {
- Contract.Assert(v != null);
- info.privateVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.OutParams)
- {
- Contract.Assert(v != null);
- info.privateVars.Add(translator.LookupVariable(v));
- }
-
- info.interfaceExprVars = new List<VCExprVar>();
-
- foreach (Variable v in info.interfaceVars)
- {
- Contract.Assert(v != null);
- VCExprVar ev = translator.LookupVariable(v);
- Contract.Assert(ev != null);
- info.interfaceExprVars.Add(ev);
- interfaceExprs.Add(ev);
- }
- }
-
- Function function = cce.NonNull(info.function);
- Contract.Assert(function != null);
- info.funcExpr = gen.Function(function, interfaceExprs);
- info.vcexpr = vcexpr;
-
- if (mode == Mode.Boogie)
- {
- Term z3vc = boogieContext.VCExprToTerm(vcexpr, linOptions);
- FactorVCs(z3vc, DualityVCs);
- }
- else
- {
- // Index the procedures by relational variable
- FuncDecl R = boogieContext.VCExprToTerm(info.funcExpr, linOptions).GetAppDecl();
- relationToProc.Add(R, info);
- info.node = rpfp.CreateNode(boogieContext.VCExprToTerm(info.funcExpr, linOptions));
- rpfp.nodes.Add(info.node);
- if (info.isMain || QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- info.node.Bound.Formula = ctx.MkFalse();
- }
- }
-
- // This returns a new FuncDel with same sort as top-level function
- // of term t, but with numeric suffix appended to name.
-
- private FuncDecl SuffixFuncDecl(Term t, int n)
- {
- var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString();
- return ctx.MkFuncDecl(name, t.GetAppDecl());
- }
-
- // Collect the relational paremeters
-
- private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term,Term> done)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- var kind = t.GetKind();
- if (kind == TermKind.App)
- {
- var f = t.GetAppDecl();
- var args = t.GetAppArgs();
- args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray();
- StratifiedInliningInfo info;
- if (relationToProc.TryGetValue(f, out info))
- {
- if (done.ContainsKey(t))
- res = done[t];
- else
- {
- f = SuffixFuncDecl(t, parms.Count);
- parms.Add(f);
- nodes.Add(info.node);
- res = ctx.MkApp(f, args);
- done.Add(t,res); // don't count same expression twice!
- }
- }
- else
- res = ctx.CloneApp(t, args);
- } // TODO: handle quantifiers
- else res = t;
- memo.Add(t, res);
- return res;
- }
-
- public void GetTransformer(StratifiedInliningInfo info)
- {
- Term vcTerm = boogieContext.VCExprToTerm(info.vcexpr, linOptions);
- Term[] paramTerms = info.interfaceExprVars.Select(x => boogieContext.VCExprToTerm(x, linOptions)).ToArray();
- var relParams = new List<FuncDecl>();
- var nodeParams = new List<RPFP.Node>();
- var memo = new TermDict< Term>();
- var done = new Dictionary<Term,Term>(); // note this hashes on equality, not reference!
- vcTerm = CollectParamsRec(memo, vcTerm, relParams, nodeParams,done);
- // var ops = new Util.ContextOps(ctx);
- // var foo = ops.simplify_lhs(vcTerm);
- // vcTerm = foo.Item1;
- info.F = rpfp.CreateTransformer(relParams.ToArray(), paramTerms, vcTerm);
- info.edge = rpfp.CreateEdge(info.node, info.F, nodeParams.ToArray());
- rpfp.edges.Add(info.edge);
- // TODO labels[info.edge.number] = foo.Item2;
- }
-
- public RPFP.Node GetNodeOfImpl(Implementation/*!*/ impl)
- {
- return implName2StratifiedInliningInfo[impl.Name].node;
- }
-
- public class CyclicLiveVariableAnalysis : Microsoft.Boogie.LiveVariableAnalysis
- {
- public new static void ComputeLiveVariables(Implementation impl)
- {
-
- bool some_change = true;
- List<Block> sortedNodes = new List<Block>();
- foreach (var block in impl.Blocks)
- {
- sortedNodes.Add(block);
- }
- sortedNodes.Reverse();
-
- while (some_change)
- {
- some_change = false;
- foreach (Block/*!*/ block in sortedNodes)
- {
- Contract.Assert(block != null);
- HashSet<Variable/*!*/>/*!*/ liveVarsAfter = new HashSet<Variable/*!*/>();
- if (block.TransferCmd is GotoCmd)
- {
- GotoCmd gotoCmd = (GotoCmd)block.TransferCmd;
- if (gotoCmd.labelTargets != null)
- {
- foreach (Block/*!*/ succ in gotoCmd.labelTargets)
- {
- Contract.Assert(succ != null);
- if (succ.liveVarsBefore != null)
- liveVarsAfter.UnionWith(succ.liveVarsBefore);
- }
- }
- }
-
- List<Cmd> cmds = block.Cmds;
- int len = cmds.Count;
- for (int i = len - 1; i >= 0; i--)
- {
- if (cmds[i] is CallCmd)
- {
- Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc);
- if (InterProcGenKill.HasSummary(proc.Name))
- {
- liveVarsAfter =
- InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter);
- continue;
- }
- }
- Propagate(cmds[i], liveVarsAfter);
- }
-
- if (block.liveVarsBefore == null)
- block.liveVarsBefore = new HashSet<Variable>();
- if (!liveVarsAfter.IsSubsetOf(block.liveVarsBefore))
- {
- block.liveVarsBefore = liveVarsAfter;
- some_change = true;
- }
- }
- }
- }
- }
-
- public void Generate()
- {
-
- var oldDagOption = CommandLineOptions.Clo.vcVariety;
- CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Dag;
-
- // MarkAllFunctionImplementationsInline(); // This is for SMACK, which goes crazy with functions
-
- // Run live variable analysis (TODO: should this be here?)
-#if false
- if (CommandLineOptions.Clo.LiveVariableAnalysis == 2)
- {
- Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program);
- }
-#endif
-
- #region In Boogie mode, annotate the program
- if (mode == Mode.Boogie)
- {
-
- // find the name of the main procedure
- main_proc_name = null; // default in case no entry point defined
- foreach (var impl in program.Implementations)
- {
- if (QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- main_proc_name = impl.Proc.Name;
- }
- if (main_proc_name == null)
- {
- foreach (var impl in program.Implementations)
- {
- if (impl.Proc.Name == "main" || impl.Proc.Name.EndsWith(".main"))
- main_proc_name = impl.Proc.Name;
- }
- }
- if (main_proc_name == null)
- main_proc_name = "main";
-
- if (style == AnnotationStyle.Flat)
- {
- InlineAll();
- Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program);
- foreach (var impl in program.Implementations)
- {
- if (main_proc_name == impl.Proc.Name)
- {
- Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl);
- CyclicLiveVariableAnalysis.ComputeLiveVariables(impl);
- AnnotateLoops(impl, boogieContext);
- }
- }
- }
- else
- {
-
- if (style == AnnotationStyle.Procedure || style == AnnotationStyle.Call)
- {
- foreach (var impl in program.Implementations)
- {
- if (!QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))
- AnnotateProcRequires(impl.Proc, impl, boogieContext);
- AnnotateProcEnsures(impl.Proc, impl, boogieContext);
- }
- if (style == AnnotationStyle.Call)
- {
-
- }
- }
-
- // must do this after annotating procedures, else calls
- // will be prematurely desugared
-
- foreach (var impl in program.Implementations)
- {
- Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl);
- CyclicLiveVariableAnalysis.ComputeLiveVariables(impl);
- }
-
-
- if (style == AnnotationStyle.Flat || style == AnnotationStyle.Call)
- {
- foreach (var impl in program.Implementations)
- {
- AnnotateLoops(impl, boogieContext);
- }
- }
- if (style == AnnotationStyle.Call)
- {
- Dictionary<string, bool> impls = new Dictionary<string, bool>();
- foreach (var impl in program.Implementations)
- {
- impls.Add(impl.Proc.Name, true);
- }
- foreach (var impl in program.Implementations)
- {
- AnnotateCallSites(impl, boogieContext, impls);
- }
- }
- if (style == AnnotationStyle.Flat)
- InlineAll();
- }
- }
- #endregion
-
- /* Generate the VC's */
- GenerateVCsForStratifiedInlining();
-
- /* Generate the background axioms */
- Term background = ctx.MkTrue(); // TODO boogieContext.VCExprToTerm(boogieContext.Axioms, linOptions);
- rpfp.AssertAxiom(background);
-
- int save_option = CommandLineOptions.Clo.StratifiedInlining; // need this to get funcall labels
- CommandLineOptions.Clo.StratifiedInlining = 1;
-
- /* Create the nodes, indexing procedures by their relational symbols. */
- foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values)
- GenerateVCForStratifiedInlining(program, info, checker);
-
- CommandLineOptions.Clo.StratifiedInlining = save_option;
-
- if (mode == Mode.Boogie)
- {
- // var ops = new Util.ContextOps(ctx);
- var vcs = DualityVCs;
- DualityVCs = new List<Term>();
- foreach (var vc in vcs)
- {
- // var foo = ops.simplify_lhs(vc.GetAppArgs()[0]);
- var foo = vc.GetAppArgs()[0];
- if (!foo.IsFalse())
- DualityVCs.Add(ctx.MkImplies(foo, vc.GetAppArgs()[1]));
- }
-
- rpfp.FromClauses(DualityVCs.ToArray());
- // TODO rpfp.HornClauses = style == AnnotationStyle.Flat;
- }
- else
- {
- /* Generate the edges. */
- foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values)
- GetTransformer(info);
- }
-
- // save some information for debugging purposes
- // TODO rpfp.ls.SetAnnotationInfo(annotationInfo);
-
- CommandLineOptions.Clo.vcVariety = oldDagOption;
- }
-
-
- private class ErrorHandler : ProverInterface.ErrorHandler
- {
- //TODO: anything we need to handle?
- }
-
- Dictionary<int, Dictionary<string, string>> varSubst = null;
-
- /** Check the RPFP, and return a counterexample if there is one. */
-
- public RPFP.LBool Check(ref RPFP.Node cexroot)
- {
- var start = DateTime.Now;
-
- ErrorHandler handler = new ErrorHandler();
- RPFP.Node cex;
- varSubst = new Dictionary<int,Dictionary<string,string>>();
-
-#if false
- int origRecursionBound = CommandLineOptions.Clo.RecursionBound;
- if (CommandLineOptions.Clo.RecursionBound > 0 && extraRecBound != null)
- {
- int maxExtra = 0;
- foreach (string s in extraRecBound.Keys)
- {
- int extra = extraRecBound[s];
- if (extra > maxExtra) maxExtra = extra;
- }
- CommandLineOptions.Clo.RecursionBound += maxExtra;
- }
-#endif
-
- ProverInterface.Outcome outcome =
- checker.TheoremProver.CheckRPFP("name", rpfp, handler, out cex, varSubst, extraRecBound);
- cexroot = cex;
-
-#if false
- CommandLineOptions.Clo.RecursionBound = origRecursionBound;
-#endif
-
- Console.WriteLine("solve: {0}s", (DateTime.Now - start).TotalSeconds);
-
- switch(outcome)
- {
- case ProverInterface.Outcome.Valid:
- return RPFP.LBool.False;
- case ProverInterface.Outcome.Invalid:
- return RPFP.LBool.True;
- default:
- return RPFP.LBool.Undef;
- }
- }
-
- private bool generated = false;
-
- static private Object thisLock = new Object();
-
- public override VC.VCGen.Outcome VerifyImplementation(Implementation impl, VerifierCallback collector)
- {
-
- lock (thisLock)
- {
- Procedure proc = impl.Proc;
-
- // we verify all the impls at once, so we need to execute only once
- // TODO: make sure needToCheck is true only once
- bool needToCheck = false;
- if (mode == Mode.OldCorral)
- needToCheck = proc.FindExprAttribute("inline") == null && !(proc is LoopProcedure);
- else if (mode == Mode.Corral || mode == Mode.Boogie)
- needToCheck = QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint") && !(proc is LoopProcedure);
- else
- needToCheck = impl.Name == main_proc_name;
-
- if (needToCheck)
- {
-
- var start = DateTime.Now;
-
- if (!generated)
- {
- Generate();
- Console.WriteLine("generate: {0}s", (DateTime.Now - start).TotalSeconds);
- generated = true;
- }
-
-
- Console.WriteLine("Verifying {0}...", impl.Name);
-
- RPFP.Node cexroot = null;
- // start = DateTime.Now;
- var checkres = Check(ref cexroot);
- Console.WriteLine("check: {0}s", (DateTime.Now - start).TotalSeconds);
- switch (checkres)
- {
- case RPFP.LBool.True:
- Console.WriteLine("Counterexample found.\n");
- // start = DateTime.Now;
- Counterexample cex = CreateBoogieCounterExample(cexroot.owner, cexroot, impl);
- // cexroot.owner.DisposeDualModel();
- // cex.Print(0); // just for testing
- collector.OnCounterexample(cex, "assertion failure");
- Console.WriteLine("cex: {0}s", (DateTime.Now - start).TotalSeconds);
- ConjecturesToSpecs();
- return VC.ConditionGeneration.Outcome.Errors;
- case RPFP.LBool.False:
- Console.WriteLine("Procedure is correct.");
- FixedPointToSpecs();
- ConjecturesToSpecs();
- return Outcome.Correct;
- case RPFP.LBool.Undef:
- Console.WriteLine("Inconclusive result.");
- ConjecturesToSpecs();
- return Outcome.ReachedBound;
- }
-
- }
-
- return Outcome.Inconclusive;
- }
- }
-
- public void FindLabelsRec(HashSet<Term> memo, Term t, Dictionary<string, Term> res)
- {
- if (memo.Contains(t))
- return;
- if (t.IsLabel())
- {
- string l = t.LabelName();
- if (!res.ContainsKey(l))
- res.Add(l, t.GetAppArgs()[0]);
- }
- if (t.GetKind() == TermKind.App)
- {
- var args = t.GetAppArgs();
- foreach (var a in args)
- FindLabelsRec(memo, a, res);
- } // TODO: handle quantifiers
-
- memo.Add(t);
- }
-
- public void FindLabels()
- {
- labels = new Dictionary<string, Term>();
- foreach(var e in rpfp.edges){
- int id = e.number;
- HashSet<Term> memo = new HashSet<Term>(ReferenceComparer<Term>.Instance);
- FindLabelsRec(memo, e.F.Formula, labels);
- }
- }
-
- public string CodeLabel(Absy code, StratifiedInliningInfo info, string prefix)
- {
- if (info.label2absyInv == null)
- {
- info.label2absyInv = new Dictionary<Absy, string>();
- foreach (int foo in info.label2absy.Keys)
- {
- Absy bar = info.label2absy[foo] as Absy;
- string lbl = foo.ToString();
- info.label2absyInv.Add(bar, lbl);
- }
- }
- if (info.label2absyInv.ContainsKey(code))
- {
- string label = info.label2absyInv[code];
- return prefix+label;
- }
- return null;
- }
-
- public Term CodeLabeledExpr(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
- {
- string label = CodeLabel(code, info, prefix);
-
- if (label != null)
- {
- var res = labels[label];
- return res;
- }
- else return null;
- }
-
- public class LabelNotFound : Exception { };
-
- public bool CodeLabelTrue(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
- {
- string label = CodeLabel(code, info, prefix);
-
- if (label == null)
- throw new LabelNotFound();
- return root.Outgoing.labels.Contains(label);
- }
-
- public bool CodeLabelFalse(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix)
- {
- return CodeLabelTrue(rpfp, root, code, info, prefix);
- }
-
-
- private class StateId
- {
- public RPFP.Edge edge;
- public int capturePoint;
- public StratifiedInliningInfo info;
- public StateId(RPFP.Edge e, int c, StratifiedInliningInfo i)
- {
- edge = e;
- capturePoint = c;
- info = i;
- }
- }
-
-
- public Counterexample CreateBoogieCounterExample(RPFP rpfp, RPFP.Node root, Implementation mainImpl)
- {
- FindLabels();
- var orderedStateIds = new List<StateId>();
- Counterexample newCounterexample =
- GenerateTrace(rpfp, root, orderedStateIds, mainImpl,true);
- if (CommandLineOptions.Clo.ModelViewFile != null)
- {
- Model m = root.owner.GetBackgroundModel();
- GetModelWithStates(m, root, implName2StratifiedInliningInfo[mainImpl.Name],
- orderedStateIds, varSubst);
- newCounterexample.Model = m;
- newCounterexample.ModelHasStatesAlready = true;
- }
- return newCounterexample;
- }
-
-
-
- private Counterexample GenerateTrace(RPFP rpfp, RPFP.Node root,
- List<StateId> orderedStateIds, Implementation procImpl, bool toplevel)
- {
- Contract.Requires(procImpl != null);
-
- Contract.Assert(!rpfp.Empty(root));
-
-
- var info = implName2StratifiedInliningInfo[procImpl.Name];
- Block entryBlock = cce.NonNull(procImpl.Blocks[0]);
- Contract.Assert(entryBlock != null);
-
- List<Block> trace = new List<Block>();
- trace.Add(entryBlock);
-
- var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
-
- Counterexample newCounterexample =
- GenerateTraceRec(rpfp, root, orderedStateIds, entryBlock, trace, calleeCounterexamples, info, toplevel);
-
- return newCounterexample;
- }
-
- // TODO: this is a bit cheesy. Rather than finding the argument position
- // of a relational term in a transformer by linear search, better to index this
- // somewhere, but where?
- private int TransformerArgPosition(RPFP rpfp, RPFP.Node root, Term expr)
- {
- FuncDecl rel = expr.GetAppDecl();
- string relname = rel.GetDeclName();
- var rps = root.Outgoing.F.RelParams;
- for (int i = 0; i < rps.Length; i++)
- {
- string thisname = rps[i].GetDeclName();
- if (thisname == relname)
- return i;
- }
- return -1;
- }
-
- private bool EvalToFalse(RPFP rpfp, RPFP.Node root, Term expr,StratifiedInliningInfo info){
- Term res = rpfp.Eval(root.Outgoing,expr);
- return res.Equals(ctx.MkTrue());
- }
-
- private Counterexample GenerateTraceRec(
- RPFP rpfp, RPFP.Node root,
- List<StateId> orderedStateIds,
- Block/*!*/ b, List<Block>/*!*/ trace,
- Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples,
- StratifiedInliningInfo info,
- bool toplevel)
- {
- Contract.Requires(b != null);
- Contract.Requires(trace != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
-
- Stack<RPFP.Node> continuation_stack = new Stack<RPFP.Node>();
-
- // If our block is not present, try diving into precondition
- // and push a continuation.
- // TODO: is the precondition always the first child?
- while (!CodeLabelFalse(rpfp, root, b, info, "+"))
- {
- if (root.Outgoing != null && root.Outgoing.Children.Length > 0)
- {
- continuation_stack.Push(root);
- root = root.Outgoing.Children[0];
- }
- else
- {
- // can't find our block
- Contract.Assert(false);
- return null;
- }
- }
-
- // After translation, all potential errors come from asserts.
- while (true)
- {
-
-
- List<Cmd> cmds = b.Cmds;
- TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
- for (int i = 0; i < cmds.Count; i++)
- {
- Cmd cmd = cce.NonNull(cmds[i]);
-
- // Skip if 'cmd' not contained in the trace or not an assert
- if (cmd is AssertCmd)
- {
- bool is_failed_assertion = false;
- if (NoLabels)
- is_failed_assertion = true; // we assume only assertions on
- else
- is_failed_assertion = CodeLabelTrue(rpfp, root, cmd, info, "@");
-
- if (is_failed_assertion)
- {
- if (continuation_stack.Count == 0)
- {
- Counterexample newCounterexample =
- AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, new Microsoft.Boogie.Model(), info.mvInfo,
- boogieContext);
- newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
- return newCounterexample;
- }
- root = continuation_stack.Pop();
- }
- continue;
- }
-
- // Counterexample generation for inlined procedures
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null)
- continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null)
- continue;
- string calleeName = naryExpr.Fun.FunctionName;
- Contract.Assert(calleeName != null);
-
- // what is this crap???
- BinaryOperator binOp = naryExpr.Fun as BinaryOperator;
- if (binOp != null && binOp.Op == BinaryOperator.Opcode.And)
- {
- Expr expr = naryExpr.Args[0];
- NAryExpr mvStateExpr = expr as NAryExpr;
- if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == VC.ModelViewInfo.MVState_FunctionDef.Name)
- {
- LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
- // Debug.Assert(x != null);
- int foo = x.asBigNum.ToInt;
- orderedStateIds.Add(new StateId(root.Outgoing,foo,info));
- }
- }
-
- if (calleeName.EndsWith("_summary"))
- calleeName = calleeName.Substring(0, calleeName.Length - 8);
-
- if (!implName2StratifiedInliningInfo.ContainsKey(calleeName) && !calleeName.EndsWith("_summary"))
- continue;
-
- {
- Term code = CodeLabeledExpr(rpfp, root, cmd, info, "+si_fcall_");
- int pos = TransformerArgPosition(rpfp, root, code);
- if (pos >= 0)
- {
- RPFP.Node callee = root.Outgoing.Children[pos];
- orderedStateIds.Add(new StateId(callee.Outgoing, CALL,info));
- calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
- new CalleeCounterexampleInfo(
- cce.NonNull(GenerateTrace(rpfp, callee, orderedStateIds,
- implName2StratifiedInliningInfo[calleeName].impl, false)),
- new List<object>());
- orderedStateIds.Add(new StateId(root.Outgoing, RETURN,info));
- }
- }
- }
-
- GotoCmd gotoCmd = transferCmd as GotoCmd;
- List<Block> cuts = null;
- if (edgesCut.ContainsKey(b))
- cuts = edgesCut[b];
- b = null;
-
- if (gotoCmd != null)
- {
-
- foreach (Block bb in cce.NonNull(gotoCmd.labelTargets))
- {
- Contract.Assert(bb != null);
- if (CodeLabelFalse(rpfp, root, bb, info, "+"))
- {
- trace.Add(bb);
- b = bb;
- break;
- }
- }
- if (b != null) continue;
- }
- // HACK: we have to try edges that were cut in generating the VC
-
- if (cuts != null)
- foreach (var bb in cuts)
- {
- if (CodeLabelFalse(rpfp, root, bb, info, "+"))
- {
- trace.Add(bb);
- b = bb;
- break;
- }
- }
- if (b != null) continue;
-
- return null;
- }
-
-
- }
-
- public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- // Construct the set of inlined procs in the original program
- var inlinedProcs = new HashSet<string>();
- foreach (var decl in program.TopLevelDeclarations)
- {
- // Implementations
- if (decl is Implementation)
- {
- var impl = decl as Implementation;
- if (!(impl.Proc is LoopProcedure))
- {
- inlinedProcs.Add(impl.Name);
- }
- }
-
- // And recording procedures
- if (decl is Procedure)
- {
- var proc = decl as Procedure;
- if (proc.Name.StartsWith(recordProcName))
- {
- // Debug.Assert(!(decl is LoopProcedure));
- inlinedProcs.Add(proc.Name);
- }
- }
- }
- return extractLoopTraceRec(
- new CalleeCounterexampleInfo(cex, new List<object>()),
- mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
- }
-
- protected override bool elIsLoop(string procname)
- {
- StratifiedInliningInfo info = null;
- if (implName2StratifiedInliningInfo.ContainsKey(procname))
- {
- info = implName2StratifiedInliningInfo[procname];
- }
-
- if (info == null) return false;
-
- var lp = info.impl.Proc as LoopProcedure;
-
- if (lp == null) return false;
- return true;
- }
-
- private void NumberCexEdges(RPFP.Node node, Dictionary<int,RPFP.Edge> map)
- {
- if (node.Outgoing == null)
- return; // shouldn't happen
- RPFP.Edge edge = node.Outgoing;
- map[edge.number] = edge;
- foreach (var c in edge.Children)
- NumberCexEdges(c, map);
- }
-
- private void GetModelWithStates(Model m, RPFP.Node cex, StratifiedInliningInfo mainInfo,
- List<StateId> orderedStateIds,
- Dictionary<int,Dictionary<string,string>> varSubst)
- {
- if (m == null) return;
- var mvInfo = mainInfo.mvInfo;
-
-
- foreach (Variable v in mvInfo.AllVariables)
- {
- m.InitialState.AddBinding(v.Name, GetModelValue(m, v, varSubst[cex.Outgoing.number]));
- }
-
- Dictionary<int, RPFP.Edge> edgeNumbering = new Dictionary<int,RPFP.Edge>();
- NumberCexEdges(cex, edgeNumbering);
-
- int lastCandidate = 0;
- int lastCapturePoint = CALL;
- for (int i = 0; i < orderedStateIds.Count; ++i)
- {
- var s = orderedStateIds[i];
- RPFP.Edge edge = s.edge;
- int candidate = edge.number;
- int capturePoint = s.capturePoint;
- Dictionary<string, string> subst = varSubst[candidate];
-
- string implName = edge.Parent.Name.GetDeclName();
- var info = s.info.mvInfo;
-
- if (capturePoint == CALL || capturePoint == RETURN)
- {
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- continue;
- }
-
- Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count);
- VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint];
- var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate)
- ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>();
- var cs = m.MkState(map.Description);
-
- foreach (Variable v in info.AllVariables)
- {
- var e = (Expr)map.IncarnationMap[v];
-
- if (e == null)
- {
- if (lastCapturePoint == CALL || lastCapturePoint == RETURN)
- {
- cs.AddBinding(v.Name, GetModelValue(m, v, subst));
- }
- continue;
- }
-
- if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables
-
- Model.Element elt;
- if (e is IdentifierExpr)
- {
- IdentifierExpr ide = (IdentifierExpr)e;
- elt = GetModelValue(m, ide.Decl, subst);
- }
- else if (e is LiteralExpr)
- {
- LiteralExpr lit = (LiteralExpr)e;
- elt = m.MkElement(lit.Val.ToString());
- }
- else
- {
- Contract.Assume(false);
- elt = m.MkFunc(e.ToString(), 0).GetConstant();
- }
- cs.AddBinding(v.Name, elt);
- }
-
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- }
-
- return;
- }
-
-
- public readonly static int CALL = -1;
- public readonly static int RETURN = -2;
-
- private Model.Element GetModelValue(Model m, Variable v, Dictionary<string,string> subst)
- {
- // first, get the unique name
- string uniqueName;
-
- VCExprVar vvar = boogieContext.BoogieExprTranslator.TryLookupVariable(v);
-
- uniqueName = v.Name;
-
- if(subst.ContainsKey(uniqueName))
- return m.MkElement(subst[uniqueName]);
- return m.MkFunc("@undefined", 0).GetConstant();
- }
-
- class InternalError : Exception {
- }
-
-
- private BinaryOperator.Opcode VCOpToOp (VCExprOp op)
- {
- if (op == VCExpressionGenerator.AddIOp)
- return BinaryOperator.Opcode.Add;
- if (op == VCExpressionGenerator.SubIOp)
- return BinaryOperator.Opcode.Sub;
- if (op == VCExpressionGenerator.MulIOp)
- return BinaryOperator.Opcode.Mul;
- if (op == VCExpressionGenerator.DivIOp)
- return BinaryOperator.Opcode.Div;
- if (op == VCExpressionGenerator.EqOp)
- return BinaryOperator.Opcode.Eq;
- if (op == VCExpressionGenerator.LeOp)
- return BinaryOperator.Opcode.Le;
- if (op == VCExpressionGenerator.LtOp)
- return BinaryOperator.Opcode.Lt;
- if (op == VCExpressionGenerator.GeOp)
- return BinaryOperator.Opcode.Ge;
- if (op == VCExpressionGenerator.GtOp)
- return BinaryOperator.Opcode.Gt;
- if (op == VCExpressionGenerator.AndOp)
- return BinaryOperator.Opcode.And;
- if (op == VCExpressionGenerator.OrOp)
- return BinaryOperator.Opcode.Or;
- throw new InternalError();
- }
-
- private Expr MakeBinary (BinaryOperator.Opcode op, List<Expr> args)
- {
- if(args.Count == 0){
- // with zero args we need the identity of the op
- switch(op){
- case BinaryOperator.Opcode.And:
- return Expr.True;
- case BinaryOperator.Opcode.Or:
- return Expr.False;
- case BinaryOperator.Opcode.Add:
- return new LiteralExpr(Token.NoToken,Microsoft.Basetypes.BigNum.ZERO);
- default:
- throw new InternalError();
- }
- }
- var temp = args[0];
- for(int i = 1; i < args.Count; i++)
- temp = Expr.Binary(Token.NoToken,op,temp,args[i]);
- return temp;
- }
-
- private Variable MakeVar(VCExprVar v){
- var foo = new TypedIdent(Token.NoToken,v.Name.ToString(),v.Type);
- return new BoundVariable(Token.NoToken,foo);
- }
-
- private Expr VCExprToExpr (VCExpr e, Dictionary<VCExpr,Expr> bound)
- {
- if (e is VCExprVar) {
- if(bound.ContainsKey(e))
- return bound[e];
- return Expr.Ident(MakeVar(e as VCExprVar)); // TODO: this isn't right
- }
- if (e is VCExprIntLit) {
- var n = e as VCExprIntLit;
- return new LiteralExpr(Token.NoToken,n.Val);
- }
- if (e is VCExprNAry) {
- var f = e as VCExprNAry;
- var args = new List<Expr>();
- for(int i = 0; i < f.Arity; i++){
- args.Add (VCExprToExpr (f[i],bound));
- }
-
- if(f.Op == VCExpressionGenerator.NotOp)
- return Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, args[0]);
-
- if(f.Op == VCExpressionGenerator.IfThenElseOp)
- return new NAryExpr(Token.NoToken,new IfThenElse(Token.NoToken),args);
-
- if(f.Op is VCExprSelectOp){
- var idx = new List<Expr>();
- idx.Add(args[1]);
- return Expr.Select(args[0],idx);
- }
-
- if(f.Op is VCExprStoreOp){
- var idx = new List<Expr>();
- idx.Add(args[1]);
- return Expr.Store(args[0],idx,args[2]);
- }
-
- if (f.Op is VCExprBoogieFunctionOp)
- {
- return new NAryExpr(Token.NoToken,
- new FunctionCall((f.Op as VCExprBoogieFunctionOp).Func), args);
- }
-
- var op = VCOpToOp (f.Op);
- return MakeBinary(op,args);
- }
-
- if(e is VCExprQuantifier) {
- var f = e as VCExprQuantifier;
- var vs = new List<Variable>();
- var new_bound = new Dictionary<VCExpr,Expr>(bound);
- foreach(var v in f.BoundVars){
- var ve = MakeVar(v);
- vs.Add(ve);
- new_bound.Add (v,Expr.Ident (ve));
- }
- var bd = VCExprToExpr(f.Body,new_bound);
- if(f.Quan == Quantifier.EX)
- return new ExistsExpr(Token.NoToken,vs,bd);
- else
- return new ForallExpr(Token.NoToken,vs,bd);
- }
- if (e == VCExpressionGenerator.True) {
- return Expr.True;
- }
- if (e == VCExpressionGenerator.False) {
- return Expr.False;
- }
- if (e is VCExprLet) {
-
- }
-
- throw new InternalError();
- }
-
-
- }
-
-
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Diagnostics.Contracts; +using Microsoft.Boogie; +using Microsoft.Boogie.VCExprAST; + + +using Term = Microsoft.Boogie.VCExprAST.VCExpr; +using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp; +using Sort = Microsoft.Boogie.Type; +using Microsoft.Boogie.ExprExtensions; + + +namespace Microsoft.Boogie +{ + public class FixedpointVC : VC.VCGen + { + + public class AnnotationInfo + { + public enum AnnotationType { LoopInvariant, ProcedureSummary }; + public string filename; + public int lineno; + public string[] argnames; + public AnnotationType type; + }; + + static bool NoLabels = false; + + // options + bool largeblock = false; + + public bool SetOption(string option, string value) + { + if (option == "LargeBlock") + { + largeblock = true; + return true; + } + return false; + } + + Context ctx; + RPFP rpfp; + // Program program; + Microsoft.Boogie.ProverContext boogieContext; + Microsoft.Boogie.VCExpressionGenerator gen; + public readonly static string recordProcName = "boogie_si_record"; // TODO: this really needed? + private Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo + = new Dictionary<string, StratifiedInliningInfo>(); + Checker checker; + // Microsoft.Boogie.Z3.Z3InstanceOptions options = new Microsoft.Boogie.Z3.Z3InstanceOptions(); // TODO: what? + LineariserOptions linOptions; + Dictionary<FuncDecl, StratifiedInliningInfo> relationToProc = new Dictionary<FuncDecl, StratifiedInliningInfo>(); + Dictionary<string, Term> labels = new Dictionary<string, Term> (); + List<Term> DualityVCs = new List<Term>(); + Dictionary<string, bool> summaries = new Dictionary<string, bool>(); + Dictionary<Block, List<Block>> edgesCut = new Dictionary<Block, List<Block>>(); + string main_proc_name = "main"; + Dictionary<string, int> extraRecBound = null; + + + public enum Mode { Corral, OldCorral, Boogie}; + public enum AnnotationStyle { Flat, Procedure, Call }; + + Mode mode; + AnnotationStyle style; + + private static Checker old_checker = null; + + public static void CleanUp() + { + if (old_checker != null) + { + old_checker.Close(); + old_checker = null; + } + } + + public FixedpointVC( Program _program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Dictionary<string,int> _extraRecBound = null) + : base(_program, logFilePath, appendLogFile, checkers) + { + switch (CommandLineOptions.Clo.FixedPointMode) + { + case CommandLineOptions.FixedPointInferenceMode.Corral: + mode = Mode.Corral; + style = AnnotationStyle.Procedure; + break; + case CommandLineOptions.FixedPointInferenceMode.OldCorral: + mode = Mode.OldCorral; + style = AnnotationStyle.Procedure; + break; + case CommandLineOptions.FixedPointInferenceMode.Flat: + mode = Mode.Boogie; + style = AnnotationStyle.Flat; + break; + case CommandLineOptions.FixedPointInferenceMode.Procedure: + mode = Mode.Boogie; + style = AnnotationStyle.Procedure; + break; + case CommandLineOptions.FixedPointInferenceMode.Call: + mode = Mode.Boogie; + style = AnnotationStyle.Call; + break; + } + ctx = new Context(); // TODO is this right? + rpfp = new RPFP(RPFP.CreateLogicSolver(ctx)); + program = _program; + gen = ctx; + if(old_checker == null) + checker = new Checker(this, program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime, null); + else { + checker = old_checker; + checker.RetargetWithoutReset(program,checker.TheoremProver.Context); + } + old_checker = checker; + boogieContext = checker.TheoremProver.Context; + linOptions = null; // new Microsoft.Boogie.Z3.Z3LineariserOptions(false, options, new List<VCExprVar>()); + extraRecBound = _extraRecBound; + } + + Dictionary<string, AnnotationInfo> annotationInfo = new Dictionary<string, AnnotationInfo>(); + + public void AnnotateLoops(Implementation impl, ProverContext ctxt) + { + Contract.Requires(impl != null); + + CurrentLocalVariables = impl.LocVars; + variable2SequenceNumber = new Dictionary<Variable, int>(); + incarnationOriginMap = new Dictionary<Incarnation, Absy>(); + + ResetPredecessors(impl.Blocks); + + #region Create the graph by adding the source node and each edge + GraphUtil.Graph<Block> g = Program.GraphFromImpl(impl); + #endregion + + //Graph<Block> g = program.ProcessLoops(impl); + + g.ComputeLoops(); // this is the call that does all of the processing + if (!g.Reducible) + { + throw new System.Exception("Irreducible flow graphs are unsupported."); + } + + #region add a symbolic annoation to every loop head + foreach (Block header in cce.NonNull(g.Headers)) + AnnotateBlock(impl, ctxt, header); + #endregion + } + + private void AnnotateCallSites(Implementation impl, ProverContext ctxt, Dictionary<string, bool> impls){ + foreach (var b in impl.Blocks) + { + foreach (var cmd in b.Cmds) + { + if (cmd is CallCmd) + { + string name = (cmd as CallCmd).callee; + if(impls.ContainsKey(name)) + goto annotate; + } + } + continue; + annotate: + AnnotateBlock(impl, ctxt, b); + } + } + + + private void AnnotateBlock(Implementation impl, ProverContext ctxt, Block header) + { + Contract.Assert(header != null); + + string name = impl.Name + "_" + header.Label + "_invar"; + if (annotationInfo.ContainsKey(name)) + return; + + // collect the variables needed in the invariant + List<Expr> exprs = new List<Expr>(); + List<Variable> vars = new List<Variable>(); + List<string> names = new List<string>(); + + if (style == AnnotationStyle.Flat) + { + // in flat mode, all live globals should be in live set +#if false + foreach (Variable v in program.GlobalVariables) + { + vars.Add(v); + names.Add(v.ToString()); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + } +#endif + foreach (Variable v in /* impl.LocVars */ header.liveVarsBefore) + { + if (!(v is BoundVariable)) + { + vars.Add(v); + names.Add(v.ToString()); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + } + } + } + else + { + foreach (Variable v in program.GlobalVariables) + { + vars.Add(v); + names.Add("@old_" + v.ToString()); + exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v))); + } + foreach (IdentifierExpr ie in impl.Proc.Modifies) + { + if (ie.Decl == null) + continue; + vars.Add(ie.Decl); + names.Add(ie.Decl.ToString()); + exprs.Add(ie); + } + foreach (Variable v in impl.Proc.InParams) + { + Contract.Assert(v != null); + vars.Add(v); + names.Add("@old_" + v.ToString()); + exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v))); + } + foreach (Variable v in impl.LocVars) + { + vars.Add(v); + names.Add(v.ToString()); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + } + } + + TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool); + Contract.Assert(ti != null); + Formal returnVar = new Formal(Token.NoToken, ti, false); + Contract.Assert(returnVar != null); + var function = new Function(Token.NoToken, name, vars, returnVar); + ctxt.DeclareFunction(function, ""); + + Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs); + var invarAssertion = new AssertCmd(Token.NoToken, invarExpr); + List<Cmd> newCmds = new List<Cmd>(); + newCmds.Add(invarAssertion); + + // make a record in annotationInfo; + var info = new AnnotationInfo(); + info.filename = header.tok.filename; + info.lineno = header.Line; + info.argnames = names.ToArray(); + info.type = AnnotationInfo.AnnotationType.LoopInvariant; + annotationInfo.Add(name, info); + // get file and line info from havoc, if there is... + if (header.Cmds.Count > 0) + { + PredicateCmd bif = header.Cmds[0] as PredicateCmd; + if (bif != null) + { + string foo = QKeyValue.FindStringAttribute(bif.Attributes, "sourcefile"); + if (foo != null) + info.filename = foo; + int bar = QKeyValue.FindIntAttribute(bif.Attributes, "sourceline", -1); + if (bar != -1) + info.lineno = bar; + } + } + var thing = header; + foreach (Cmd c in header.Cmds) + { + newCmds.Add(c); + } + header.Cmds = newCmds; + } + +#if true + public void AnnotateProcRequires(Procedure proc, Implementation impl, ProverContext ctxt) + { + Contract.Requires(impl != null); + + CurrentLocalVariables = impl.LocVars; + + // collect the variables needed in the invariant + List<Expr> exprs = new List<Expr>(); + List<Variable> vars = new List<Variable>(); + List<string> names = new List<string>(); + + foreach (Variable v in program.GlobalVariables) + { + vars.Add(v); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + names.Add(v.Name); + } + foreach (Variable v in proc.InParams) + { + Contract.Assert(v != null); + vars.Add(v); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + names.Add(v.Name); + } + string name = impl.Name + "_precond"; + TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool); + Contract.Assert(ti != null); + Formal returnVar = new Formal(Token.NoToken, ti, false); + Contract.Assert(returnVar != null); + var function = new Function(Token.NoToken, name, vars, returnVar); + ctxt.DeclareFunction(function, ""); + + Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs); + + proc.Requires.Add(new Requires(Token.NoToken, false, invarExpr, "", null)); + + var info = new AnnotationInfo(); + info.filename = proc.tok.filename; + info.lineno = proc.Line; + info.argnames = names.ToArray(); + info.type = AnnotationInfo.AnnotationType.LoopInvariant; + annotationInfo.Add(name, info); + } + + public void AnnotateProcEnsures(Procedure proc, Implementation impl, ProverContext ctxt) + { + Contract.Requires(impl != null); + + CurrentLocalVariables = impl.LocVars; + + // collect the variables needed in the invariant + List<Expr> exprs = new List<Expr>(); + List<Variable> vars = new List<Variable>(); + List<string> names = new List<string>(); + + foreach (Variable v in program.GlobalVariables) + { + vars.Add(v); + exprs.Add(new OldExpr(Token.NoToken,new IdentifierExpr(Token.NoToken, v))); + names.Add(v.Name); + } + foreach (Variable v in proc.InParams) + { + Contract.Assert(v != null); + vars.Add(v); + exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v))); + names.Add(v.Name); + } + foreach (IdentifierExpr ie in proc.Modifies) + { + if (ie.Decl == null) + continue; + vars.Add(ie.Decl); + exprs.Add(ie); + names.Add(ie.Decl.Name + "_out"); + } + foreach (Variable v in proc.OutParams) + { + Contract.Assert(v != null); + vars.Add(v); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + names.Add(v.Name); + } + string name = impl.Name + "_summary"; + summaries.Add(name, true); + TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool); + Contract.Assert(ti != null); + Formal returnVar = new Formal(Token.NoToken, ti, false); + Contract.Assert(returnVar != null); + var function = new Function(Token.NoToken, name, vars, returnVar); + ctxt.DeclareFunction(function, ""); + + Expr invarExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs); + + proc.Ensures.Add(new Ensures(Token.NoToken, false, invarExpr, "", null)); + + var info = new AnnotationInfo(); + info.filename = proc.tok.filename; + info.lineno = proc.Line; + info.argnames = names.ToArray(); + info.type = AnnotationInfo.AnnotationType.ProcedureSummary; + annotationInfo.Add(name, info); + } +#endif + + void MarkAllFunctionImplementationsInline() + { + foreach (var func in program.Functions) + { + if (func.Body == null && func.DefinitionAxiom != null) + { + var def = func.DefinitionAxiom.Expr as QuantifierExpr; + var bod = def.Body as NAryExpr; + func.Body = bod.Args[1]; + func.DefinitionAxiom = null; + } + if (func.Body != null) + if (func.FindExprAttribute("inline") == null) + func.AddAttribute("inline", Expr.Literal(100)); + } + } + + void InlineAll() + { + foreach (var impl in program.Implementations) + { + impl.OriginalBlocks = impl.Blocks; + impl.OriginalLocVars = impl.LocVars; + if(impl.Name != main_proc_name) + if(impl.FindExprAttribute("inline") == null) + impl.AddAttribute("inline", Expr.Literal(100)); + } + foreach (var impl in program.Implementations) + { + if (!impl.SkipVerification) + { + Inliner.ProcessImplementation(program, impl); + } + } + foreach (var impl in program.Implementations) + { + impl.OriginalBlocks = null; + impl.OriginalLocVars = null; + } + } + + public class LazyInliningInfo + { + [ContractInvariantMethod] + void ObjectInvariant() + { + Contract.Invariant(impl != null); + Contract.Invariant(function != null); + Contract.Invariant(controlFlowVariable != null); + Contract.Invariant(assertExpr != null); + Contract.Invariant(cce.NonNullElements(interfaceVars)); + Contract.Invariant(incarnationOriginMap == null || cce.NonNullDictionaryAndValues(incarnationOriginMap)); + } + + public Implementation impl; + public int uniqueId; + public Function function; + public Variable controlFlowVariable; + public List<Variable> interfaceVars; + public List<List<Variable>> interfaceVarCopies; + public Expr assertExpr; + public VCExpr vcexpr; + public List<VCExprVar> privateVars; + public Dictionary<Incarnation, Absy> incarnationOriginMap; + public Hashtable /*Variable->Expr*/ exitIncarnationMap; + public Hashtable /*GotoCmd->returnCmd*/ gotoCmdOrigins; + public Dictionary<int, Absy> label2absy; + public VC.ModelViewInfo mvInfo; + + public Dictionary<Block, VCExprVar> reachVars; + public List<VCExprLetBinding> reachVarBindings; + public Variable inputErrorVariable; + public Variable outputErrorVariable; + + + + public LazyInliningInfo(Implementation impl, Program program, ProverContext ctxt, int uniqueId, GlobalVariable errorVariable) + { + Contract.Requires(impl != null); + Contract.Requires(program != null); + Procedure proc = cce.NonNull(impl.Proc); + + this.impl = impl; + this.uniqueId = uniqueId; + this.controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "cfc", Microsoft.Boogie.Type.Int)); + impl.LocVars.Add(controlFlowVariable); + + List<Variable> interfaceVars = new List<Variable>(); + Expr assertExpr = new LiteralExpr(Token.NoToken, true); + Contract.Assert(assertExpr != null); + // InParams must be obtained from impl and not proc + foreach (Variable v in impl.InParams) + { + Contract.Assert(v != null); + interfaceVars.Add(v); + } + // OutParams must be obtained from impl and not proc + foreach (Variable v in impl.OutParams) + { + Contract.Assert(v != null); + Constant c = new Constant(Token.NoToken, + new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type)); + interfaceVars.Add(c); + Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v)); + assertExpr = Expr.And(assertExpr, eqExpr); + } + foreach (Variable v in program.GlobalVariables) + { + Contract.Assert(v != null); + interfaceVars.Add(v); + if (v.Name == "error") + inputErrorVariable = v; + } + if (errorVariable != null) + { + proc.Modifies.Add(new IdentifierExpr(Token.NoToken, errorVariable)); + } + foreach (IdentifierExpr e in proc.Modifies) + { + Contract.Assert(e != null); + if (e.Decl == null) + continue; + Variable v = e.Decl; + Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type)); + interfaceVars.Add(c); + if (v.Name == "error") + { + outputErrorVariable = c; + continue; + } + Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v)); + assertExpr = Expr.And(assertExpr, eqExpr); + } + + this.interfaceVars = interfaceVars; + this.assertExpr = Expr.Not(assertExpr); + List<Variable> functionInterfaceVars = new List<Variable>(); + foreach (Variable v in interfaceVars) + { + Contract.Assert(v != null); + functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, v.Name, v.TypedIdent.Type), true)); + } + TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool); + Contract.Assert(ti != null); + Formal returnVar = new Formal(Token.NoToken, ti, false); + Contract.Assert(returnVar != null); + this.function = new Function(Token.NoToken, proc.Name, functionInterfaceVars, returnVar); + ctxt.DeclareFunction(this.function, ""); + + interfaceVarCopies = new List<List<Variable>>(); + int temp = 0; + for (int i = 0; i < /* CommandLineOptions.Clo.ProcedureCopyBound */ 0; i++) + { + interfaceVarCopies.Add(new List<Variable>()); + foreach (Variable v in interfaceVars) + { + Constant constant = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, v.Name + temp++, v.TypedIdent.Type)); + interfaceVarCopies[i].Add(constant); + //program.AddTopLevelDeclaration(constant); + } + } + } + } + + public class StratifiedInliningInfo : LazyInliningInfo + { + [ContractInvariantMethod] + void ObjectInvariant() + { + Contract.Invariant(cce.NonNullElements(privateVars)); + Contract.Invariant(cce.NonNullElements(interfaceExprVars)); + Contract.Invariant(cce.NonNullElements(interfaceExprVars)); + } + + // public StratifiedVCGenBase vcgen; + //public Implementation impl; + //public Program program; + //public ProverContext ctxt; + //public int uniqueid; + //public Function function; + //public Variable controlFlowVariable; + //public Expr assertExpr; + //public VCExpr vcexpr; + //public List<VCExprVar> interfaceExprVars; + //public List<VCExprVar> privateExprVars; + //public Dictionary<int, Absy> label2absy; + //public VC.ModelViewInfo mvInfo; + //public Dictionary<Block, List<CallSite>> callSites; + //public Dictionary<Block, List<CallSite>> recordProcCallSites; + //public IEnumerable<Block> sortedBlocks; + //public bool initialized { get; private set; } + + + public List<VCExprVar> interfaceExprVars; + // public List<VCExprVar> privateVars; + public VCExpr funcExpr; + public VCExpr falseExpr; + public RPFP.Transformer F; + public RPFP.Node node; + public RPFP.Edge edge; + public bool isMain = false; + public Dictionary<Absy, string> label2absyInv; + public ProverContext ctxt; + public Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/(); + public List<VCExprLetBinding> bindings = new List<VCExprLetBinding>(); + + public StratifiedInliningInfo(Implementation _impl, Program _program, ProverContext _ctxt, int _uniqueid) + : base(_impl,_program,_ctxt,_uniqueid,null){ + Contract.Requires(_impl != null); + Contract.Requires(_program != null); + privateVars = new List<VCExprVar>(); + interfaceExprVars = new List<VCExprVar>(); + ctxt = _ctxt; + } + + } + + protected override void addExitAssert(string implName, Block exitBlock) + { + if (implName2StratifiedInliningInfo != null + && implName2StratifiedInliningInfo.ContainsKey(implName) + && !implName2StratifiedInliningInfo[implName].isMain) + { + if (mode == Mode.Boogie) return; + Expr assertExpr = implName2StratifiedInliningInfo[implName].assertExpr; + Contract.Assert(assertExpr != null); + exitBlock.Cmds.Add(new AssertCmd(Token.NoToken, assertExpr)); + } + } + +#if false + protected override void storeIncarnationMaps(string implName, Hashtable exitIncarnationMap) + { + if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName)) + { + StratifiedInliningInfo info = implName2StratifiedInliningInfo[implName]; + Contract.Assert(info != null); + info.exitIncarnationMap = exitIncarnationMap; + info.incarnationOriginMap = this.incarnationOriginMap; + } + } +#endif + + public void GenerateVCsForStratifiedInlining() + { + Contract.Requires(program != null); + foreach (var impl in program.Implementations) + { + Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy"); + + Procedure proc = cce.NonNull(impl.Proc); + + { + StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId()); + implName2StratifiedInliningInfo[impl.Name] = info; + // We don't need controlFlowVariable for stratified Inlining + //impl.LocVars.Add(info.controlFlowVariable); + List<Expr> exprs = new List<Expr>(); + + if (mode != Mode.Boogie && QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint")) + { + proc.Ensures.Add(new Ensures(Token.NoToken, true, Microsoft.Boogie.Expr.False, "", null)); + info.assertExpr = Microsoft.Boogie.Expr.False; + // info.isMain = true; + } + else if (mode == Mode.Corral || proc.FindExprAttribute("inline") != null || proc is LoopProcedure) + { + foreach (Variable v in proc.InParams) + { + Contract.Assert(v != null); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + } + foreach (Variable v in proc.OutParams) + { + Contract.Assert(v != null); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + } + foreach (Variable v in program.GlobalVariables) + { + Contract.Assert(v != null); + exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v))); + } + foreach (IdentifierExpr ie in proc.Modifies) + { + Contract.Assert(ie != null); + if (ie.Decl == null) + continue; + exprs.Add(ie); + } + Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs); +#if true + if(mode == Mode.Corral || mode == Mode.OldCorral) + proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null))); +#endif + } + else // not marked "inline" must be main + { + Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(info.function), exprs); + info.isMain = true; + } + } + } + + if (mode == Mode.Boogie) return; + + foreach (var proc in program.Procedures) + { + if (!proc.Name.StartsWith(recordProcName)) continue; + Contract.Assert(proc.InParams.Count == 1); + + // Make a new function + TypedIdent ti = new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool); + Contract.Assert(ti != null); + Formal returnVar = new Formal(Token.NoToken, ti, false); + Contract.Assert(returnVar != null); + + // Get record type + var argtype = proc.InParams[0].TypedIdent.Type; + + var ins = new List<Variable>(); + ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true)); + + var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar); + boogieContext.DeclareFunction(recordFunc, ""); + + var exprs = new List<Expr>(); + exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0])); + + Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs); + proc.Ensures.Add(new Ensures(true, freePostExpr)); + } + } + + private void FixedPointToSpecs(){ + + if(mode != Mode.Corral || CommandLineOptions.Clo.PrintFixedPoint == null) + return; // not implemented for other annotation modes yet + + var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintFixedPoint, /*pretty=*/ false); + Dictionary<string, RPFP.Node> pmap = new Dictionary<string,RPFP.Node> (); + + foreach (var node in rpfp.nodes) + pmap.Add ((node.Name as VCExprBoogieFunctionOp).Func.Name, node); + + foreach (var impl in program.Implementations) + { + Contract.Assert(!impl.Name.StartsWith(recordProcName), "Not allowed to have an implementation for this guy"); + + Procedure proc = cce.NonNull(impl.Proc); + + { + StratifiedInliningInfo info = new StratifiedInliningInfo(impl, program, boogieContext, QuantifierExpr.GetNextSkolemId()); + implName2StratifiedInliningInfo[impl.Name] = info; + // We don't need controlFlowVariable for stratified Inlining + //impl.LocVars.Add(info.controlFlowVariable); + List<Expr> exprs = new List<Expr>(); + + { + if (pmap.ContainsKey(impl.Name)) + { + RPFP.Node node = pmap[impl.Name]; + var annot = node.Annotation; + EmitProcSpec(twr, proc, info, annot); + } + } + } + } + twr.Close (); + } + + private void EmitProcSpec(TokenTextWriter twr, Procedure proc, StratifiedInliningInfo info, RPFP.Transformer annot) + { + // last ensures clause will be the symbolic one + if (!info.isMain) + { + var ens = proc.Ensures[proc.Ensures.Count - 1]; + if (ens.Condition != Expr.False) // this is main + { + var postExpr = ens.Condition as NAryExpr; + var args = postExpr.Args; + + var ind = annot.IndParams; + var bound = new Dictionary<VCExpr, Expr>(); + for (int i = 0; i < args.Count; i++) + { + bound[ind[i]] = args[i]; + } + var new_ens_cond = VCExprToExpr(annot.Formula, bound); + if (new_ens_cond != Expr.True) + { + var new_ens = new Ensures(false, new_ens_cond); + var enslist = new List<Ensures>(); + enslist.Add(new_ens); + var new_proc = new Procedure(proc.tok, proc.Name, proc.TypeParameters, proc.InParams, + proc.OutParams, new List<Requires>(), new List<IdentifierExpr>(), enslist); + new_proc.Emit(twr, 0); + } + } + } + } + + static int ConjectureFileCounter = 0; + + private void ConjecturesToSpecs() + { + + if (mode != Mode.Corral || CommandLineOptions.Clo.PrintConjectures == null) + return; // not implemented for other annotation modes yet + + var twr = new TokenTextWriter(CommandLineOptions.Clo.PrintConjectures + "." + ConjectureFileCounter.ToString(), /*pretty=*/ false); + ConjectureFileCounter++; + + foreach (var c in rpfp.conjectures) + { + var name = c.node.Name.GetDeclName(); + if (implName2StratifiedInliningInfo.ContainsKey(name)) + { + StratifiedInliningInfo info = implName2StratifiedInliningInfo[c.node.Name.GetDeclName()]; + Implementation impl = info.impl; + Procedure proc = impl.Proc; + EmitProcSpec(twr, proc, info, c.bound); + } + } + + twr.Close (); + } + + private Term ExtractSmallerVCsRec(TermDict< Term> memo, Term t, List<Term> small, Term lbl = null) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + var kind = t.GetKind(); + if (kind == TermKind.App) + { + var f = t.GetAppDecl(); + if (f.GetKind() == DeclKind.Implies){ + var lhs = t.GetAppArgs()[0]; + if(lhs.GetKind() == TermKind.App){ + var r = lhs.GetAppDecl(); + if (r.GetKind() == DeclKind.And) + { + Term q = t.GetAppArgs()[1]; + var lhsargs = lhs.GetAppArgs(); + for (int i = lhsargs.Length-1; i >= 0; --i) + { + q = ctx.MkImplies(lhsargs[i], q); + } + res = ExtractSmallerVCsRec(memo, q, small,lbl); + goto done; + } + if (r.GetKind() == DeclKind.Label) + { + var arg = lhs; + arg = lhs.GetAppArgs()[0]; + if (!(arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted)) + goto normal; + if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant)) + goto normal; + var sm = ctx.MkImplies(lhs, ExtractSmallerVCsRec(memo, t.GetAppArgs()[1], small)); + if (lbl != null) + sm = ctx.MkImplies(lbl, sm); + small.Add(sm); + res = ctx.MkTrue(); + goto done; + } + if (r.GetKind() == DeclKind.Uninterpreted) + { + var arg = lhs; + if (!(annotationInfo.ContainsKey(arg.GetAppDecl().GetDeclName()) && annotationInfo[arg.GetAppDecl().GetDeclName()].type == AnnotationInfo.AnnotationType.LoopInvariant)) + goto normal; + var sm = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small)); + if (lbl != null) + sm = ctx.MkImplies(lbl, sm); + small.Add(sm); + res = ctx.MkTrue(); + goto done; + } + } + normal: + Term newlbl = null; + if (lhs.IsLabel() && lhs.GetAppArgs()[0] == ctx.MkTrue()) + newlbl = lhs; + res = ctx.MkImplies(lhs,ExtractSmallerVCsRec(memo,t.GetAppArgs()[1],small,newlbl)); + } + else if (f.GetKind() == DeclKind.And) + { + res = ctx.MkApp(f,t.GetAppArgs().Select(x => ExtractSmallerVCsRec(memo, x, small)).ToArray()); + } + else + res = t; + } + else + res = t; + done: + memo.Add(t, res); + return res; + } + + private void ExtractSmallerVCs(Term t, List<Term> small){ + TermDict< Term> memo = new TermDict< Term>(); + Term top = ExtractSmallerVCsRec(memo, t, small); + small.Add(top); + } + + private Dictionary<FuncDecl, int> goalNumbering = new Dictionary<FuncDecl, int>(); + + private Term NormalizeGoal(Term goal, FuncDecl label) + { + var f = goal.GetAppDecl(); + var args = goal.GetAppArgs(); + int number; + if (!goalNumbering.TryGetValue(f, out number)) + { + number = goalNumbering.Count; + goalNumbering.Add(f, number); + } + Term[] tvars = new Term[args.Length]; + Term[] eqns = new Term[args.Length]; + AnnotationInfo info = null; + annotationInfo.TryGetValue(f.GetDeclName(), out info); + for (int i = 0; i < args.Length; i++) + { + string pname = (info == null) ? i.ToString() : info.argnames[i]; + tvars[i] = ctx.MkConst("@a" + number.ToString() + "_" + pname, args[i].GetSort()); + eqns[i] = ctx.MkEq(tvars[i], args[i]); + } + return ctx.MkImplies(ctx.MkAnd(eqns), ctx.MkApp(label, ctx.MkApp(f, tvars))); + } + + private Term MergeGoalsRec(TermDict< Term> memo, Term t) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + var kind = t.GetKind(); + if (kind == TermKind.App) + { + var f = t.GetAppDecl(); + var args = t.GetAppArgs(); + if (f.GetKind() == DeclKind.Implies) + { + res = ctx.MkImplies(args[0], MergeGoalsRec(memo, args[1])); + goto done; + } + else if (f.GetKind() == DeclKind.And) + { + args = args.Select(x => MergeGoalsRec(memo, x)).ToArray(); + res = ctx.MkApp(f, args); + goto done; + } + else if (f.GetKind() == DeclKind.Label) + { + var arg = t.GetAppArgs()[0]; + var r = arg.GetAppDecl(); + if (r.GetKind() == DeclKind.Uninterpreted) + { + res = NormalizeGoal(arg, f); + goto done; + } + } + } + res = t; + done: + memo.Add(t, res); + return res; + } + + private Term MergeGoals(Term t) + { + TermDict< Term> memo = new TermDict< Term>(); + return MergeGoalsRec(memo, t); + } + + private Term CollectGoalsRec(TermDict< Term> memo, Term t, List<Term> goals, List<Term> cruft) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + var kind = t.GetKind(); + if (kind == TermKind.App) + { + var f = t.GetAppDecl(); + if (f.GetKind() == DeclKind.Implies) + { + CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft); + goto done; + } + else if (f.GetKind() == DeclKind.And) + { + foreach (var arg in t.GetAppArgs()) + { + CollectGoalsRec(memo, arg, goals, cruft); + } + goto done; + } + else if (f.GetKind() == DeclKind.Label) + { + var arg = t.GetAppArgs()[0]; + if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted) + { + var r = arg.GetAppDecl(); + if (memo.TryGetValue(arg, out res)) + goto done; + if (!annotationInfo.ContainsKey(r.GetDeclName()) && !arg.GetAppDecl().GetDeclName().StartsWith("_solve_")) + goto done; + goals.Add(arg); + memo.Add(arg, arg); + goto done; + } + else + return CollectGoalsRec(memo, arg, goals, cruft); + } + else if (f.GetKind() == DeclKind.Uninterpreted) + { + string name = f.GetDeclName(); + if (name.StartsWith("_solve_")) + { + if (memo.TryGetValue(t, out res)) + goto done; + goals.Add(t); + memo.Add(t, t); + return t; + } + } + } + // else the goal must be cruft + cruft.Add(t); + done: + res = t; // just to return something + memo.Add(t, res); + return res; + } + + private void CollectGoals(Term t, List<Term> goals, List<Term> cruft) + { + TermDict< Term> memo = new TermDict< Term>(); + CollectGoalsRec(memo, t.GetAppArgs()[1], goals, cruft); + } + + private Term SubstRec(TermDict< Term> memo, Term t) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + var kind = t.GetKind(); + if (kind == TermKind.App) + { + // var f = t.GetAppDecl(); + var args = t.GetAppArgs().Select(x => SubstRec(memo, x)).ToArray(); + res = ctx.CloneApp(t, args); + } + else res = t; + memo.Add(t, res); + return res; + } + + private Term SubstRecGoals(TermDict< Term> memo, Term t) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + var kind = t.GetKind(); + if (kind == TermKind.App) + { + var f = t.GetAppDecl(); + var args = t.GetAppArgs(); + if (f.GetKind() == DeclKind.Implies){ + res = SubstRecGoals(memo, args[1]); + if (res != ctx.MkTrue()) + res = ctx.MkImplies(args[0],res); + goto done; + } + else if (f.GetKind() == DeclKind.And) + { + args = args.Select(x => SubstRecGoals(memo, x)).ToArray(); + args = args.Where(x => x != ctx.MkTrue()).ToArray(); + res = ctx.MkAnd(args); + goto done; + } + else if (f.GetKind() == DeclKind.Label) + { + var arg = t.GetAppArgs()[0]; + if (arg.GetKind() == TermKind.App && arg.GetAppDecl().GetKind() == DeclKind.Uninterpreted) + { + var r = arg.GetAppDecl(); + if (memo.TryGetValue(arg, out res)) + { + if(res != ctx.MkTrue()) + res = ctx.MkApp(f, res); + goto done; + } + } + else + { + res = ctx.MkApp(f, SubstRecGoals(memo, arg)); + goto done; + } + + } + // what's left could be cruft! + if (memo.TryGetValue(t, out res)) + { + goto done; + } + } + res = t; + done: + memo.Add(t, res); + return res; + } + + private void FactorVCs(Term t, List<Term> vcs) + { + List<Term> small = new List<Term>(); + ExtractSmallerVCs(t, small); + foreach (var smm in small) + { + List<Term> goals = new List<Term>(); + List<Term> cruft = new List<Term>(); + var sm = largeblock ? MergeGoals(smm) : smm; + CollectGoals(sm, goals,cruft); + foreach (var goal in goals) + { + TermDict< Term> memo = new TermDict< Term>(); + foreach (var othergoal in goals) + memo.Add(othergoal, othergoal.Equals(goal) ? ctx.MkFalse() : ctx.MkTrue()); + foreach (var thing in cruft) + memo.Add(thing, ctx.MkTrue()); + var vc = SubstRecGoals(memo, sm); + vc = ctx.MkImplies(ctx.MkNot(vc), goal); + vcs.Add(vc); + } + { + TermDict< Term> memo = new TermDict< Term>(); + foreach (var othergoal in goals) + memo.Add(othergoal, ctx.MkTrue()); + var vc = SubstRecGoals(memo, sm); + if (vc != ctx.MkTrue()) + { + vc = ctx.MkImplies(ctx.MkNot(vc), ctx.MkFalse()); + vcs.Add(vc); + } + } + } + } + + + + private void GenerateVCForStratifiedInlining(Program program, StratifiedInliningInfo info, Checker checker) + { + Contract.Requires(program != null); + Contract.Requires(info != null); + Contract.Requires(checker != null); + Contract.Requires(info.impl != null); + Contract.Requires(info.impl.Proc != null); + + + + Implementation impl = info.impl; + if (mode == Mode.Boogie && style == AnnotationStyle.Flat && impl.Name != main_proc_name) + return; + Contract.Assert(impl != null); + ConvertCFG2DAG(impl,edgesCut); + VC.ModelViewInfo mvInfo; + PassifyImpl(impl, out mvInfo); + Dictionary<int, Absy> label2absy = null; + VCExpressionGenerator gen = checker.VCExprGen; + Contract.Assert(gen != null); + VCExpr vcexpr; + if(NoLabels){ + // int assertionCount = 0; + VCExpr startCorrect = null; /* VC.VCGen.LetVC(cce.NonNull(impl.Blocks[0]), null, null, info.blockVariables, info.bindings, + info.ctxt, out assertionCount); */ + vcexpr = gen.Let(info.bindings, startCorrect); + } + else vcexpr = GenerateVC(impl, null /* info.controlFlowVariable */, out label2absy, info.ctxt); + if(mode != Mode.Boogie) + vcexpr = gen.Not(vcexpr); + Contract.Assert(vcexpr != null); + info.label2absy = label2absy; + info.mvInfo = mvInfo; + List<VCExpr> interfaceExprs = new List<VCExpr>(); + + if (true /* was: !info.isMain */) + { + Boogie2VCExprTranslator translator = checker.TheoremProver.Context.BoogieExprTranslator; + Contract.Assert(translator != null); + info.privateVars = new List<VCExprVar>(); + foreach (Variable v in impl.LocVars) + { + Contract.Assert(v != null); + info.privateVars.Add(translator.LookupVariable(v)); + } + foreach (Variable v in impl.OutParams) + { + Contract.Assert(v != null); + info.privateVars.Add(translator.LookupVariable(v)); + } + + info.interfaceExprVars = new List<VCExprVar>(); + + foreach (Variable v in info.interfaceVars) + { + Contract.Assert(v != null); + VCExprVar ev = translator.LookupVariable(v); + Contract.Assert(ev != null); + info.interfaceExprVars.Add(ev); + interfaceExprs.Add(ev); + } + } + + Function function = cce.NonNull(info.function); + Contract.Assert(function != null); + info.funcExpr = gen.Function(function, interfaceExprs); + info.vcexpr = vcexpr; + + if (mode == Mode.Boogie) + { + Term z3vc = boogieContext.VCExprToTerm(vcexpr, linOptions); + FactorVCs(z3vc, DualityVCs); + } + else + { + // Index the procedures by relational variable + FuncDecl R = boogieContext.VCExprToTerm(info.funcExpr, linOptions).GetAppDecl(); + relationToProc.Add(R, info); + info.node = rpfp.CreateNode(boogieContext.VCExprToTerm(info.funcExpr, linOptions)); + rpfp.nodes.Add(info.node); + if (info.isMain || QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint")) + info.node.Bound.Formula = ctx.MkFalse(); + } + } + + // This returns a new FuncDel with same sort as top-level function + // of term t, but with numeric suffix appended to name. + + private FuncDecl SuffixFuncDecl(Term t, int n) + { + var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString(); + return ctx.MkFuncDecl(name, t.GetAppDecl()); + } + + // Collect the relational paremeters + + private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term,Term> done) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + var kind = t.GetKind(); + if (kind == TermKind.App) + { + var f = t.GetAppDecl(); + var args = t.GetAppArgs(); + args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray(); + StratifiedInliningInfo info; + if (relationToProc.TryGetValue(f, out info)) + { + if (done.ContainsKey(t)) + res = done[t]; + else + { + f = SuffixFuncDecl(t, parms.Count); + parms.Add(f); + nodes.Add(info.node); + res = ctx.MkApp(f, args); + done.Add(t,res); // don't count same expression twice! + } + } + else + res = ctx.CloneApp(t, args); + } // TODO: handle quantifiers + else res = t; + memo.Add(t, res); + return res; + } + + public void GetTransformer(StratifiedInliningInfo info) + { + Term vcTerm = boogieContext.VCExprToTerm(info.vcexpr, linOptions); + Term[] paramTerms = info.interfaceExprVars.Select(x => boogieContext.VCExprToTerm(x, linOptions)).ToArray(); + var relParams = new List<FuncDecl>(); + var nodeParams = new List<RPFP.Node>(); + var memo = new TermDict< Term>(); + var done = new Dictionary<Term,Term>(); // note this hashes on equality, not reference! + vcTerm = CollectParamsRec(memo, vcTerm, relParams, nodeParams,done); + // var ops = new Util.ContextOps(ctx); + // var foo = ops.simplify_lhs(vcTerm); + // vcTerm = foo.Item1; + info.F = rpfp.CreateTransformer(relParams.ToArray(), paramTerms, vcTerm); + info.edge = rpfp.CreateEdge(info.node, info.F, nodeParams.ToArray()); + rpfp.edges.Add(info.edge); + // TODO labels[info.edge.number] = foo.Item2; + } + + public RPFP.Node GetNodeOfImpl(Implementation/*!*/ impl) + { + return implName2StratifiedInliningInfo[impl.Name].node; + } + + public class CyclicLiveVariableAnalysis : Microsoft.Boogie.LiveVariableAnalysis + { + public new static void ComputeLiveVariables(Implementation impl) + { + + bool some_change = true; + List<Block> sortedNodes = new List<Block>(); + foreach (var block in impl.Blocks) + { + sortedNodes.Add(block); + } + sortedNodes.Reverse(); + + while (some_change) + { + some_change = false; + foreach (Block/*!*/ block in sortedNodes) + { + Contract.Assert(block != null); + HashSet<Variable/*!*/>/*!*/ liveVarsAfter = new HashSet<Variable/*!*/>(); + if (block.TransferCmd is GotoCmd) + { + GotoCmd gotoCmd = (GotoCmd)block.TransferCmd; + if (gotoCmd.labelTargets != null) + { + foreach (Block/*!*/ succ in gotoCmd.labelTargets) + { + Contract.Assert(succ != null); + if (succ.liveVarsBefore != null) + liveVarsAfter.UnionWith(succ.liveVarsBefore); + } + } + } + + List<Cmd> cmds = block.Cmds; + int len = cmds.Count; + for (int i = len - 1; i >= 0; i--) + { + if (cmds[i] is CallCmd) + { + Procedure/*!*/ proc = cce.NonNull(cce.NonNull((CallCmd/*!*/)cmds[i]).Proc); + if (InterProcGenKill.HasSummary(proc.Name)) + { + liveVarsAfter = + InterProcGenKill.PropagateLiveVarsAcrossCall(cce.NonNull((CallCmd/*!*/)cmds[i]), liveVarsAfter); + continue; + } + } + Propagate(cmds[i], liveVarsAfter); + } + + if (block.liveVarsBefore == null) + block.liveVarsBefore = new HashSet<Variable>(); + if (!liveVarsAfter.IsSubsetOf(block.liveVarsBefore)) + { + block.liveVarsBefore = liveVarsAfter; + some_change = true; + } + } + } + } + } + + public void Generate() + { + + var oldDagOption = CommandLineOptions.Clo.vcVariety; + CommandLineOptions.Clo.vcVariety = CommandLineOptions.VCVariety.Dag; + + // MarkAllFunctionImplementationsInline(); // This is for SMACK, which goes crazy with functions + + // Run live variable analysis (TODO: should this be here?) +#if false + if (CommandLineOptions.Clo.LiveVariableAnalysis == 2) + { + Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program); + } +#endif + + #region In Boogie mode, annotate the program + if (mode == Mode.Boogie) + { + + // find the name of the main procedure + main_proc_name = null; // default in case no entry point defined + foreach (var impl in program.Implementations) + { + if (QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint")) + main_proc_name = impl.Proc.Name; + } + if (main_proc_name == null) + { + foreach (var impl in program.Implementations) + { + if (impl.Proc.Name == "main" || impl.Proc.Name.EndsWith(".main")) + main_proc_name = impl.Proc.Name; + } + } + if (main_proc_name == null) + main_proc_name = "main"; + + if (style == AnnotationStyle.Flat) + { + InlineAll(); + Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program); + foreach (var impl in program.Implementations) + { + if (main_proc_name == impl.Proc.Name) + { + Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl); + CyclicLiveVariableAnalysis.ComputeLiveVariables(impl); + AnnotateLoops(impl, boogieContext); + } + } + } + else + { + + if (style == AnnotationStyle.Procedure || style == AnnotationStyle.Call) + { + foreach (var impl in program.Implementations) + { + if (!QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint")) + AnnotateProcRequires(impl.Proc, impl, boogieContext); + AnnotateProcEnsures(impl.Proc, impl, boogieContext); + } + if (style == AnnotationStyle.Call) + { + + } + } + + // must do this after annotating procedures, else calls + // will be prematurely desugared + + foreach (var impl in program.Implementations) + { + Microsoft.Boogie.LiveVariableAnalysis.ClearLiveVariables(impl); + CyclicLiveVariableAnalysis.ComputeLiveVariables(impl); + } + + + if (style == AnnotationStyle.Flat || style == AnnotationStyle.Call) + { + foreach (var impl in program.Implementations) + { + AnnotateLoops(impl, boogieContext); + } + } + if (style == AnnotationStyle.Call) + { + Dictionary<string, bool> impls = new Dictionary<string, bool>(); + foreach (var impl in program.Implementations) + { + impls.Add(impl.Proc.Name, true); + } + foreach (var impl in program.Implementations) + { + AnnotateCallSites(impl, boogieContext, impls); + } + } + if (style == AnnotationStyle.Flat) + InlineAll(); + } + } + #endregion + + /* Generate the VC's */ + GenerateVCsForStratifiedInlining(); + + /* Generate the background axioms */ + Term background = ctx.MkTrue(); // TODO boogieContext.VCExprToTerm(boogieContext.Axioms, linOptions); + rpfp.AssertAxiom(background); + + int save_option = CommandLineOptions.Clo.StratifiedInlining; // need this to get funcall labels + CommandLineOptions.Clo.StratifiedInlining = 1; + + /* Create the nodes, indexing procedures by their relational symbols. */ + foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values) + GenerateVCForStratifiedInlining(program, info, checker); + + CommandLineOptions.Clo.StratifiedInlining = save_option; + + if (mode == Mode.Boogie) + { + // var ops = new Util.ContextOps(ctx); + var vcs = DualityVCs; + DualityVCs = new List<Term>(); + foreach (var vc in vcs) + { + // var foo = ops.simplify_lhs(vc.GetAppArgs()[0]); + var foo = vc.GetAppArgs()[0]; + if (!foo.IsFalse()) + DualityVCs.Add(ctx.MkImplies(foo, vc.GetAppArgs()[1])); + } + + rpfp.FromClauses(DualityVCs.ToArray()); + // TODO rpfp.HornClauses = style == AnnotationStyle.Flat; + } + else + { + /* Generate the edges. */ + foreach (StratifiedInliningInfo info in implName2StratifiedInliningInfo.Values) + GetTransformer(info); + } + + // save some information for debugging purposes + // TODO rpfp.ls.SetAnnotationInfo(annotationInfo); + + CommandLineOptions.Clo.vcVariety = oldDagOption; + } + + + private class ErrorHandler : ProverInterface.ErrorHandler + { + //TODO: anything we need to handle? + } + + Dictionary<int, Dictionary<string, string>> varSubst = null; + + /** Check the RPFP, and return a counterexample if there is one. */ + + public VC.ConditionGeneration.Outcome Check(ref RPFP.Node cexroot) + { + var start = DateTime.Now; + + ErrorHandler handler = new ErrorHandler(); + RPFP.Node cex; + varSubst = new Dictionary<int,Dictionary<string,string>>(); + +#if false + int origRecursionBound = CommandLineOptions.Clo.RecursionBound; + if (CommandLineOptions.Clo.RecursionBound > 0 && extraRecBound != null) + { + int maxExtra = 0; + foreach (string s in extraRecBound.Keys) + { + int extra = extraRecBound[s]; + if (extra > maxExtra) maxExtra = extra; + } + CommandLineOptions.Clo.RecursionBound += maxExtra; + } +#endif + + ProverInterface.Outcome outcome = + checker.TheoremProver.CheckRPFP("name", rpfp, handler, out cex, varSubst, extraRecBound); + cexroot = cex; + +#if false + CommandLineOptions.Clo.RecursionBound = origRecursionBound; +#endif + + Console.WriteLine("solve: {0}s", (DateTime.Now - start).TotalSeconds); + + switch(outcome) + { + case ProverInterface.Outcome.Valid: + return VC.ConditionGeneration.Outcome.Correct; + case ProverInterface.Outcome.Bounded: + return VC.ConditionGeneration.Outcome.ReachedBound; + case ProverInterface.Outcome.Invalid: + return VC.ConditionGeneration.Outcome.Errors; + case ProverInterface.Outcome.TimeOut: + return VC.ConditionGeneration.Outcome.TimedOut; + default: + return VC.ConditionGeneration.Outcome.Inconclusive; + } + } + + private bool generated = false; + + static private Object thisLock = new Object(); + + public override VC.VCGen.Outcome VerifyImplementation(Implementation impl, VerifierCallback collector) + { + + lock (thisLock) + { + Procedure proc = impl.Proc; + + // we verify all the impls at once, so we need to execute only once + // TODO: make sure needToCheck is true only once + bool needToCheck = false; + if (mode == Mode.OldCorral) + needToCheck = proc.FindExprAttribute("inline") == null && !(proc is LoopProcedure); + else if (mode == Mode.Corral || mode == Mode.Boogie) + needToCheck = QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint") && !(proc is LoopProcedure); + else + needToCheck = impl.Name == main_proc_name; + + if (needToCheck) + { + + var start = DateTime.Now; + + if (!generated) + { + Generate(); + Console.WriteLine("generate: {0}s", (DateTime.Now - start).TotalSeconds); + generated = true; + } + + + Console.WriteLine("Verifying {0}...", impl.Name); + + RPFP.Node cexroot = null; + // start = DateTime.Now; + var checkres = Check(ref cexroot); + Console.WriteLine("check: {0}s", (DateTime.Now - start).TotalSeconds); + switch (checkres) + { + case Outcome.Errors: + Console.WriteLine("Counterexample found.\n"); + // start = DateTime.Now; + Counterexample cex = CreateBoogieCounterExample(cexroot.owner, cexroot, impl); + // cexroot.owner.DisposeDualModel(); + // cex.Print(0); // just for testing + collector.OnCounterexample(cex, "assertion failure"); + Console.WriteLine("cex: {0}s", (DateTime.Now - start).TotalSeconds); + ConjecturesToSpecs(); + break; + case Outcome.Correct: + Console.WriteLine("Procedure is correct. (fixed point reached)"); + FixedPointToSpecs(); + ConjecturesToSpecs(); + break; + case Outcome.ReachedBound: + Console.WriteLine("Procedure is correct. (recursion bound reached)"); + FixedPointToSpecs(); + ConjecturesToSpecs(); + break; + default: + Console.WriteLine("Inconclusive result."); + ConjecturesToSpecs(); + break; + } + return checkres; + + } + + return Outcome.Inconclusive; + } + } + + public void FindLabelsRec(HashSet<Term> memo, Term t, Dictionary<string, Term> res) + { + if (memo.Contains(t)) + return; + if (t.IsLabel()) + { + string l = t.LabelName(); + if (!res.ContainsKey(l)) + res.Add(l, t.GetAppArgs()[0]); + } + if (t.GetKind() == TermKind.App) + { + var args = t.GetAppArgs(); + foreach (var a in args) + FindLabelsRec(memo, a, res); + } // TODO: handle quantifiers + + memo.Add(t); + } + + public void FindLabels() + { + labels = new Dictionary<string, Term>(); + foreach(var e in rpfp.edges){ + int id = e.number; + HashSet<Term> memo = new HashSet<Term>(ReferenceComparer<Term>.Instance); + FindLabelsRec(memo, e.F.Formula, labels); + } + } + + public string CodeLabel(Absy code, StratifiedInliningInfo info, string prefix) + { + if (info.label2absyInv == null) + { + info.label2absyInv = new Dictionary<Absy, string>(); + foreach (int foo in info.label2absy.Keys) + { + Absy bar = info.label2absy[foo] as Absy; + string lbl = foo.ToString(); + info.label2absyInv.Add(bar, lbl); + } + } + if (info.label2absyInv.ContainsKey(code)) + { + string label = info.label2absyInv[code]; + return prefix+label; + } + return null; + } + + public Term CodeLabeledExpr(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix) + { + string label = CodeLabel(code, info, prefix); + + if (label != null) + { + var res = labels[label]; + return res; + } + else return null; + } + + public class LabelNotFound : Exception { }; + + public bool CodeLabelTrue(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix) + { + string label = CodeLabel(code, info, prefix); + + if (label == null) + throw new LabelNotFound(); + return root.Outgoing.labels.Contains(label); + } + + public bool CodeLabelFalse(RPFP rpfp, RPFP.Node root, Absy code, StratifiedInliningInfo info, string prefix) + { + return CodeLabelTrue(rpfp, root, code, info, prefix); + } + + + private class StateId + { + public RPFP.Edge edge; + public int capturePoint; + public StratifiedInliningInfo info; + public StateId(RPFP.Edge e, int c, StratifiedInliningInfo i) + { + edge = e; + capturePoint = c; + info = i; + } + } + + + public Counterexample CreateBoogieCounterExample(RPFP rpfp, RPFP.Node root, Implementation mainImpl) + { + FindLabels(); + var orderedStateIds = new List<StateId>(); + Counterexample newCounterexample = + GenerateTrace(rpfp, root, orderedStateIds, mainImpl,true); + if (CommandLineOptions.Clo.ModelViewFile != null) + { + Model m = root.owner.GetBackgroundModel(); + GetModelWithStates(m, root, implName2StratifiedInliningInfo[mainImpl.Name], + orderedStateIds, varSubst); + newCounterexample.Model = m; + newCounterexample.ModelHasStatesAlready = true; + } + return newCounterexample; + } + + + + private Counterexample GenerateTrace(RPFP rpfp, RPFP.Node root, + List<StateId> orderedStateIds, Implementation procImpl, bool toplevel) + { + Contract.Requires(procImpl != null); + + Contract.Assert(!rpfp.Empty(root)); + + + var info = implName2StratifiedInliningInfo[procImpl.Name]; + Block entryBlock = cce.NonNull(procImpl.Blocks[0]); + Contract.Assert(entryBlock != null); + + List<Block> trace = new List<Block>(); + trace.Add(entryBlock); + + var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>(); + + Counterexample newCounterexample = + GenerateTraceRec(rpfp, root, orderedStateIds, entryBlock, trace, calleeCounterexamples, info, toplevel); + + return newCounterexample; + } + + // TODO: this is a bit cheesy. Rather than finding the argument position + // of a relational term in a transformer by linear search, better to index this + // somewhere, but where? + private int TransformerArgPosition(RPFP rpfp, RPFP.Node root, Term expr) + { + FuncDecl rel = expr.GetAppDecl(); + string relname = rel.GetDeclName(); + var rps = root.Outgoing.F.RelParams; + for (int i = 0; i < rps.Length; i++) + { + string thisname = rps[i].GetDeclName(); + if (thisname == relname) + return i; + } + return -1; + } + + private bool EvalToFalse(RPFP rpfp, RPFP.Node root, Term expr,StratifiedInliningInfo info){ + Term res = rpfp.Eval(root.Outgoing,expr); + return res.Equals(ctx.MkTrue()); + } + + private Counterexample GenerateTraceRec( + RPFP rpfp, RPFP.Node root, + List<StateId> orderedStateIds, + Block/*!*/ b, List<Block>/*!*/ trace, + Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples, + StratifiedInliningInfo info, + bool toplevel) + { + Contract.Requires(b != null); + Contract.Requires(trace != null); + Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples)); + + Stack<RPFP.Node> continuation_stack = new Stack<RPFP.Node>(); + + // If our block is not present, try diving into precondition + // and push a continuation. + // TODO: is the precondition always the first child? + while (!CodeLabelFalse(rpfp, root, b, info, "+")) + { + if (root.Outgoing != null && root.Outgoing.Children.Length > 0) + { + continuation_stack.Push(root); + root = root.Outgoing.Children[0]; + } + else + { + // can't find our block + Contract.Assert(false); + return null; + } + } + + // After translation, all potential errors come from asserts. + while (true) + { + + + List<Cmd> cmds = b.Cmds; + TransferCmd transferCmd = cce.NonNull(b.TransferCmd); + for (int i = 0; i < cmds.Count; i++) + { + Cmd cmd = cce.NonNull(cmds[i]); + + // Skip if 'cmd' not contained in the trace or not an assert + if (cmd is AssertCmd) + { + bool is_failed_assertion = false; + if (NoLabels) + is_failed_assertion = true; // we assume only assertions on + else + is_failed_assertion = CodeLabelTrue(rpfp, root, cmd, info, "@"); + + if (is_failed_assertion) + { + if (continuation_stack.Count == 0) + { + Counterexample newCounterexample = + AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, new Microsoft.Boogie.Model(), info.mvInfo, + boogieContext); + newCounterexample.AddCalleeCounterexample(calleeCounterexamples); + return newCounterexample; + } + root = continuation_stack.Pop(); + } + continue; + } + + // Counterexample generation for inlined procedures + AssumeCmd assumeCmd = cmd as AssumeCmd; + if (assumeCmd == null) + continue; + NAryExpr naryExpr = assumeCmd.Expr as NAryExpr; + if (naryExpr == null) + continue; + string calleeName = naryExpr.Fun.FunctionName; + Contract.Assert(calleeName != null); + + // what is this crap??? + BinaryOperator binOp = naryExpr.Fun as BinaryOperator; + if (binOp != null && binOp.Op == BinaryOperator.Opcode.And) + { + Expr expr = naryExpr.Args[0]; + NAryExpr mvStateExpr = expr as NAryExpr; + if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == VC.ModelViewInfo.MVState_FunctionDef.Name) + { + LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr; + // Debug.Assert(x != null); + int foo = x.asBigNum.ToInt; + orderedStateIds.Add(new StateId(root.Outgoing,foo,info)); + } + } + + if (calleeName.EndsWith("_summary")) + calleeName = calleeName.Substring(0, calleeName.Length - 8); + + if (!implName2StratifiedInliningInfo.ContainsKey(calleeName) && !calleeName.EndsWith("_summary")) + continue; + + { + Term code = CodeLabeledExpr(rpfp, root, cmd, info, "+si_fcall_"); + int pos = TransformerArgPosition(rpfp, root, code); + if (pos >= 0) + { + RPFP.Node callee = root.Outgoing.Children[pos]; + orderedStateIds.Add(new StateId(callee.Outgoing, CALL,info)); + calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] = + new CalleeCounterexampleInfo( + cce.NonNull(GenerateTrace(rpfp, callee, orderedStateIds, + implName2StratifiedInliningInfo[calleeName].impl, false)), + new List<object>()); + orderedStateIds.Add(new StateId(root.Outgoing, RETURN,info)); + } + } + } + + GotoCmd gotoCmd = transferCmd as GotoCmd; + List<Block> cuts = null; + if (edgesCut.ContainsKey(b)) + cuts = edgesCut[b]; + b = null; + + if (gotoCmd != null) + { + + foreach (Block bb in cce.NonNull(gotoCmd.labelTargets)) + { + Contract.Assert(bb != null); + if (CodeLabelFalse(rpfp, root, bb, info, "+")) + { + trace.Add(bb); + b = bb; + break; + } + } + if (b != null) continue; + } + // HACK: we have to try edges that were cut in generating the VC + + if (cuts != null) + foreach (var bb in cuts) + { + if (CodeLabelFalse(rpfp, root, bb, info, "+")) + { + trace.Add(bb); + b = bb; + break; + } + } + if (b != null) continue; + + return null; + } + + + } + + public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) + { + // Construct the set of inlined procs in the original program + var inlinedProcs = new HashSet<string>(); + foreach (var decl in program.TopLevelDeclarations) + { + // Implementations + if (decl is Implementation) + { + var impl = decl as Implementation; + if (!(impl.Proc is LoopProcedure)) + { + inlinedProcs.Add(impl.Name); + } + } + + // And recording procedures + if (decl is Procedure) + { + var proc = decl as Procedure; + if (proc.Name.StartsWith(recordProcName)) + { + // Debug.Assert(!(decl is LoopProcedure)); + inlinedProcs.Add(proc.Name); + } + } + } + return extractLoopTraceRec( + new CalleeCounterexampleInfo(cex, new List<object>()), + mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample; + } + + protected override bool elIsLoop(string procname) + { + StratifiedInliningInfo info = null; + if (implName2StratifiedInliningInfo.ContainsKey(procname)) + { + info = implName2StratifiedInliningInfo[procname]; + } + + if (info == null) return false; + + var lp = info.impl.Proc as LoopProcedure; + + if (lp == null) return false; + return true; + } + + private void NumberCexEdges(RPFP.Node node, Dictionary<int,RPFP.Edge> map) + { + if (node.Outgoing == null) + return; // shouldn't happen + RPFP.Edge edge = node.Outgoing; + map[edge.number] = edge; + foreach (var c in edge.Children) + NumberCexEdges(c, map); + } + + private void GetModelWithStates(Model m, RPFP.Node cex, StratifiedInliningInfo mainInfo, + List<StateId> orderedStateIds, + Dictionary<int,Dictionary<string,string>> varSubst) + { + if (m == null) return; + var mvInfo = mainInfo.mvInfo; + + + foreach (Variable v in mvInfo.AllVariables) + { + m.InitialState.AddBinding(v.Name, GetModelValue(m, v, varSubst[cex.Outgoing.number])); + } + + Dictionary<int, RPFP.Edge> edgeNumbering = new Dictionary<int,RPFP.Edge>(); + NumberCexEdges(cex, edgeNumbering); + + int lastCandidate = 0; + int lastCapturePoint = CALL; + for (int i = 0; i < orderedStateIds.Count; ++i) + { + var s = orderedStateIds[i]; + RPFP.Edge edge = s.edge; + int candidate = edge.number; + int capturePoint = s.capturePoint; + Dictionary<string, string> subst = varSubst[candidate]; + + string implName = edge.Parent.Name.GetDeclName(); + var info = s.info.mvInfo; + + if (capturePoint == CALL || capturePoint == RETURN) + { + lastCandidate = candidate; + lastCapturePoint = capturePoint; + continue; + } + + Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count); + VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint]; + var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate) + ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>(); + var cs = m.MkState(map.Description); + + foreach (Variable v in info.AllVariables) + { + var e = (Expr)map.IncarnationMap[v]; + + if (e == null) + { + if (lastCapturePoint == CALL || lastCapturePoint == RETURN) + { + cs.AddBinding(v.Name, GetModelValue(m, v, subst)); + } + continue; + } + + if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables + + Model.Element elt; + if (e is IdentifierExpr) + { + IdentifierExpr ide = (IdentifierExpr)e; + elt = GetModelValue(m, ide.Decl, subst); + } + else if (e is LiteralExpr) + { + LiteralExpr lit = (LiteralExpr)e; + elt = m.MkElement(lit.Val.ToString()); + } + else + { + Contract.Assume(false); + elt = m.MkFunc(e.ToString(), 0).GetConstant(); + } + cs.AddBinding(v.Name, elt); + } + + lastCandidate = candidate; + lastCapturePoint = capturePoint; + } + + return; + } + + + public readonly static int CALL = -1; + public readonly static int RETURN = -2; + + private Model.Element GetModelValue(Model m, Variable v, Dictionary<string,string> subst) + { + // first, get the unique name + string uniqueName; + + VCExprVar vvar = boogieContext.BoogieExprTranslator.TryLookupVariable(v); + + uniqueName = v.Name; + + if(subst.ContainsKey(uniqueName)) + return m.MkElement(subst[uniqueName]); + return m.MkFunc("@undefined", 0).GetConstant(); + } + + class InternalError : Exception { + } + + + private BinaryOperator.Opcode VCOpToOp (VCExprOp op) + { + if (op == VCExpressionGenerator.AddIOp) + return BinaryOperator.Opcode.Add; + if (op == VCExpressionGenerator.SubIOp) + return BinaryOperator.Opcode.Sub; + if (op == VCExpressionGenerator.MulIOp) + return BinaryOperator.Opcode.Mul; + if (op == VCExpressionGenerator.DivIOp) + return BinaryOperator.Opcode.Div; + if (op == VCExpressionGenerator.EqOp) + return BinaryOperator.Opcode.Eq; + if (op == VCExpressionGenerator.LeOp) + return BinaryOperator.Opcode.Le; + if (op == VCExpressionGenerator.LtOp) + return BinaryOperator.Opcode.Lt; + if (op == VCExpressionGenerator.GeOp) + return BinaryOperator.Opcode.Ge; + if (op == VCExpressionGenerator.GtOp) + return BinaryOperator.Opcode.Gt; + if (op == VCExpressionGenerator.AndOp) + return BinaryOperator.Opcode.And; + if (op == VCExpressionGenerator.OrOp) + return BinaryOperator.Opcode.Or; + throw new InternalError(); + } + + private Expr MakeBinary (BinaryOperator.Opcode op, List<Expr> args) + { + if(args.Count == 0){ + // with zero args we need the identity of the op + switch(op){ + case BinaryOperator.Opcode.And: + return Expr.True; + case BinaryOperator.Opcode.Or: + return Expr.False; + case BinaryOperator.Opcode.Add: + return new LiteralExpr(Token.NoToken,Microsoft.Basetypes.BigNum.ZERO); + default: + throw new InternalError(); + } + } + var temp = args[0]; + for(int i = 1; i < args.Count; i++) + temp = Expr.Binary(Token.NoToken,op,temp,args[i]); + return temp; + } + + private Variable MakeVar(VCExprVar v){ + var foo = new TypedIdent(Token.NoToken,v.Name.ToString(),v.Type); + return new BoundVariable(Token.NoToken,foo); + } + + private Expr VCExprToExpr (VCExpr e, Dictionary<VCExpr,Expr> bound) + { + if (e is VCExprVar) { + if(bound.ContainsKey(e)) + return bound[e]; + return Expr.Ident(MakeVar(e as VCExprVar)); // TODO: this isn't right + } + if (e is VCExprIntLit) { + var n = e as VCExprIntLit; + return new LiteralExpr(Token.NoToken,n.Val); + } + if (e is VCExprNAry) { + var f = e as VCExprNAry; + var args = new List<Expr>(); + for(int i = 0; i < f.Arity; i++){ + args.Add (VCExprToExpr (f[i],bound)); + } + + if(f.Op == VCExpressionGenerator.NotOp) + return Expr.Unary(Token.NoToken, UnaryOperator.Opcode.Not, args[0]); + + if(f.Op == VCExpressionGenerator.IfThenElseOp) + return new NAryExpr(Token.NoToken,new IfThenElse(Token.NoToken),args); + + if(f.Op is VCExprSelectOp){ + var idx = new List<Expr>(); + idx.Add(args[1]); + return Expr.Select(args[0],idx); + } + + if(f.Op is VCExprStoreOp){ + var idx = new List<Expr>(); + idx.Add(args[1]); + return Expr.Store(args[0],idx,args[2]); + } + + if (f.Op is VCExprBoogieFunctionOp) + { + return new NAryExpr(Token.NoToken, + new FunctionCall((f.Op as VCExprBoogieFunctionOp).Func), args); + } + + var op = VCOpToOp (f.Op); + return MakeBinary(op,args); + } + + if(e is VCExprQuantifier) { + var f = e as VCExprQuantifier; + var vs = new List<Variable>(); + var new_bound = new Dictionary<VCExpr,Expr>(bound); + foreach(var v in f.BoundVars){ + var ve = MakeVar(v); + vs.Add(ve); + new_bound.Add (v,Expr.Ident (ve)); + } + var bd = VCExprToExpr(f.Body,new_bound); + if(f.Quan == Quantifier.EX) + return new ExistsExpr(Token.NoToken,vs,bd); + else + return new ForallExpr(Token.NoToken,vs,bd); + } + if (e == VCExpressionGenerator.True) { + return Expr.True; + } + if (e == VCExpressionGenerator.False) { + return Expr.False; + } + if (e is VCExprLet) { + + } + + throw new InternalError(); + } + + + } + + +} diff --git a/Source/VCGeneration/OrderingAxioms.cs b/Source/VCGeneration/OrderingAxioms.cs index dbb97764..9284601f 100644 --- a/Source/VCGeneration/OrderingAxioms.cs +++ b/Source/VCGeneration/OrderingAxioms.cs @@ -1,338 +1,338 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Text;
-using System.Linq;
-using System.Diagnostics.Contracts;
-using Microsoft.Boogie.VCExprAST;
-
-// Class for constructing and collecting the axioms of the partial
-// order <:. The class also manages "unique" attributes of constants
-// and generated the necessary assumptions for the theorem prover.
-
-// TODO: there should be an interface so that different ways to handle
-// ordering relations can be accessed uniformly
-
-namespace Microsoft.Boogie {
-
- public class OrderingAxiomBuilder {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(Gen != null);
- Contract.Invariant(Translator != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(OneStepFuns));
- Contract.Invariant(cce.NonNullElements(Constants));
- Contract.Invariant(cce.NonNullElements(CompleteConstantsOpen));
- Contract.Invariant(cce.NonNullElements(AllAxioms));
- Contract.Invariant(cce.NonNullElements(IncAxioms));
- }
-
-
- private readonly VCExpressionGenerator Gen;
- private readonly Boogie2VCExprTranslator Translator;
- private readonly IDictionary<Type, Function> OneStepFuns;
- private readonly List<Constant> Constants = new List<Constant>();
-
- // A list to handle constants whose direct children are fully
- // specified (the "complete" keyword). Constants are removed from
- // the list as soon as the corresponding axiom has been generated,
- // which means that from this point on no further children can be
- // added
- private readonly List<Constant> CompleteConstantsOpen = new List<Constant>();
-
- // list in which all axioms are collected
- private readonly List<VCExpr> AllAxioms = new List<VCExpr>();
-
- // list in which axioms are incrementally collected
- private readonly List<VCExpr> IncAxioms = new List<VCExpr>();
-
-
- public OrderingAxiomBuilder(VCExpressionGenerator gen,
- Boogie2VCExprTranslator translator) {
- Contract.Requires(gen != null);
- Contract.Requires(translator != null);
- this.Gen = gen;
- this.Translator = translator;
- OneStepFuns = new Dictionary<Type, Function>();
- Constants = new List<Constant>();
- CompleteConstantsOpen = new List<Constant>();
- AllAxioms = new List<VCExpr>();
- IncAxioms = new List<VCExpr>();
- }
-
- public OrderingAxiomBuilder(VCExpressionGenerator gen,
- Boogie2VCExprTranslator translator,
- OrderingAxiomBuilder builder) {
- Contract.Requires(gen != null);
- Contract.Requires(translator != null);
- Contract.Requires(builder != null);
- this.Gen = gen;
- this.Translator = translator;
- OneStepFuns = new Dictionary<Type, Function>(builder.OneStepFuns);
- Constants = new List<Constant>(builder.Constants);
- CompleteConstantsOpen = new List<Constant>(builder.CompleteConstantsOpen);
- AllAxioms = new List<VCExpr>(builder.AllAxioms);
- IncAxioms = new List<VCExpr>(builder.IncAxioms);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- // Used to axiomatise the disjoint-sub-dag specs that are
- // described by parents with the "unique" flag
-
-
- private Function OneStepFunFor(Type t) {
- Contract.Requires(t != null);
- Contract.Ensures(Contract.Result<Function>() != null);
-
- Function res;
- if (!OneStepFuns.TryGetValue(t, out res)) {
- List<Variable> args = new List<Variable>();
- args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg0", t), true));
- args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg1", t), true));
- Formal result = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "res", t), false);
- res = new Function(Token.NoToken, "oneStep", new List<TypeVariable>(), args, result);
- OneStepFuns.Add(t, res);
- }
- return cce.NonNull(res);
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
-
- private void AddAxiom(VCExpr axiom) {
- Contract.Requires(axiom != null);
- if (axiom.Equals(VCExpressionGenerator.True))
- return;
- AllAxioms.Add(axiom);
- IncAxioms.Add(axiom);
- }
-
- // Return all axioms that were added since the last time NewAxioms
- // was called
- public VCExpr GetNewAxioms() {
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- CloseChildrenCompleteConstants();
- VCExpr res = Gen.NAry(VCExpressionGenerator.AndOp, IncAxioms);
- IncAxioms.Clear();
- return res;
- }
-
- // return all axioms
- public VCExpr Axioms {
- get {
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- CloseChildrenCompleteConstants();
- return Gen.NAry(VCExpressionGenerator.AndOp, AllAxioms);
- }
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- // Generate the normal axioms for a partial order relation
- public void Setup() {
- TypeVariable alpha = new TypeVariable(Token.NoToken, "alpha");
- Contract.Assert(alpha != null);
- List<TypeVariable> typeParams = new List<TypeVariable>();
- typeParams.Add(alpha);
-
- List<VCTrigger> triggers = new List<VCTrigger>();
-
- VCExprVar x = Gen.Variable("x", alpha);
- Contract.Assert(x != null);
- VCExprVar y = Gen.Variable("y", alpha);
- Contract.Assert(y != null);
- VCExprVar z = Gen.Variable("z", alpha);
- Contract.Assert(z != null);
-
- List<VCExprVar> boundVars = new List<VCExprVar>();
-
- // reflexivity
- boundVars.Add(x);
- AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
- new VCQuantifierInfos("bg:subtype-refl", -1, false, null),
- Gen.AtMost(x, x)));
-
- // transitivity
- boundVars = new List<VCExprVar>();
- boundVars.Add(x);
- boundVars.Add(y);
- boundVars.Add(z);
- triggers = new List<VCTrigger>();
- triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, z)));
- VCExpr body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, z)),
- Gen.AtMost(x, z));
- Contract.Assert(body != null);
- AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
- new VCQuantifierInfos("bg:subtype-trans", -1, false, null),
- body));
-
- // anti-symmetry
- boundVars = new List<VCExprVar>();
- boundVars.Add(x);
- boundVars.Add(y);
- triggers = new List<VCTrigger>();
- triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, x)));
- body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, x)),
- Gen.Eq(x, y));
- AddAxiom(Gen.Forall(typeParams, boundVars, triggers,
- new VCQuantifierInfos("bg:subtype-antisymm", -1, false, null),
- body));
- }
-
- ////////////////////////////////////////////////////////////////////////////
-
- public void AddConstant(Constant c) {
- Contract.Requires(c != null);
- AddAxiom(GenParentConstraints(c));
- Constants.Add(c);
- if (c.ChildrenComplete)
- CompleteConstantsOpen.Add(c);
-
- // ensure that no further children are added to closed
- // children-complete constants
- Contract.Assert(!(c.Parents != null && Contract.Exists(c.Parents, p => cce.NonNull((Constant)p.Parent.Decl).ChildrenComplete && !CompleteConstantsOpen.Contains((Constant)p.Parent.Decl))));
- }
-
- // Generate the constraints telling that parents of a constant are
- // strictly greater than the constant itself, and are the minimal
- // elements with this property
- private VCExpr GenParentConstraints(Constant c) {
- Contract.Requires(c != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr res = VCExpressionGenerator.True;
-
- if (c.Parents == null)
- return res;
-
- VCExprVar cAsVar = Translator.LookupVariable(c);
- VCExprVar w = Gen.Variable("w", c.TypedIdent.Type);
-
- // Parents of c are proper ancestors of c
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl));
- res = Gen.AndSimp(res, Gen.Neq(cAsVar, par));
- res = Gen.AndSimp(res, Gen.AtMost(cAsVar, par));
- }
-
- // Parents are direct ancestors of c (no other elements are in
- // between c and a parent)
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl));
- Contract.Assert(par != null);
- VCExpr antecedent1 = Gen.AtMost(cAsVar, w);
- Contract.Assert(antecedent1 != null);
- VCExpr antecedent2 = Gen.AtMost(w, par);
- Contract.Assert(antecedent2 != null);
- VCExpr body = Gen.Implies(Gen.And(antecedent1, antecedent2),
- Gen.Or(Gen.Eq(cAsVar, w), Gen.Eq(par, w)));
- Contract.Assert(body != null);
- res = Gen.AndSimp(res,
- Gen.Forall(w,
- Gen.Trigger(true, antecedent1, antecedent2),
- body));
- }
-
- // Ancestors of c are only c itself and the ancestors of the
- // parents of c
- VCExpr minAncestors = Gen.Eq(cAsVar, w);
- Contract.Assert(minAncestors != null);
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- minAncestors =
- Gen.Or(minAncestors,
- Gen.AtMost(Translator.LookupVariable(cce.NonNull(p.Parent.Decl)), w));
- }
- VCExpr antecedent = Gen.AtMost(cAsVar, w);
- Contract.Assert(antecedent != null);
- res = Gen.AndSimp(res,
- Gen.Forall(w,
- Gen.Trigger(true, antecedent),
- Gen.Implies(antecedent, minAncestors)));
-
- // Constraints for unique child-parent edges
- foreach (ConstantParent p in c.Parents) {
- Contract.Assert(p != null);
- if (p.Unique)
- res =
- Gen.AndSimp(res,
- GenUniqueParentConstraint(c, cce.NonNull((Constant)p.Parent.Decl)));
- }
-
- return res;
- }
-
- // Generate axioms that state that all direct children of c are
- // specified; this is the dual of the axiom stating that all direct
- // ancestors of a constant are known
- private VCExpr GenCompleteChildrenConstraints(Constant c) {
- Contract.Requires(c != null);
- Contract.Requires(c.ChildrenComplete);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
-
- VCExprVar cAsVar = Translator.LookupVariable(c);
- VCExprVar w = Gen.Variable("w", c.TypedIdent.Type);
-
- VCExpr maxDescendants = Gen.Eq(cAsVar, w);
- foreach (Constant d in Constants) {
- Contract.Assert(d != null);
- if (d.Parents != null && d.Parents.Any(p => c.Equals(p.Parent.Decl)))
- maxDescendants = Gen.Or(maxDescendants,
- Gen.AtMost(w, Translator.LookupVariable(d)));
- }
-
- VCExpr antecedent = Gen.AtMost(w, cAsVar);
- Contract.Assert(antecedent != null);
- return Gen.Forall(w,
- Gen.Trigger(true, antecedent),
- Gen.Implies(antecedent, maxDescendants));
- }
-
- private void CloseChildrenCompleteConstants() {
- foreach (Constant c in CompleteConstantsOpen) {
- Contract.Assert(c != null);
- AddAxiom(GenCompleteChildrenConstraints(c));
- }
- CompleteConstantsOpen.Clear();
- }
-
- // Generate the axiom ensuring that the sub-dags underneath unique
- // child-parent edges are all disjoint
- private VCExpr GenUniqueParentConstraint(Constant child, Constant parent) {
- Contract.Requires(child != null);
- Contract.Requires(parent != null);
- Contract.Requires(child.TypedIdent.Type.Equals(parent.TypedIdent.Type));
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
-
-
- VCExprVar w = Gen.Variable("w", child.TypedIdent.Type);
- Contract.Assert(w != null);
- VCExpr antecedent =
- Gen.AtMost(w, Translator.LookupVariable(child));
- Contract.Assert(antecedent != null);
- VCExpr succedent =
- Gen.Eq(Gen.Function(OneStepFunFor(child.TypedIdent.Type),
- Translator.LookupVariable(parent), w),
- Translator.LookupVariable(child));
- Contract.Assert(succedent != null);
-
- return Gen.Forall(w,
- Gen.Trigger(true, antecedent),
- Gen.Implies(antecedent, succedent));
- }
-
- }
-
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Linq; +using System.Diagnostics.Contracts; +using Microsoft.Boogie.VCExprAST; + +// Class for constructing and collecting the axioms of the partial +// order <:. The class also manages "unique" attributes of constants +// and generated the necessary assumptions for the theorem prover. + +// TODO: there should be an interface so that different ways to handle +// ordering relations can be accessed uniformly + +namespace Microsoft.Boogie { + + public class OrderingAxiomBuilder { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(Gen != null); + Contract.Invariant(Translator != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(OneStepFuns)); + Contract.Invariant(cce.NonNullElements(Constants)); + Contract.Invariant(cce.NonNullElements(CompleteConstantsOpen)); + Contract.Invariant(cce.NonNullElements(AllAxioms)); + Contract.Invariant(cce.NonNullElements(IncAxioms)); + } + + + private readonly VCExpressionGenerator Gen; + private readonly Boogie2VCExprTranslator Translator; + private readonly IDictionary<Type, Function> OneStepFuns; + private readonly List<Constant> Constants = new List<Constant>(); + + // A list to handle constants whose direct children are fully + // specified (the "complete" keyword). Constants are removed from + // the list as soon as the corresponding axiom has been generated, + // which means that from this point on no further children can be + // added + private readonly List<Constant> CompleteConstantsOpen = new List<Constant>(); + + // list in which all axioms are collected + private readonly List<VCExpr> AllAxioms = new List<VCExpr>(); + + // list in which axioms are incrementally collected + private readonly List<VCExpr> IncAxioms = new List<VCExpr>(); + + + public OrderingAxiomBuilder(VCExpressionGenerator gen, + Boogie2VCExprTranslator translator) { + Contract.Requires(gen != null); + Contract.Requires(translator != null); + this.Gen = gen; + this.Translator = translator; + OneStepFuns = new Dictionary<Type, Function>(); + Constants = new List<Constant>(); + CompleteConstantsOpen = new List<Constant>(); + AllAxioms = new List<VCExpr>(); + IncAxioms = new List<VCExpr>(); + } + + public OrderingAxiomBuilder(VCExpressionGenerator gen, + Boogie2VCExprTranslator translator, + OrderingAxiomBuilder builder) { + Contract.Requires(gen != null); + Contract.Requires(translator != null); + Contract.Requires(builder != null); + this.Gen = gen; + this.Translator = translator; + OneStepFuns = new Dictionary<Type, Function>(builder.OneStepFuns); + Constants = new List<Constant>(builder.Constants); + CompleteConstantsOpen = new List<Constant>(builder.CompleteConstantsOpen); + AllAxioms = new List<VCExpr>(builder.AllAxioms); + IncAxioms = new List<VCExpr>(builder.IncAxioms); + } + + //////////////////////////////////////////////////////////////////////////// + + // Used to axiomatise the disjoint-sub-dag specs that are + // described by parents with the "unique" flag + + + private Function OneStepFunFor(Type t) { + Contract.Requires(t != null); + Contract.Ensures(Contract.Result<Function>() != null); + + Function res; + if (!OneStepFuns.TryGetValue(t, out res)) { + List<Variable> args = new List<Variable>(); + args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg0", t), true)); + args.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "arg1", t), true)); + Formal result = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "res", t), false); + res = new Function(Token.NoToken, "oneStep", new List<TypeVariable>(), args, result); + OneStepFuns.Add(t, res); + } + return cce.NonNull(res); + } + + //////////////////////////////////////////////////////////////////////////// + + + private void AddAxiom(VCExpr axiom) { + Contract.Requires(axiom != null); + if (axiom.Equals(VCExpressionGenerator.True)) + return; + AllAxioms.Add(axiom); + IncAxioms.Add(axiom); + } + + // Return all axioms that were added since the last time NewAxioms + // was called + public VCExpr GetNewAxioms() { + Contract.Ensures(Contract.Result<VCExpr>() != null); + + CloseChildrenCompleteConstants(); + VCExpr res = Gen.NAry(VCExpressionGenerator.AndOp, IncAxioms); + IncAxioms.Clear(); + return res; + } + + // return all axioms + public VCExpr Axioms { + get { + Contract.Ensures(Contract.Result<VCExpr>() != null); + + CloseChildrenCompleteConstants(); + return Gen.NAry(VCExpressionGenerator.AndOp, AllAxioms); + } + } + + //////////////////////////////////////////////////////////////////////////// + + // Generate the normal axioms for a partial order relation + public void Setup() { + TypeVariable alpha = new TypeVariable(Token.NoToken, "alpha"); + Contract.Assert(alpha != null); + List<TypeVariable> typeParams = new List<TypeVariable>(); + typeParams.Add(alpha); + + List<VCTrigger> triggers = new List<VCTrigger>(); + + VCExprVar x = Gen.Variable("x", alpha); + Contract.Assert(x != null); + VCExprVar y = Gen.Variable("y", alpha); + Contract.Assert(y != null); + VCExprVar z = Gen.Variable("z", alpha); + Contract.Assert(z != null); + + List<VCExprVar> boundVars = new List<VCExprVar>(); + + // reflexivity + boundVars.Add(x); + AddAxiom(Gen.Forall(typeParams, boundVars, triggers, + new VCQuantifierInfos("bg:subtype-refl", -1, false, null), + Gen.AtMost(x, x))); + + // transitivity + boundVars = new List<VCExprVar>(); + boundVars.Add(x); + boundVars.Add(y); + boundVars.Add(z); + triggers = new List<VCTrigger>(); + triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, z))); + VCExpr body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, z)), + Gen.AtMost(x, z)); + Contract.Assert(body != null); + AddAxiom(Gen.Forall(typeParams, boundVars, triggers, + new VCQuantifierInfos("bg:subtype-trans", -1, false, null), + body)); + + // anti-symmetry + boundVars = new List<VCExprVar>(); + boundVars.Add(x); + boundVars.Add(y); + triggers = new List<VCTrigger>(); + triggers.Add(Gen.Trigger(true, Gen.AtMost(x, y), Gen.AtMost(y, x))); + body = Gen.Implies(Gen.And(Gen.AtMost(x, y), Gen.AtMost(y, x)), + Gen.Eq(x, y)); + AddAxiom(Gen.Forall(typeParams, boundVars, triggers, + new VCQuantifierInfos("bg:subtype-antisymm", -1, false, null), + body)); + } + + //////////////////////////////////////////////////////////////////////////// + + public void AddConstant(Constant c) { + Contract.Requires(c != null); + AddAxiom(GenParentConstraints(c)); + Constants.Add(c); + if (c.ChildrenComplete) + CompleteConstantsOpen.Add(c); + + // ensure that no further children are added to closed + // children-complete constants + Contract.Assert(!(c.Parents != null && Contract.Exists(c.Parents, p => cce.NonNull((Constant)p.Parent.Decl).ChildrenComplete && !CompleteConstantsOpen.Contains((Constant)p.Parent.Decl)))); + } + + // Generate the constraints telling that parents of a constant are + // strictly greater than the constant itself, and are the minimal + // elements with this property + private VCExpr GenParentConstraints(Constant c) { + Contract.Requires(c != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpr res = VCExpressionGenerator.True; + + if (c.Parents == null) + return res; + + VCExprVar cAsVar = Translator.LookupVariable(c); + VCExprVar w = Gen.Variable("w", c.TypedIdent.Type); + + // Parents of c are proper ancestors of c + foreach (ConstantParent p in c.Parents) { + Contract.Assert(p != null); + VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl)); + res = Gen.AndSimp(res, Gen.Neq(cAsVar, par)); + res = Gen.AndSimp(res, Gen.AtMost(cAsVar, par)); + } + + // Parents are direct ancestors of c (no other elements are in + // between c and a parent) + foreach (ConstantParent p in c.Parents) { + Contract.Assert(p != null); + VCExprVar par = Translator.LookupVariable(cce.NonNull(p.Parent.Decl)); + Contract.Assert(par != null); + VCExpr antecedent1 = Gen.AtMost(cAsVar, w); + Contract.Assert(antecedent1 != null); + VCExpr antecedent2 = Gen.AtMost(w, par); + Contract.Assert(antecedent2 != null); + VCExpr body = Gen.Implies(Gen.And(antecedent1, antecedent2), + Gen.Or(Gen.Eq(cAsVar, w), Gen.Eq(par, w))); + Contract.Assert(body != null); + res = Gen.AndSimp(res, + Gen.Forall(w, + Gen.Trigger(true, antecedent1, antecedent2), + body)); + } + + // Ancestors of c are only c itself and the ancestors of the + // parents of c + VCExpr minAncestors = Gen.Eq(cAsVar, w); + Contract.Assert(minAncestors != null); + foreach (ConstantParent p in c.Parents) { + Contract.Assert(p != null); + minAncestors = + Gen.Or(minAncestors, + Gen.AtMost(Translator.LookupVariable(cce.NonNull(p.Parent.Decl)), w)); + } + VCExpr antecedent = Gen.AtMost(cAsVar, w); + Contract.Assert(antecedent != null); + res = Gen.AndSimp(res, + Gen.Forall(w, + Gen.Trigger(true, antecedent), + Gen.Implies(antecedent, minAncestors))); + + // Constraints for unique child-parent edges + foreach (ConstantParent p in c.Parents) { + Contract.Assert(p != null); + if (p.Unique) + res = + Gen.AndSimp(res, + GenUniqueParentConstraint(c, cce.NonNull((Constant)p.Parent.Decl))); + } + + return res; + } + + // Generate axioms that state that all direct children of c are + // specified; this is the dual of the axiom stating that all direct + // ancestors of a constant are known + private VCExpr GenCompleteChildrenConstraints(Constant c) { + Contract.Requires(c != null); + Contract.Requires(c.ChildrenComplete); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + + VCExprVar cAsVar = Translator.LookupVariable(c); + VCExprVar w = Gen.Variable("w", c.TypedIdent.Type); + + VCExpr maxDescendants = Gen.Eq(cAsVar, w); + foreach (Constant d in Constants) { + Contract.Assert(d != null); + if (d.Parents != null && d.Parents.Any(p => c.Equals(p.Parent.Decl))) + maxDescendants = Gen.Or(maxDescendants, + Gen.AtMost(w, Translator.LookupVariable(d))); + } + + VCExpr antecedent = Gen.AtMost(w, cAsVar); + Contract.Assert(antecedent != null); + return Gen.Forall(w, + Gen.Trigger(true, antecedent), + Gen.Implies(antecedent, maxDescendants)); + } + + private void CloseChildrenCompleteConstants() { + foreach (Constant c in CompleteConstantsOpen) { + Contract.Assert(c != null); + AddAxiom(GenCompleteChildrenConstraints(c)); + } + CompleteConstantsOpen.Clear(); + } + + // Generate the axiom ensuring that the sub-dags underneath unique + // child-parent edges are all disjoint + private VCExpr GenUniqueParentConstraint(Constant child, Constant parent) { + Contract.Requires(child != null); + Contract.Requires(parent != null); + Contract.Requires(child.TypedIdent.Type.Equals(parent.TypedIdent.Type)); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + + + VCExprVar w = Gen.Variable("w", child.TypedIdent.Type); + Contract.Assert(w != null); + VCExpr antecedent = + Gen.AtMost(w, Translator.LookupVariable(child)); + Contract.Assert(antecedent != null); + VCExpr succedent = + Gen.Eq(Gen.Function(OneStepFunFor(child.TypedIdent.Type), + Translator.LookupVariable(parent), w), + Translator.LookupVariable(child)); + Contract.Assert(succedent != null); + + return Gen.Forall(w, + Gen.Trigger(true, antecedent), + Gen.Implies(antecedent, succedent)); + } + + } + +} diff --git a/Source/VCGeneration/RPFP.cs b/Source/VCGeneration/RPFP.cs index ed3842d5..9d38eb47 100644 --- a/Source/VCGeneration/RPFP.cs +++ b/Source/VCGeneration/RPFP.cs @@ -1,609 +1,609 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-using Term = Microsoft.Boogie.VCExprAST.VCExpr;
-using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp;
-using Sort = Microsoft.Boogie.Type;
-using Microsoft.Boogie.VCExprAST;
-
-
-using Microsoft.Boogie.ExprExtensions;
-
-
-namespace Microsoft.Boogie
-{
-
-
-
-
- /** This class represents a relation post-fixed point (RPFP) problem as
- * a "problem graph". The graph consists of Nodes and hyper-edges.
- *
- * A node consists of
- * - Annotation, a symbolic relation
- * - Bound, a symbolic relation giving an upper bound on Annotation
- *
- *
- * A hyper-edge consists of:
- * - Children, a sequence of children Nodes,
- * - F, a symbolic relational transformer,
- * - Parent, a single parent Node.
- *
- * The graph is "solved" when:
- * - For every Node n, n.Annotation subseteq n.Bound
- * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation
- *
- * where, if x is a sequence of Nodes, x.Annotation is the sequences
- * of Annotations of the nodes in the sequence.
- *
- * A symbolic Transformer consists of
- * - RelParams, a sequence of relational symbols
- * - IndParams, a sequence of individual symbols
- * - Formula, a formula over RelParams and IndParams
- *
- * A Transformer t represents a function that takes sequence R of relations
- * and yields the relation lambda (t.Indparams). Formula(R/RelParams).
- *
- * As a special case, a nullary Transformer (where RelParams is the empty sequence)
- * represents a fixed relation.
- *
- * An RPFP consists of
- * - Nodes, a set of Nodes
- * - Edges, a set of hyper-edges
- * - Context, a prover context that contains formula AST's
- *
- * Multiple RPFP's can use the same Context, but you should be careful
- * that only one RPFP asserts constraints in the context at any time.
- *
- * */
- public class RPFP
- {
- /** Symbolic representation of a relational transformer */
- public class Transformer
- {
- public FuncDecl[] RelParams;
- public Term[] IndParams;
- public Term Formula;
- public RPFP owner;
-
- public Transformer Clone()
- {
- return (Transformer)this.MemberwiseClone();
- }
- }
-
- /** Create a symbolic transformer. */
- public Transformer CreateTransformer(FuncDecl[] _RelParams, Term[] _IndParams, Term _Formula)
- {
- Transformer t = new Transformer();
- t.RelParams = _RelParams;
- t.IndParams = _IndParams;
- t.Formula = _Formula;
- t.owner = this;
- return t;
- }
-
- /** Create a relation (nullary relational transformer) */
- public Transformer CreateRelation(Term[] _IndParams, Term _Formula)
- {
- return CreateTransformer(new FuncDecl[0], _IndParams, _Formula);
- }
-
- /** A node in the RPFP graph */
- public class Node
- {
- public FuncDecl Name;
- public Transformer Annotation;
- public Transformer Bound;
- public RPFP owner;
- public int number;
- public Edge Outgoing;
- public List<Edge> Incoming;
- public Term dual;
- public Node map;
- }
-
- /** Create a node in the graph. The input is a term R(v_1...v_n)
- * where R is an arbitrary relational symbol and v_1...v_n are
- * arbitary distinct variables. The names are only of mnemonic value,
- * however, the number and type of arguments determine the type
- * of the relation at this node. */
-
- public Node CreateNode(Term t)
- {
- Node n = new Node();
- // Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry;
- // Term[] _IndParams = tn.ToArray();
- Term[] _IndParams = t.GetAppArgs();
- FuncDecl Name = t.GetAppDecl();
- n.Annotation = CreateRelation(_IndParams,ctx.MkTrue());
- n.Bound = CreateRelation(_IndParams, ctx.MkTrue());
- n.owner = this;
- n.number = ++nodeCount;
- n.Name = Name; // just to have a unique name
- n.Incoming = new List<Edge>();
- return n;
- }
-
- /** Clone a node (can be from another graph). */
-
- public Node CloneNode(Node old)
- {
- Node n = new Node();
- n.Annotation = old.Annotation.Clone();
- n.Bound = old.Bound.Clone();
- n.owner = this;
- n.number = ++nodeCount;
- n.Name = old.Name; // just to have a unique name
- n.Incoming = new List<Edge>();
- return n;
- }
-
- /** This class represents a hyper-edge in the RPFP graph */
-
- public class Edge
- {
- public Transformer F;
- public Node Parent;
- public Node[] Children;
- public RPFP owner;
- public int number;
- public Edge map;
- public HashSet<string> labels;
- internal Term dual;
- internal TermDict<Term> valuation;
- }
-
-
- /** Create a hyper-edge. */
- public Edge CreateEdge(Node _Parent, Transformer _F, Node[] _Children)
- {
- Edge e = new Edge();
- e.Parent = _Parent;
- e.F = _F;
- e.Children = _Children;
- e.owner = this;
- e.number = ++edgeCount;
- _Parent.Outgoing = e;
- foreach (var c in _Children)
- if(c != null)
- c.Incoming.Add(e);
- return e;
- }
-
- /** Create an edge that lower-bounds its parent. */
- public Edge CreateLowerBoundEdge(Node _Parent)
- {
- return CreateEdge(_Parent, _Parent.Annotation, new RPFP.Node[0]);
- }
-
-
-
-
- /** Assert a background axiom. Background axioms can be used to provide the
- * theory of auxilliary functions or relations. All symbols appearing in
- * background axioms are considered global, and may appear in both transformer
- * and relational solutions. Semantically, a solution to the RPFP gives
- * an interpretation of the unknown relations for each interpretation of the
- * auxilliary symbols that is consistent with the axioms. Axioms should be
- * asserted before any calls to Push. They cannot be de-asserted by Pop. */
-
- public void AssertAxiom(Term t)
- {
- ctx.AddAxiom(t);
- }
-
- /** Do not call this. */
-
- public void RemoveAxiom(Term t)
- {
- ctx.RemoveAxiom(t);
- }
-
- /** Type of solve results */
- public enum LBool { False, True, Undef };
-
-
- /** Solve an RPFP graph. This means either strengthen the annotation
- * so that the bound at the given root node is satisfied, or
- * show that this cannot be done by giving a dual solution
- * (i.e., a counterexample).
- *
- * In the current implementation, this only works for graphs that
- * are:
- * - tree-like
- *
- * - closed.
- *
- * In a tree-like graph, every nod has out most one incoming and one out-going edge,
- * and there are no cycles. In a closed graph, every node has exactly one out-going
- * edge. This means that the leaves of the tree are all hyper-edges with no
- * children. Such an edge represents a relation (nullary transformer) and thus
- * a lower bound on its parent. The parameter root must be the root of this tree.
- *
- * If Solve returns LBool.False, this indicates success. The annotation of the tree
- * has been updated to satisfy the upper bound at the root.
- *
- * If Solve returns LBool.True, this indicates a counterexample. For each edge,
- * you can then call Eval to determine the values of symbols in the transformer formula.
- * You can also call Empty on a node to determine if its value in the counterexample
- * is the empty relation.
- *
- * \param root The root of the tree
- * \param persist Number of context pops through which result should persist
- *
- *
- */
-
- public LBool Solve(Node root, int persist)
- {
- return LBool.False; // TODO
- }
-
-
- /** Dispose of the dual model (counterexample) if there is one. */
-
- public void DisposeDualModel()
- {
- // TODO dualModel = null;
- }
-
-
- /** Determines the value in the counterexample of a symbol occuring in the transformer formula of
- * a given edge. */
-
- public Term Eval(Edge e, Term t)
- {
- if (e.valuation == null)
- e.valuation = new TermDict< Term>();
- if (e.valuation.ContainsKey(t))
- return e.valuation[t];
- return null; // TODO
- }
-
- /** Sets the value in the counterexample of a symbol occuring in the transformer formula of
- * a given edge. */
-
- public void SetValue(Edge e, Term variable, Term value)
- {
- if (e.valuation == null)
- e.valuation = new TermDict< Term>();
- e.valuation.Add(variable, value);
- }
-
-
- /** Returns true if the given node is empty in the primal solution. For proecudure summaries,
- this means that the procedure is not called in the current counter-model. */
-
- public bool Empty(Node p)
- {
- return false; // TODO
- }
-
- /** Push a scope. Assertions made after Push can be undone by Pop. */
-
- public void Push()
- {
- stack.Push(new stack_entry());
- // TODO: do we need push/pop?
- }
-
- /** Pop a scope (see Push). Note, you cannot pop axioms. */
-
- public void Pop(int num_scopes)
- {
- //TODO ctx.Pop((uint)num_scopes);
- for (uint i = 0; i < num_scopes; i++)
- {
- stack_entry back = stack.Pop();
- foreach (var e in back.edges)
- e.dual = null;
- foreach (var n in back.nodes)
- n.dual = null;
- }
- }
-
- public Context ctx;
-
- public class LogicSolver {
- public Context ctx;
- };
-
- public LogicSolver solver;
-
- static public LogicSolver CreateLogicSolver(Context _ctx){
- LogicSolver res = new LogicSolver();
- res.ctx = _ctx;
- return res;
- }
-
- /** This represents a conjecture that a given node is upper-boudned
- by bound. */
- public class Conjecture
- {
- public Node node;
- public Transformer bound;
- }
-
- /** This is a list of conjectures generated during solving. */
-
- public List<Conjecture> conjectures = new List<Conjecture>();
-
- /** Construct an RPFP graph with a given interpolating prover context. It is allowed to
- have multiple RPFP's use the same context, but you should never have teo RPFP's
- with the same conext asserting nodes or edges at the same time. Note, if you create
- axioms in one RPFP, them create a second RPFP with the same context, the second will
- inherit the axioms.
- */
-
- public RPFP(LogicSolver slvr)
- {
- solver = slvr;
- ctx = slvr.ctx;
- stack = new Stack<stack_entry>();
- stack.Push(new stack_entry());
- }
-
-
- /** Convert an array of clauses to an RPFP.
- */
-
- public void FromClauses(Term[] clauses){
- FuncDecl failName = ctx.MkFuncDecl("@Fail", ctx.MkBoolSort());
- foreach(var clause in clauses){
- Node foo = GetNodeFromClause(clause,failName);
- if(foo != null)
- nodes.Add(foo);
- }
- foreach (var clause in clauses)
- edges.Add(GetEdgeFromClause(clause,failName));
- }
-
-
- // This returns a new FuncDel with same sort as top-level function
- // of term t, but with numeric suffix appended to name.
-
- private FuncDecl SuffixFuncDecl(Term t, int n)
- {
- var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString();
- return ctx.MkFuncDecl(name, t.GetAppDecl());
- }
-
- // Collect the relational paremeters
-
- Dictionary<FuncDecl, Node> relationToNode = new Dictionary<FuncDecl, Node>();
-
- private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term, Term> done)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- if (t.GetKind() == TermKind.App)
- {
- var f = t.GetAppDecl();
- Node node;
- if (relationToNode.TryGetValue(f, out node))
- {
- if (done.ContainsKey(t))
- res = done[t];
- else
- {
- f = SuffixFuncDecl(t, parms.Count);
- parms.Add(f);
- nodes.Add(node);
- done.Add(t,res); // don't count same expression twice!
- }
- }
- var args = t.GetAppArgs();
- args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray();
- res = ctx.CloneApp(t, args);
- } // TODO: handle quantifiers
- else
- res = t;
- memo.Add(t, res);
- return res;
- }
-
- private bool IsVariable(Term t)
- {
- // TODO: is this right?
- // return t.IsFunctionApp() && t.GetAppArgs().Length == 0;
- return t is VCExprVar && !(t is VCExprConstant);
- }
-
- private Edge GetEdgeFromClause(Term t, FuncDecl failName)
- {
- Term[] args = t.GetAppArgs();
- Term body = args[0];
- Term head = args[1];
- Term[] _IndParams;
- FuncDecl Name;
- if (head.IsFalse())
- {
- Name = failName;
- _IndParams = new Term[0];
- }
- else
- {
- _IndParams = head.GetAppArgs();
- Name = head.GetAppDecl();
- }
- for(int i = 0; i < _IndParams.Length; i++)
- if (!IsVariable(_IndParams[i]))
- {
- Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort());
- body = ctx.MkAnd(body, ctx.MkEq(v, _IndParams[i]));
- _IndParams[i] = v;
- }
- var relParams = new List<FuncDecl>();
- var nodeParams = new List<RPFP.Node>();
- var memo = new TermDict< Term>();
- var done = new Dictionary<Term, Term>(); // note this hashes on equality, not reference!
- body = CollectParamsRec(memo, body, relParams, nodeParams,done);
- Transformer F = CreateTransformer(relParams.ToArray(), _IndParams, body);
- Node parent = relationToNode[Name];
- return CreateEdge(parent, F, nodeParams.ToArray());
- }
-
- private Node GetNodeFromClause(Term t, FuncDecl failName)
- {
- Term[] args = t.GetAppArgs();
- Term body = args[0];
- Term head = args[1];
- FuncDecl Name;
- Term[] _IndParams;
- bool is_query = false;
- if (head.Equals(ctx.MkFalse()))
- {
- Name = failName;
- is_query = true;
- _IndParams = new Term[0];
- }
- else
- {
- Name = head.GetAppDecl();
- _IndParams = head.GetAppArgs();
- }
- if (relationToNode.ContainsKey(Name))
- return null;
- for (int i = 0; i < _IndParams.Length; i++)
- if (!IsVariable(_IndParams[i]))
- {
- Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort());
- _IndParams[i] = v;
- }
- Term foo = ctx.MkApp(Name, _IndParams);
- Node node = CreateNode(foo);
- relationToNode[Name] = node;
- if (is_query)
- node.Bound = CreateRelation(new Term[0], ctx.MkFalse());
- return node;
- }
-
- /////////////////////////////////////////////////////////////////////////////////////////
- // Convert RPFP to Z3 rules
- /////////////////////////////////////////////////////////////////////////////////////////
-
- /** Get the Z3 rule corresponding to an edge */
-
- public Term GetRule(Edge edge)
- {
- Dictionary<FuncDecl, FuncDecl> predSubst = new Dictionary<FuncDecl, FuncDecl>();
- for (int i = 0; i < edge.Children.Length; i++)
- predSubst.Add(edge.F.RelParams[i], edge.Children[i].Name);
- Term body = SubstPreds(predSubst, edge.F.Formula);
- Term head = ctx.MkApp(edge.Parent.Name, edge.F.IndParams);
- var rule = BindVariables(ctx.MkImplies(body, head));
- rule = ctx.Letify(rule); // put in let bindings for theorem prover
- return rule;
- }
-
- /** Get the Z3 query corresponding to the conjunction of the node bounds. */
-
- public Term GetQuery()
- {
- List<Term> conjuncts = new List<Term>();
- foreach (var node in nodes)
- {
- if (node.Bound.Formula != ctx.MkTrue())
- conjuncts.Add(ctx.MkImplies(ctx.MkApp(node.Name, node.Bound.IndParams), node.Bound.Formula));
- }
- Term query = ctx.MkNot(ctx.MkAnd(conjuncts.ToArray()));
- query = BindVariables(query,false); // bind variables existentially
- query = ctx.Letify(query); // put in let bindings for theorem prover
- return query;
- }
-
- private void CollectVariables(TermDict< bool> memo, Term t, List<Term> vars)
- {
- if (memo.ContainsKey(t))
- return;
- if (IsVariable(t))
- vars.Add(t);
- if (t.GetKind() == TermKind.App)
- {
- foreach (var s in t.GetAppArgs())
- CollectVariables(memo, s, vars);
- }
- memo.Add(t, true);
- }
-
- private Term BindVariables(Term t, bool universal = true)
- {
- TermDict< bool> memo = new TermDict<bool>();
- List<Term> vars = new List<Term>();
- CollectVariables(memo,t,vars);
- return universal ? ctx.MkForall(vars.ToArray(), t) : ctx.MkExists(vars.ToArray(), t);
- }
-
- private Term SubstPredsRec(TermDict< Term> memo, Dictionary<FuncDecl,FuncDecl> subst, Term t)
- {
- Term res;
- if (memo.TryGetValue(t, out res))
- return res;
- if (t.GetKind() == TermKind.App)
- {
- var args = t.GetAppArgs();
- args = args.Select(x => SubstPredsRec(memo,subst,x)).ToArray();
- FuncDecl nf = null;
- var f = t.GetAppDecl();
- if (subst.TryGetValue(f, out nf))
- {
- res = ctx.MkApp(nf, args);
- }
- else
- {
- res = ctx.CloneApp(t, args);
- }
- } // TODO: handle quantifiers
- else
- res = t;
- memo.Add(t, res);
- return res;
- }
-
- private Term SubstPreds(Dictionary<FuncDecl, FuncDecl> subst, Term t)
- {
- TermDict< Term> memo = new TermDict< Term>();
- return SubstPredsRec(memo, subst, t);
- }
-
- /* Everything after here is private. */
-
- private class stack_entry
- {
- public List<Edge> edges = new List<Edge>();
- public List<Node> nodes = new List<Node>();
- };
-
- /** Set the model of the background theory used in a counterexample. */
- public void SetBackgroundModel(Model m)
- {
- dualModel = m;
- }
-
- /** Set the model of the background theory used in a counterexample. */
- public Model GetBackgroundModel()
- {
- return dualModel;
- }
-
- private int nodeCount = 0;
- private int edgeCount = 0;
- private Model dualModel;
- // private LabeledLiterals dualLabels;
- private Stack<stack_entry> stack;
- public List<Node> nodes = new List<Node>();
- public List<Edge> edges = new List<Edge>();
-
-
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) 2012 Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using Term = Microsoft.Boogie.VCExprAST.VCExpr; +using FuncDecl = Microsoft.Boogie.VCExprAST.VCExprOp; +using Sort = Microsoft.Boogie.Type; +using Microsoft.Boogie.VCExprAST; + + +using Microsoft.Boogie.ExprExtensions; + + +namespace Microsoft.Boogie +{ + + + + + /** This class represents a relation post-fixed point (RPFP) problem as + * a "problem graph". The graph consists of Nodes and hyper-edges. + * + * A node consists of + * - Annotation, a symbolic relation + * - Bound, a symbolic relation giving an upper bound on Annotation + * + * + * A hyper-edge consists of: + * - Children, a sequence of children Nodes, + * - F, a symbolic relational transformer, + * - Parent, a single parent Node. + * + * The graph is "solved" when: + * - For every Node n, n.Annotation subseteq n.Bound + * - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation + * + * where, if x is a sequence of Nodes, x.Annotation is the sequences + * of Annotations of the nodes in the sequence. + * + * A symbolic Transformer consists of + * - RelParams, a sequence of relational symbols + * - IndParams, a sequence of individual symbols + * - Formula, a formula over RelParams and IndParams + * + * A Transformer t represents a function that takes sequence R of relations + * and yields the relation lambda (t.Indparams). Formula(R/RelParams). + * + * As a special case, a nullary Transformer (where RelParams is the empty sequence) + * represents a fixed relation. + * + * An RPFP consists of + * - Nodes, a set of Nodes + * - Edges, a set of hyper-edges + * - Context, a prover context that contains formula AST's + * + * Multiple RPFP's can use the same Context, but you should be careful + * that only one RPFP asserts constraints in the context at any time. + * + * */ + public class RPFP + { + /** Symbolic representation of a relational transformer */ + public class Transformer + { + public FuncDecl[] RelParams; + public Term[] IndParams; + public Term Formula; + public RPFP owner; + + public Transformer Clone() + { + return (Transformer)this.MemberwiseClone(); + } + } + + /** Create a symbolic transformer. */ + public Transformer CreateTransformer(FuncDecl[] _RelParams, Term[] _IndParams, Term _Formula) + { + Transformer t = new Transformer(); + t.RelParams = _RelParams; + t.IndParams = _IndParams; + t.Formula = _Formula; + t.owner = this; + return t; + } + + /** Create a relation (nullary relational transformer) */ + public Transformer CreateRelation(Term[] _IndParams, Term _Formula) + { + return CreateTransformer(new FuncDecl[0], _IndParams, _Formula); + } + + /** A node in the RPFP graph */ + public class Node + { + public FuncDecl Name; + public Transformer Annotation; + public Transformer Bound; + public RPFP owner; + public int number; + public Edge Outgoing; + public List<Edge> Incoming; + public Term dual; + public Node map; + } + + /** Create a node in the graph. The input is a term R(v_1...v_n) + * where R is an arbitrary relational symbol and v_1...v_n are + * arbitary distinct variables. The names are only of mnemonic value, + * however, the number and type of arguments determine the type + * of the relation at this node. */ + + public Node CreateNode(Term t) + { + Node n = new Node(); + // Microsoft.Boogie.VCExprAST.VCExprNAry tn = t as Microsoft.Boogie.VCExprAST.VCExprNAry; + // Term[] _IndParams = tn.ToArray(); + Term[] _IndParams = t.GetAppArgs(); + FuncDecl Name = t.GetAppDecl(); + n.Annotation = CreateRelation(_IndParams,ctx.MkTrue()); + n.Bound = CreateRelation(_IndParams, ctx.MkTrue()); + n.owner = this; + n.number = ++nodeCount; + n.Name = Name; // just to have a unique name + n.Incoming = new List<Edge>(); + return n; + } + + /** Clone a node (can be from another graph). */ + + public Node CloneNode(Node old) + { + Node n = new Node(); + n.Annotation = old.Annotation.Clone(); + n.Bound = old.Bound.Clone(); + n.owner = this; + n.number = ++nodeCount; + n.Name = old.Name; // just to have a unique name + n.Incoming = new List<Edge>(); + return n; + } + + /** This class represents a hyper-edge in the RPFP graph */ + + public class Edge + { + public Transformer F; + public Node Parent; + public Node[] Children; + public RPFP owner; + public int number; + public Edge map; + public HashSet<string> labels; + internal Term dual; + internal TermDict<Term> valuation; + } + + + /** Create a hyper-edge. */ + public Edge CreateEdge(Node _Parent, Transformer _F, Node[] _Children) + { + Edge e = new Edge(); + e.Parent = _Parent; + e.F = _F; + e.Children = _Children; + e.owner = this; + e.number = ++edgeCount; + _Parent.Outgoing = e; + foreach (var c in _Children) + if(c != null) + c.Incoming.Add(e); + return e; + } + + /** Create an edge that lower-bounds its parent. */ + public Edge CreateLowerBoundEdge(Node _Parent) + { + return CreateEdge(_Parent, _Parent.Annotation, new RPFP.Node[0]); + } + + + + + /** Assert a background axiom. Background axioms can be used to provide the + * theory of auxilliary functions or relations. All symbols appearing in + * background axioms are considered global, and may appear in both transformer + * and relational solutions. Semantically, a solution to the RPFP gives + * an interpretation of the unknown relations for each interpretation of the + * auxilliary symbols that is consistent with the axioms. Axioms should be + * asserted before any calls to Push. They cannot be de-asserted by Pop. */ + + public void AssertAxiom(Term t) + { + ctx.AddAxiom(t); + } + + /** Do not call this. */ + + public void RemoveAxiom(Term t) + { + ctx.RemoveAxiom(t); + } + + /** Type of solve results */ + public enum LBool { False, True, Undef }; + + + /** Solve an RPFP graph. This means either strengthen the annotation + * so that the bound at the given root node is satisfied, or + * show that this cannot be done by giving a dual solution + * (i.e., a counterexample). + * + * In the current implementation, this only works for graphs that + * are: + * - tree-like + * + * - closed. + * + * In a tree-like graph, every nod has out most one incoming and one out-going edge, + * and there are no cycles. In a closed graph, every node has exactly one out-going + * edge. This means that the leaves of the tree are all hyper-edges with no + * children. Such an edge represents a relation (nullary transformer) and thus + * a lower bound on its parent. The parameter root must be the root of this tree. + * + * If Solve returns LBool.False, this indicates success. The annotation of the tree + * has been updated to satisfy the upper bound at the root. + * + * If Solve returns LBool.True, this indicates a counterexample. For each edge, + * you can then call Eval to determine the values of symbols in the transformer formula. + * You can also call Empty on a node to determine if its value in the counterexample + * is the empty relation. + * + * \param root The root of the tree + * \param persist Number of context pops through which result should persist + * + * + */ + + public LBool Solve(Node root, int persist) + { + return LBool.False; // TODO + } + + + /** Dispose of the dual model (counterexample) if there is one. */ + + public void DisposeDualModel() + { + // TODO dualModel = null; + } + + + /** Determines the value in the counterexample of a symbol occuring in the transformer formula of + * a given edge. */ + + public Term Eval(Edge e, Term t) + { + if (e.valuation == null) + e.valuation = new TermDict< Term>(); + if (e.valuation.ContainsKey(t)) + return e.valuation[t]; + return null; // TODO + } + + /** Sets the value in the counterexample of a symbol occuring in the transformer formula of + * a given edge. */ + + public void SetValue(Edge e, Term variable, Term value) + { + if (e.valuation == null) + e.valuation = new TermDict< Term>(); + e.valuation.Add(variable, value); + } + + + /** Returns true if the given node is empty in the primal solution. For proecudure summaries, + this means that the procedure is not called in the current counter-model. */ + + public bool Empty(Node p) + { + return false; // TODO + } + + /** Push a scope. Assertions made after Push can be undone by Pop. */ + + public void Push() + { + stack.Push(new stack_entry()); + // TODO: do we need push/pop? + } + + /** Pop a scope (see Push). Note, you cannot pop axioms. */ + + public void Pop(int num_scopes) + { + //TODO ctx.Pop((uint)num_scopes); + for (uint i = 0; i < num_scopes; i++) + { + stack_entry back = stack.Pop(); + foreach (var e in back.edges) + e.dual = null; + foreach (var n in back.nodes) + n.dual = null; + } + } + + public Context ctx; + + public class LogicSolver { + public Context ctx; + }; + + public LogicSolver solver; + + static public LogicSolver CreateLogicSolver(Context _ctx){ + LogicSolver res = new LogicSolver(); + res.ctx = _ctx; + return res; + } + + /** This represents a conjecture that a given node is upper-boudned + by bound. */ + public class Conjecture + { + public Node node; + public Transformer bound; + } + + /** This is a list of conjectures generated during solving. */ + + public List<Conjecture> conjectures = new List<Conjecture>(); + + /** Construct an RPFP graph with a given interpolating prover context. It is allowed to + have multiple RPFP's use the same context, but you should never have teo RPFP's + with the same conext asserting nodes or edges at the same time. Note, if you create + axioms in one RPFP, them create a second RPFP with the same context, the second will + inherit the axioms. + */ + + public RPFP(LogicSolver slvr) + { + solver = slvr; + ctx = slvr.ctx; + stack = new Stack<stack_entry>(); + stack.Push(new stack_entry()); + } + + + /** Convert an array of clauses to an RPFP. + */ + + public void FromClauses(Term[] clauses){ + FuncDecl failName = ctx.MkFuncDecl("@Fail", ctx.MkBoolSort()); + foreach(var clause in clauses){ + Node foo = GetNodeFromClause(clause,failName); + if(foo != null) + nodes.Add(foo); + } + foreach (var clause in clauses) + edges.Add(GetEdgeFromClause(clause,failName)); + } + + + // This returns a new FuncDel with same sort as top-level function + // of term t, but with numeric suffix appended to name. + + private FuncDecl SuffixFuncDecl(Term t, int n) + { + var name = t.GetAppDecl().GetDeclName() + "_" + n.ToString(); + return ctx.MkFuncDecl(name, t.GetAppDecl()); + } + + // Collect the relational paremeters + + Dictionary<FuncDecl, Node> relationToNode = new Dictionary<FuncDecl, Node>(); + + private Term CollectParamsRec(TermDict<Term> memo, Term t, List<FuncDecl> parms, List<RPFP.Node> nodes, Dictionary<Term, Term> done) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + if (t.GetKind() == TermKind.App) + { + var f = t.GetAppDecl(); + Node node; + if (relationToNode.TryGetValue(f, out node)) + { + if (done.ContainsKey(t)) + res = done[t]; + else + { + f = SuffixFuncDecl(t, parms.Count); + parms.Add(f); + nodes.Add(node); + done.Add(t,res); // don't count same expression twice! + } + } + var args = t.GetAppArgs(); + args = args.Select(x => CollectParamsRec(memo, x, parms, nodes, done)).ToArray(); + res = ctx.CloneApp(t, args); + } // TODO: handle quantifiers + else + res = t; + memo.Add(t, res); + return res; + } + + private bool IsVariable(Term t) + { + // TODO: is this right? + // return t.IsFunctionApp() && t.GetAppArgs().Length == 0; + return t is VCExprVar && !(t is VCExprConstant); + } + + private Edge GetEdgeFromClause(Term t, FuncDecl failName) + { + Term[] args = t.GetAppArgs(); + Term body = args[0]; + Term head = args[1]; + Term[] _IndParams; + FuncDecl Name; + if (head.IsFalse()) + { + Name = failName; + _IndParams = new Term[0]; + } + else + { + _IndParams = head.GetAppArgs(); + Name = head.GetAppDecl(); + } + for(int i = 0; i < _IndParams.Length; i++) + if (!IsVariable(_IndParams[i])) + { + Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort()); + body = ctx.MkAnd(body, ctx.MkEq(v, _IndParams[i])); + _IndParams[i] = v; + } + var relParams = new List<FuncDecl>(); + var nodeParams = new List<RPFP.Node>(); + var memo = new TermDict< Term>(); + var done = new Dictionary<Term, Term>(); // note this hashes on equality, not reference! + body = CollectParamsRec(memo, body, relParams, nodeParams,done); + Transformer F = CreateTransformer(relParams.ToArray(), _IndParams, body); + Node parent = relationToNode[Name]; + return CreateEdge(parent, F, nodeParams.ToArray()); + } + + private Node GetNodeFromClause(Term t, FuncDecl failName) + { + Term[] args = t.GetAppArgs(); + Term body = args[0]; + Term head = args[1]; + FuncDecl Name; + Term[] _IndParams; + bool is_query = false; + if (head.Equals(ctx.MkFalse())) + { + Name = failName; + is_query = true; + _IndParams = new Term[0]; + } + else + { + Name = head.GetAppDecl(); + _IndParams = head.GetAppArgs(); + } + if (relationToNode.ContainsKey(Name)) + return null; + for (int i = 0; i < _IndParams.Length; i++) + if (!IsVariable(_IndParams[i])) + { + Term v = ctx.MkConst("@a" + i.ToString(), _IndParams[i].GetSort()); + _IndParams[i] = v; + } + Term foo = ctx.MkApp(Name, _IndParams); + Node node = CreateNode(foo); + relationToNode[Name] = node; + if (is_query) + node.Bound = CreateRelation(new Term[0], ctx.MkFalse()); + return node; + } + + ///////////////////////////////////////////////////////////////////////////////////////// + // Convert RPFP to Z3 rules + ///////////////////////////////////////////////////////////////////////////////////////// + + /** Get the Z3 rule corresponding to an edge */ + + public Term GetRule(Edge edge) + { + Dictionary<FuncDecl, FuncDecl> predSubst = new Dictionary<FuncDecl, FuncDecl>(); + for (int i = 0; i < edge.Children.Length; i++) + predSubst.Add(edge.F.RelParams[i], edge.Children[i].Name); + Term body = SubstPreds(predSubst, edge.F.Formula); + Term head = ctx.MkApp(edge.Parent.Name, edge.F.IndParams); + var rule = BindVariables(ctx.MkImplies(body, head)); + rule = ctx.Letify(rule); // put in let bindings for theorem prover + return rule; + } + + /** Get the Z3 query corresponding to the conjunction of the node bounds. */ + + public Term GetQuery() + { + List<Term> conjuncts = new List<Term>(); + foreach (var node in nodes) + { + if (node.Bound.Formula != ctx.MkTrue()) + conjuncts.Add(ctx.MkImplies(ctx.MkApp(node.Name, node.Bound.IndParams), node.Bound.Formula)); + } + Term query = ctx.MkNot(ctx.MkAnd(conjuncts.ToArray())); + query = BindVariables(query,false); // bind variables existentially + query = ctx.Letify(query); // put in let bindings for theorem prover + return query; + } + + private void CollectVariables(TermDict< bool> memo, Term t, List<Term> vars) + { + if (memo.ContainsKey(t)) + return; + if (IsVariable(t)) + vars.Add(t); + if (t.GetKind() == TermKind.App) + { + foreach (var s in t.GetAppArgs()) + CollectVariables(memo, s, vars); + } + memo.Add(t, true); + } + + private Term BindVariables(Term t, bool universal = true) + { + TermDict< bool> memo = new TermDict<bool>(); + List<Term> vars = new List<Term>(); + CollectVariables(memo,t,vars); + return universal ? ctx.MkForall(vars.ToArray(), t) : ctx.MkExists(vars.ToArray(), t); + } + + private Term SubstPredsRec(TermDict< Term> memo, Dictionary<FuncDecl,FuncDecl> subst, Term t) + { + Term res; + if (memo.TryGetValue(t, out res)) + return res; + if (t.GetKind() == TermKind.App) + { + var args = t.GetAppArgs(); + args = args.Select(x => SubstPredsRec(memo,subst,x)).ToArray(); + FuncDecl nf = null; + var f = t.GetAppDecl(); + if (subst.TryGetValue(f, out nf)) + { + res = ctx.MkApp(nf, args); + } + else + { + res = ctx.CloneApp(t, args); + } + } // TODO: handle quantifiers + else + res = t; + memo.Add(t, res); + return res; + } + + private Term SubstPreds(Dictionary<FuncDecl, FuncDecl> subst, Term t) + { + TermDict< Term> memo = new TermDict< Term>(); + return SubstPredsRec(memo, subst, t); + } + + /* Everything after here is private. */ + + private class stack_entry + { + public List<Edge> edges = new List<Edge>(); + public List<Node> nodes = new List<Node>(); + }; + + /** Set the model of the background theory used in a counterexample. */ + public void SetBackgroundModel(Model m) + { + dualModel = m; + } + + /** Set the model of the background theory used in a counterexample. */ + public Model GetBackgroundModel() + { + return dualModel; + } + + private int nodeCount = 0; + private int edgeCount = 0; + private Model dualModel; + // private LabeledLiterals dualLabels; + private Stack<stack_entry> stack; + public List<Node> nodes = new List<Node>(); + public List<Edge> edges = new List<Edge>(); + + + } +} diff --git a/Source/VCGeneration/StratifiedVC.cs b/Source/VCGeneration/StratifiedVC.cs index 037fa2be..789f86f5 100644 --- a/Source/VCGeneration/StratifiedVC.cs +++ b/Source/VCGeneration/StratifiedVC.cs @@ -1,2903 +1,2906 @@ -using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Threading;
-using System.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.IO;
-using Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-using Microsoft.Boogie.VCExprAST;
-
-namespace VC {
- using Bpl = Microsoft.Boogie;
-
- public class StratifiedVC {
- public StratifiedInliningInfo info;
- public int id;
- public List<VCExprVar> interfaceExprVars;
-
- // boolControlVC (block -> its bool variable)
- public Dictionary<Block, VCExpr> blockToControlVar;
- // While using labels (block -> its label)
- public Dictionary<Absy, string> block2label;
-
- public Dictionary<Block, List<StratifiedCallSite>> callSites;
- public Dictionary<Block, List<StratifiedCallSite>> recordProcCallSites;
- public VCExpr vcexpr;
-
- // Must-Reach Information
- Dictionary<Block, VCExprVar> mustReachVar;
- List<VCExprLetBinding> mustReachBindings;
-
- public StratifiedVC(StratifiedInliningInfo siInfo, HashSet<string> procCalls) {
- info = siInfo;
- info.GenerateVC();
- var vcgen = info.vcgen;
- var prover = vcgen.prover;
- VCExpressionGenerator gen = prover.VCExprGen;
- var bet = prover.Context.BoogieExprTranslator;
-
- vcexpr = info.vcexpr;
- id = vcgen.CreateNewId();
- interfaceExprVars = new List<VCExprVar>();
- Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>();
- foreach (VCExprVar v in info.interfaceExprVars) {
- VCExprVar newVar = vcgen.CreateNewVar(v.Type);
- interfaceExprVars.Add(newVar);
- substDict.Add(v, newVar);
- }
- foreach (VCExprVar v in info.privateExprVars) {
- substDict.Add(v, vcgen.CreateNewVar(v.Type));
- }
- if(info.controlFlowVariable != null)
- substDict.Add(bet.LookupVariable(info.controlFlowVariable), gen.Integer(BigNum.FromInt(id)));
- VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
- SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen);
- vcexpr = substVisitor.Mutate(vcexpr, subst);
-
- // For BoolControlVC generation
- if (info.blockToControlVar != null)
- {
- blockToControlVar = new Dictionary<Block, VCExpr>();
- foreach (var tup in info.blockToControlVar)
- blockToControlVar.Add(tup.Key, substDict[tup.Value]);
- }
-
- // labels
- if (info.label2absy != null)
- {
- block2label = new Dictionary<Absy, string>();
- vcexpr = RenameVCExprLabels.Apply(vcexpr, info.vcgen.prover.VCExprGen, info.label2absy, block2label);
- }
-
- if(procCalls != null)
- vcexpr = RemoveProcedureCalls.Apply(vcexpr, info.vcgen.prover.VCExprGen, procCalls);
-
- callSites = new Dictionary<Block, List<StratifiedCallSite>>();
- foreach (Block b in info.callSites.Keys) {
- callSites[b] = new List<StratifiedCallSite>();
- foreach (CallSite cs in info.callSites[b]) {
- callSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst));
- }
- }
-
- recordProcCallSites = new Dictionary<Block, List<StratifiedCallSite>>();
- foreach (Block b in info.recordProcCallSites.Keys) {
- recordProcCallSites[b] = new List<StratifiedCallSite>();
- foreach (CallSite cs in info.recordProcCallSites[b]) {
- recordProcCallSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst));
- }
- }
- }
-
- public VCExpr MustReach(Block block)
- {
- Contract.Assert(!CommandLineOptions.Clo.UseLabels);
-
- // This information is computed lazily
- if (mustReachBindings == null)
- {
- var vcgen = info.vcgen;
- var gen = vcgen.prover.VCExprGen;
- var impl = info.impl;
- mustReachVar = new Dictionary<Block, VCExprVar>();
- mustReachBindings = new List<VCExprLetBinding>();
- foreach (Block b in impl.Blocks)
- mustReachVar[b] = vcgen.CreateNewVar(Bpl.Type.Bool);
-
- var dag = new Graph<Block>();
- dag.AddSource(impl.Blocks[0]);
- foreach (Block b in impl.Blocks)
- {
- var gtc = b.TransferCmd as GotoCmd;
- if (gtc != null)
- foreach (Block dest in gtc.labelTargets)
- dag.AddEdge(dest, b);
- }
- IEnumerable sortedNodes = dag.TopologicalSort();
-
- foreach (Block currBlock in dag.TopologicalSort())
- {
- if (currBlock == impl.Blocks[0])
- {
- mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], VCExpressionGenerator.True));
- continue;
- }
-
- VCExpr expr = VCExpressionGenerator.False;
- foreach (var pred in dag.Successors(currBlock))
- {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(gen.Integer(BigNum.FromInt(id)), gen.Integer(BigNum.FromInt(pred.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(currBlock.UniqueId)));
- expr = gen.Or(expr, gen.And(mustReachVar[pred], controlTransferExpr));
- }
- mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], expr));
- }
- }
-
- Contract.Assert(mustReachVar.ContainsKey(block));
- return info.vcgen.prover.VCExprGen.Let(mustReachBindings, mustReachVar[block]);
- }
-
- public List<StratifiedCallSite> CallSites {
- get {
- var ret = new List<StratifiedCallSite>();
- foreach (var b in callSites.Keys) {
- foreach (var cs in callSites[b]) {
- ret.Add(cs);
- }
- }
- return ret;
- }
- }
-
- public List<StratifiedCallSite> RecordProcCallSites {
- get {
- var ret = new List<StratifiedCallSite>();
- foreach (var b in recordProcCallSites.Keys) {
- foreach (var cs in recordProcCallSites[b]) {
- ret.Add(cs);
- }
- }
- return ret;
- }
- }
-
- public override string ToString()
- {
- return info.impl.Name;
- }
- }
-
- // Rename all labels in a VC to (globally) fresh labels
- class RenameVCExprLabels : MutatingVCExprVisitor<bool>
- {
- Dictionary<int, Absy> label2absy;
- Dictionary<Absy, string> absy2newlabel;
- static int counter = 11;
-
- RenameVCExprLabels(VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel)
- : base(gen)
- {
- this.label2absy = label2absy;
- this.absy2newlabel = absy2newlabel;
- }
-
- public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel)
- {
- return (new RenameVCExprLabels(gen, label2absy, absy2newlabel)).Mutate(expr, true);
- }
-
- // Finds labels and changes them to a globally unique label:
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- bool changed,
- bool arg)
- {
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op,
- newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
- if (lop == null) return ret;
- if (!(ret is VCExprNAry)) return ret;
- VCExprNAry retnary = (VCExprNAry)ret;
-
- // remove the sign
- var nosign = 0;
- if (!Int32.TryParse(lop.label.Substring(1), out nosign))
- return ret;
-
- if (!label2absy.ContainsKey(nosign))
- return ret;
-
- string newLabel = "SI" + counter.ToString();
- counter++;
- absy2newlabel[label2absy[nosign]] = newLabel;
-
- if (lop.pos)
- {
- return Gen.LabelPos(newLabel, retnary[0]);
- }
- else
- {
- return Gen.LabelNeg(newLabel, retnary[0]);
- }
-
- }
- }
-
- // Remove the uninterpreted function calls that substitute procedure calls
- class RemoveProcedureCalls : MutatingVCExprVisitor<bool>
- {
- HashSet<string> procNames;
-
- RemoveProcedureCalls(VCExpressionGenerator gen, HashSet<string> procNames)
- : base(gen)
- {
- this.procNames = procNames;
- }
-
- public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, HashSet<string> procNames)
- {
- return (new RemoveProcedureCalls(gen, procNames)).Mutate(expr, true);
- }
-
- // Finds labels and changes them to a globally unique label:
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- bool changed,
- bool arg)
- {
- //Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op,
- newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- if (!(ret is VCExprNAry)) return ret;
- VCExprNAry retnary = (VCExprNAry)ret;
- if (!(retnary.Op is VCExprBoogieFunctionOp))
- return ret;
-
- var fcall = (retnary.Op as VCExprBoogieFunctionOp).Func.Name;
- if (procNames.Contains(fcall))
- return VCExpressionGenerator.True;
- return ret;
- }
- }
-
-
- public class CallSite {
- public string calleeName;
- public List<VCExpr> interfaceExprs;
- public Block block;
- public int numInstr; // for TraceLocation
- public VCExprVar callSiteVar;
- public QKeyValue Attributes; // attributes on the call cmd
- public CallSite(string callee, List<VCExpr> interfaceExprs, VCExprVar callSiteVar, Block block, int numInstr, QKeyValue Attributes)
- {
- this.calleeName = callee;
- this.interfaceExprs = interfaceExprs;
- this.callSiteVar = callSiteVar;
- this.block = block;
- this.numInstr = numInstr;
- this.Attributes = Attributes;
- }
- }
-
- public class StratifiedCallSite {
- public CallSite callSite;
- public List<VCExpr> interfaceExprs;
- public VCExpr callSiteExpr;
-
- public StratifiedCallSite(CallSite cs, SubstitutingVCExprVisitor substVisitor, VCExprSubstitution subst) {
- callSite = cs;
- interfaceExprs = new List<VCExpr>();
- foreach (VCExpr v in cs.interfaceExprs) {
- interfaceExprs.Add(substVisitor.Mutate(v, subst));
- }
- if (callSite.callSiteVar != null)
- callSiteExpr = substVisitor.Mutate(callSite.callSiteVar, subst);
- }
-
- public VCExpr Attach(StratifiedVC svc) {
- Contract.Assert(interfaceExprs.Count == svc.interfaceExprVars.Count);
- StratifiedInliningInfo info = svc.info;
- ProverInterface prover = info.vcgen.prover;
- VCExpressionGenerator gen = prover.VCExprGen;
-
- Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>();
- for (int i = 0; i < svc.interfaceExprVars.Count; i++) {
- VCExprVar v = svc.interfaceExprVars[i];
- substDict.Add(v, interfaceExprs[i]);
- }
- VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
- SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen);
- svc.vcexpr = substVisitor.Mutate(svc.vcexpr, subst);
- foreach (StratifiedCallSite scs in svc.CallSites) {
- List<VCExpr> newInterfaceExprs = new List<VCExpr>();
- foreach (VCExpr expr in scs.interfaceExprs) {
- newInterfaceExprs.Add(substVisitor.Mutate(expr, subst));
- }
- scs.interfaceExprs = newInterfaceExprs;
- }
- foreach (StratifiedCallSite scs in svc.RecordProcCallSites) {
- List<VCExpr> newInterfaceExprs = new List<VCExpr>();
- foreach (VCExpr expr in scs.interfaceExprs) {
- newInterfaceExprs.Add(substVisitor.Mutate(expr, subst));
- }
- scs.interfaceExprs = newInterfaceExprs;
- }
- //return gen.Implies(callSiteExpr, svc.vcexpr);
- return svc.vcexpr;
- }
-
- public override string ToString()
- {
- return callSite.calleeName;
- }
- }
-
- public class StratifiedInliningInfo {
- public StratifiedVCGenBase vcgen;
- public Implementation impl;
- public Function function;
- public Variable controlFlowVariable;
- public Cmd exitAssertCmd;
- public VCExpr vcexpr;
- public List<VCExprVar> interfaceExprVars;
- public List<VCExprVar> privateExprVars;
- public Dictionary<int, Absy> label2absy;
- public ModelViewInfo mvInfo;
- public Dictionary<Block, List<CallSite>> callSites;
- public Dictionary<Block, List<CallSite>> recordProcCallSites;
- public bool initialized { get; private set; }
- // Instrumentation to apply after PassiveImpl, but before VCGen
- Action<Implementation> PassiveImplInstrumentation;
-
- // boolControlVC (block -> its Bool variable)
- public Dictionary<Block, VCExprVar> blockToControlVar;
-
- public StratifiedInliningInfo(Implementation implementation, StratifiedVCGenBase stratifiedVcGen, Action<Implementation> PassiveImplInstrumentation) {
- vcgen = stratifiedVcGen;
- impl = implementation;
- this.PassiveImplInstrumentation = PassiveImplInstrumentation;
-
- List<Variable> functionInterfaceVars = new List<Variable>();
- foreach (Variable v in vcgen.program.GlobalVariables) {
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
- }
- foreach (Variable v in impl.InParams) {
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
- }
- foreach (Variable v in impl.OutParams) {
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true));
- }
- foreach (IdentifierExpr e in impl.Proc.Modifies) {
- if (e.Decl == null) continue;
- functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", e.Decl.TypedIdent.Type), true));
- }
- Formal returnVar = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false);
- function = new Function(Token.NoToken, impl.Name, functionInterfaceVars, returnVar);
- vcgen.prover.Context.DeclareFunction(function, "");
-
- List<Expr> exprs = new List<Expr>();
- foreach (Variable v in vcgen.program.GlobalVariables) {
- Contract.Assert(v != null);
- exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v)));
- }
- foreach (Variable v in impl.Proc.InParams) {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (Variable v in impl.Proc.OutParams) {
- Contract.Assert(v != null);
- exprs.Add(new IdentifierExpr(Token.NoToken, v));
- }
- foreach (IdentifierExpr ie in impl.Proc.Modifies) {
- Contract.Assert(ie != null);
- if (ie.Decl == null)
- continue;
- exprs.Add(ie);
- }
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs);
- impl.Proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null)));
-
- initialized = false;
- }
-
- public void GenerateVCBoolControl()
- {
- Debug.Assert(!initialized);
- Debug.Assert(CommandLineOptions.Clo.SIBoolControlVC);
-
- // fix names for exit variables
- var outputVariables = new List<Variable>();
- var assertConjuncts = new List<Expr>();
- foreach (Variable v in impl.OutParams)
- {
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- foreach (IdentifierExpr e in impl.Proc.Modifies)
- {
- if (e.Decl == null) continue;
- Variable v = e.Decl;
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- exitAssertCmd = new AssumeCmd(Token.NoToken, Expr.BinaryTreeAnd(assertConjuncts));
- (exitAssertCmd as AssumeCmd).Attributes = new QKeyValue(Token.NoToken, "exitAssert", new List<object>(), null);
-
- // no need for label2absy
- label2absy = new Dictionary<int, Absy>();
-
- // Passify
- Program program = vcgen.program;
- ProverInterface proverInterface = vcgen.prover;
- vcgen.ConvertCFG2DAG(impl);
- vcgen.PassifyImpl(impl, out mvInfo);
-
- VCExpressionGenerator gen = proverInterface.VCExprGen;
- var exprGen = proverInterface.Context.ExprGen;
- var translator = proverInterface.Context.BoogieExprTranslator;
-
- // add a boolean variable at each call site
- vcgen.InstrumentCallSites(impl);
-
- // typecheck
- var tc = new TypecheckingContext(null);
- impl.Typecheck(tc);
-
- ///////////////////
- // Generate the VC
- ///////////////////
-
- // block -> bool variable
- blockToControlVar = new Dictionary<Block, VCExprVar>();
- foreach (var b in impl.Blocks)
- blockToControlVar.Add(b, gen.Variable(b.Label + "_holds", Bpl.Type.Bool));
-
- vcexpr = VCExpressionGenerator.True;
- foreach (var b in impl.Blocks)
- {
- // conjoin all assume cmds
- VCExpr c = VCExpressionGenerator.True;
- foreach (var cmd in b.Cmds)
- {
- var acmd = cmd as AssumeCmd;
- if (acmd == null)
- {
- Debug.Assert(cmd is AssertCmd && (cmd as AssertCmd).Expr is LiteralExpr &&
- ((cmd as AssertCmd).Expr as LiteralExpr).IsTrue);
- continue;
- }
- var expr = translator.Translate(acmd.Expr);
- // Label the assume if it is a procedure call
- NAryExpr naryExpr = acmd.Expr as NAryExpr;
- if (naryExpr != null && naryExpr.Fun is FunctionCall)
- {
- var id = acmd.UniqueId;
- label2absy[id] = acmd;
- expr = gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), expr);
- }
-
- c = gen.AndSimp(c, expr);
- }
-
- // block implies a disjunction of successors
- Debug.Assert(!(b.TransferCmd is ReturnExprCmd), "Not supported");
- var gc = b.TransferCmd as GotoCmd;
- if (gc != null)
- {
- VCExpr succ = VCExpressionGenerator.False;
- foreach (var sb in gc.labelTargets)
- succ = gen.OrSimp(succ, blockToControlVar[sb]);
- c = gen.AndSimp(c, succ);
- }
- else
- {
- // nothing to do
- }
- vcexpr = gen.AndSimp(vcexpr, gen.Eq(blockToControlVar[b], c));
- }
- // assert start block
- vcexpr = gen.AndSimp(vcexpr, blockToControlVar[impl.Blocks[0]]);
-
- //Console.WriteLine("VC of {0}: {1}", impl.Name, vcexpr);
- // Collect other information
- callSites = vcgen.CollectCallSites(impl);
- recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl);
-
- // record interface variables
- privateExprVars = new List<VCExprVar>();
- foreach (Variable v in impl.LocVars)
- {
- privateExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.OutParams)
- {
- privateExprVars.Add(translator.LookupVariable(v));
- }
- privateExprVars.AddRange(blockToControlVar.Values);
-
- interfaceExprVars = new List<VCExprVar>();
- foreach (Variable v in program.GlobalVariables)
- {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.InParams)
- {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in outputVariables)
- {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- }
-
- public void GenerateVC() {
- if (initialized) return;
- if (CommandLineOptions.Clo.SIBoolControlVC)
- {
- GenerateVCBoolControl();
- initialized = true;
- return;
- }
- List<Variable> outputVariables = new List<Variable>();
- List<Expr> assertConjuncts = new List<Expr>();
- foreach (Variable v in impl.OutParams) {
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- foreach (IdentifierExpr e in impl.Proc.Modifies) {
- if (e.Decl == null) continue;
- Variable v = e.Decl;
- Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type));
- outputVariables.Add(c);
- Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v));
- assertConjuncts.Add(eqExpr);
- }
- exitAssertCmd = new AssertCmd(Token.NoToken, Expr.Not(Expr.BinaryTreeAnd(assertConjuncts)));
-
- Program program = vcgen.program;
- ProverInterface proverInterface = vcgen.prover;
- vcgen.ConvertCFG2DAG(impl);
- vcgen.PassifyImpl(impl, out mvInfo);
-
- if (PassiveImplInstrumentation != null)
- PassiveImplInstrumentation(impl);
-
- VCExpressionGenerator gen = proverInterface.VCExprGen;
- var exprGen = proverInterface.Context.ExprGen;
- var translator = proverInterface.Context.BoogieExprTranslator;
-
- VCExpr controlFlowVariableExpr = null;
- if (!CommandLineOptions.Clo.UseLabels) {
- controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "@cfc", Microsoft.Boogie.Type.Int));
- controlFlowVariableExpr = translator.LookupVariable(controlFlowVariable);
- }
-
- vcgen.InstrumentCallSites(impl);
-
- label2absy = new Dictionary<int, Absy>();
- VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, proverInterface.Context);
- translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
- vcexpr = gen.Not(vcgen.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverInterface.Context));
-
- if (controlFlowVariableExpr != null)
- {
- VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, exprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vcexpr = exprGen.And(eqExpr, vcexpr);
- }
-
- callSites = vcgen.CollectCallSites(impl);
- recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl);
-
- privateExprVars = new List<VCExprVar>();
- foreach (Variable v in impl.LocVars) {
- privateExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.OutParams) {
- privateExprVars.Add(translator.LookupVariable(v));
- }
-
- interfaceExprVars = new List<VCExprVar>();
- foreach (Variable v in program.GlobalVariables) {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in impl.InParams) {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
- foreach (Variable v in outputVariables) {
- interfaceExprVars.Add(translator.LookupVariable(v));
- }
-
- initialized = true;
- }
- }
-
- public abstract class StratifiedVCGenBase : VCGen {
- public readonly static string recordProcName = "boogie_si_record";
- public Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo;
- public ProverInterface prover;
-
- public StratifiedVCGenBase(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Action<Implementation> PassiveImplInstrumentation)
- : base(program, logFilePath, appendLogFile, checkers) {
- implName2StratifiedInliningInfo = new Dictionary<string, StratifiedInliningInfo>();
- prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime);
- foreach (var impl in program.Implementations) {
- implName2StratifiedInliningInfo[impl.Name] = new StratifiedInliningInfo(impl, this, PassiveImplInstrumentation);
- }
- GenerateRecordFunctions();
- }
-
- private void GenerateRecordFunctions() {
- foreach (var proc in program.Procedures) {
- if (!proc.Name.StartsWith(recordProcName)) continue;
- Contract.Assert(proc.InParams.Count == 1);
-
- // Make a new function
- TypedIdent ti = new TypedIdent(Token.NoToken, "", Bpl.Type.Bool);
- Contract.Assert(ti != null);
- Formal returnVar = new Formal(Token.NoToken, ti, false);
- Contract.Assert(returnVar != null);
-
- // Get record type
- var argtype = proc.InParams[0].TypedIdent.Type;
-
- var ins = new List<Variable>();
- ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true));
-
- var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar);
- prover.Context.DeclareFunction(recordFunc, "");
-
- var exprs = new List<Expr>();
- exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0]));
-
- Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs);
- proc.Ensures.Add(new Ensures(true, freePostExpr));
- }
- }
-
- public override void Close() {
- prover.Close();
- base.Close();
- }
-
- public void InstrumentCallSites(Implementation implementation) {
- var callSiteId = 0;
- foreach (Block block in implementation.Blocks) {
- List<Cmd> newCmds = new List<Cmd>();
- for (int i = 0; i < block.Cmds.Count; i++) {
- Cmd cmd = block.Cmds[i];
- newCmds.Add(cmd);
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null) continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null) continue;
- if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue;
- Variable callSiteVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "SICS" + callSiteId, Microsoft.Boogie.Type.Bool));
- implementation.LocVars.Add(callSiteVar);
- newCmds.Add(new AssumeCmd(Token.NoToken, new IdentifierExpr(Token.NoToken, callSiteVar)));
- callSiteId++;
- }
- block.Cmds = newCmds;
- }
- }
-
- public Dictionary<Block, List<CallSite>> CollectCallSites(Implementation implementation) {
- var callSites = new Dictionary<Block, List<CallSite>>();
- foreach (Block block in implementation.Blocks) {
- for (int i = 0; i < block.Cmds.Count; i++) {
- Cmd cmd = block.Cmds[i];
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null) continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null) continue;
- if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue;
- List<VCExpr> interfaceExprs = new List<VCExpr>();
- foreach (Expr e in naryExpr.Args) {
- interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e));
- }
- int instr = i;
- i++;
- AssumeCmd callSiteAssumeCmd = (AssumeCmd)block.Cmds[i];
- IdentifierExpr iexpr = (IdentifierExpr) callSiteAssumeCmd.Expr;
- CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, prover.Context.BoogieExprTranslator.LookupVariable(iexpr.Decl), block, instr, assumeCmd.Attributes);
- if (!callSites.ContainsKey(block))
- callSites[block] = new List<CallSite>();
- callSites[block].Add(cs);
- }
- }
- return callSites;
- }
-
- public Dictionary<Block, List<CallSite>> CollectRecordProcedureCallSites(Implementation implementation) {
- var callSites = new Dictionary<Block, List<CallSite>>();
- foreach (Block block in implementation.Blocks) {
- for (int i = 0; i < block.Cmds.Count; i++) {
- AssumeCmd assumeCmd = block.Cmds[i] as AssumeCmd;
- if (assumeCmd == null) continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null) continue;
- if (!naryExpr.Fun.FunctionName.StartsWith(recordProcName)) continue;
- List<VCExpr> interfaceExprs = new List<VCExpr>();
- foreach (Expr e in naryExpr.Args) {
- interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e));
- }
- CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, null, block, i, assumeCmd.Attributes);
- if (!callSites.ContainsKey(block))
- callSites[block] = new List<CallSite>();
- callSites[block].Add(cs);
- }
- }
- return callSites;
- }
-
- private int macroCountForStratifiedInlining = 0;
- public Macro CreateNewMacro() {
- string newName = "SIMacro@" + macroCountForStratifiedInlining.ToString();
- macroCountForStratifiedInlining++;
- return new Macro(Token.NoToken, newName, new List<Variable>(), new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool), false));
- }
- private int varCountForStratifiedInlining = 0;
- public VCExprVar CreateNewVar(Microsoft.Boogie.Type type) {
- string newName = "SIV@" + varCountForStratifiedInlining.ToString();
- varCountForStratifiedInlining++;
- Constant newVar = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, type));
- prover.Context.DeclareConstant(newVar, false, null);
- return prover.VCExprGen.Variable(newVar.Name, type);
- }
- private int idCountForStratifiedInlining = 0;
- public int CreateNewId() {
- return idCountForStratifiedInlining++;
- }
-
- // Used inside PassifyImpl
- protected override void addExitAssert(string implName, Block exitBlock) {
- if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName)) {
- var exitAssertCmd = implName2StratifiedInliningInfo[implName].exitAssertCmd;
- if(exitAssertCmd != null) exitBlock.Cmds.Add(exitAssertCmd);
- }
- }
-
- public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) {
- // Construct the set of inlined procs in the original program
- var inlinedProcs = new HashSet<string>();
- foreach (var decl in program.TopLevelDeclarations) {
- // Implementations
- if (decl is Implementation) {
- var impl = decl as Implementation;
- if (!(impl.Proc is LoopProcedure)) {
- inlinedProcs.Add(impl.Name);
- }
- }
-
- // And recording procedures
- if (decl is Procedure) {
- var proc = decl as Procedure;
- if (proc.Name.StartsWith(recordProcName)) {
- Debug.Assert(!(decl is LoopProcedure));
- inlinedProcs.Add(proc.Name);
- }
- }
- }
-
- return extractLoopTraceRec(
- new CalleeCounterexampleInfo(cex, new List<object>()),
- mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
- }
-
- protected override bool elIsLoop(string procname) {
- StratifiedInliningInfo info = null;
- if (implName2StratifiedInliningInfo.ContainsKey(procname)) {
- info = implName2StratifiedInliningInfo[procname];
- }
-
- if (info == null) return false;
-
- var lp = info.impl.Proc as LoopProcedure;
-
- if (lp == null) return false;
- return true;
- }
-
- public abstract Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars);
- }
-
- public class StratifiedVCGen : StratifiedVCGenBase {
- public bool PersistCallTree;
- public static HashSet<string> callTree = null;
- public int numInlined = 0;
- public int vcsize = 0;
- private HashSet<string> procsThatReachedRecBound;
- private Dictionary<string, int> extraRecBound;
-
- public StratifiedVCGen(bool usePrevCallTree, HashSet<string> prevCallTree,
- Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : this(program, logFilePath, appendLogFile, checkers)
- {
- if (usePrevCallTree) {
- callTree = prevCallTree;
- PersistCallTree = true;
- }
- else {
- PersistCallTree = false;
- }
- }
-
- public StratifiedVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : base(program, logFilePath, appendLogFile, checkers, null) {
- PersistCallTree = false;
- procsThatReachedRecBound = new HashSet<string>();
-
- extraRecBound = new Dictionary<string, int>();
- program.TopLevelDeclarations.OfType<Implementation>()
- .Iter(impl =>
- {
- var b = QKeyValue.FindIntAttribute(impl.Attributes, "SIextraRecBound", -1);
- if (b != -1) extraRecBound.Add(impl.Name, b);
- });
- }
-
- // Extra rec bound for procedures
- public int GetExtraRecBound(string procName) {
- if (!extraRecBound.ContainsKey(procName))
- return 0;
- else return extraRecBound[procName];
- }
-
- public class ApiChecker {
- public ProverInterface prover;
- public ProverInterface.ErrorHandler reporter;
-
- public ApiChecker(ProverInterface prover, ProverInterface.ErrorHandler reporter) {
- this.reporter = reporter;
- this.prover = prover;
- }
-
- private Outcome CheckVC() {
- prover.Check();
- ProverInterface.Outcome outcome = prover.CheckOutcomeCore(reporter);
-
- return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
-
- public Outcome CheckAssumptions(List<VCExpr> assumptions) {
- if (assumptions.Count == 0) {
- return CheckVC();
- }
-
- prover.Push();
- foreach (var a in assumptions) {
- prover.Assert(a, true);
- }
- Outcome ret = CheckVC();
- prover.Pop();
- return ret;
- }
-
- public Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions) {
- List<int> unsatisfiedSoftAssumptions;
- ProverInterface.Outcome outcome = prover.CheckAssumptions(hardAssumptions, softAssumptions, out unsatisfiedSoftAssumptions, reporter);
- return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
-
- public Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore) {
- ProverInterface.Outcome outcome = prover.CheckAssumptions(assumptions, out unsatCore, reporter);
- return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
- }
-
- // Store important information related to a single VerifyImplementation query
- public class VerificationState {
- // The call tree
- public FCallHandler calls;
- public ApiChecker checker;
- // For statistics
- public int vcSize;
- public int expansionCount;
-
- public VerificationState(VCExpr vcMain, FCallHandler calls, ProverInterface prover, ProverInterface.ErrorHandler reporter) {
- prover.Assert(vcMain, true);
- this.calls = calls;
- this.checker = new ApiChecker(prover, reporter);
- vcSize = 0;
- expansionCount = 0;
- }
- }
-
- class FindLeastOORException : Exception
- {
- public Outcome outcome;
-
- public FindLeastOORException(string msg, Outcome outcome)
- : base(msg)
- {
- this.outcome = outcome;
- }
- }
-
- public override Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars) {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- // Record current time
- var startTime = DateTime.UtcNow;
-
- // No Max: avoids theorem prover restarts
- CommandLineOptions.Clo.MaxProverMemory = 0;
-
- // Initialize cache
- satQueryCache = new Dictionary<int, List<HashSet<string>>>();
- unsatQueryCache = new Dictionary<int, List<HashSet<string>>>();
-
- Contract.Assert(implName2StratifiedInliningInfo != null);
-
- // Build VCs for all procedures
- implName2StratifiedInliningInfo.Values
- .Iter(info => info.GenerateVC());
-
- // Get the VC of the current procedure
- VCExpr vcMain = implName2StratifiedInliningInfo[impl.Name].vcexpr;
- Dictionary<int, Absy> mainLabel2absy = implName2StratifiedInliningInfo[impl.Name].label2absy;
-
- // Find all procedure calls in vc and put labels on them
- FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
- calls.setCurrProcAsMain();
- vcMain = calls.Mutate(vcMain, true);
-
- try
- {
-
- // Put all of the necessary state into one object
- var vState = new VerificationState(vcMain, calls, prover, new EmptyErrorHandler());
-
- // We'll restore the original state of the theorem prover at the end
- // of this procedure
- vState.checker.prover.Push();
-
- // Do eager inlining
- while (calls.currCandidates.Count > 0)
- {
- List<int> toExpand = new List<int>();
-
- foreach (int id in calls.currCandidates)
- {
- Debug.Assert(calls.getRecursionBound(id) <= 1, "Recursion not supported");
- toExpand.Add(id);
- }
- DoExpansion(toExpand, vState);
- }
-
- // Find all the boolean constants
- var allConsts = new HashSet<VCExprVar>();
- foreach (var constant in program.Constants)
- {
- if (!allBoolVars.Contains(constant.Name)) continue;
- var v = prover.Context.BoogieExprTranslator.LookupVariable(constant);
- allConsts.Add(v);
- }
-
- // Now, lets start the algo
- var min = refinementLoop(vState.checker, new HashSet<VCExprVar>(), allConsts, allConsts);
-
- var ret = new HashSet<string>();
- foreach (var v in min)
- {
- //Console.WriteLine(v.Name);
- ret.Add(v.Name);
- }
- allBoolVars = ret;
-
- vState.checker.prover.Pop();
-
- return Outcome.Correct;
- }
- catch (FindLeastOORException e)
- {
- Console.WriteLine("Exception in FindLeastToVerify: {0}, {1}", e.Message, e.outcome);
- return e.outcome;
- }
- }
-
- private HashSet<VCExprVar> refinementLoop(ApiChecker apiChecker, HashSet<VCExprVar> trackedVars, HashSet<VCExprVar> trackedVarsUpperBound, HashSet<VCExprVar> allVars) {
- Debug.Assert(trackedVars.IsSubsetOf(trackedVarsUpperBound));
-
- // If we already know the fate of all vars, then we're done.
- if (trackedVars.Count == trackedVarsUpperBound.Count)
- return new HashSet<VCExprVar>(trackedVars);
-
- // See if we already have enough variables tracked
- var success = refinementLoopCheckPath(apiChecker, trackedVars, allVars);
- if (success) {
- // We have enough
- return new HashSet<VCExprVar>(trackedVars);
- }
-
- // If all that remains is 1 variable, then we know that we must track it
- if (trackedVars.Count + 1 == trackedVarsUpperBound.Count)
- return new HashSet<VCExprVar>(trackedVarsUpperBound);
-
- // Partition the remaining set of variables
- HashSet<VCExprVar> part1, part2;
- var temp = new HashSet<VCExprVar>(trackedVarsUpperBound);
- temp.ExceptWith(trackedVars);
- Partition<VCExprVar>(temp, out part1, out part2);
-
- // First half
- var fh = new HashSet<VCExprVar>(trackedVars); fh.UnionWith(part2);
- var s1 = refinementLoop(apiChecker, fh, trackedVarsUpperBound, allVars);
-
- var a = new HashSet<VCExprVar>(part1); a.IntersectWith(s1);
- var b = new HashSet<VCExprVar>(part1); b.ExceptWith(s1);
- var c = new HashSet<VCExprVar>(trackedVarsUpperBound); c.ExceptWith(b);
- a.UnionWith(trackedVars);
-
- // Second half
- return refinementLoop(apiChecker, a, c, allVars);
- }
-
- Dictionary<int, List<HashSet<string>>> satQueryCache;
- Dictionary<int, List<HashSet<string>>> unsatQueryCache;
-
- private bool refinementLoopCheckPath(ApiChecker apiChecker, HashSet<VCExprVar> varsToSet, HashSet<VCExprVar> allVars) {
- var assumptions = new List<VCExpr>();
- var prover = apiChecker.prover;
- var query = new HashSet<string>();
- varsToSet.Iter(v => query.Add(v.Name));
-
- if (checkCache(query, unsatQueryCache)) {
- prover.LogComment("FindLeast: Query Cache Hit");
- return true;
- }
- if (checkCache(query, satQueryCache)) {
- prover.LogComment("FindLeast: Query Cache Hit");
- return false;
- }
-
- prover.LogComment("FindLeast: Query Begin");
-
- foreach (var c in allVars) {
- if (varsToSet.Contains(c)) {
- assumptions.Add(c);
- }
- else {
- assumptions.Add(prover.VCExprGen.Not(c));
- }
- }
-
- var o = apiChecker.CheckAssumptions(assumptions);
- if (o != Outcome.Correct && o != Outcome.Errors)
- {
- throw new FindLeastOORException("OOR", o);
- }
- //Console.WriteLine("Result = " + o.ToString());
- prover.LogComment("FindLeast: Query End");
-
- if (o == Outcome.Correct) {
- insertCache(query, unsatQueryCache);
- return true;
- }
-
- insertCache(query, satQueryCache);
- return false;
- }
-
- private bool checkCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) {
- if (!cache.ContainsKey(q.Count)) return false;
- foreach (var s in cache[q.Count]) {
- if (q.SetEquals(s)) return true;
- }
- return false;
- }
-
- private void insertCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) {
- if (!cache.ContainsKey(q.Count)) {
- cache.Add(q.Count, new List<HashSet<string>>());
- }
- cache[q.Count].Add(q);
- }
-
- public static void Partition<T>(HashSet<T> values, out HashSet<T> part1, out HashSet<T> part2) {
- part1 = new HashSet<T>();
- part2 = new HashSet<T>();
- var size = values.Count;
- var crossed = false;
- var curr = 0;
- foreach (var s in values) {
- if (crossed) part2.Add(s);
- else part1.Add(s);
- curr++;
- if (!crossed && curr >= size / 2) crossed = true;
- }
- }
-
- public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) {
- Debug.Assert(QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"));
- Debug.Assert(this.program == program);
-
- // Record current time
- var startTime = DateTime.UtcNow;
-
- // Flush any axioms that came with the program before we start SI on this implementation
- prover.AssertAxioms();
-
- // Run live variable analysis
- if (CommandLineOptions.Clo.LiveVariableAnalysis == 2) {
- Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program);
- }
-
- // Get the VC of the current procedure
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[impl.Name];
- info.GenerateVC();
- VCExpr vc = info.vcexpr;
- Dictionary<int, Absy> mainLabel2absy = info.label2absy;
- var reporter = new StratifiedInliningErrorReporter(implName2StratifiedInliningInfo, prover, callback, info);
-
- // Find all procedure calls in vc and put labels on them
- FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy);
- calls.setCurrProcAsMain();
- vc = calls.Mutate(vc, true);
- reporter.SetCandidateHandler(calls);
- calls.id2VC.Add(0, vc);
- calls.extraRecursion = extraRecBound;
- if (CommandLineOptions.Clo.SIBoolControlVC)
- {
- calls.candiate2block2controlVar.Add(0, new Dictionary<Block, VCExpr>());
- implName2StratifiedInliningInfo[impl.Name].blockToControlVar.Iter(tup =>
- calls.candiate2block2controlVar[0].Add(tup.Key, tup.Value));
- }
-
- // We'll restore the original state of the theorem prover at the end
- // of this procedure
- prover.Push();
-
- // Put all of the necessary state into one object
- var vState = new VerificationState(vc, calls, prover, reporter);
- vState.vcSize += SizeComputingVisitor.ComputeSize(vc);
-
- Outcome ret = Outcome.ReachedBound;
-
- #region eager inlining
- for (int i = 1; i < CommandLineOptions.Clo.StratifiedInlining && calls.currCandidates.Count > 0; i++) {
- List<int> toExpand = new List<int>();
-
- foreach (int id in calls.currCandidates) {
- if (calls.getRecursionBound(id) <= CommandLineOptions.Clo.RecursionBound) {
- toExpand.Add(id);
- }
- }
- DoExpansion(toExpand, vState);
- }
- #endregion
-
- #region Repopulate call tree, if there is one
- if (PersistCallTree && callTree != null) {
- bool expand = true;
- while (expand) {
- List<int> toExpand = new List<int>();
- foreach (int id in calls.currCandidates) {
- if (callTree.Contains(calls.getPersistentId(id))) {
- toExpand.Add(id);
- }
- }
- if (toExpand.Count == 0) expand = false;
- else {
- DoExpansion(toExpand, vState);
- }
- }
- }
- #endregion
-
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) {
- Console.WriteLine(">> SI: Size of VC after eager inlining: {0}", vState.vcSize);
- }
-
- // Under-approx query is only needed if something was inlined since
- // the last time an under-approx query was made
- // TODO: introduce this
- // bool underApproxNeeded = true;
-
- // The recursion bound for stratified search
- int bound = CommandLineOptions.Clo.NonUniformUnfolding ? CommandLineOptions.Clo.RecursionBound : 1;
-
- int done = 0;
-
- int iters = 0;
-
- // for blocking candidates (and focusing on a counterexample)
- var block = new HashSet<int>();
-
- // Process tasks while not done. We're done when:
- // case 1: (correct) We didn't find a bug (either an over-approx query was valid
- // or we reached the recursion bound) and the task is "step"
- // case 2: (bug) We find a bug
- // case 3: (internal error) The theorem prover TimesOut of runs OutOfMemory
- while (true)
- {
- // Check timeout
- if (CommandLineOptions.Clo.ProverKillTime != -1)
- {
- if ((DateTime.UtcNow - startTime).TotalSeconds > CommandLineOptions.Clo.ProverKillTime)
- {
- ret = Outcome.TimedOut;
- break;
- }
- }
-
- if (done > 0)
- {
- break;
- }
-
- // Stratified Step
- ret = stratifiedStep(bound, vState, block);
- iters++;
-
- // Sorry, out of luck (time/memory)
- if (ret == Outcome.Inconclusive || ret == Outcome.OutOfMemory || ret == Outcome.TimedOut)
- {
- done = 3;
- continue;
- }
-
- if (ret == Outcome.Errors && reporter.underapproximationMode)
- {
- // Found a bug
- done = 2;
- }
- else if (ret == Outcome.Correct)
- {
- if (block.Count == 0)
- {
- // Correct
- done = 1;
- }
- else
- {
- // reset blocked and continue loop
- block.Clear();
- }
- }
- else if (ret == Outcome.ReachedBound)
- {
- if (block.Count == 0)
- {
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 0)
- Console.WriteLine(">> SI: Exhausted Bound {0}", bound);
-
- // Increment bound
- bound++;
-
- if (bound > CommandLineOptions.Clo.RecursionBound)
- {
- // Correct under bound
- done = 1;
- }
- }
- else
- {
- // reset blocked and continue loop
- block.Clear();
- }
- }
- else
- {
- // Do inlining
- Debug.Assert(ret == Outcome.Errors && !reporter.underapproximationMode);
- Contract.Assert(reporter.candidatesToExpand.Count != 0);
-
- #region expand call tree
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1)
- {
- Console.Write(">> SI Inlining: ");
- reporter.candidatesToExpand
- .Select(c => calls.getProc(c))
- .Iter(c => Console.Write("{0} ", c));
-
- Console.WriteLine();
- }
-
- // Expand and try again
- vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion begin ;;;;;;;;;;");
- DoExpansion(reporter.candidatesToExpand, vState);
- vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion end ;;;;;;;;;;");
-
- #endregion
- }
- }
-
- // Pop off everything that we pushed so that there are no side effects from
- // this call to VerifyImplementation
- vState.checker.prover.Pop();
-
- if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) {
- Console.WriteLine(">> SI: Expansions performed: {0}", vState.expansionCount);
- Console.WriteLine(">> SI: Candidates left: {0}", calls.currCandidates.Count);
- Console.WriteLine(">> SI: VC Size: {0}", vState.vcSize);
- }
-
- vcsize = vState.vcSize;
- numInlined = (calls.candidateParent.Keys.Count + 1) - (calls.currCandidates.Count);
-
- var rbound = "Procs that reached bound: ";
- foreach (var s in procsThatReachedRecBound) rbound += " " + s;
- if (ret == Outcome.ReachedBound) Helpers.ExtraTraceInformation(rbound);
- if (CommandLineOptions.Clo.StackDepthBound > 0 && ret == Outcome.Correct) ret = Outcome.ReachedBound;
-
- // Store current call tree
- if (PersistCallTree && (ret == Outcome.Correct || ret == Outcome.Errors || ret == Outcome.ReachedBound)) {
- callTree = new HashSet<string>();
- //var persistentNodes = new HashSet<int>(calls.candidateParent.Values);
- var persistentNodes = new HashSet<int>(calls.candidateParent.Keys);
- persistentNodes.Add(0);
- persistentNodes.ExceptWith(calls.currCandidates);
-
- foreach (var id in persistentNodes) {
- var pid = calls.getPersistentId(id);
- Debug.Assert(!callTree.Contains(pid));
- callTree.Add(pid);
- }
- }
- return ret;
- }
-
- // A step of the stratified inlining algorithm: both under-approx and over-approx queries
- private Outcome stratifiedStep(int bound, VerificationState vState, HashSet<int> block) {
- var calls = vState.calls;
- var checker = vState.checker;
- var prover = checker.prover;
- var reporter = checker.reporter as StratifiedInliningErrorReporter;
-
- reporter.underapproximationMode = true;
- prover.LogComment(";;;;;;;;;;;; Underapprox mode begin ;;;;;;;;;;");
- List<VCExpr> assumptions = new List<VCExpr>();
-
- foreach (int id in calls.currCandidates) {
- assumptions.Add(calls.getFalseExpr(id));
- }
- Outcome ret = checker.CheckAssumptions(assumptions);
- prover.LogComment(";;;;;;;;;;;; Underapprox mode end ;;;;;;;;;;");
-
- if (ret != Outcome.Correct) {
- // Either the query returned an error or it ran out of memory or time.
- // In all cases, we are done.
- return ret;
- }
-
- if (calls.currCandidates.Count == 0) {
- // If we didn't underapproximate, then we're done
- return ret;
- }
-
- prover.LogComment(";;;;;;;;;;;; Overapprox mode begin ;;;;;;;;;;");
-
- // Over-approx query
- reporter.underapproximationMode = false;
-
- // Push "true" for all, except:
- // push "false" for all candidates that have reached
- // the recursion bounds
-
- bool allTrue = true;
- bool allFalse = true;
- List<VCExpr> softAssumptions = new List<VCExpr>();
-
- assumptions = new List<VCExpr>();
- procsThatReachedRecBound.Clear();
-
- foreach (int id in calls.currCandidates) {
-
- int idBound = calls.getRecursionBound(id);
- int sd = calls.getStackDepth(id);
- if (idBound <= bound && (CommandLineOptions.Clo.StackDepthBound == 0 || sd <= CommandLineOptions.Clo.StackDepthBound)) {
- if (idBound > 1)
- softAssumptions.Add(calls.getFalseExpr(id));
-
- if (block.Contains(id)) {
- assumptions.Add(calls.getFalseExpr(id));
- allTrue = false;
- }
- else {
- allFalse = false;
- }
- }
- else {
- procsThatReachedRecBound.Add(calls.getProc(id));
- assumptions.Add(calls.getFalseExpr(id));
- allTrue = false;
- }
- }
-
- if (allFalse) {
- // If we made all candidates false, then this is the same
- // as the underapprox query. We already know the answer.
- ret = Outcome.Correct;
- }
- else {
- ret = CommandLineOptions.Clo.NonUniformUnfolding
- ? checker.CheckAssumptions(assumptions, softAssumptions)
- : checker.CheckAssumptions(assumptions);
- }
-
- if (ret != Outcome.Correct && ret != Outcome.Errors) {
- // The query ran out of memory or time, that's it,
- // we cannot do better. Give up!
- return ret;
- }
-
- if (ret == Outcome.Correct) {
- // If nothing was made false, then the program is correct
- if (allTrue) {
- return ret;
- }
-
- // Nothing more can be done with current recursion bound.
- return Outcome.ReachedBound;
- }
-
- Contract.Assert(ret == Outcome.Errors);
-
- prover.LogComment(";;;;;;;;;;;; Overapprox mode end ;;;;;;;;;;");
-
- return ret;
- }
-
- // A counter for adding new variables
- static int newVarCnt = 0;
-
- // Does on-demand inlining -- pushes procedure bodies on the theorem prover stack.
- private void DoExpansion(List<int>/*!*/ candidates, VerificationState vState) {
- Contract.Requires(candidates != null);
- Contract.Requires(vState.calls != null);
- Contract.Requires(vState.checker.prover != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- vState.expansionCount += candidates.Count;
-
- var prover = vState.checker.prover;
- var calls = vState.calls;
-
- VCExpr exprToPush = VCExpressionGenerator.True;
- Contract.Assert(exprToPush != null);
- foreach (int id in candidates) {
- VCExprNAry expr = calls.id2Candidate[id];
- Contract.Assert(expr != null);
- string procName = cce.NonNull(expr.Op as VCExprBoogieFunctionOp).Func.Name;
- if (!implName2StratifiedInliningInfo.ContainsKey(procName)) continue;
-
- StratifiedInliningInfo info = implName2StratifiedInliningInfo[procName];
- info.GenerateVC();
- //Console.WriteLine("Inlining {0}", procName);
- VCExpr expansion = cce.NonNull(info.vcexpr);
-
- // Instantiate the "forall" variables
- Dictionary<VCExprVar, VCExpr> substForallDict = new Dictionary<VCExprVar, VCExpr>();
- Contract.Assert(info.interfaceExprVars.Count == expr.Length);
- for (int i = 0; i < info.interfaceExprVars.Count; i++) {
- substForallDict.Add(info.interfaceExprVars[i], expr[i]);
- }
- VCExprSubstitution substForall = new VCExprSubstitution(substForallDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
-
- SubstitutingVCExprVisitor subst = new SubstitutingVCExprVisitor(prover.VCExprGen);
- Contract.Assert(subst != null);
- expansion = subst.Mutate(expansion, substForall);
-
- // Instantiate and declare the "exists" variables
- Dictionary<VCExprVar, VCExpr> substExistsDict = new Dictionary<VCExprVar, VCExpr>();
- foreach (VCExprVar v in info.privateExprVars) {
- Contract.Assert(v != null);
- string newName = v.Name + "_si_" + newVarCnt.ToString();
- newVarCnt++;
- prover.Context.DeclareConstant(new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, v.Type)), false, null);
- substExistsDict.Add(v, prover.VCExprGen.Variable(newName, v.Type));
- }
- if (CommandLineOptions.Clo.SIBoolControlVC)
- {
- // record the mapping for control booleans (for tracing the path later)
- calls.candiate2block2controlVar[id] = new Dictionary<Block, VCExpr>();
- foreach (var tup in info.blockToControlVar)
- {
- calls.candiate2block2controlVar[id].Add(tup.Key,
- substExistsDict[tup.Value]);
- }
- }
- if (CommandLineOptions.Clo.ModelViewFile != null) {
- SaveSubstitution(vState, id, substForallDict, substExistsDict);
- }
- VCExprSubstitution substExists = new VCExprSubstitution(substExistsDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>());
-
- subst = new SubstitutingVCExprVisitor(prover.VCExprGen);
- expansion = subst.Mutate(expansion, substExists);
-
- if (!calls.currCandidates.Contains(id)) {
- Console.WriteLine("Don't know what we just expanded");
- }
-
- calls.currCandidates.Remove(id);
-
- // Record the new set of candidates and rename absy labels
- calls.currInlineCount = id;
- calls.setCurrProc(procName);
- expansion = calls.Mutate(expansion, true);
-
- //expansion = checker.VCExprGen.Eq(calls.id2ControlVar[id], expansion);
- expansion = prover.VCExprGen.Implies(calls.id2ControlVar[id], expansion);
- calls.id2VC.Add(id, expansion);
-
- exprToPush = prover.VCExprGen.And(exprToPush, expansion);
- }
- vState.checker.prover.Assert(exprToPush, true);
- vState.vcSize += SizeComputingVisitor.ComputeSize(exprToPush);
- }
-
- private void SaveSubstitution(VerificationState vState, int id,
- Dictionary<VCExprVar, VCExpr> substForallDict, Dictionary<VCExprVar, VCExpr> substExistsDict) {
- var prover = vState.checker.prover;
- var calls = vState.calls;
- Boogie2VCExprTranslator translator = prover.Context.BoogieExprTranslator;
- VCExprVar mvStateConstant = translator.LookupVariable(ModelViewInfo.MVState_ConstantDef);
- substExistsDict.Add(mvStateConstant, prover.VCExprGen.Integer(BigNum.FromInt(id)));
- Dictionary<VCExprVar, VCExpr> mapping = new Dictionary<VCExprVar, VCExpr>();
- foreach (var key in substForallDict.Keys)
- mapping[key] = substForallDict[key];
- foreach (var key in substExistsDict.Keys)
- mapping[key] = substExistsDict[key];
- calls.id2Vars[id] = mapping;
- }
-
- // Uniquely identifies a procedure call (the call expr, instance)
- public class BoogieCallExpr : IEquatable<BoogieCallExpr> {
- public NAryExpr expr;
- public int inlineCnt;
-
- public BoogieCallExpr(NAryExpr expr, int inlineCnt) {
- this.expr = expr;
- this.inlineCnt = inlineCnt;
- }
-
- public override int GetHashCode() {
- return expr.GetHashCode() + 131 * inlineCnt.GetHashCode();
- }
-
- public override bool Equals(object obj) {
- BoogieCallExpr that = obj as BoogieCallExpr;
- return (expr == that.expr && inlineCnt == that.inlineCnt);
- }
-
- public bool Equals(BoogieCallExpr that) {
- return (expr == that.expr && inlineCnt == that.inlineCnt);
- }
- }
-
- // This class is used to traverse VCs and do the following:
- // -- collect the set of FunctionCall nodes and label them with a unique string
- // -- Rename all other labels (so that calling this on the same VC results in
- // VCs with different labels each time)
- public class FCallHandler : MutatingVCExprVisitor<bool> {
- Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo;
- public readonly Dictionary<int, Absy>/*!*/ mainLabel2absy;
- public Dictionary<BoogieCallExpr/*!*/, int>/*!*/ boogieExpr2Id;
- public Dictionary<BoogieCallExpr/*!*/, VCExpr>/*!*/ recordExpr2Var;
- public Dictionary<int, VCExprNAry/*!*/>/*!*/ id2Candidate;
- public Dictionary<int, VCExprVar/*!*/>/*!*/ id2ControlVar;
- public Dictionary<int, VCExpr> id2VC;
- public Dictionary<string/*!*/, int>/*!*/ label2Id;
- // candidate to block to Bool Control variable
- public Dictionary<int, Dictionary<Block, VCExpr>> candiate2block2controlVar;
- // Stores the candidate from which this one originated
- public Dictionary<int, int> candidateParent;
- // Mapping from candidate Id to the "si_unique_call" id that led to
- // this candidate. This is useful for getting persistent names for
- // candidates
- public Dictionary<int, int> candidate2callId;
- // A cache for candidate id to its persistent name
- public Dictionary<int, string> persistentNameCache;
- // Inverse of the above map
- public Dictionary<string, int> persistentNameInv;
- // Used to record candidates recently added
- public HashSet<int> recentlyAddedCandidates;
- // Name of main procedure
- private string mainProcName;
- // A map from candidate id to the VCExpr that represents its
- // first argument (used for obtaining concrete values in error trace)
- public Dictionary<int, VCExpr> argExprMap;
-
- // map from candidate to summary candidates
- public Dictionary<int, List<Tuple<VCExprVar, VCExpr>>> summaryCandidates;
- private Dictionary<string, List<Tuple<VCExprVar, VCExpr>>> summaryTemp;
- // set of all boolean guards of summaries
- public HashSet<VCExprVar> allSummaryConst;
-
- public HashSet<int> forcedCandidates;
-
- // User info -- to decrease/increase calculation of recursion bound
- public Dictionary<int, int> recursionIncrement;
- public Dictionary<string, int> extraRecursion;
-
- public HashSet<int> currCandidates;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Invariant(mainLabel2absy != null);
- Contract.Invariant(boogieExpr2Id != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(id2Candidate));
- Contract.Invariant(cce.NonNullDictionaryAndValues(id2ControlVar));
- Contract.Invariant(label2Id != null);
- }
-
- // Name of the procedure whose VC we're mutating
- string currProc;
-
- // The 0^th candidate is main
- static int candidateCount = 1;
- public int currInlineCount;
-
- public Dictionary<int, Dictionary<VCExprVar, VCExpr>> id2Vars;
-
- public FCallHandler(VCExpressionGenerator/*!*/ gen,
- Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo,
- string mainProcName, Dictionary<int, Absy>/*!*/ mainLabel2absy)
- : base(gen) {
- Contract.Requires(gen != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Requires(mainLabel2absy != null);
- this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
- this.mainProcName = mainProcName;
- this.mainLabel2absy = mainLabel2absy;
- id2Candidate = new Dictionary<int, VCExprNAry>();
- id2ControlVar = new Dictionary<int, VCExprVar>();
- boogieExpr2Id = new Dictionary<BoogieCallExpr, int>();
- label2Id = new Dictionary<string, int>();
- currCandidates = new HashSet<int>();
- currInlineCount = 0;
- currProc = null;
- labelRenamer = new Dictionary<string, int>();
- labelRenamerInv = new Dictionary<string, string>();
- candidateParent = new Dictionary<int, int>();
- //callGraphMapping = new Dictionary<int, int>();
- recursionIncrement = new Dictionary<int, int>();
- candidate2callId = new Dictionary<int, int>();
- persistentNameCache = new Dictionary<int, string>();
- persistentNameInv = new Dictionary<string, int>();
- persistentNameCache[0] = "0";
- persistentNameInv["0"] = 0;
- recentlyAddedCandidates = new HashSet<int>();
- argExprMap = new Dictionary<int, VCExpr>();
- recordExpr2Var = new Dictionary<BoogieCallExpr, VCExpr>();
- candiate2block2controlVar = new Dictionary<int, Dictionary<Block, VCExpr>>();
-
- forcedCandidates = new HashSet<int>();
- extraRecursion = new Dictionary<string, int>();
-
- id2Vars = new Dictionary<int, Dictionary<VCExprVar, VCExpr>>();
- summaryCandidates = new Dictionary<int, List<Tuple<VCExprVar, VCExpr>>>();
- summaryTemp = new Dictionary<string, List<Tuple<VCExprVar, VCExpr>>>();
- allSummaryConst = new HashSet<VCExprVar>();
- id2VC = new Dictionary<int, VCExpr>();
- }
-
- public void Clear() {
- currCandidates = new HashSet<int>();
- }
-
- // Return the set of all candidates
- public HashSet<int> getAllCandidates() {
- var ret = new HashSet<int>(candidateParent.Keys);
- ret.Add(0);
- return ret;
- }
-
- // Given a candidate "id", let proc(id) be the
- // procedure corresponding to id. This procedure returns
- // the number of times proc(id) appears as an ancestor
- // of id. This is the same as the number of times we've
- // recursed on proc(id)
- public int getRecursionBound(int id) {
- int ret = 1;
- var str = getProc(id);
-
- while (candidateParent.ContainsKey(id)) {
- if (recursionIncrement.ContainsKey(id)) ret += recursionIncrement[id];
- id = candidateParent[id];
- if (getProc(id) == str && !forcedCandidates.Contains(id)) ret++;
- }
-
- // Usual
- if (!extraRecursion.ContainsKey(str))
- return ret;
-
- // Usual
- if (ret <= CommandLineOptions.Clo.RecursionBound - 1)
- return ret;
-
- // Special
- if (ret >= CommandLineOptions.Clo.RecursionBound &&
- ret <= CommandLineOptions.Clo.RecursionBound + extraRecursion[str] - 1)
- return CommandLineOptions.Clo.RecursionBound - 1;
-
- // Special
- return ret - extraRecursion[str];
- }
-
- // This procedure returns the stack depth of the candidate
- // (distance from main)
- public int getStackDepth(int id)
- {
- int ret = 1;
-
- while (candidateParent.ContainsKey(id))
- {
- ret++;
- id = candidateParent[id];
- }
-
- return ret;
- }
-
- // Set user-define increment/decrement to recursionBound
- public void setRecursionIncrement(int id, int incr) {
- if (recursionIncrement.ContainsKey(id))
- recursionIncrement[id] = incr;
- else
- recursionIncrement.Add(id, incr);
- }
-
- // Returns the name of the procedure corresponding to candidate id
- public string getProc(int id) {
- if (id == 0) return mainProcName;
-
- return (id2Candidate[id].Op as VCExprBoogieFunctionOp).Func.Name;
- }
-
- // Get a unique id for this candidate (dependent only on the Call
- // graph of the program). The persistent id is:
- // 0: for main
- // a_b_c: where a is the persistent id of parent, and b is the procedure name
- // and c is the unique call id (if any)
- public string getPersistentId(int top_id) {
- if (top_id == 0) return "0";
- Debug.Assert(candidateParent.ContainsKey(top_id));
- if (persistentNameCache.ContainsKey(top_id))
- return persistentNameCache[top_id];
-
- var parent_id = getPersistentId(candidateParent[top_id]);
- var call_id = candidate2callId.ContainsKey(top_id) ? candidate2callId[top_id] : -1;
- var ret = string.Format("{0}_131_{1}_131_{2}", parent_id, getProc(top_id), call_id);
- persistentNameCache[top_id] = ret;
- persistentNameInv[ret] = top_id;
- return ret;
- }
-
- public int getCandidateFromGraphNode(string n) {
- if (!persistentNameInv.ContainsKey(n)) {
- return -1;
- }
- return persistentNameInv[n];
- }
-
- private int GetNewId(VCExprNAry vc) {
- Contract.Requires(vc != null);
- int id = candidateCount;
-
- id2Candidate[id] = vc;
- id2ControlVar[id] = Gen.Variable("si_control_var_bool_" + id.ToString(), Microsoft.Boogie.Type.Bool);
-
- candidateCount++;
- currCandidates.Add(id);
- recentlyAddedCandidates.Add(id);
-
- return id;
- }
-
- private string GetLabel(int id) {
- Contract.Ensures(Contract.Result<string>() != null);
-
- string ret = "si_fcall_" + id.ToString();
- if (!label2Id.ContainsKey(ret))
- label2Id[ret] = id;
-
- return ret;
- }
-
- public int GetId(string label) {
- Contract.Requires(label != null);
- if (!label2Id.ContainsKey(label))
- return -1;
- return label2Id[label];
- }
-
- Dictionary<string, int> labelRenamer;
- Dictionary<string, string> labelRenamerInv;
-
- public string RenameAbsyLabel(string label) {
- Contract.Requires(label != null);
- Contract.Requires(label.Length >= 1);
- Contract.Ensures(Contract.Result<string>() != null);
-
- // Remove the sign from the label
- string nosign = label.Substring(1);
- var ret = "si_inline_" + currInlineCount.ToString() + "_" + nosign;
-
- if (!labelRenamer.ContainsKey(ret)) {
- var c = labelRenamer.Count + 11; // two digit labels only
- labelRenamer.Add(ret, c);
- labelRenamerInv.Add(c.ToString(), ret);
- }
- return labelRenamer[ret].ToString();
- }
-
- public string ParseRenamedAbsyLabel(string label, int cnt) {
- Contract.Requires(label != null);
- if (!labelRenamerInv.ContainsKey(label)) {
- return null;
- }
- var str = labelRenamerInv[label];
- var prefix = "si_inline_" + cnt.ToString() + "_";
- if (!str.StartsWith(prefix)) return null;
- return str.Substring(prefix.Length);
- }
-
- public void setCurrProc(string name) {
- Contract.Requires(name != null);
- currProc = name;
- Contract.Assert(implName2StratifiedInliningInfo.ContainsKey(name));
- }
-
- public void setCurrProcAsMain() {
- currProc = "";
- }
-
- // Return the formula (candidate IFF false)
- public VCExpr getFalseExpr(int candidateId) {
- //return Gen.Eq(VCExpressionGenerator.False, id2ControlVar[candidateId]);
- return Gen.Not(id2ControlVar[candidateId]);
- }
-
- // Return the formula (candidate IFF true)
- public VCExpr getTrueExpr(int candidateId) {
- return Gen.Eq(VCExpressionGenerator.True, id2ControlVar[candidateId]);
- }
-
- public Dictionary<int, Absy> getLabel2absy() {
- Contract.Ensures(Contract.Result<Dictionary<int, Absy>>() != null);
-
- Contract.Assert(currProc != null);
- if (currProc == "") {
- return mainLabel2absy;
- }
- return cce.NonNull(implName2StratifiedInliningInfo[currProc].label2absy);
- }
-
- // Finds labels and changes them:
- // si_fcall_id: if "id" corresponds to a tracked procedure call, then
- // si_control_var_candidateId
- // si_fcall_id: if "id" does not corresponds to a tracked procedure call, then
- // delete
- // num: si_inline_num
- //
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- // has any of the subexpressions changed?
- bool changed,
- bool arg) {
- //Contract.Requires(originalNode != null);
- //Contract.Requires(cce.NonNullElements(newSubExprs));
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op,
- newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
- if (lop == null) return ret;
- if (!(ret is VCExprNAry)) return ret;
-
- VCExprNAry retnary = (VCExprNAry)ret;
- Contract.Assert(retnary != null);
- string prefix = "si_fcall_"; // from Wlp.ssc::Cmd(...)
- if (lop.label.Substring(1).StartsWith(prefix)) {
- int id = Int32.Parse(lop.label.Substring(prefix.Length + 1));
- Dictionary<int, Absy> label2absy = getLabel2absy();
- Absy cmd = label2absy[id] as Absy;
- //label2absy.Remove(id);
-
- Contract.Assert(cmd != null);
- AssumeCmd acmd = cmd as AssumeCmd;
- Contract.Assert(acmd != null);
- NAryExpr naryExpr = acmd.Expr as NAryExpr;
- Contract.Assert(naryExpr != null);
-
- string calleeName = naryExpr.Fun.FunctionName;
-
- VCExprNAry callExpr = retnary[0] as VCExprNAry;
-
- if (implName2StratifiedInliningInfo.ContainsKey(calleeName)) {
- Contract.Assert(callExpr != null);
- int candidateId = GetNewId(callExpr);
- boogieExpr2Id[new BoogieCallExpr(naryExpr, currInlineCount)] = candidateId;
- candidateParent[candidateId] = currInlineCount;
- candiate2block2controlVar[candidateId] = new Dictionary<Block, VCExpr>();
-
- string label = GetLabel(candidateId);
- var unique_call_id = QKeyValue.FindIntAttribute(acmd.Attributes, "si_unique_call", -1);
- if (unique_call_id != -1)
- candidate2callId[candidateId] = unique_call_id;
-
- //return Gen.LabelPos(label, callExpr);
- return Gen.LabelPos(label, id2ControlVar[candidateId]);
- }
- else if (calleeName.StartsWith(recordProcName)) {
- Contract.Assert(callExpr != null);
- Debug.Assert(callExpr.Length == 1);
- Debug.Assert(callExpr[0] != null);
- recordExpr2Var[new BoogieCallExpr(naryExpr, currInlineCount)] = callExpr[0];
- return callExpr;
- }
- else {
- // callExpr can be null; this happens when the FunctionCall was on a
- // pure function (not procedure) and the function got inlined
- return retnary[0];
- }
- }
-
- // Else, rename label
- string newLabel = RenameAbsyLabel(lop.label);
- if (lop.pos) {
- return Gen.LabelPos(newLabel, retnary[0]);
- }
- else {
- return Gen.LabelNeg(newLabel, retnary[0]);
- }
-
- }
-
- // Upgrades summaryTemp to summaryCandidates by matching ensure clauses with
- // the appropriate candidate they came from
- public void matchSummaries() {
- var id2Set = new Dictionary<string, List<Tuple<int, HashSet<VCExprVar>>>>();
- foreach (var id in recentlyAddedCandidates) {
- var collect = new CollectVCVars();
- var proc = getProc(id);
- if (!id2Set.ContainsKey(proc)) id2Set.Add(proc, new List<Tuple<int, HashSet<VCExprVar>>>());
- id2Set[proc].Add(Tuple.Create(id, collect.Collect(id2Candidate[id], true)));
- }
-
- foreach (var kvp in summaryTemp) {
- Contract.Assert(id2Set.ContainsKey(kvp.Key));
- var ls = id2Set[kvp.Key];
- foreach (var tup in kvp.Value) {
- var collect = new CollectVCVars();
- var s1 = collect.Collect(tup.Item2, true);
- var found = false;
- foreach (var t in ls) {
- var s2 = t.Item2;
- if (s1.IsSubsetOf(s2)) {
- if (!summaryCandidates.ContainsKey(t.Item1))
- summaryCandidates.Add(t.Item1, new List<Tuple<VCExprVar, VCExpr>>());
- summaryCandidates[t.Item1].Add(tup);
- allSummaryConst.Add(tup.Item1);
- found = true;
- break;
- }
- }
- Contract.Assert(found);
- }
- }
- summaryTemp.Clear();
- }
-
- public IEnumerable<int> getInlinedCandidates() {
- return candidateParent.Keys.Except(currCandidates).Union(new int[] { 0 });
- }
-
- } // end FCallHandler
-
- // Collects the set of all VCExprVar in a given VCExpr
- class CollectVCVars : CollectingVCExprVisitor<HashSet<VCExprVar>, bool> {
- public override HashSet<VCExprVar> Visit(VCExprVar node, bool arg) {
- var ret = new HashSet<VCExprVar>();
- ret.Add(node);
- return ret;
- }
-
- protected override HashSet<VCExprVar> CombineResults(List<HashSet<VCExprVar>> results, bool arg) {
- var ret = new HashSet<VCExprVar>();
- results.Iter(s => ret.UnionWith(s));
- return ret;
- }
- }
-
- public class FCallInliner : MutatingVCExprVisitor<bool> {
- public Dictionary<int, VCExpr/*!*/>/*!*/ subst;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullDictionaryAndValues(subst));
- }
-
-
- public FCallInliner(VCExpressionGenerator gen)
- : base(gen) {
- Contract.Requires(gen != null);
- subst = new Dictionary<int, VCExpr>();
- }
-
- public void Clear() {
- subst = new Dictionary<int, VCExpr>();
- }
-
- protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode,
- List<VCExpr/*!*/>/*!*/ newSubExprs,
- // has any of the subexpressions changed?
- bool changed,
- bool arg) {
- //Contract.Requires(originalNode != null);Contract.Requires(newSubExprs != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr ret;
- if (changed)
- ret = Gen.Function(originalNode.Op, newSubExprs, originalNode.TypeArguments);
- else
- ret = originalNode;
-
- VCExprLabelOp lop = originalNode.Op as VCExprLabelOp;
- if (lop == null) return ret;
- if (!(ret is VCExprNAry)) return ret;
-
- string prefix = "si_fcall_"; // from FCallHandler::GetLabel
- if (lop.label.Substring(1).StartsWith(prefix)) {
- int id = Int32.Parse(lop.label.Substring(prefix.Length + 1));
- if (subst.ContainsKey(id)) {
- return subst[id];
- }
- }
- return ret;
- }
-
- } // end FCallInliner
-
-
-
- public class StratifiedInliningErrorReporter : ProverInterface.ErrorHandler {
- Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo;
- ProverInterface theoremProver;
- VerifierCallback callback;
- FCallHandler calls;
- StratifiedInliningInfo mainInfo;
- StratifiedVC mainVC;
-
- public bool underapproximationMode;
- public List<int> candidatesToExpand;
- public List<StratifiedCallSite> callSitesToExpand;
-
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(candidatesToExpand != null);
- Contract.Invariant(mainInfo != null);
- Contract.Invariant(callback != null);
- Contract.Invariant(theoremProver != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- }
-
-
- public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo,
- ProverInterface theoremProver, VerifierCallback callback,
- StratifiedInliningInfo mainInfo) {
- Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Requires(theoremProver != null);
- Contract.Requires(callback != null);
- Contract.Requires(mainInfo != null);
- this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
- this.theoremProver = theoremProver;
- this.callback = callback;
- this.mainInfo = mainInfo;
- this.underapproximationMode = false;
- this.calls = null;
- this.candidatesToExpand = new List<int>();
- }
-
- public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo,
- ProverInterface theoremProver, VerifierCallback callback,
- StratifiedVC mainVC) {
- Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo));
- Contract.Requires(theoremProver != null);
- Contract.Requires(callback != null);
- Contract.Requires(mainVC != null);
- this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo;
- this.theoremProver = theoremProver;
- this.callback = callback;
- this.mainVC = mainVC;
- this.underapproximationMode = false;
- this.candidatesToExpand = new List<int>();
- }
-
- public void SetCandidateHandler(FCallHandler calls) {
- Contract.Requires(calls != null);
- this.calls = calls;
- }
-
- List<Tuple<int, int>> orderedStateIds;
-
- private Model.Element GetModelValue(Model m, Variable v, int candidateId) {
- // first, get the unique name
- string uniqueName;
-
- VCExprVar vvar = theoremProver.Context.BoogieExprTranslator.TryLookupVariable(v);
- if (vvar == null) {
- uniqueName = v.Name;
- }
- else {
- if (candidateId != 0) {
- Dictionary<VCExprVar, VCExpr> mapping = calls.id2Vars[candidateId];
- if (mapping.ContainsKey(vvar)) {
- VCExpr e = mapping[vvar];
- if (e is VCExprLiteral) {
- VCExprLiteral lit = (VCExprLiteral)e;
- return m.MkElement(lit.ToString());
- }
- vvar = (VCExprVar)mapping[vvar];
- }
- }
- uniqueName = theoremProver.Context.Lookup(vvar);
- }
-
- var f = m.TryGetFunc(uniqueName);
- if (f == null)
- return m.MkFunc("@undefined", 0).GetConstant();
- return f.GetConstant();
- }
-
- public readonly static int CALL = -1;
- public readonly static int RETURN = -2;
-
- public void PrintModel(Model model) {
- var filename = CommandLineOptions.Clo.ModelViewFile;
- if (model == null || filename == null) return;
-
- if (filename == "-") {
- model.Write(Console.Out);
- Console.Out.Flush();
- }
- else {
- using (var wr = new StreamWriter(filename, !Counterexample.firstModelFile)) {
- Counterexample.firstModelFile = false;
- model.Write(wr);
- }
- }
- }
-
- private void GetModelWithStates(Model m) {
- if (m == null) return;
- var mvInfo = mainInfo.mvInfo;
- var mvstates = m.TryGetFunc("$mv_state");
- if (mvstates == null)
- return;
-
- Contract.Assert(mvstates.Arity == 2);
-
- foreach (Variable v in mvInfo.AllVariables) {
- m.InitialState.AddBinding(v.Name, GetModelValue(m, v, 0));
- }
-
- int lastCandidate = 0;
- int lastCapturePoint = CALL;
- for (int i = 0; i < this.orderedStateIds.Count; ++i) {
- var s = orderedStateIds[i];
- int candidate = s.Item1;
- int capturePoint = s.Item2;
- string implName = calls.getProc(candidate);
- ModelViewInfo info = candidate == 0 ? mvInfo : implName2StratifiedInliningInfo[implName].mvInfo;
-
- if (capturePoint == CALL || capturePoint == RETURN) {
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- continue;
- }
-
- Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count);
- VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint];
- var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate)
- ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>();
- var cs = m.MkState(map.Description);
-
- foreach (Variable v in info.AllVariables) {
- var e = (Expr)map.IncarnationMap[v];
-
- if (e == null) {
- if (lastCapturePoint == CALL || lastCapturePoint == RETURN) {
- cs.AddBinding(v.Name, GetModelValue(m, v, candidate));
- }
- continue;
- }
-
- if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables
-
- Model.Element elt;
- if (e is IdentifierExpr) {
- IdentifierExpr ide = (IdentifierExpr)e;
- elt = GetModelValue(m, ide.Decl, candidate);
- }
- else if (e is LiteralExpr) {
- LiteralExpr lit = (LiteralExpr)e;
- elt = m.MkElement(lit.Val.ToString());
- }
- else {
- Contract.Assume(false);
- elt = m.MkFunc(e.ToString(), 0).GetConstant();
- }
- cs.AddBinding(v.Name, elt);
- }
-
- lastCandidate = candidate;
- lastCapturePoint = capturePoint;
- }
-
- return;
- }
-
- public override void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null)
- {
- //Contract.Requires(message != null);
- }
-
- public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
- if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
- model.Write(ErrorReporter.ModelWriter);
- ErrorReporter.ModelWriter.Flush();
- }
-
- // Timeout?
- if (proverOutcome != ProverInterface.Outcome.Invalid)
- return;
-
- candidatesToExpand = new List<int>();
- orderedStateIds = new List<Tuple<int, int>>();
- var cex = GenerateTrace(labels, model, 0, mainInfo.impl, mainInfo.mvInfo);
-
- if (underapproximationMode && cex != null) {
- //Debug.Assert(candidatesToExpand.All(calls.isSkipped));
- GetModelWithStates(model);
- callback.OnCounterexample(cex, null);
- this.PrintModel(model);
- }
- }
-
- private Counterexample GenerateTrace(IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel,
- int candidateId, Implementation procImpl, ModelViewInfo mvInfo) {
- Contract.Requires(cce.NonNullElements(labels));
- Contract.Requires(procImpl != null);
-
- Hashtable traceNodes = new Hashtable();
-
- if (!CommandLineOptions.Clo.SIBoolControlVC)
- {
- foreach (string s in labels)
- {
- Contract.Assert(s != null);
- var absylabel = calls.ParseRenamedAbsyLabel(s, candidateId);
-
- if (absylabel == null) continue;
-
- Absy absy;
-
- if (candidateId == 0)
- {
- absy = Label2Absy(absylabel);
- }
- else
- {
- absy = Label2Absy(procImpl.Name, absylabel);
- }
-
- if (traceNodes.ContainsKey(absy))
- System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes");
- else
- traceNodes.Add(absy, null);
- }
- }
- else
- {
- Debug.Assert(CommandLineOptions.Clo.UseProverEvaluate, "Must use prover evaluate option with boolControlVC");
- var block = procImpl.Blocks[0];
- traceNodes.Add(block, null);
- while (true)
- {
- var gc = block.TransferCmd as GotoCmd;
- if (gc == null) break;
- Block next = null;
- foreach (var succ in gc.labelTargets)
- {
- var succtaken = (bool) theoremProver.Evaluate(calls.candiate2block2controlVar[candidateId][succ]);
- if (succtaken)
- {
- next = succ;
- traceNodes.Add(succ, null);
- break;
- }
- }
- Debug.Assert(next != null, "Must find a successor");
- Debug.Assert(traceNodes.ContainsKey(next), "CFG cannot be cyclic");
- block = next;
- }
- }
-
- List<Block> trace = new List<Block>();
- Block entryBlock = cce.NonNull(procImpl.Blocks[0]);
- Contract.Assert(entryBlock != null);
- Contract.Assert(traceNodes.Contains(entryBlock));
- trace.Add(entryBlock);
-
- var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
- Counterexample newCounterexample = GenerateTraceRec(labels, errModel, mvInfo, candidateId, entryBlock, traceNodes, trace, calleeCounterexamples);
-
- return newCounterexample;
- }
-
- private Counterexample GenerateTraceRec(
- IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel, ModelViewInfo mvInfo,
- int candidateId,
- Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace,
- Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples) {
- Contract.Requires(cce.NonNullElements(labels));
- Contract.Requires(b != null);
- Contract.Requires(traceNodes != null);
- Contract.Requires(trace != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
- // After translation, all potential errors come from asserts.
- while (true) {
- List<Cmd> cmds = b.Cmds;
- TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
- for (int i = 0; i < cmds.Count; i++) {
- Cmd cmd = cce.NonNull(cmds[i]);
-
- // Skip if 'cmd' not contained in the trace or not an assert
- if ((cmd is AssertCmd && traceNodes.Contains(cmd)) ||
- (cmd is AssumeCmd && QKeyValue.FindBoolAttribute((cmd as AssumeCmd).Attributes, "exitAssert")))
- {
- var acmd = cmd as AssertCmd;
- if (acmd == null) { acmd = new AssertCmd(Token.NoToken, Expr.True); }
- Counterexample newCounterexample = AssertCmdToCounterexample(acmd, transferCmd, trace, errModel, mvInfo, theoremProver.Context);
- newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
- return newCounterexample;
- }
-
- // Counterexample generation for inlined procedures
- AssumeCmd assumeCmd = cmd as AssumeCmd;
- if (assumeCmd == null)
- continue;
- NAryExpr naryExpr = assumeCmd.Expr as NAryExpr;
- if (naryExpr == null)
- continue;
- string calleeName = naryExpr.Fun.FunctionName;
- Contract.Assert(calleeName != null);
-
- BinaryOperator binOp = naryExpr.Fun as BinaryOperator;
- if (binOp != null && binOp.Op == BinaryOperator.Opcode.And) {
- Expr expr = naryExpr.Args[0];
- NAryExpr mvStateExpr = expr as NAryExpr;
- if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == ModelViewInfo.MVState_FunctionDef.Name) {
- LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr;
- orderedStateIds.Add(new Tuple<int, int>(candidateId, x.asBigNum.ToInt));
- }
- }
-
- if (calleeName.StartsWith(recordProcName) && (errModel != null || CommandLineOptions.Clo.UseProverEvaluate)) {
- var expr = calls.recordExpr2Var[new BoogieCallExpr(naryExpr, candidateId)];
-
- // Record concrete value of the argument to this procedure
- var args = new List<object>();
- if (errModel == null && CommandLineOptions.Clo.UseProverEvaluate)
- {
- object exprv;
- try
- {
- exprv = theoremProver.Evaluate(expr);
- }
- catch (Exception)
- {
- exprv = null;
- }
- args.Add(exprv);
- }
- else
- {
- if (expr is VCExprIntLit)
- {
- args.Add(errModel.MkElement((expr as VCExprIntLit).Val.ToString()));
- }
- else if (expr == VCExpressionGenerator.True)
- {
- args.Add(errModel.MkElement("true"));
- }
- else if (expr == VCExpressionGenerator.False)
- {
- args.Add(errModel.MkElement("false"));
- }
- else if (expr is VCExprVar)
- {
- var idExpr = expr as VCExprVar;
- string name = theoremProver.Context.Lookup(idExpr);
- Contract.Assert(name != null);
- Model.Func f = errModel.TryGetFunc(name);
- if (f != null)
- {
- args.Add(f.GetConstant());
- }
- }
- else
- {
- Contract.Assert(false);
- }
- }
- calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
- new CalleeCounterexampleInfo(null, args);
- continue;
- }
-
- if (!implName2StratifiedInliningInfo.ContainsKey(calleeName))
- continue;
-
- Contract.Assert(calls != null);
-
- int calleeId = calls.boogieExpr2Id[new BoogieCallExpr(naryExpr, candidateId)];
-
- if (calls.currCandidates.Contains(calleeId)) {
- candidatesToExpand.Add(calleeId);
- }
- else {
- orderedStateIds.Add(new Tuple<int, int>(calleeId, StratifiedInliningErrorReporter.CALL));
- var calleeInfo = implName2StratifiedInliningInfo[calleeName];
- calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] =
- new CalleeCounterexampleInfo(GenerateTrace(labels, errModel, calleeId, calleeInfo.impl, calleeInfo.mvInfo), new List<object>());
- orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN));
- }
- }
-
- GotoCmd gotoCmd = transferCmd as GotoCmd;
- if (gotoCmd != null) {
- b = null;
- foreach (Block bb in cce.NonNull(gotoCmd.labelTargets)) {
- Contract.Assert(bb != null);
- if (traceNodes.Contains(bb)) {
- trace.Add(bb);
- b = bb;
- break;
- }
- }
- if (b != null) continue;
- }
- return null;
- }
- }
-
- public override Absy Label2Absy(string label) {
- //Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- Contract.Assert(calls != null);
- return cce.NonNull((Absy)calls.mainLabel2absy[id]);
- }
-
- public Absy Label2Absy(string procName, string label) {
- Contract.Requires(label != null);
- Contract.Requires(procName != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- Dictionary<int, Absy> l2a = cce.NonNull(implName2StratifiedInliningInfo[procName]).label2absy;
- return cce.NonNull((Absy)l2a[id]);
- }
-
- public override void OnProverWarning(string msg) {
- //Contract.Requires(msg != null);
- callback.OnWarning(msg);
- }
- }
-
- } // class StratifiedVCGen
-
- public class EmptyErrorHandler : ProverInterface.ErrorHandler
- {
- public override void OnModel(IList<string> labels, Model model, ProverInterface.Outcome proverOutcome)
- { }
- }
-
- public class InvalidProgramForSecureVc : Exception
- {
- public InvalidProgramForSecureVc(string msg) :
- base(msg) { }
- }
-
- public class SecureVCGen : VCGen
- {
- // Z3
- ProverInterface prover;
- // Handler
- ErrorReporter handler;
- // dump file
- public static TokenTextWriter outfile = null;
-
-
- public SecureVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : base(program, logFilePath, appendLogFile, checkers)
- {
- prover = null;
- handler = null;
- if (CommandLineOptions.Clo.SecureVcGen != "" && outfile == null)
- {
- outfile = new TokenTextWriter(new StreamWriter(CommandLineOptions.Clo.SecureVcGen));
- CommandLineOptions.Clo.PrintInstrumented = true;
- var implsToVerify = new HashSet<string>(
- program.TopLevelDeclarations.OfType<Implementation>()
- .Where(impl => !impl.SkipVerification)
- .Select(impl => impl.Name));
-
- foreach (var decl in program.TopLevelDeclarations)
- {
- if (decl is NamedDeclaration && implsToVerify.Contains((decl as NamedDeclaration).Name))
- continue;
- decl.Emit(outfile, 0);
- }
- }
- }
-
- private Block GetExitBlock(Implementation impl)
- {
- var exitblocks = impl.Blocks.Where(blk => blk.TransferCmd is ReturnCmd);
- if (exitblocks.Count() == 1)
- return exitblocks.First();
- // create a new exit block
- var eb = new Block(Token.NoToken, "SVCeb", new List<Cmd>(), new ReturnCmd(Token.NoToken));
- foreach (var b in exitblocks)
- {
- b.TransferCmd = new GotoCmd(Token.NoToken, new List<Block> { eb });
- }
- impl.Blocks.Add(eb);
- return eb;
- }
-
- //static int LocalVarCounter = 0;
- private LocalVariable GetNewLocal(Variable v, string suffix)
- {
- return new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken,
- string.Format("svc_{0}_{1}", v.Name, suffix), v.TypedIdent.Type));
- }
-
- private void GenVc(Implementation impl, VerifierCallback collector)
- {
- if (impl.Proc.Requires.Any())
- throw new InvalidProgramForSecureVc("SecureVc: Requires not supported");
- if(impl.LocVars.Any(v => isVisible(v)))
- throw new InvalidProgramForSecureVc("SecureVc: Visible Local variables not allowed");
-
- // Desugar procedure calls
- DesugarCalls(impl);
-
- // Gather spec, remove existing ensures
- var secureAsserts = new List<AssertCmd>();
- var logicalAsserts = new List<AssertCmd>();
-
- foreach (var ens in impl.Proc.Ensures)
- {
- if(ens.Free)
- throw new InvalidProgramForSecureVc("SecureVc: Free Ensures not supported");
- var dd = new Duplicator();
- secureAsserts.Add(new AssertCmd(ens.tok, Expr.Not(ens.Condition)));
- logicalAsserts.Add(dd.VisitAssertCmd(new AssertCmd(ens.tok, ens.Condition)) as AssertCmd);
- }
- impl.Proc.Ensures.Clear();
-
- // Make a copy of the impl
- var dup = new Duplicator();
- var implDup = dup.VisitImplementation(impl);
-
- // Get exit block
- var eb = GetExitBlock(impl);
-
- // Create two blocks: one for secureAsserts, one for logical asserts
- var ebSecure = new Block(Token.NoToken, "svc_secure_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken));
- var ebLogical = new Block(Token.NoToken, "svc_logical_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken));
-
- eb.TransferCmd = new GotoCmd(eb.TransferCmd.tok, new List<Block> { ebSecure, ebLogical });
- impl.Blocks.Add(ebSecure);
- impl.Blocks.Add(ebLogical);
-
- // Rename spec, while create copies of the hidden variables
- var substOld = new Dictionary<Variable, Expr>();
- var substVarSpec = new Dictionary<Variable, Expr>();
- var substVarPath = new Dictionary<Variable, Expr>();
- foreach (var g in program.GlobalVariables)
- {
- if (!isHidden(g)) continue;
- var lv = GetNewLocal(g, "In");
- impl.LocVars.Add(lv);
- substOld.Add(g, Expr.Ident(lv));
- }
-
- for(int i = 0; i < impl.InParams.Count; i++)
- {
- var v = impl.Proc.InParams[i];
- if (!isHidden(v))
- {
- substVarSpec.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i]));
- continue;
- }
-
- var lv = GetNewLocal(v, "In");
- impl.LocVars.Add(lv);
- substVarSpec.Add(v, Expr.Ident(lv));
- substVarPath.Add(impl.InParams[i], Expr.Ident(lv));
- }
-
- for (int i = 0; i < impl.OutParams.Count; i++)
- {
- var v = impl.Proc.OutParams[i];
- if (!isHidden(v))
- {
- substVarSpec.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i]));
- continue;
- }
-
- var lv = GetNewLocal(v, "Out");
- impl.LocVars.Add(lv);
- substVarSpec.Add(v, Expr.Ident(lv));
- substVarPath.Add(impl.OutParams[i], Expr.Ident(lv));
- }
-
- foreach (var g in program.GlobalVariables)
- {
- if (!isHidden(g)) continue;
- if (!impl.Proc.Modifies.Any(ie => ie.Name == g.Name)) continue;
-
- var lv = GetNewLocal(g, "Out");
- impl.LocVars.Add(lv);
- substVarSpec.Add(g, Expr.Ident(lv));
- substVarPath.Add(g, Expr.Ident(lv));
- }
-
- secureAsserts = secureAsserts.ConvertAll(ac =>
- Substituter.ApplyReplacingOldExprs(
- Substituter.SubstitutionFromHashtable(substVarSpec),
- Substituter.SubstitutionFromHashtable(substOld),
- ac) as AssertCmd);
-
- var substVarProcToImpl = new Dictionary<Variable, Expr>();
- for (int i = 0; i < impl.InParams.Count; i++)
- substVarProcToImpl.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i]));
-
- for (int i = 0; i < impl.OutParams.Count; i++)
- substVarProcToImpl.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i]));
-
- logicalAsserts = logicalAsserts.ConvertAll(ac =>
- Substituter.Apply(Substituter.SubstitutionFromHashtable(substVarProcToImpl), ac)
- as AssertCmd);
-
- // Paths
- foreach (var path in GetAllPaths(implDup))
- {
- var wp = ComputeWP(implDup, path);
-
- // replace hidden variables to match those used in the spec
- wp = Substituter.ApplyReplacingOldExprs(
- Substituter.SubstitutionFromHashtable(substVarPath),
- Substituter.SubstitutionFromHashtable(substOld),
- wp);
-
- ebSecure.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(wp)));
- }
-
- ebSecure.Cmds.AddRange(secureAsserts);
- ebLogical.Cmds.AddRange(logicalAsserts);
-
- if (outfile != null)
- {
- impl.Proc.Emit(outfile, 0);
- impl.Emit(outfile, 0);
- }
-
- ModelViewInfo mvInfo;
- ConvertCFG2DAG(impl);
- var gotoCmdOrigins = PassifyImpl(impl, out mvInfo);
-
- var gen = prover.VCExprGen;
- var exprGen = prover.Context.ExprGen;
- var translator = prover.Context.BoogieExprTranslator;
-
- var label2absy = new Dictionary<int, Absy>();
- VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, prover.Context);
- translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
- var implVc = gen.Not(GenerateVCAux(impl, null, label2absy, prover.Context));
-
- handler = new VCGen.ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, incarnationOriginMap, collector, mvInfo, prover.Context, program);
-
- prover.Assert(implVc, true);
- }
-
- Expr ComputeWP(Implementation impl, List<Cmd> path)
- {
- Expr expr = Expr.True;
-
- // create constants for out varibles
- var subst = new Dictionary<Variable, Expr>();
- foreach (var g in impl.Proc.Modifies)
- {
- var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
- "svc_out_const_" + g.Name, g.Decl.TypedIdent.Type));
- subst.Add(c, g);
- expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), g));
- }
-
- foreach (var v in impl.OutParams)
- {
- var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken,
- "svc_out_const_" + v.Name, v.TypedIdent.Type));
- subst.Add(c, Expr.Ident(v));
- expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), Expr.Ident(v)));
- }
-
- // we need this technicality
- var subst1 = new Dictionary<Variable, Expr>();
- foreach (var g in program.GlobalVariables)
- {
- subst1.Add(g, new OldExpr(Token.NoToken, Expr.Ident(g)));
- }
-
- // Implicitly close with havoc of all the locals and OutParams
- path.Insert(0, new HavocCmd(Token.NoToken, new List<IdentifierExpr>(
- impl.LocVars.Select(v => Expr.Ident(v)).Concat(
- impl.OutParams.Select(v => Expr.Ident(v))))));
-
- for (int i = path.Count - 1; i >= 0; i--)
- {
- var cmd = path[i];
- if (cmd is AssumeCmd)
- {
- expr = Expr.And(expr, (cmd as AssumeCmd).Expr);
- }
- else if (cmd is AssignCmd)
- {
- var h = new Dictionary<Variable, Expr>();
- var acmd = cmd as AssignCmd;
- for (int j = 0; j < acmd.Lhss.Count; j++)
- {
- h.Add(acmd.Lhss[j].DeepAssignedVariable, acmd.Rhss[j]);
- }
- var s = Substituter.SubstitutionFromHashtable(h);
- expr = Substituter.Apply(s, expr);
- }
- else if (cmd is HavocCmd)
- {
- var h = new Dictionary<Variable, Expr>();
- var formals = new List<Variable>();
-
- var vc = new VariableCollector();
- vc.VisitExpr(expr);
-
- foreach (var ie in (cmd as HavocCmd).Vars)
- {
- if (!vc.usedVars.Contains(ie.Decl)) continue;
- var f = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken,
- ie.Decl.Name + "_formal", ie.Decl.TypedIdent.Type));
- h.Add(ie.Decl, Expr.Ident(f));
- formals.Add(f);
- }
- if (!formals.Any())
- continue;
- var s = Substituter.SubstitutionFromHashtable(h);
- expr = Substituter.Apply(s, expr);
- expr = new ExistsExpr(Token.NoToken, formals, expr);
- }
- else
- {
- throw new InvalidProgramForSecureVc(string.Format("Unhandled cmd: {0}", cmd));
- }
- }
-
- // Implicitly close with havoc of all the locals and OutParams
-
-
-
- expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst1), expr);
- expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst),
- Substituter.SubstitutionFromHashtable(new Dictionary<Variable,Expr>()), expr);
- expr.Typecheck(new TypecheckingContext(null));
- return expr;
- }
-
- // Generate all paths in the impl
- IEnumerable<List<Cmd>> GetAllPaths(Implementation impl)
- {
- var stk = new Stack<Tuple<Block, int>>();
- stk.Push(Tuple.Create(impl.Blocks[0], 0));
-
- while (stk.Any())
- {
- var tup = stk.Peek();
- if (tup.Item1.TransferCmd is ReturnCmd)
- {
- var ret = new List<Cmd>();
- var ls = stk.ToList();
- ls.Iter(t => ret.AddRange(t.Item1.Cmds));
- yield return ret;
-
- stk.Pop();
- continue;
- }
-
- stk.Pop();
-
- var gc = tup.Item1.TransferCmd as GotoCmd;
- if (gc.labelTargets.Count <= tup.Item2)
- continue;
-
- stk.Push(Tuple.Create(tup.Item1, tup.Item2 + 1));
- stk.Push(Tuple.Create(gc.labelTargets[tup.Item2], 0));
- }
- yield break;
- }
-
- bool isHidden(Variable v)
- {
- return QKeyValue.FindBoolAttribute(v.Attributes, "hidden");
- }
-
- bool isVisible(Variable v)
- {
- return !isHidden(v);
- }
-
- public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback)
- {
- Debug.Assert(this.program == program);
-
- // Record current time
- var startTime = DateTime.UtcNow;
-
- CommandLineOptions.Clo.ProverCCLimit = 1;
- prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime);
-
- // Flush any axioms that came with the program before we start SI on this implementation
- prover.AssertAxioms();
-
- GenVc(impl, callback);
-
- prover.Check();
- var outcome = prover.CheckOutcomeCore(handler);
- //var outcome = ProverInterface.Outcome.Valid;
-
- prover.Close();
-
-
-
- //Console.WriteLine("Answer = {0}", outcome);
-
- return ProverInterfaceOutcomeToConditionGenerationOutcome(outcome);
- }
- }
-
-} // namespace VC
+using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC { + using Bpl = Microsoft.Boogie; + + public class StratifiedVC { + public StratifiedInliningInfo info; + public int id; + public List<VCExprVar> interfaceExprVars; + + // boolControlVC (block -> its bool variable) + public Dictionary<Block, VCExpr> blockToControlVar; + // While using labels (block -> its label) + public Dictionary<Absy, string> block2label; + + public Dictionary<Block, List<StratifiedCallSite>> callSites; + public Dictionary<Block, List<StratifiedCallSite>> recordProcCallSites; + public VCExpr vcexpr; + + // Must-Reach Information + Dictionary<Block, VCExprVar> mustReachVar; + List<VCExprLetBinding> mustReachBindings; + + public StratifiedVC(StratifiedInliningInfo siInfo, HashSet<string> procCalls) { + info = siInfo; + info.GenerateVC(); + var vcgen = info.vcgen; + var prover = vcgen.prover; + VCExpressionGenerator gen = prover.VCExprGen; + var bet = prover.Context.BoogieExprTranslator; + + vcexpr = info.vcexpr; + id = vcgen.CreateNewId(); + interfaceExprVars = new List<VCExprVar>(); + Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>(); + foreach (VCExprVar v in info.interfaceExprVars) { + VCExprVar newVar = vcgen.CreateNewVar(v.Type); + interfaceExprVars.Add(newVar); + substDict.Add(v, newVar); + } + foreach (VCExprVar v in info.privateExprVars) { + substDict.Add(v, vcgen.CreateNewVar(v.Type)); + } + if(info.controlFlowVariable != null) + substDict.Add(bet.LookupVariable(info.controlFlowVariable), gen.Integer(BigNum.FromInt(id))); + VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>()); + SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen); + vcexpr = substVisitor.Mutate(vcexpr, subst); + + // For BoolControlVC generation + if (info.blockToControlVar != null) + { + blockToControlVar = new Dictionary<Block, VCExpr>(); + foreach (var tup in info.blockToControlVar) + blockToControlVar.Add(tup.Key, substDict[tup.Value]); + } + + // labels + if (info.label2absy != null) + { + block2label = new Dictionary<Absy, string>(); + vcexpr = RenameVCExprLabels.Apply(vcexpr, info.vcgen.prover.VCExprGen, info.label2absy, block2label); + } + + if(procCalls != null) + vcexpr = RemoveProcedureCalls.Apply(vcexpr, info.vcgen.prover.VCExprGen, procCalls); + + callSites = new Dictionary<Block, List<StratifiedCallSite>>(); + foreach (Block b in info.callSites.Keys) { + callSites[b] = new List<StratifiedCallSite>(); + foreach (CallSite cs in info.callSites[b]) { + callSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst)); + } + } + + recordProcCallSites = new Dictionary<Block, List<StratifiedCallSite>>(); + foreach (Block b in info.recordProcCallSites.Keys) { + recordProcCallSites[b] = new List<StratifiedCallSite>(); + foreach (CallSite cs in info.recordProcCallSites[b]) { + recordProcCallSites[b].Add(new StratifiedCallSite(cs, substVisitor, subst)); + } + } + } + + public VCExpr MustReach(Block block) + { + Contract.Assert(!CommandLineOptions.Clo.UseLabels); + + // This information is computed lazily + if (mustReachBindings == null) + { + var vcgen = info.vcgen; + var gen = vcgen.prover.VCExprGen; + var impl = info.impl; + mustReachVar = new Dictionary<Block, VCExprVar>(); + mustReachBindings = new List<VCExprLetBinding>(); + foreach (Block b in impl.Blocks) + mustReachVar[b] = vcgen.CreateNewVar(Bpl.Type.Bool); + + var dag = new Graph<Block>(); + dag.AddSource(impl.Blocks[0]); + foreach (Block b in impl.Blocks) + { + var gtc = b.TransferCmd as GotoCmd; + if (gtc != null) + foreach (Block dest in gtc.labelTargets) + dag.AddEdge(dest, b); + } + IEnumerable sortedNodes = dag.TopologicalSort(); + + foreach (Block currBlock in dag.TopologicalSort()) + { + if (currBlock == impl.Blocks[0]) + { + mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], VCExpressionGenerator.True)); + continue; + } + + VCExpr expr = VCExpressionGenerator.False; + foreach (var pred in dag.Successors(currBlock)) + { + VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(gen.Integer(BigNum.FromInt(id)), gen.Integer(BigNum.FromInt(pred.UniqueId))); + VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(currBlock.UniqueId))); + expr = gen.Or(expr, gen.And(mustReachVar[pred], controlTransferExpr)); + } + mustReachBindings.Add(gen.LetBinding(mustReachVar[currBlock], expr)); + } + } + + Contract.Assert(mustReachVar.ContainsKey(block)); + return info.vcgen.prover.VCExprGen.Let(mustReachBindings, mustReachVar[block]); + } + + public List<StratifiedCallSite> CallSites { + get { + var ret = new List<StratifiedCallSite>(); + foreach (var b in callSites.Keys) { + foreach (var cs in callSites[b]) { + ret.Add(cs); + } + } + return ret; + } + } + + public List<StratifiedCallSite> RecordProcCallSites { + get { + var ret = new List<StratifiedCallSite>(); + foreach (var b in recordProcCallSites.Keys) { + foreach (var cs in recordProcCallSites[b]) { + ret.Add(cs); + } + } + return ret; + } + } + + public override string ToString() + { + return info.impl.Name; + } + } + + // Rename all labels in a VC to (globally) fresh labels + class RenameVCExprLabels : MutatingVCExprVisitor<bool> + { + Dictionary<int, Absy> label2absy; + Dictionary<Absy, string> absy2newlabel; + static int counter = 11; + + RenameVCExprLabels(VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel) + : base(gen) + { + this.label2absy = label2absy; + this.absy2newlabel = absy2newlabel; + } + + public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, Dictionary<int, Absy> label2absy, Dictionary<Absy, string> absy2newlabel) + { + return (new RenameVCExprLabels(gen, label2absy, absy2newlabel)).Mutate(expr, true); + } + + // Finds labels and changes them to a globally unique label: + protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode, + List<VCExpr/*!*/>/*!*/ newSubExprs, + bool changed, + bool arg) + { + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpr ret; + if (changed) + ret = Gen.Function(originalNode.Op, + newSubExprs, originalNode.TypeArguments); + else + ret = originalNode; + + VCExprLabelOp lop = originalNode.Op as VCExprLabelOp; + if (lop == null) return ret; + if (!(ret is VCExprNAry)) return ret; + VCExprNAry retnary = (VCExprNAry)ret; + + // remove the sign + var nosign = 0; + if (!Int32.TryParse(lop.label.Substring(1), out nosign)) + return ret; + + if (!label2absy.ContainsKey(nosign)) + return ret; + + string newLabel = "SI" + counter.ToString(); + counter++; + absy2newlabel[label2absy[nosign]] = newLabel; + + if (lop.pos) + { + return Gen.LabelPos(newLabel, retnary[0]); + } + else + { + return Gen.LabelNeg(newLabel, retnary[0]); + } + + } + } + + // Remove the uninterpreted function calls that substitute procedure calls + class RemoveProcedureCalls : MutatingVCExprVisitor<bool> + { + HashSet<string> procNames; + + RemoveProcedureCalls(VCExpressionGenerator gen, HashSet<string> procNames) + : base(gen) + { + this.procNames = procNames; + } + + public static VCExpr Apply(VCExpr expr, VCExpressionGenerator gen, HashSet<string> procNames) + { + return (new RemoveProcedureCalls(gen, procNames)).Mutate(expr, true); + } + + // Finds labels and changes them to a globally unique label: + protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode, + List<VCExpr/*!*/>/*!*/ newSubExprs, + bool changed, + bool arg) + { + //Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpr ret; + if (changed) + ret = Gen.Function(originalNode.Op, + newSubExprs, originalNode.TypeArguments); + else + ret = originalNode; + + if (!(ret is VCExprNAry)) return ret; + VCExprNAry retnary = (VCExprNAry)ret; + if (!(retnary.Op is VCExprBoogieFunctionOp)) + return ret; + + var fcall = (retnary.Op as VCExprBoogieFunctionOp).Func.Name; + if (procNames.Contains(fcall)) + return VCExpressionGenerator.True; + return ret; + } + } + + + public class CallSite { + public string calleeName; + public List<VCExpr> interfaceExprs; + public Block block; + public int numInstr; // for TraceLocation + public VCExprVar callSiteVar; + public QKeyValue Attributes; // attributes on the call cmd + public CallSite(string callee, List<VCExpr> interfaceExprs, VCExprVar callSiteVar, Block block, int numInstr, QKeyValue Attributes) + { + this.calleeName = callee; + this.interfaceExprs = interfaceExprs; + this.callSiteVar = callSiteVar; + this.block = block; + this.numInstr = numInstr; + this.Attributes = Attributes; + } + } + + public class StratifiedCallSite { + public CallSite callSite; + public List<VCExpr> interfaceExprs; + public VCExpr callSiteExpr; + + public StratifiedCallSite(CallSite cs, SubstitutingVCExprVisitor substVisitor, VCExprSubstitution subst) { + callSite = cs; + interfaceExprs = new List<VCExpr>(); + foreach (VCExpr v in cs.interfaceExprs) { + interfaceExprs.Add(substVisitor.Mutate(v, subst)); + } + if (callSite.callSiteVar != null) + callSiteExpr = substVisitor.Mutate(callSite.callSiteVar, subst); + } + + public VCExpr Attach(StratifiedVC svc) { + Contract.Assert(interfaceExprs.Count == svc.interfaceExprVars.Count); + StratifiedInliningInfo info = svc.info; + ProverInterface prover = info.vcgen.prover; + VCExpressionGenerator gen = prover.VCExprGen; + + Dictionary<VCExprVar, VCExpr> substDict = new Dictionary<VCExprVar, VCExpr>(); + for (int i = 0; i < svc.interfaceExprVars.Count; i++) { + VCExprVar v = svc.interfaceExprVars[i]; + substDict.Add(v, interfaceExprs[i]); + } + VCExprSubstitution subst = new VCExprSubstitution(substDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>()); + SubstitutingVCExprVisitor substVisitor = new SubstitutingVCExprVisitor(prover.VCExprGen); + svc.vcexpr = substVisitor.Mutate(svc.vcexpr, subst); + foreach (StratifiedCallSite scs in svc.CallSites) { + List<VCExpr> newInterfaceExprs = new List<VCExpr>(); + foreach (VCExpr expr in scs.interfaceExprs) { + newInterfaceExprs.Add(substVisitor.Mutate(expr, subst)); + } + scs.interfaceExprs = newInterfaceExprs; + } + foreach (StratifiedCallSite scs in svc.RecordProcCallSites) { + List<VCExpr> newInterfaceExprs = new List<VCExpr>(); + foreach (VCExpr expr in scs.interfaceExprs) { + newInterfaceExprs.Add(substVisitor.Mutate(expr, subst)); + } + scs.interfaceExprs = newInterfaceExprs; + } + //return gen.Implies(callSiteExpr, svc.vcexpr); + return svc.vcexpr; + } + + public override string ToString() + { + return callSite.calleeName; + } + } + + public class StratifiedInliningInfo { + public StratifiedVCGenBase vcgen; + public Implementation impl; + public Function function; + public Variable controlFlowVariable; + public Cmd exitAssertCmd; + public VCExpr vcexpr; + public List<VCExprVar> interfaceExprVars; + public List<VCExprVar> privateExprVars; + public Dictionary<int, Absy> label2absy; + public ModelViewInfo mvInfo; + public Dictionary<Block, List<CallSite>> callSites; + public Dictionary<Block, List<CallSite>> recordProcCallSites; + public bool initialized { get; private set; } + // Instrumentation to apply after PassiveImpl, but before VCGen + Action<Implementation> PassiveImplInstrumentation; + + // boolControlVC (block -> its Bool variable) + public Dictionary<Block, VCExprVar> blockToControlVar; + + public StratifiedInliningInfo(Implementation implementation, StratifiedVCGenBase stratifiedVcGen, Action<Implementation> PassiveImplInstrumentation) { + vcgen = stratifiedVcGen; + impl = implementation; + this.PassiveImplInstrumentation = PassiveImplInstrumentation; + + List<Variable> functionInterfaceVars = new List<Variable>(); + foreach (Variable v in vcgen.program.GlobalVariables) { + functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true)); + } + foreach (Variable v in impl.InParams) { + functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true)); + } + foreach (Variable v in impl.OutParams) { + functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", v.TypedIdent.Type), true)); + } + foreach (IdentifierExpr e in impl.Proc.Modifies) { + if (e.Decl == null) continue; + functionInterfaceVars.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", e.Decl.TypedIdent.Type), true)); + } + Formal returnVar = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Bpl.Type.Bool), false); + function = new Function(Token.NoToken, impl.Name, functionInterfaceVars, returnVar); + vcgen.prover.Context.DeclareFunction(function, ""); + + List<Expr> exprs = new List<Expr>(); + foreach (Variable v in vcgen.program.GlobalVariables) { + Contract.Assert(v != null); + exprs.Add(new OldExpr(Token.NoToken, new IdentifierExpr(Token.NoToken, v))); + } + foreach (Variable v in impl.Proc.InParams) { + Contract.Assert(v != null); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + } + foreach (Variable v in impl.Proc.OutParams) { + Contract.Assert(v != null); + exprs.Add(new IdentifierExpr(Token.NoToken, v)); + } + foreach (IdentifierExpr ie in impl.Proc.Modifies) { + Contract.Assert(ie != null); + if (ie.Decl == null) + continue; + exprs.Add(ie); + } + Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(function), exprs); + impl.Proc.Ensures.Add(new Ensures(Token.NoToken, true, freePostExpr, "", new QKeyValue(Token.NoToken, "si_fcall", new List<object>(), null))); + + initialized = false; + } + + public void GenerateVCBoolControl() + { + Debug.Assert(!initialized); + Debug.Assert(CommandLineOptions.Clo.SIBoolControlVC); + + // fix names for exit variables + var outputVariables = new List<Variable>(); + var assertConjuncts = new List<Expr>(); + foreach (Variable v in impl.OutParams) + { + Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type)); + outputVariables.Add(c); + Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v)); + assertConjuncts.Add(eqExpr); + } + foreach (IdentifierExpr e in impl.Proc.Modifies) + { + if (e.Decl == null) continue; + Variable v = e.Decl; + Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type)); + outputVariables.Add(c); + Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v)); + assertConjuncts.Add(eqExpr); + } + exitAssertCmd = new AssumeCmd(Token.NoToken, Expr.BinaryTreeAnd(assertConjuncts)); + (exitAssertCmd as AssumeCmd).Attributes = new QKeyValue(Token.NoToken, "exitAssert", new List<object>(), null); + + // no need for label2absy + label2absy = new Dictionary<int, Absy>(); + + // Passify + Program program = vcgen.program; + ProverInterface proverInterface = vcgen.prover; + vcgen.ConvertCFG2DAG(impl); + vcgen.PassifyImpl(impl, out mvInfo); + + VCExpressionGenerator gen = proverInterface.VCExprGen; + var exprGen = proverInterface.Context.ExprGen; + var translator = proverInterface.Context.BoogieExprTranslator; + + // add a boolean variable at each call site + vcgen.InstrumentCallSites(impl); + + // typecheck + var tc = new TypecheckingContext(null); + impl.Typecheck(tc); + + /////////////////// + // Generate the VC + /////////////////// + + // block -> bool variable + blockToControlVar = new Dictionary<Block, VCExprVar>(); + foreach (var b in impl.Blocks) + blockToControlVar.Add(b, gen.Variable(b.Label + "_holds", Bpl.Type.Bool)); + + vcexpr = VCExpressionGenerator.True; + foreach (var b in impl.Blocks) + { + // conjoin all assume cmds + VCExpr c = VCExpressionGenerator.True; + foreach (var cmd in b.Cmds) + { + var acmd = cmd as AssumeCmd; + if (acmd == null) + { + Debug.Assert(cmd is AssertCmd && (cmd as AssertCmd).Expr is LiteralExpr && + ((cmd as AssertCmd).Expr as LiteralExpr).IsTrue); + continue; + } + var expr = translator.Translate(acmd.Expr); + // Label the assume if it is a procedure call + NAryExpr naryExpr = acmd.Expr as NAryExpr; + if (naryExpr != null && naryExpr.Fun is FunctionCall) + { + var id = acmd.UniqueId; + label2absy[id] = acmd; + expr = gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), expr); + } + + c = gen.AndSimp(c, expr); + } + + // block implies a disjunction of successors + Debug.Assert(!(b.TransferCmd is ReturnExprCmd), "Not supported"); + var gc = b.TransferCmd as GotoCmd; + if (gc != null) + { + VCExpr succ = VCExpressionGenerator.False; + foreach (var sb in gc.labelTargets) + succ = gen.OrSimp(succ, blockToControlVar[sb]); + c = gen.AndSimp(c, succ); + } + else + { + // nothing to do + } + vcexpr = gen.AndSimp(vcexpr, gen.Eq(blockToControlVar[b], c)); + } + // assert start block + vcexpr = gen.AndSimp(vcexpr, blockToControlVar[impl.Blocks[0]]); + + //Console.WriteLine("VC of {0}: {1}", impl.Name, vcexpr); + // Collect other information + callSites = vcgen.CollectCallSites(impl); + recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl); + + // record interface variables + privateExprVars = new List<VCExprVar>(); + foreach (Variable v in impl.LocVars) + { + privateExprVars.Add(translator.LookupVariable(v)); + } + foreach (Variable v in impl.OutParams) + { + privateExprVars.Add(translator.LookupVariable(v)); + } + privateExprVars.AddRange(blockToControlVar.Values); + + interfaceExprVars = new List<VCExprVar>(); + foreach (Variable v in program.GlobalVariables) + { + interfaceExprVars.Add(translator.LookupVariable(v)); + } + foreach (Variable v in impl.InParams) + { + interfaceExprVars.Add(translator.LookupVariable(v)); + } + foreach (Variable v in outputVariables) + { + interfaceExprVars.Add(translator.LookupVariable(v)); + } + } + + public void GenerateVC() { + if (initialized) return; + if (CommandLineOptions.Clo.SIBoolControlVC) + { + GenerateVCBoolControl(); + initialized = true; + return; + } + List<Variable> outputVariables = new List<Variable>(); + List<Expr> assertConjuncts = new List<Expr>(); + foreach (Variable v in impl.OutParams) { + Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type)); + outputVariables.Add(c); + Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v)); + assertConjuncts.Add(eqExpr); + } + foreach (IdentifierExpr e in impl.Proc.Modifies) { + if (e.Decl == null) continue; + Variable v = e.Decl; + Constant c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, impl.Name + "_" + v.Name, v.TypedIdent.Type)); + outputVariables.Add(c); + Expr eqExpr = Expr.Eq(new IdentifierExpr(Token.NoToken, c), new IdentifierExpr(Token.NoToken, v)); + assertConjuncts.Add(eqExpr); + } + exitAssertCmd = new AssertCmd(Token.NoToken, Expr.Not(Expr.BinaryTreeAnd(assertConjuncts))); + + Program program = vcgen.program; + ProverInterface proverInterface = vcgen.prover; + vcgen.ConvertCFG2DAG(impl); + vcgen.PassifyImpl(impl, out mvInfo); + + VCExpressionGenerator gen = proverInterface.VCExprGen; + var exprGen = proverInterface.Context.ExprGen; + var translator = proverInterface.Context.BoogieExprTranslator; + + VCExpr controlFlowVariableExpr = null; + if (!CommandLineOptions.Clo.UseLabels) { + controlFlowVariable = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "@cfc", Microsoft.Boogie.Type.Int)); + controlFlowVariableExpr = translator.LookupVariable(controlFlowVariable); + } + + vcgen.InstrumentCallSites(impl); + + if (PassiveImplInstrumentation != null) + PassiveImplInstrumentation(impl); + + label2absy = new Dictionary<int, Absy>(); + VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, proverInterface.Context); + translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition); + vcexpr = gen.Not(vcgen.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverInterface.Context)); + + if (controlFlowVariableExpr != null) + { + VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(controlFlowVariableExpr, exprGen.Integer(BigNum.ZERO)); + VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId))); + vcexpr = exprGen.And(eqExpr, vcexpr); + } + + callSites = vcgen.CollectCallSites(impl); + recordProcCallSites = vcgen.CollectRecordProcedureCallSites(impl); + + privateExprVars = new List<VCExprVar>(); + foreach (Variable v in impl.LocVars) { + privateExprVars.Add(translator.LookupVariable(v)); + } + foreach (Variable v in impl.OutParams) { + privateExprVars.Add(translator.LookupVariable(v)); + } + + interfaceExprVars = new List<VCExprVar>(); + foreach (Variable v in program.GlobalVariables) { + interfaceExprVars.Add(translator.LookupVariable(v)); + } + foreach (Variable v in impl.InParams) { + interfaceExprVars.Add(translator.LookupVariable(v)); + } + foreach (Variable v in outputVariables) { + interfaceExprVars.Add(translator.LookupVariable(v)); + } + + initialized = true; + } + } + + public abstract class StratifiedVCGenBase : VCGen { + public readonly static string recordProcName = "boogie_si_record"; + public readonly static string callSiteVarAttr = "callSiteVar"; + public Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo; + public ProverInterface prover; + + public StratifiedVCGenBase(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers, Action<Implementation> PassiveImplInstrumentation) + : base(program, logFilePath, appendLogFile, checkers) { + implName2StratifiedInliningInfo = new Dictionary<string, StratifiedInliningInfo>(); + prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime); + foreach (var impl in program.Implementations) { + implName2StratifiedInliningInfo[impl.Name] = new StratifiedInliningInfo(impl, this, PassiveImplInstrumentation); + } + GenerateRecordFunctions(); + } + + private void GenerateRecordFunctions() { + foreach (var proc in program.Procedures) { + if (!proc.Name.StartsWith(recordProcName)) continue; + Contract.Assert(proc.InParams.Count == 1); + + // Make a new function + TypedIdent ti = new TypedIdent(Token.NoToken, "", Bpl.Type.Bool); + Contract.Assert(ti != null); + Formal returnVar = new Formal(Token.NoToken, ti, false); + Contract.Assert(returnVar != null); + + // Get record type + var argtype = proc.InParams[0].TypedIdent.Type; + + var ins = new List<Variable>(); + ins.Add(new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "x", argtype), true)); + + var recordFunc = new Function(Token.NoToken, proc.Name, ins, returnVar); + prover.Context.DeclareFunction(recordFunc, ""); + + var exprs = new List<Expr>(); + exprs.Add(new IdentifierExpr(Token.NoToken, proc.InParams[0])); + + Expr freePostExpr = new NAryExpr(Token.NoToken, new FunctionCall(recordFunc), exprs); + proc.Ensures.Add(new Ensures(true, freePostExpr)); + } + } + + public override void Close() { + prover.Close(); + base.Close(); + } + + public void InstrumentCallSites(Implementation implementation) { + var callSiteId = 0; + foreach (Block block in implementation.Blocks) { + List<Cmd> newCmds = new List<Cmd>(); + for (int i = 0; i < block.Cmds.Count; i++) { + Cmd cmd = block.Cmds[i]; + newCmds.Add(cmd); + AssumeCmd assumeCmd = cmd as AssumeCmd; + if (assumeCmd == null) continue; + NAryExpr naryExpr = assumeCmd.Expr as NAryExpr; + if (naryExpr == null) continue; + if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue; + Variable callSiteVar = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, "SICS" + callSiteId, Microsoft.Boogie.Type.Bool)); + implementation.LocVars.Add(callSiteVar); + var toInsert = new AssumeCmd(Token.NoToken, new IdentifierExpr(Token.NoToken, callSiteVar), + new QKeyValue(Token.NoToken, callSiteVarAttr, new List<object>(), null)); + newCmds.Add(toInsert); + callSiteId++; + } + block.Cmds = newCmds; + } + } + + public Dictionary<Block, List<CallSite>> CollectCallSites(Implementation implementation) { + var callSites = new Dictionary<Block, List<CallSite>>(); + foreach (Block block in implementation.Blocks) { + for (int i = 0; i < block.Cmds.Count; i++) { + Cmd cmd = block.Cmds[i]; + AssumeCmd assumeCmd = cmd as AssumeCmd; + if (assumeCmd == null) continue; + NAryExpr naryExpr = assumeCmd.Expr as NAryExpr; + if (naryExpr == null) continue; + if (!implName2StratifiedInliningInfo.ContainsKey(naryExpr.Fun.FunctionName)) continue; + List<VCExpr> interfaceExprs = new List<VCExpr>(); + foreach (Expr e in naryExpr.Args) { + interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e)); + } + int instr = i; + i++; + AssumeCmd callSiteAssumeCmd = (AssumeCmd)block.Cmds[i]; + IdentifierExpr iexpr = (IdentifierExpr) callSiteAssumeCmd.Expr; + CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, prover.Context.BoogieExprTranslator.LookupVariable(iexpr.Decl), block, instr, assumeCmd.Attributes); + if (!callSites.ContainsKey(block)) + callSites[block] = new List<CallSite>(); + callSites[block].Add(cs); + } + } + return callSites; + } + + public Dictionary<Block, List<CallSite>> CollectRecordProcedureCallSites(Implementation implementation) { + var callSites = new Dictionary<Block, List<CallSite>>(); + foreach (Block block in implementation.Blocks) { + for (int i = 0; i < block.Cmds.Count; i++) { + AssumeCmd assumeCmd = block.Cmds[i] as AssumeCmd; + if (assumeCmd == null) continue; + NAryExpr naryExpr = assumeCmd.Expr as NAryExpr; + if (naryExpr == null) continue; + if (!naryExpr.Fun.FunctionName.StartsWith(recordProcName)) continue; + List<VCExpr> interfaceExprs = new List<VCExpr>(); + foreach (Expr e in naryExpr.Args) { + interfaceExprs.Add(prover.Context.BoogieExprTranslator.Translate(e)); + } + CallSite cs = new CallSite(naryExpr.Fun.FunctionName, interfaceExprs, null, block, i, assumeCmd.Attributes); + if (!callSites.ContainsKey(block)) + callSites[block] = new List<CallSite>(); + callSites[block].Add(cs); + } + } + return callSites; + } + + private int macroCountForStratifiedInlining = 0; + public Macro CreateNewMacro() { + string newName = "SIMacro@" + macroCountForStratifiedInlining.ToString(); + macroCountForStratifiedInlining++; + return new Macro(Token.NoToken, newName, new List<Variable>(), new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "", Microsoft.Boogie.Type.Bool), false)); + } + private int varCountForStratifiedInlining = 0; + public VCExprVar CreateNewVar(Microsoft.Boogie.Type type) { + string newName = "SIV@" + varCountForStratifiedInlining.ToString(); + varCountForStratifiedInlining++; + Constant newVar = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, type)); + prover.Context.DeclareConstant(newVar, false, null); + return prover.VCExprGen.Variable(newVar.Name, type); + } + private int idCountForStratifiedInlining = 0; + public int CreateNewId() { + return idCountForStratifiedInlining++; + } + + // Used inside PassifyImpl + protected override void addExitAssert(string implName, Block exitBlock) { + if (implName2StratifiedInliningInfo != null && implName2StratifiedInliningInfo.ContainsKey(implName)) { + var exitAssertCmd = implName2StratifiedInliningInfo[implName].exitAssertCmd; + if(exitAssertCmd != null) exitBlock.Cmds.Add(exitAssertCmd); + } + } + + public override Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) { + // Construct the set of inlined procs in the original program + var inlinedProcs = new HashSet<string>(); + foreach (var decl in program.TopLevelDeclarations) { + // Implementations + if (decl is Implementation) { + var impl = decl as Implementation; + if (!(impl.Proc is LoopProcedure)) { + inlinedProcs.Add(impl.Name); + } + } + + // And recording procedures + if (decl is Procedure) { + var proc = decl as Procedure; + if (proc.Name.StartsWith(recordProcName)) { + Debug.Assert(!(decl is LoopProcedure)); + inlinedProcs.Add(proc.Name); + } + } + } + + return extractLoopTraceRec( + new CalleeCounterexampleInfo(cex, new List<object>()), + mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample; + } + + protected override bool elIsLoop(string procname) { + StratifiedInliningInfo info = null; + if (implName2StratifiedInliningInfo.ContainsKey(procname)) { + info = implName2StratifiedInliningInfo[procname]; + } + + if (info == null) return false; + + var lp = info.impl.Proc as LoopProcedure; + + if (lp == null) return false; + return true; + } + + public abstract Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars); + } + + public class StratifiedVCGen : StratifiedVCGenBase { + public bool PersistCallTree; + public static HashSet<string> callTree = null; + public int numInlined = 0; + public int vcsize = 0; + private HashSet<string> procsThatReachedRecBound; + private Dictionary<string, int> extraRecBound; + + public StratifiedVCGen(bool usePrevCallTree, HashSet<string> prevCallTree, + Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers) + : this(program, logFilePath, appendLogFile, checkers) + { + if (usePrevCallTree) { + callTree = prevCallTree; + PersistCallTree = true; + } + else { + PersistCallTree = false; + } + } + + public StratifiedVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers) + : base(program, logFilePath, appendLogFile, checkers, null) { + PersistCallTree = false; + procsThatReachedRecBound = new HashSet<string>(); + + extraRecBound = new Dictionary<string, int>(); + program.TopLevelDeclarations.OfType<Implementation>() + .Iter(impl => + { + var b = QKeyValue.FindIntAttribute(impl.Attributes, "SIextraRecBound", -1); + if (b != -1) extraRecBound.Add(impl.Name, b); + }); + } + + // Extra rec bound for procedures + public int GetExtraRecBound(string procName) { + if (!extraRecBound.ContainsKey(procName)) + return 0; + else return extraRecBound[procName]; + } + + public class ApiChecker { + public ProverInterface prover; + public ProverInterface.ErrorHandler reporter; + + public ApiChecker(ProverInterface prover, ProverInterface.ErrorHandler reporter) { + this.reporter = reporter; + this.prover = prover; + } + + private Outcome CheckVC() { + prover.Check(); + ProverInterface.Outcome outcome = prover.CheckOutcomeCore(reporter); + + return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome); + } + + public Outcome CheckAssumptions(List<VCExpr> assumptions) { + if (assumptions.Count == 0) { + return CheckVC(); + } + + prover.Push(); + foreach (var a in assumptions) { + prover.Assert(a, true); + } + Outcome ret = CheckVC(); + prover.Pop(); + return ret; + } + + public Outcome CheckAssumptions(List<VCExpr> hardAssumptions, List<VCExpr> softAssumptions) { + List<int> unsatisfiedSoftAssumptions; + ProverInterface.Outcome outcome = prover.CheckAssumptions(hardAssumptions, softAssumptions, out unsatisfiedSoftAssumptions, reporter); + return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome); + } + + public Outcome CheckAssumptions(List<VCExpr> assumptions, out List<int> unsatCore) { + ProverInterface.Outcome outcome = prover.CheckAssumptions(assumptions, out unsatCore, reporter); + return ConditionGeneration.ProverInterfaceOutcomeToConditionGenerationOutcome(outcome); + } + } + + // Store important information related to a single VerifyImplementation query + public class VerificationState { + // The call tree + public FCallHandler calls; + public ApiChecker checker; + // For statistics + public int vcSize; + public int expansionCount; + + public VerificationState(VCExpr vcMain, FCallHandler calls, ProverInterface prover, ProverInterface.ErrorHandler reporter) { + prover.Assert(vcMain, true); + this.calls = calls; + this.checker = new ApiChecker(prover, reporter); + vcSize = 0; + expansionCount = 0; + } + } + + class FindLeastOORException : Exception + { + public Outcome outcome; + + public FindLeastOORException(string msg, Outcome outcome) + : base(msg) + { + this.outcome = outcome; + } + } + + public override Outcome FindLeastToVerify(Implementation impl, ref HashSet<string> allBoolVars) { + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + + // Record current time + var startTime = DateTime.UtcNow; + + // No Max: avoids theorem prover restarts + CommandLineOptions.Clo.MaxProverMemory = 0; + + // Initialize cache + satQueryCache = new Dictionary<int, List<HashSet<string>>>(); + unsatQueryCache = new Dictionary<int, List<HashSet<string>>>(); + + Contract.Assert(implName2StratifiedInliningInfo != null); + + // Build VCs for all procedures + implName2StratifiedInliningInfo.Values + .Iter(info => info.GenerateVC()); + + // Get the VC of the current procedure + VCExpr vcMain = implName2StratifiedInliningInfo[impl.Name].vcexpr; + Dictionary<int, Absy> mainLabel2absy = implName2StratifiedInliningInfo[impl.Name].label2absy; + + // Find all procedure calls in vc and put labels on them + FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy); + calls.setCurrProcAsMain(); + vcMain = calls.Mutate(vcMain, true); + + try + { + + // Put all of the necessary state into one object + var vState = new VerificationState(vcMain, calls, prover, new EmptyErrorHandler()); + + // We'll restore the original state of the theorem prover at the end + // of this procedure + vState.checker.prover.Push(); + + // Do eager inlining + while (calls.currCandidates.Count > 0) + { + List<int> toExpand = new List<int>(); + + foreach (int id in calls.currCandidates) + { + Debug.Assert(calls.getRecursionBound(id) <= 1, "Recursion not supported"); + toExpand.Add(id); + } + DoExpansion(toExpand, vState); + } + + // Find all the boolean constants + var allConsts = new HashSet<VCExprVar>(); + foreach (var constant in program.Constants) + { + if (!allBoolVars.Contains(constant.Name)) continue; + var v = prover.Context.BoogieExprTranslator.LookupVariable(constant); + allConsts.Add(v); + } + + // Now, lets start the algo + var min = refinementLoop(vState.checker, new HashSet<VCExprVar>(), allConsts, allConsts); + + var ret = new HashSet<string>(); + foreach (var v in min) + { + //Console.WriteLine(v.Name); + ret.Add(v.Name); + } + allBoolVars = ret; + + vState.checker.prover.Pop(); + + return Outcome.Correct; + } + catch (FindLeastOORException e) + { + Console.WriteLine("Exception in FindLeastToVerify: {0}, {1}", e.Message, e.outcome); + return e.outcome; + } + } + + private HashSet<VCExprVar> refinementLoop(ApiChecker apiChecker, HashSet<VCExprVar> trackedVars, HashSet<VCExprVar> trackedVarsUpperBound, HashSet<VCExprVar> allVars) { + Debug.Assert(trackedVars.IsSubsetOf(trackedVarsUpperBound)); + + // If we already know the fate of all vars, then we're done. + if (trackedVars.Count == trackedVarsUpperBound.Count) + return new HashSet<VCExprVar>(trackedVars); + + // See if we already have enough variables tracked + var success = refinementLoopCheckPath(apiChecker, trackedVars, allVars); + if (success) { + // We have enough + return new HashSet<VCExprVar>(trackedVars); + } + + // If all that remains is 1 variable, then we know that we must track it + if (trackedVars.Count + 1 == trackedVarsUpperBound.Count) + return new HashSet<VCExprVar>(trackedVarsUpperBound); + + // Partition the remaining set of variables + HashSet<VCExprVar> part1, part2; + var temp = new HashSet<VCExprVar>(trackedVarsUpperBound); + temp.ExceptWith(trackedVars); + Partition<VCExprVar>(temp, out part1, out part2); + + // First half + var fh = new HashSet<VCExprVar>(trackedVars); fh.UnionWith(part2); + var s1 = refinementLoop(apiChecker, fh, trackedVarsUpperBound, allVars); + + var a = new HashSet<VCExprVar>(part1); a.IntersectWith(s1); + var b = new HashSet<VCExprVar>(part1); b.ExceptWith(s1); + var c = new HashSet<VCExprVar>(trackedVarsUpperBound); c.ExceptWith(b); + a.UnionWith(trackedVars); + + // Second half + return refinementLoop(apiChecker, a, c, allVars); + } + + Dictionary<int, List<HashSet<string>>> satQueryCache; + Dictionary<int, List<HashSet<string>>> unsatQueryCache; + + private bool refinementLoopCheckPath(ApiChecker apiChecker, HashSet<VCExprVar> varsToSet, HashSet<VCExprVar> allVars) { + var assumptions = new List<VCExpr>(); + var prover = apiChecker.prover; + var query = new HashSet<string>(); + varsToSet.Iter(v => query.Add(v.Name)); + + if (checkCache(query, unsatQueryCache)) { + prover.LogComment("FindLeast: Query Cache Hit"); + return true; + } + if (checkCache(query, satQueryCache)) { + prover.LogComment("FindLeast: Query Cache Hit"); + return false; + } + + prover.LogComment("FindLeast: Query Begin"); + + foreach (var c in allVars) { + if (varsToSet.Contains(c)) { + assumptions.Add(c); + } + else { + assumptions.Add(prover.VCExprGen.Not(c)); + } + } + + var o = apiChecker.CheckAssumptions(assumptions); + if (o != Outcome.Correct && o != Outcome.Errors) + { + throw new FindLeastOORException("OOR", o); + } + //Console.WriteLine("Result = " + o.ToString()); + prover.LogComment("FindLeast: Query End"); + + if (o == Outcome.Correct) { + insertCache(query, unsatQueryCache); + return true; + } + + insertCache(query, satQueryCache); + return false; + } + + private bool checkCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) { + if (!cache.ContainsKey(q.Count)) return false; + foreach (var s in cache[q.Count]) { + if (q.SetEquals(s)) return true; + } + return false; + } + + private void insertCache(HashSet<string> q, Dictionary<int, List<HashSet<string>>> cache) { + if (!cache.ContainsKey(q.Count)) { + cache.Add(q.Count, new List<HashSet<string>>()); + } + cache[q.Count].Add(q); + } + + public static void Partition<T>(HashSet<T> values, out HashSet<T> part1, out HashSet<T> part2) { + part1 = new HashSet<T>(); + part2 = new HashSet<T>(); + var size = values.Count; + var crossed = false; + var curr = 0; + foreach (var s in values) { + if (crossed) part2.Add(s); + else part1.Add(s); + curr++; + if (!crossed && curr >= size / 2) crossed = true; + } + } + + public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) { + Debug.Assert(QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint")); + Debug.Assert(this.program == program); + + // Record current time + var startTime = DateTime.UtcNow; + + // Flush any axioms that came with the program before we start SI on this implementation + prover.AssertAxioms(); + + // Run live variable analysis + if (CommandLineOptions.Clo.LiveVariableAnalysis == 2) { + Microsoft.Boogie.InterProcGenKill.ComputeLiveVars(impl, program); + } + + // Get the VC of the current procedure + StratifiedInliningInfo info = implName2StratifiedInliningInfo[impl.Name]; + info.GenerateVC(); + VCExpr vc = info.vcexpr; + Dictionary<int, Absy> mainLabel2absy = info.label2absy; + var reporter = new StratifiedInliningErrorReporter(implName2StratifiedInliningInfo, prover, callback, info); + + // Find all procedure calls in vc and put labels on them + FCallHandler calls = new FCallHandler(prover.VCExprGen, implName2StratifiedInliningInfo, impl.Name, mainLabel2absy); + calls.setCurrProcAsMain(); + vc = calls.Mutate(vc, true); + reporter.SetCandidateHandler(calls); + calls.id2VC.Add(0, vc); + calls.extraRecursion = extraRecBound; + if (CommandLineOptions.Clo.SIBoolControlVC) + { + calls.candiate2block2controlVar.Add(0, new Dictionary<Block, VCExpr>()); + implName2StratifiedInliningInfo[impl.Name].blockToControlVar.Iter(tup => + calls.candiate2block2controlVar[0].Add(tup.Key, tup.Value)); + } + + // We'll restore the original state of the theorem prover at the end + // of this procedure + prover.Push(); + + // Put all of the necessary state into one object + var vState = new VerificationState(vc, calls, prover, reporter); + vState.vcSize += SizeComputingVisitor.ComputeSize(vc); + + Outcome ret = Outcome.ReachedBound; + + #region eager inlining + for (int i = 1; i < CommandLineOptions.Clo.StratifiedInlining && calls.currCandidates.Count > 0; i++) { + List<int> toExpand = new List<int>(); + + foreach (int id in calls.currCandidates) { + if (calls.getRecursionBound(id) <= CommandLineOptions.Clo.RecursionBound) { + toExpand.Add(id); + } + } + DoExpansion(toExpand, vState); + } + #endregion + + #region Repopulate call tree, if there is one + if (PersistCallTree && callTree != null) { + bool expand = true; + while (expand) { + List<int> toExpand = new List<int>(); + foreach (int id in calls.currCandidates) { + if (callTree.Contains(calls.getPersistentId(id))) { + toExpand.Add(id); + } + } + if (toExpand.Count == 0) expand = false; + else { + DoExpansion(toExpand, vState); + } + } + } + #endregion + + if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) { + Console.WriteLine(">> SI: Size of VC after eager inlining: {0}", vState.vcSize); + } + + // Under-approx query is only needed if something was inlined since + // the last time an under-approx query was made + // TODO: introduce this + // bool underApproxNeeded = true; + + // The recursion bound for stratified search + int bound = CommandLineOptions.Clo.NonUniformUnfolding ? CommandLineOptions.Clo.RecursionBound : 1; + + int done = 0; + + int iters = 0; + + // for blocking candidates (and focusing on a counterexample) + var block = new HashSet<int>(); + + // Process tasks while not done. We're done when: + // case 1: (correct) We didn't find a bug (either an over-approx query was valid + // or we reached the recursion bound) and the task is "step" + // case 2: (bug) We find a bug + // case 3: (internal error) The theorem prover TimesOut of runs OutOfMemory + while (true) + { + // Check timeout + if (CommandLineOptions.Clo.ProverKillTime != -1) + { + if ((DateTime.UtcNow - startTime).TotalSeconds > CommandLineOptions.Clo.ProverKillTime) + { + ret = Outcome.TimedOut; + break; + } + } + + if (done > 0) + { + break; + } + + // Stratified Step + ret = stratifiedStep(bound, vState, block); + iters++; + + // Sorry, out of luck (time/memory) + if (ret == Outcome.Inconclusive || ret == Outcome.OutOfMemory || ret == Outcome.TimedOut) + { + done = 3; + continue; + } + + if (ret == Outcome.Errors && reporter.underapproximationMode) + { + // Found a bug + done = 2; + } + else if (ret == Outcome.Correct) + { + if (block.Count == 0) + { + // Correct + done = 1; + } + else + { + // reset blocked and continue loop + block.Clear(); + } + } + else if (ret == Outcome.ReachedBound) + { + if (block.Count == 0) + { + if (CommandLineOptions.Clo.StratifiedInliningVerbose > 0) + Console.WriteLine(">> SI: Exhausted Bound {0}", bound); + + // Increment bound + bound++; + + if (bound > CommandLineOptions.Clo.RecursionBound) + { + // Correct under bound + done = 1; + } + } + else + { + // reset blocked and continue loop + block.Clear(); + } + } + else + { + // Do inlining + Debug.Assert(ret == Outcome.Errors && !reporter.underapproximationMode); + Contract.Assert(reporter.candidatesToExpand.Count != 0); + + #region expand call tree + if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) + { + Console.Write(">> SI Inlining: "); + reporter.candidatesToExpand + .Select(c => calls.getProc(c)) + .Iter(c => Console.Write("{0} ", c)); + + Console.WriteLine(); + } + + // Expand and try again + vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion begin ;;;;;;;;;;"); + DoExpansion(reporter.candidatesToExpand, vState); + vState.checker.prover.LogComment(";;;;;;;;;;;; Expansion end ;;;;;;;;;;"); + + #endregion + } + } + + // Pop off everything that we pushed so that there are no side effects from + // this call to VerifyImplementation + vState.checker.prover.Pop(); + + if (CommandLineOptions.Clo.StratifiedInliningVerbose > 1) { + Console.WriteLine(">> SI: Expansions performed: {0}", vState.expansionCount); + Console.WriteLine(">> SI: Candidates left: {0}", calls.currCandidates.Count); + Console.WriteLine(">> SI: VC Size: {0}", vState.vcSize); + } + + vcsize = vState.vcSize; + numInlined = (calls.candidateParent.Keys.Count + 1) - (calls.currCandidates.Count); + + var rbound = "Procs that reached bound: "; + foreach (var s in procsThatReachedRecBound) rbound += " " + s; + if (ret == Outcome.ReachedBound) Helpers.ExtraTraceInformation(rbound); + if (CommandLineOptions.Clo.StackDepthBound > 0 && ret == Outcome.Correct) ret = Outcome.ReachedBound; + + // Store current call tree + if (PersistCallTree && (ret == Outcome.Correct || ret == Outcome.Errors || ret == Outcome.ReachedBound)) { + callTree = new HashSet<string>(); + //var persistentNodes = new HashSet<int>(calls.candidateParent.Values); + var persistentNodes = new HashSet<int>(calls.candidateParent.Keys); + persistentNodes.Add(0); + persistentNodes.ExceptWith(calls.currCandidates); + + foreach (var id in persistentNodes) { + var pid = calls.getPersistentId(id); + Debug.Assert(!callTree.Contains(pid)); + callTree.Add(pid); + } + } + return ret; + } + + // A step of the stratified inlining algorithm: both under-approx and over-approx queries + private Outcome stratifiedStep(int bound, VerificationState vState, HashSet<int> block) { + var calls = vState.calls; + var checker = vState.checker; + var prover = checker.prover; + var reporter = checker.reporter as StratifiedInliningErrorReporter; + + reporter.underapproximationMode = true; + prover.LogComment(";;;;;;;;;;;; Underapprox mode begin ;;;;;;;;;;"); + List<VCExpr> assumptions = new List<VCExpr>(); + + foreach (int id in calls.currCandidates) { + assumptions.Add(calls.getFalseExpr(id)); + } + Outcome ret = checker.CheckAssumptions(assumptions); + prover.LogComment(";;;;;;;;;;;; Underapprox mode end ;;;;;;;;;;"); + + if (ret != Outcome.Correct) { + // Either the query returned an error or it ran out of memory or time. + // In all cases, we are done. + return ret; + } + + if (calls.currCandidates.Count == 0) { + // If we didn't underapproximate, then we're done + return ret; + } + + prover.LogComment(";;;;;;;;;;;; Overapprox mode begin ;;;;;;;;;;"); + + // Over-approx query + reporter.underapproximationMode = false; + + // Push "true" for all, except: + // push "false" for all candidates that have reached + // the recursion bounds + + bool allTrue = true; + bool allFalse = true; + List<VCExpr> softAssumptions = new List<VCExpr>(); + + assumptions = new List<VCExpr>(); + procsThatReachedRecBound.Clear(); + + foreach (int id in calls.currCandidates) { + + int idBound = calls.getRecursionBound(id); + int sd = calls.getStackDepth(id); + if (idBound <= bound && (CommandLineOptions.Clo.StackDepthBound == 0 || sd <= CommandLineOptions.Clo.StackDepthBound)) { + if (idBound > 1) + softAssumptions.Add(calls.getFalseExpr(id)); + + if (block.Contains(id)) { + assumptions.Add(calls.getFalseExpr(id)); + allTrue = false; + } + else { + allFalse = false; + } + } + else { + procsThatReachedRecBound.Add(calls.getProc(id)); + assumptions.Add(calls.getFalseExpr(id)); + allTrue = false; + } + } + + if (allFalse) { + // If we made all candidates false, then this is the same + // as the underapprox query. We already know the answer. + ret = Outcome.Correct; + } + else { + ret = CommandLineOptions.Clo.NonUniformUnfolding + ? checker.CheckAssumptions(assumptions, softAssumptions) + : checker.CheckAssumptions(assumptions); + } + + if (ret != Outcome.Correct && ret != Outcome.Errors) { + // The query ran out of memory or time, that's it, + // we cannot do better. Give up! + return ret; + } + + if (ret == Outcome.Correct) { + // If nothing was made false, then the program is correct + if (allTrue) { + return ret; + } + + // Nothing more can be done with current recursion bound. + return Outcome.ReachedBound; + } + + Contract.Assert(ret == Outcome.Errors); + + prover.LogComment(";;;;;;;;;;;; Overapprox mode end ;;;;;;;;;;"); + + return ret; + } + + // A counter for adding new variables + static int newVarCnt = 0; + + // Does on-demand inlining -- pushes procedure bodies on the theorem prover stack. + private void DoExpansion(List<int>/*!*/ candidates, VerificationState vState) { + Contract.Requires(candidates != null); + Contract.Requires(vState.calls != null); + Contract.Requires(vState.checker.prover != null); + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + + vState.expansionCount += candidates.Count; + + var prover = vState.checker.prover; + var calls = vState.calls; + + VCExpr exprToPush = VCExpressionGenerator.True; + Contract.Assert(exprToPush != null); + foreach (int id in candidates) { + VCExprNAry expr = calls.id2Candidate[id]; + Contract.Assert(expr != null); + string procName = cce.NonNull(expr.Op as VCExprBoogieFunctionOp).Func.Name; + if (!implName2StratifiedInliningInfo.ContainsKey(procName)) continue; + + StratifiedInliningInfo info = implName2StratifiedInliningInfo[procName]; + info.GenerateVC(); + //Console.WriteLine("Inlining {0}", procName); + VCExpr expansion = cce.NonNull(info.vcexpr); + + // Instantiate the "forall" variables + Dictionary<VCExprVar, VCExpr> substForallDict = new Dictionary<VCExprVar, VCExpr>(); + Contract.Assert(info.interfaceExprVars.Count == expr.Length); + for (int i = 0; i < info.interfaceExprVars.Count; i++) { + substForallDict.Add(info.interfaceExprVars[i], expr[i]); + } + VCExprSubstitution substForall = new VCExprSubstitution(substForallDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>()); + + SubstitutingVCExprVisitor subst = new SubstitutingVCExprVisitor(prover.VCExprGen); + Contract.Assert(subst != null); + expansion = subst.Mutate(expansion, substForall); + + // Instantiate and declare the "exists" variables + Dictionary<VCExprVar, VCExpr> substExistsDict = new Dictionary<VCExprVar, VCExpr>(); + foreach (VCExprVar v in info.privateExprVars) { + Contract.Assert(v != null); + string newName = v.Name + "_si_" + newVarCnt.ToString(); + newVarCnt++; + prover.Context.DeclareConstant(new Constant(Token.NoToken, new TypedIdent(Token.NoToken, newName, v.Type)), false, null); + substExistsDict.Add(v, prover.VCExprGen.Variable(newName, v.Type)); + } + if (CommandLineOptions.Clo.SIBoolControlVC) + { + // record the mapping for control booleans (for tracing the path later) + calls.candiate2block2controlVar[id] = new Dictionary<Block, VCExpr>(); + foreach (var tup in info.blockToControlVar) + { + calls.candiate2block2controlVar[id].Add(tup.Key, + substExistsDict[tup.Value]); + } + } + if (CommandLineOptions.Clo.ModelViewFile != null) { + SaveSubstitution(vState, id, substForallDict, substExistsDict); + } + VCExprSubstitution substExists = new VCExprSubstitution(substExistsDict, new Dictionary<TypeVariable, Microsoft.Boogie.Type>()); + + subst = new SubstitutingVCExprVisitor(prover.VCExprGen); + expansion = subst.Mutate(expansion, substExists); + + if (!calls.currCandidates.Contains(id)) { + Console.WriteLine("Don't know what we just expanded"); + } + + calls.currCandidates.Remove(id); + + // Record the new set of candidates and rename absy labels + calls.currInlineCount = id; + calls.setCurrProc(procName); + expansion = calls.Mutate(expansion, true); + + //expansion = checker.VCExprGen.Eq(calls.id2ControlVar[id], expansion); + expansion = prover.VCExprGen.Implies(calls.id2ControlVar[id], expansion); + calls.id2VC.Add(id, expansion); + + exprToPush = prover.VCExprGen.And(exprToPush, expansion); + } + vState.checker.prover.Assert(exprToPush, true); + vState.vcSize += SizeComputingVisitor.ComputeSize(exprToPush); + } + + private void SaveSubstitution(VerificationState vState, int id, + Dictionary<VCExprVar, VCExpr> substForallDict, Dictionary<VCExprVar, VCExpr> substExistsDict) { + var prover = vState.checker.prover; + var calls = vState.calls; + Boogie2VCExprTranslator translator = prover.Context.BoogieExprTranslator; + VCExprVar mvStateConstant = translator.LookupVariable(ModelViewInfo.MVState_ConstantDef); + substExistsDict.Add(mvStateConstant, prover.VCExprGen.Integer(BigNum.FromInt(id))); + Dictionary<VCExprVar, VCExpr> mapping = new Dictionary<VCExprVar, VCExpr>(); + foreach (var key in substForallDict.Keys) + mapping[key] = substForallDict[key]; + foreach (var key in substExistsDict.Keys) + mapping[key] = substExistsDict[key]; + calls.id2Vars[id] = mapping; + } + + // Uniquely identifies a procedure call (the call expr, instance) + public class BoogieCallExpr : IEquatable<BoogieCallExpr> { + public NAryExpr expr; + public int inlineCnt; + + public BoogieCallExpr(NAryExpr expr, int inlineCnt) { + this.expr = expr; + this.inlineCnt = inlineCnt; + } + + public override int GetHashCode() { + return expr.GetHashCode() + 131 * inlineCnt.GetHashCode(); + } + + public override bool Equals(object obj) { + BoogieCallExpr that = obj as BoogieCallExpr; + return (expr == that.expr && inlineCnt == that.inlineCnt); + } + + public bool Equals(BoogieCallExpr that) { + return (expr == that.expr && inlineCnt == that.inlineCnt); + } + } + + // This class is used to traverse VCs and do the following: + // -- collect the set of FunctionCall nodes and label them with a unique string + // -- Rename all other labels (so that calling this on the same VC results in + // VCs with different labels each time) + public class FCallHandler : MutatingVCExprVisitor<bool> { + Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo; + public readonly Dictionary<int, Absy>/*!*/ mainLabel2absy; + public Dictionary<BoogieCallExpr/*!*/, int>/*!*/ boogieExpr2Id; + public Dictionary<BoogieCallExpr/*!*/, VCExpr>/*!*/ recordExpr2Var; + public Dictionary<int, VCExprNAry/*!*/>/*!*/ id2Candidate; + public Dictionary<int, VCExprVar/*!*/>/*!*/ id2ControlVar; + public Dictionary<int, VCExpr> id2VC; + public Dictionary<string/*!*/, int>/*!*/ label2Id; + // candidate to block to Bool Control variable + public Dictionary<int, Dictionary<Block, VCExpr>> candiate2block2controlVar; + // Stores the candidate from which this one originated + public Dictionary<int, int> candidateParent; + // Mapping from candidate Id to the "si_unique_call" id that led to + // this candidate. This is useful for getting persistent names for + // candidates + public Dictionary<int, int> candidate2callId; + // A cache for candidate id to its persistent name + public Dictionary<int, string> persistentNameCache; + // Inverse of the above map + public Dictionary<string, int> persistentNameInv; + // Used to record candidates recently added + public HashSet<int> recentlyAddedCandidates; + // Name of main procedure + private string mainProcName; + // A map from candidate id to the VCExpr that represents its + // first argument (used for obtaining concrete values in error trace) + public Dictionary<int, VCExpr> argExprMap; + + // map from candidate to summary candidates + public Dictionary<int, List<Tuple<VCExprVar, VCExpr>>> summaryCandidates; + private Dictionary<string, List<Tuple<VCExprVar, VCExpr>>> summaryTemp; + // set of all boolean guards of summaries + public HashSet<VCExprVar> allSummaryConst; + + public HashSet<int> forcedCandidates; + + // User info -- to decrease/increase calculation of recursion bound + public Dictionary<int, int> recursionIncrement; + public Dictionary<string, int> extraRecursion; + + public HashSet<int> currCandidates; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo)); + Contract.Invariant(mainLabel2absy != null); + Contract.Invariant(boogieExpr2Id != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(id2Candidate)); + Contract.Invariant(cce.NonNullDictionaryAndValues(id2ControlVar)); + Contract.Invariant(label2Id != null); + } + + // Name of the procedure whose VC we're mutating + string currProc; + + // The 0^th candidate is main + static int candidateCount = 1; + public int currInlineCount; + + public Dictionary<int, Dictionary<VCExprVar, VCExpr>> id2Vars; + + public FCallHandler(VCExpressionGenerator/*!*/ gen, + Dictionary<string/*!*/, StratifiedInliningInfo/*!*/>/*!*/ implName2StratifiedInliningInfo, + string mainProcName, Dictionary<int, Absy>/*!*/ mainLabel2absy) + : base(gen) { + Contract.Requires(gen != null); + Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo)); + Contract.Requires(mainLabel2absy != null); + this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo; + this.mainProcName = mainProcName; + this.mainLabel2absy = mainLabel2absy; + id2Candidate = new Dictionary<int, VCExprNAry>(); + id2ControlVar = new Dictionary<int, VCExprVar>(); + boogieExpr2Id = new Dictionary<BoogieCallExpr, int>(); + label2Id = new Dictionary<string, int>(); + currCandidates = new HashSet<int>(); + currInlineCount = 0; + currProc = null; + labelRenamer = new Dictionary<string, int>(); + labelRenamerInv = new Dictionary<string, string>(); + candidateParent = new Dictionary<int, int>(); + //callGraphMapping = new Dictionary<int, int>(); + recursionIncrement = new Dictionary<int, int>(); + candidate2callId = new Dictionary<int, int>(); + persistentNameCache = new Dictionary<int, string>(); + persistentNameInv = new Dictionary<string, int>(); + persistentNameCache[0] = "0"; + persistentNameInv["0"] = 0; + recentlyAddedCandidates = new HashSet<int>(); + argExprMap = new Dictionary<int, VCExpr>(); + recordExpr2Var = new Dictionary<BoogieCallExpr, VCExpr>(); + candiate2block2controlVar = new Dictionary<int, Dictionary<Block, VCExpr>>(); + + forcedCandidates = new HashSet<int>(); + extraRecursion = new Dictionary<string, int>(); + + id2Vars = new Dictionary<int, Dictionary<VCExprVar, VCExpr>>(); + summaryCandidates = new Dictionary<int, List<Tuple<VCExprVar, VCExpr>>>(); + summaryTemp = new Dictionary<string, List<Tuple<VCExprVar, VCExpr>>>(); + allSummaryConst = new HashSet<VCExprVar>(); + id2VC = new Dictionary<int, VCExpr>(); + } + + public void Clear() { + currCandidates = new HashSet<int>(); + } + + // Return the set of all candidates + public HashSet<int> getAllCandidates() { + var ret = new HashSet<int>(candidateParent.Keys); + ret.Add(0); + return ret; + } + + // Given a candidate "id", let proc(id) be the + // procedure corresponding to id. This procedure returns + // the number of times proc(id) appears as an ancestor + // of id. This is the same as the number of times we've + // recursed on proc(id) + public int getRecursionBound(int id) { + int ret = 1; + var str = getProc(id); + + while (candidateParent.ContainsKey(id)) { + if (recursionIncrement.ContainsKey(id)) ret += recursionIncrement[id]; + id = candidateParent[id]; + if (getProc(id) == str && !forcedCandidates.Contains(id)) ret++; + } + + // Usual + if (!extraRecursion.ContainsKey(str)) + return ret; + + // Usual + if (ret <= CommandLineOptions.Clo.RecursionBound - 1) + return ret; + + // Special + if (ret >= CommandLineOptions.Clo.RecursionBound && + ret <= CommandLineOptions.Clo.RecursionBound + extraRecursion[str] - 1) + return CommandLineOptions.Clo.RecursionBound - 1; + + // Special + return ret - extraRecursion[str]; + } + + // This procedure returns the stack depth of the candidate + // (distance from main) + public int getStackDepth(int id) + { + int ret = 1; + + while (candidateParent.ContainsKey(id)) + { + ret++; + id = candidateParent[id]; + } + + return ret; + } + + // Set user-define increment/decrement to recursionBound + public void setRecursionIncrement(int id, int incr) { + if (recursionIncrement.ContainsKey(id)) + recursionIncrement[id] = incr; + else + recursionIncrement.Add(id, incr); + } + + // Returns the name of the procedure corresponding to candidate id + public string getProc(int id) { + if (id == 0) return mainProcName; + + return (id2Candidate[id].Op as VCExprBoogieFunctionOp).Func.Name; + } + + // Get a unique id for this candidate (dependent only on the Call + // graph of the program). The persistent id is: + // 0: for main + // a_b_c: where a is the persistent id of parent, and b is the procedure name + // and c is the unique call id (if any) + public string getPersistentId(int top_id) { + if (top_id == 0) return "0"; + Debug.Assert(candidateParent.ContainsKey(top_id)); + if (persistentNameCache.ContainsKey(top_id)) + return persistentNameCache[top_id]; + + var parent_id = getPersistentId(candidateParent[top_id]); + var call_id = candidate2callId.ContainsKey(top_id) ? candidate2callId[top_id] : -1; + var ret = string.Format("{0}_131_{1}_131_{2}", parent_id, getProc(top_id), call_id); + persistentNameCache[top_id] = ret; + persistentNameInv[ret] = top_id; + return ret; + } + + public int getCandidateFromGraphNode(string n) { + if (!persistentNameInv.ContainsKey(n)) { + return -1; + } + return persistentNameInv[n]; + } + + private int GetNewId(VCExprNAry vc) { + Contract.Requires(vc != null); + int id = candidateCount; + + id2Candidate[id] = vc; + id2ControlVar[id] = Gen.Variable("si_control_var_bool_" + id.ToString(), Microsoft.Boogie.Type.Bool); + + candidateCount++; + currCandidates.Add(id); + recentlyAddedCandidates.Add(id); + + return id; + } + + private string GetLabel(int id) { + Contract.Ensures(Contract.Result<string>() != null); + + string ret = "si_fcall_" + id.ToString(); + if (!label2Id.ContainsKey(ret)) + label2Id[ret] = id; + + return ret; + } + + public int GetId(string label) { + Contract.Requires(label != null); + if (!label2Id.ContainsKey(label)) + return -1; + return label2Id[label]; + } + + Dictionary<string, int> labelRenamer; + Dictionary<string, string> labelRenamerInv; + + public string RenameAbsyLabel(string label) { + Contract.Requires(label != null); + Contract.Requires(label.Length >= 1); + Contract.Ensures(Contract.Result<string>() != null); + + // Remove the sign from the label + string nosign = label.Substring(1); + var ret = "si_inline_" + currInlineCount.ToString() + "_" + nosign; + + if (!labelRenamer.ContainsKey(ret)) { + var c = labelRenamer.Count + 11; // two digit labels only + labelRenamer.Add(ret, c); + labelRenamerInv.Add(c.ToString(), ret); + } + return labelRenamer[ret].ToString(); + } + + public string ParseRenamedAbsyLabel(string label, int cnt) { + Contract.Requires(label != null); + if (!labelRenamerInv.ContainsKey(label)) { + return null; + } + var str = labelRenamerInv[label]; + var prefix = "si_inline_" + cnt.ToString() + "_"; + if (!str.StartsWith(prefix)) return null; + return str.Substring(prefix.Length); + } + + public void setCurrProc(string name) { + Contract.Requires(name != null); + currProc = name; + Contract.Assert(implName2StratifiedInliningInfo.ContainsKey(name)); + } + + public void setCurrProcAsMain() { + currProc = ""; + } + + // Return the formula (candidate IFF false) + public VCExpr getFalseExpr(int candidateId) { + //return Gen.Eq(VCExpressionGenerator.False, id2ControlVar[candidateId]); + return Gen.Not(id2ControlVar[candidateId]); + } + + // Return the formula (candidate IFF true) + public VCExpr getTrueExpr(int candidateId) { + return Gen.Eq(VCExpressionGenerator.True, id2ControlVar[candidateId]); + } + + public Dictionary<int, Absy> getLabel2absy() { + Contract.Ensures(Contract.Result<Dictionary<int, Absy>>() != null); + + Contract.Assert(currProc != null); + if (currProc == "") { + return mainLabel2absy; + } + return cce.NonNull(implName2StratifiedInliningInfo[currProc].label2absy); + } + + // Finds labels and changes them: + // si_fcall_id: if "id" corresponds to a tracked procedure call, then + // si_control_var_candidateId + // si_fcall_id: if "id" does not corresponds to a tracked procedure call, then + // delete + // num: si_inline_num + // + protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode, + List<VCExpr/*!*/>/*!*/ newSubExprs, + // has any of the subexpressions changed? + bool changed, + bool arg) { + //Contract.Requires(originalNode != null); + //Contract.Requires(cce.NonNullElements(newSubExprs)); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpr ret; + if (changed) + ret = Gen.Function(originalNode.Op, + newSubExprs, originalNode.TypeArguments); + else + ret = originalNode; + + VCExprLabelOp lop = originalNode.Op as VCExprLabelOp; + if (lop == null) return ret; + if (!(ret is VCExprNAry)) return ret; + + VCExprNAry retnary = (VCExprNAry)ret; + Contract.Assert(retnary != null); + string prefix = "si_fcall_"; // from Wlp.ssc::Cmd(...) + if (lop.label.Substring(1).StartsWith(prefix)) { + int id = Int32.Parse(lop.label.Substring(prefix.Length + 1)); + Dictionary<int, Absy> label2absy = getLabel2absy(); + Absy cmd = label2absy[id] as Absy; + //label2absy.Remove(id); + + Contract.Assert(cmd != null); + AssumeCmd acmd = cmd as AssumeCmd; + Contract.Assert(acmd != null); + NAryExpr naryExpr = acmd.Expr as NAryExpr; + Contract.Assert(naryExpr != null); + + string calleeName = naryExpr.Fun.FunctionName; + + VCExprNAry callExpr = retnary[0] as VCExprNAry; + + if (implName2StratifiedInliningInfo.ContainsKey(calleeName)) { + Contract.Assert(callExpr != null); + int candidateId = GetNewId(callExpr); + boogieExpr2Id[new BoogieCallExpr(naryExpr, currInlineCount)] = candidateId; + candidateParent[candidateId] = currInlineCount; + candiate2block2controlVar[candidateId] = new Dictionary<Block, VCExpr>(); + + string label = GetLabel(candidateId); + var unique_call_id = QKeyValue.FindIntAttribute(acmd.Attributes, "si_unique_call", -1); + if (unique_call_id != -1) + candidate2callId[candidateId] = unique_call_id; + + //return Gen.LabelPos(label, callExpr); + return Gen.LabelPos(label, id2ControlVar[candidateId]); + } + else if (calleeName.StartsWith(recordProcName)) { + Contract.Assert(callExpr != null); + Debug.Assert(callExpr.Length == 1); + Debug.Assert(callExpr[0] != null); + recordExpr2Var[new BoogieCallExpr(naryExpr, currInlineCount)] = callExpr[0]; + return callExpr; + } + else { + // callExpr can be null; this happens when the FunctionCall was on a + // pure function (not procedure) and the function got inlined + return retnary[0]; + } + } + + // Else, rename label + string newLabel = RenameAbsyLabel(lop.label); + if (lop.pos) { + return Gen.LabelPos(newLabel, retnary[0]); + } + else { + return Gen.LabelNeg(newLabel, retnary[0]); + } + + } + + // Upgrades summaryTemp to summaryCandidates by matching ensure clauses with + // the appropriate candidate they came from + public void matchSummaries() { + var id2Set = new Dictionary<string, List<Tuple<int, HashSet<VCExprVar>>>>(); + foreach (var id in recentlyAddedCandidates) { + var collect = new CollectVCVars(); + var proc = getProc(id); + if (!id2Set.ContainsKey(proc)) id2Set.Add(proc, new List<Tuple<int, HashSet<VCExprVar>>>()); + id2Set[proc].Add(Tuple.Create(id, collect.Collect(id2Candidate[id], true))); + } + + foreach (var kvp in summaryTemp) { + Contract.Assert(id2Set.ContainsKey(kvp.Key)); + var ls = id2Set[kvp.Key]; + foreach (var tup in kvp.Value) { + var collect = new CollectVCVars(); + var s1 = collect.Collect(tup.Item2, true); + var found = false; + foreach (var t in ls) { + var s2 = t.Item2; + if (s1.IsSubsetOf(s2)) { + if (!summaryCandidates.ContainsKey(t.Item1)) + summaryCandidates.Add(t.Item1, new List<Tuple<VCExprVar, VCExpr>>()); + summaryCandidates[t.Item1].Add(tup); + allSummaryConst.Add(tup.Item1); + found = true; + break; + } + } + Contract.Assert(found); + } + } + summaryTemp.Clear(); + } + + public IEnumerable<int> getInlinedCandidates() { + return candidateParent.Keys.Except(currCandidates).Union(new int[] { 0 }); + } + + } // end FCallHandler + + // Collects the set of all VCExprVar in a given VCExpr + class CollectVCVars : CollectingVCExprVisitor<HashSet<VCExprVar>, bool> { + public override HashSet<VCExprVar> Visit(VCExprVar node, bool arg) { + var ret = new HashSet<VCExprVar>(); + ret.Add(node); + return ret; + } + + protected override HashSet<VCExprVar> CombineResults(List<HashSet<VCExprVar>> results, bool arg) { + var ret = new HashSet<VCExprVar>(); + results.Iter(s => ret.UnionWith(s)); + return ret; + } + } + + public class FCallInliner : MutatingVCExprVisitor<bool> { + public Dictionary<int, VCExpr/*!*/>/*!*/ subst; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullDictionaryAndValues(subst)); + } + + + public FCallInliner(VCExpressionGenerator gen) + : base(gen) { + Contract.Requires(gen != null); + subst = new Dictionary<int, VCExpr>(); + } + + public void Clear() { + subst = new Dictionary<int, VCExpr>(); + } + + protected override VCExpr/*!*/ UpdateModifiedNode(VCExprNAry/*!*/ originalNode, + List<VCExpr/*!*/>/*!*/ newSubExprs, + // has any of the subexpressions changed? + bool changed, + bool arg) { + //Contract.Requires(originalNode != null);Contract.Requires(newSubExprs != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpr ret; + if (changed) + ret = Gen.Function(originalNode.Op, newSubExprs, originalNode.TypeArguments); + else + ret = originalNode; + + VCExprLabelOp lop = originalNode.Op as VCExprLabelOp; + if (lop == null) return ret; + if (!(ret is VCExprNAry)) return ret; + + string prefix = "si_fcall_"; // from FCallHandler::GetLabel + if (lop.label.Substring(1).StartsWith(prefix)) { + int id = Int32.Parse(lop.label.Substring(prefix.Length + 1)); + if (subst.ContainsKey(id)) { + return subst[id]; + } + } + return ret; + } + + } // end FCallInliner + + + + public class StratifiedInliningErrorReporter : ProverInterface.ErrorHandler { + Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo; + ProverInterface theoremProver; + VerifierCallback callback; + FCallHandler calls; + StratifiedInliningInfo mainInfo; + StratifiedVC mainVC; + + public bool underapproximationMode; + public List<int> candidatesToExpand; + public List<StratifiedCallSite> callSitesToExpand; + + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(candidatesToExpand != null); + Contract.Invariant(mainInfo != null); + Contract.Invariant(callback != null); + Contract.Invariant(theoremProver != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo)); + } + + + public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo, + ProverInterface theoremProver, VerifierCallback callback, + StratifiedInliningInfo mainInfo) { + Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo)); + Contract.Requires(theoremProver != null); + Contract.Requires(callback != null); + Contract.Requires(mainInfo != null); + this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo; + this.theoremProver = theoremProver; + this.callback = callback; + this.mainInfo = mainInfo; + this.underapproximationMode = false; + this.calls = null; + this.candidatesToExpand = new List<int>(); + } + + public StratifiedInliningErrorReporter(Dictionary<string, StratifiedInliningInfo> implName2StratifiedInliningInfo, + ProverInterface theoremProver, VerifierCallback callback, + StratifiedVC mainVC) { + Contract.Requires(cce.NonNullDictionaryAndValues(implName2StratifiedInliningInfo)); + Contract.Requires(theoremProver != null); + Contract.Requires(callback != null); + Contract.Requires(mainVC != null); + this.implName2StratifiedInliningInfo = implName2StratifiedInliningInfo; + this.theoremProver = theoremProver; + this.callback = callback; + this.mainVC = mainVC; + this.underapproximationMode = false; + this.candidatesToExpand = new List<int>(); + } + + public void SetCandidateHandler(FCallHandler calls) { + Contract.Requires(calls != null); + this.calls = calls; + } + + List<Tuple<int, int>> orderedStateIds; + + private Model.Element GetModelValue(Model m, Variable v, int candidateId) { + // first, get the unique name + string uniqueName; + + VCExprVar vvar = theoremProver.Context.BoogieExprTranslator.TryLookupVariable(v); + if (vvar == null) { + uniqueName = v.Name; + } + else { + if (candidateId != 0) { + Dictionary<VCExprVar, VCExpr> mapping = calls.id2Vars[candidateId]; + if (mapping.ContainsKey(vvar)) { + VCExpr e = mapping[vvar]; + if (e is VCExprLiteral) { + VCExprLiteral lit = (VCExprLiteral)e; + return m.MkElement(lit.ToString()); + } + vvar = (VCExprVar)mapping[vvar]; + } + } + uniqueName = theoremProver.Context.Lookup(vvar); + } + + var f = m.TryGetFunc(uniqueName); + if (f == null) + return m.MkFunc("@undefined", 0).GetConstant(); + return f.GetConstant(); + } + + public readonly static int CALL = -1; + public readonly static int RETURN = -2; + + public void PrintModel(Model model) { + var filename = CommandLineOptions.Clo.ModelViewFile; + if (model == null || filename == null) return; + + if (filename == "-") { + model.Write(Console.Out); + Console.Out.Flush(); + } + else { + using (var wr = new StreamWriter(filename, !Counterexample.firstModelFile)) { + Counterexample.firstModelFile = false; + model.Write(wr); + } + } + } + + private void GetModelWithStates(Model m) { + if (m == null) return; + var mvInfo = mainInfo.mvInfo; + var mvstates = m.TryGetFunc("$mv_state"); + if (mvstates == null) + return; + + Contract.Assert(mvstates.Arity == 2); + + foreach (Variable v in mvInfo.AllVariables) { + m.InitialState.AddBinding(v.Name, GetModelValue(m, v, 0)); + } + + int lastCandidate = 0; + int lastCapturePoint = CALL; + for (int i = 0; i < this.orderedStateIds.Count; ++i) { + var s = orderedStateIds[i]; + int candidate = s.Item1; + int capturePoint = s.Item2; + string implName = calls.getProc(candidate); + ModelViewInfo info = candidate == 0 ? mvInfo : implName2StratifiedInliningInfo[implName].mvInfo; + + if (capturePoint == CALL || capturePoint == RETURN) { + lastCandidate = candidate; + lastCapturePoint = capturePoint; + continue; + } + + Contract.Assume(0 <= capturePoint && capturePoint < info.CapturePoints.Count); + VC.ModelViewInfo.Mapping map = info.CapturePoints[capturePoint]; + var prevInc = (lastCapturePoint != CALL && lastCapturePoint != RETURN && candidate == lastCandidate) + ? info.CapturePoints[lastCapturePoint].IncarnationMap : new Dictionary<Variable, Expr>(); + var cs = m.MkState(map.Description); + + foreach (Variable v in info.AllVariables) { + var e = (Expr)map.IncarnationMap[v]; + + if (e == null) { + if (lastCapturePoint == CALL || lastCapturePoint == RETURN) { + cs.AddBinding(v.Name, GetModelValue(m, v, candidate)); + } + continue; + } + + if (lastCapturePoint != CALL && lastCapturePoint != RETURN && prevInc[v] == e) continue; // skip unchanged variables + + Model.Element elt; + if (e is IdentifierExpr) { + IdentifierExpr ide = (IdentifierExpr)e; + elt = GetModelValue(m, ide.Decl, candidate); + } + else if (e is LiteralExpr) { + LiteralExpr lit = (LiteralExpr)e; + elt = m.MkElement(lit.Val.ToString()); + } + else { + Contract.Assume(false); + elt = m.MkFunc(e.ToString(), 0).GetConstant(); + } + cs.AddBinding(v.Name, elt); + } + + lastCandidate = candidate; + lastCapturePoint = capturePoint; + } + + return; + } + + public override void OnResourceExceeded(string message, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) + { + //Contract.Requires(message != null); + } + + public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) { + if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) { + model.Write(ErrorReporter.ModelWriter); + ErrorReporter.ModelWriter.Flush(); + } + + // Timeout? + if (proverOutcome != ProverInterface.Outcome.Invalid) + return; + + candidatesToExpand = new List<int>(); + orderedStateIds = new List<Tuple<int, int>>(); + var cex = GenerateTrace(labels, model, 0, mainInfo.impl, mainInfo.mvInfo); + + if (underapproximationMode && cex != null) { + //Debug.Assert(candidatesToExpand.All(calls.isSkipped)); + GetModelWithStates(model); + callback.OnCounterexample(cex, null); + this.PrintModel(model); + } + } + + private Counterexample GenerateTrace(IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel, + int candidateId, Implementation procImpl, ModelViewInfo mvInfo) { + Contract.Requires(cce.NonNullElements(labels)); + Contract.Requires(procImpl != null); + + Hashtable traceNodes = new Hashtable(); + + if (!CommandLineOptions.Clo.SIBoolControlVC) + { + foreach (string s in labels) + { + Contract.Assert(s != null); + var absylabel = calls.ParseRenamedAbsyLabel(s, candidateId); + + if (absylabel == null) continue; + + Absy absy; + + if (candidateId == 0) + { + absy = Label2Absy(absylabel); + } + else + { + absy = Label2Absy(procImpl.Name, absylabel); + } + + if (traceNodes.ContainsKey(absy)) + System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes"); + else + traceNodes.Add(absy, null); + } + } + else + { + Debug.Assert(CommandLineOptions.Clo.UseProverEvaluate, "Must use prover evaluate option with boolControlVC"); + var block = procImpl.Blocks[0]; + traceNodes.Add(block, null); + while (true) + { + var gc = block.TransferCmd as GotoCmd; + if (gc == null) break; + Block next = null; + foreach (var succ in gc.labelTargets) + { + var succtaken = (bool) theoremProver.Evaluate(calls.candiate2block2controlVar[candidateId][succ]); + if (succtaken) + { + next = succ; + traceNodes.Add(succ, null); + break; + } + } + Debug.Assert(next != null, "Must find a successor"); + Debug.Assert(traceNodes.ContainsKey(next), "CFG cannot be cyclic"); + block = next; + } + } + + List<Block> trace = new List<Block>(); + Block entryBlock = cce.NonNull(procImpl.Blocks[0]); + Contract.Assert(entryBlock != null); + Contract.Assert(traceNodes.Contains(entryBlock)); + trace.Add(entryBlock); + + var calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>(); + Counterexample newCounterexample = GenerateTraceRec(labels, errModel, mvInfo, candidateId, entryBlock, traceNodes, trace, calleeCounterexamples); + + return newCounterexample; + } + + private Counterexample GenerateTraceRec( + IList<string/*!*/>/*!*/ labels, Model/*!*/ errModel, ModelViewInfo mvInfo, + int candidateId, + Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace, + Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples) { + Contract.Requires(cce.NonNullElements(labels)); + Contract.Requires(b != null); + Contract.Requires(traceNodes != null); + Contract.Requires(trace != null); + Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples)); + // After translation, all potential errors come from asserts. + while (true) { + List<Cmd> cmds = b.Cmds; + TransferCmd transferCmd = cce.NonNull(b.TransferCmd); + for (int i = 0; i < cmds.Count; i++) { + Cmd cmd = cce.NonNull(cmds[i]); + + // Skip if 'cmd' not contained in the trace or not an assert + if ((cmd is AssertCmd && traceNodes.Contains(cmd)) || + (cmd is AssumeCmd && QKeyValue.FindBoolAttribute((cmd as AssumeCmd).Attributes, "exitAssert"))) + { + var acmd = cmd as AssertCmd; + if (acmd == null) { acmd = new AssertCmd(Token.NoToken, Expr.True); } + Counterexample newCounterexample = AssertCmdToCounterexample(acmd, transferCmd, trace, errModel, mvInfo, theoremProver.Context); + newCounterexample.AddCalleeCounterexample(calleeCounterexamples); + return newCounterexample; + } + + // Counterexample generation for inlined procedures + AssumeCmd assumeCmd = cmd as AssumeCmd; + if (assumeCmd == null) + continue; + NAryExpr naryExpr = assumeCmd.Expr as NAryExpr; + if (naryExpr == null) + continue; + string calleeName = naryExpr.Fun.FunctionName; + Contract.Assert(calleeName != null); + + BinaryOperator binOp = naryExpr.Fun as BinaryOperator; + if (binOp != null && binOp.Op == BinaryOperator.Opcode.And) { + Expr expr = naryExpr.Args[0]; + NAryExpr mvStateExpr = expr as NAryExpr; + if (mvStateExpr != null && mvStateExpr.Fun.FunctionName == ModelViewInfo.MVState_FunctionDef.Name) { + LiteralExpr x = mvStateExpr.Args[1] as LiteralExpr; + orderedStateIds.Add(new Tuple<int, int>(candidateId, x.asBigNum.ToInt)); + } + } + + if (calleeName.StartsWith(recordProcName) && (errModel != null || CommandLineOptions.Clo.UseProverEvaluate)) { + var expr = calls.recordExpr2Var[new BoogieCallExpr(naryExpr, candidateId)]; + + // Record concrete value of the argument to this procedure + var args = new List<object>(); + if (errModel == null && CommandLineOptions.Clo.UseProverEvaluate) + { + object exprv; + try + { + exprv = theoremProver.Evaluate(expr); + } + catch (Exception) + { + exprv = null; + } + args.Add(exprv); + } + else + { + if (expr is VCExprIntLit) + { + args.Add(errModel.MkElement((expr as VCExprIntLit).Val.ToString())); + } + else if (expr == VCExpressionGenerator.True) + { + args.Add(errModel.MkElement("true")); + } + else if (expr == VCExpressionGenerator.False) + { + args.Add(errModel.MkElement("false")); + } + else if (expr is VCExprVar) + { + var idExpr = expr as VCExprVar; + string name = theoremProver.Context.Lookup(idExpr); + Contract.Assert(name != null); + Model.Func f = errModel.TryGetFunc(name); + if (f != null) + { + args.Add(f.GetConstant()); + } + } + else + { + Contract.Assert(false); + } + } + calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] = + new CalleeCounterexampleInfo(null, args); + continue; + } + + if (!implName2StratifiedInliningInfo.ContainsKey(calleeName)) + continue; + + Contract.Assert(calls != null); + + int calleeId = calls.boogieExpr2Id[new BoogieCallExpr(naryExpr, candidateId)]; + + if (calls.currCandidates.Contains(calleeId)) { + candidatesToExpand.Add(calleeId); + } + else { + orderedStateIds.Add(new Tuple<int, int>(calleeId, StratifiedInliningErrorReporter.CALL)); + var calleeInfo = implName2StratifiedInliningInfo[calleeName]; + calleeCounterexamples[new TraceLocation(trace.Count - 1, i)] = + new CalleeCounterexampleInfo(GenerateTrace(labels, errModel, calleeId, calleeInfo.impl, calleeInfo.mvInfo), new List<object>()); + orderedStateIds.Add(new Tuple<int, int>(candidateId, StratifiedInliningErrorReporter.RETURN)); + } + } + + GotoCmd gotoCmd = transferCmd as GotoCmd; + if (gotoCmd != null) { + b = null; + foreach (Block bb in cce.NonNull(gotoCmd.labelTargets)) { + Contract.Assert(bb != null); + if (traceNodes.Contains(bb)) { + trace.Add(bb); + b = bb; + break; + } + } + if (b != null) continue; + } + return null; + } + } + + public override Absy Label2Absy(string label) { + //Contract.Requires(label != null); + Contract.Ensures(Contract.Result<Absy>() != null); + + int id = int.Parse(label); + Contract.Assert(calls != null); + return cce.NonNull((Absy)calls.mainLabel2absy[id]); + } + + public Absy Label2Absy(string procName, string label) { + Contract.Requires(label != null); + Contract.Requires(procName != null); + Contract.Ensures(Contract.Result<Absy>() != null); + + int id = int.Parse(label); + Dictionary<int, Absy> l2a = cce.NonNull(implName2StratifiedInliningInfo[procName]).label2absy; + return cce.NonNull((Absy)l2a[id]); + } + + public override void OnProverWarning(string msg) { + //Contract.Requires(msg != null); + callback.OnWarning(msg); + } + } + + } // class StratifiedVCGen + + public class EmptyErrorHandler : ProverInterface.ErrorHandler + { + public override void OnModel(IList<string> labels, Model model, ProverInterface.Outcome proverOutcome) + { } + } + + public class InvalidProgramForSecureVc : Exception + { + public InvalidProgramForSecureVc(string msg) : + base(msg) { } + } + + public class SecureVCGen : VCGen + { + // Z3 + ProverInterface prover; + // Handler + ErrorReporter handler; + // dump file + public static TokenTextWriter outfile = null; + + + public SecureVCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers) + : base(program, logFilePath, appendLogFile, checkers) + { + prover = null; + handler = null; + if (CommandLineOptions.Clo.SecureVcGen != "" && outfile == null) + { + outfile = new TokenTextWriter(new StreamWriter(CommandLineOptions.Clo.SecureVcGen)); + CommandLineOptions.Clo.PrintInstrumented = true; + var implsToVerify = new HashSet<string>( + program.TopLevelDeclarations.OfType<Implementation>() + .Where(impl => !impl.SkipVerification) + .Select(impl => impl.Name)); + + foreach (var decl in program.TopLevelDeclarations) + { + if (decl is NamedDeclaration && implsToVerify.Contains((decl as NamedDeclaration).Name)) + continue; + decl.Emit(outfile, 0); + } + } + } + + private Block GetExitBlock(Implementation impl) + { + var exitblocks = impl.Blocks.Where(blk => blk.TransferCmd is ReturnCmd); + if (exitblocks.Count() == 1) + return exitblocks.First(); + // create a new exit block + var eb = new Block(Token.NoToken, "SVCeb", new List<Cmd>(), new ReturnCmd(Token.NoToken)); + foreach (var b in exitblocks) + { + b.TransferCmd = new GotoCmd(Token.NoToken, new List<Block> { eb }); + } + impl.Blocks.Add(eb); + return eb; + } + + //static int LocalVarCounter = 0; + private LocalVariable GetNewLocal(Variable v, string suffix) + { + return new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, + string.Format("svc_{0}_{1}", v.Name, suffix), v.TypedIdent.Type)); + } + + private void GenVc(Implementation impl, VerifierCallback collector) + { + if (impl.Proc.Requires.Any()) + throw new InvalidProgramForSecureVc("SecureVc: Requires not supported"); + if(impl.LocVars.Any(v => isVisible(v))) + throw new InvalidProgramForSecureVc("SecureVc: Visible Local variables not allowed"); + + // Desugar procedure calls + DesugarCalls(impl); + + // Gather spec, remove existing ensures + var secureAsserts = new List<AssertCmd>(); + var logicalAsserts = new List<AssertCmd>(); + + foreach (var ens in impl.Proc.Ensures) + { + if(ens.Free) + throw new InvalidProgramForSecureVc("SecureVc: Free Ensures not supported"); + var dd = new Duplicator(); + secureAsserts.Add(new AssertCmd(ens.tok, Expr.Not(ens.Condition))); + logicalAsserts.Add(dd.VisitAssertCmd(new AssertCmd(ens.tok, ens.Condition)) as AssertCmd); + } + impl.Proc.Ensures.Clear(); + + // Make a copy of the impl + var dup = new Duplicator(); + var implDup = dup.VisitImplementation(impl); + + // Get exit block + var eb = GetExitBlock(impl); + + // Create two blocks: one for secureAsserts, one for logical asserts + var ebSecure = new Block(Token.NoToken, "svc_secure_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken)); + var ebLogical = new Block(Token.NoToken, "svc_logical_asserts", new List<Cmd>(), new ReturnCmd(Token.NoToken)); + + eb.TransferCmd = new GotoCmd(eb.TransferCmd.tok, new List<Block> { ebSecure, ebLogical }); + impl.Blocks.Add(ebSecure); + impl.Blocks.Add(ebLogical); + + // Rename spec, while create copies of the hidden variables + var substOld = new Dictionary<Variable, Expr>(); + var substVarSpec = new Dictionary<Variable, Expr>(); + var substVarPath = new Dictionary<Variable, Expr>(); + foreach (var g in program.GlobalVariables) + { + if (!isHidden(g)) continue; + var lv = GetNewLocal(g, "In"); + impl.LocVars.Add(lv); + substOld.Add(g, Expr.Ident(lv)); + } + + for(int i = 0; i < impl.InParams.Count; i++) + { + var v = impl.Proc.InParams[i]; + if (!isHidden(v)) + { + substVarSpec.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i])); + continue; + } + + var lv = GetNewLocal(v, "In"); + impl.LocVars.Add(lv); + substVarSpec.Add(v, Expr.Ident(lv)); + substVarPath.Add(impl.InParams[i], Expr.Ident(lv)); + } + + for (int i = 0; i < impl.OutParams.Count; i++) + { + var v = impl.Proc.OutParams[i]; + if (!isHidden(v)) + { + substVarSpec.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i])); + continue; + } + + var lv = GetNewLocal(v, "Out"); + impl.LocVars.Add(lv); + substVarSpec.Add(v, Expr.Ident(lv)); + substVarPath.Add(impl.OutParams[i], Expr.Ident(lv)); + } + + foreach (var g in program.GlobalVariables) + { + if (!isHidden(g)) continue; + if (!impl.Proc.Modifies.Any(ie => ie.Name == g.Name)) continue; + + var lv = GetNewLocal(g, "Out"); + impl.LocVars.Add(lv); + substVarSpec.Add(g, Expr.Ident(lv)); + substVarPath.Add(g, Expr.Ident(lv)); + } + + secureAsserts = secureAsserts.ConvertAll(ac => + Substituter.ApplyReplacingOldExprs( + Substituter.SubstitutionFromHashtable(substVarSpec), + Substituter.SubstitutionFromHashtable(substOld), + ac) as AssertCmd); + + var substVarProcToImpl = new Dictionary<Variable, Expr>(); + for (int i = 0; i < impl.InParams.Count; i++) + substVarProcToImpl.Add(impl.Proc.InParams[i], Expr.Ident(impl.InParams[i])); + + for (int i = 0; i < impl.OutParams.Count; i++) + substVarProcToImpl.Add(impl.Proc.OutParams[i], Expr.Ident(impl.OutParams[i])); + + logicalAsserts = logicalAsserts.ConvertAll(ac => + Substituter.Apply(Substituter.SubstitutionFromHashtable(substVarProcToImpl), ac) + as AssertCmd); + + // Paths + foreach (var path in GetAllPaths(implDup)) + { + var wp = ComputeWP(implDup, path); + + // replace hidden variables to match those used in the spec + wp = Substituter.ApplyReplacingOldExprs( + Substituter.SubstitutionFromHashtable(substVarPath), + Substituter.SubstitutionFromHashtable(substOld), + wp); + + ebSecure.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.Not(wp))); + } + + ebSecure.Cmds.AddRange(secureAsserts); + ebLogical.Cmds.AddRange(logicalAsserts); + + if (outfile != null) + { + impl.Proc.Emit(outfile, 0); + impl.Emit(outfile, 0); + } + + ModelViewInfo mvInfo; + ConvertCFG2DAG(impl); + var gotoCmdOrigins = PassifyImpl(impl, out mvInfo); + + var gen = prover.VCExprGen; + var exprGen = prover.Context.ExprGen; + var translator = prover.Context.BoogieExprTranslator; + + var label2absy = new Dictionary<int, Absy>(); + VCGen.CodeExprConversionClosure cc = new VCGen.CodeExprConversionClosure(label2absy, prover.Context); + translator.SetCodeExprConverter(cc.CodeExprToVerificationCondition); + var implVc = gen.Not(GenerateVCAux(impl, null, label2absy, prover.Context)); + + handler = new VCGen.ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, incarnationOriginMap, collector, mvInfo, prover.Context, program); + + prover.Assert(implVc, true); + } + + Expr ComputeWP(Implementation impl, List<Cmd> path) + { + Expr expr = Expr.True; + + // create constants for out varibles + var subst = new Dictionary<Variable, Expr>(); + foreach (var g in impl.Proc.Modifies) + { + var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, + "svc_out_const_" + g.Name, g.Decl.TypedIdent.Type)); + subst.Add(c, g); + expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), g)); + } + + foreach (var v in impl.OutParams) + { + var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, + "svc_out_const_" + v.Name, v.TypedIdent.Type)); + subst.Add(c, Expr.Ident(v)); + expr = Expr.And(expr, Expr.Eq(Expr.Ident(c), Expr.Ident(v))); + } + + // we need this technicality + var subst1 = new Dictionary<Variable, Expr>(); + foreach (var g in program.GlobalVariables) + { + subst1.Add(g, new OldExpr(Token.NoToken, Expr.Ident(g))); + } + + // Implicitly close with havoc of all the locals and OutParams + path.Insert(0, new HavocCmd(Token.NoToken, new List<IdentifierExpr>( + impl.LocVars.Select(v => Expr.Ident(v)).Concat( + impl.OutParams.Select(v => Expr.Ident(v)))))); + + for (int i = path.Count - 1; i >= 0; i--) + { + var cmd = path[i]; + if (cmd is AssumeCmd) + { + expr = Expr.And(expr, (cmd as AssumeCmd).Expr); + } + else if (cmd is AssignCmd) + { + var h = new Dictionary<Variable, Expr>(); + var acmd = cmd as AssignCmd; + for (int j = 0; j < acmd.Lhss.Count; j++) + { + h.Add(acmd.Lhss[j].DeepAssignedVariable, acmd.Rhss[j]); + } + var s = Substituter.SubstitutionFromHashtable(h); + expr = Substituter.Apply(s, expr); + } + else if (cmd is HavocCmd) + { + var h = new Dictionary<Variable, Expr>(); + var formals = new List<Variable>(); + + var vc = new VariableCollector(); + vc.VisitExpr(expr); + + foreach (var ie in (cmd as HavocCmd).Vars) + { + if (!vc.usedVars.Contains(ie.Decl)) continue; + var f = new BoundVariable(Token.NoToken, new TypedIdent(Token.NoToken, + ie.Decl.Name + "_formal", ie.Decl.TypedIdent.Type)); + h.Add(ie.Decl, Expr.Ident(f)); + formals.Add(f); + } + if (!formals.Any()) + continue; + var s = Substituter.SubstitutionFromHashtable(h); + expr = Substituter.Apply(s, expr); + expr = new ExistsExpr(Token.NoToken, formals, expr); + } + else + { + throw new InvalidProgramForSecureVc(string.Format("Unhandled cmd: {0}", cmd)); + } + } + + // Implicitly close with havoc of all the locals and OutParams + + + + expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst1), expr); + expr = Substituter.Apply(Substituter.SubstitutionFromHashtable(subst), + Substituter.SubstitutionFromHashtable(new Dictionary<Variable,Expr>()), expr); + expr.Typecheck(new TypecheckingContext(null)); + return expr; + } + + // Generate all paths in the impl + IEnumerable<List<Cmd>> GetAllPaths(Implementation impl) + { + var stk = new Stack<Tuple<Block, int>>(); + stk.Push(Tuple.Create(impl.Blocks[0], 0)); + + while (stk.Any()) + { + var tup = stk.Peek(); + if (tup.Item1.TransferCmd is ReturnCmd) + { + var ret = new List<Cmd>(); + var ls = stk.ToList(); + ls.Iter(t => ret.AddRange(t.Item1.Cmds)); + yield return ret; + + stk.Pop(); + continue; + } + + stk.Pop(); + + var gc = tup.Item1.TransferCmd as GotoCmd; + if (gc.labelTargets.Count <= tup.Item2) + continue; + + stk.Push(Tuple.Create(tup.Item1, tup.Item2 + 1)); + stk.Push(Tuple.Create(gc.labelTargets[tup.Item2], 0)); + } + yield break; + } + + bool isHidden(Variable v) + { + return QKeyValue.FindBoolAttribute(v.Attributes, "hidden"); + } + + bool isVisible(Variable v) + { + return !isHidden(v); + } + + public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) + { + Debug.Assert(this.program == program); + + // Record current time + var startTime = DateTime.UtcNow; + + CommandLineOptions.Clo.ProverCCLimit = 1; + prover = ProverInterface.CreateProver(program, logFilePath, appendLogFile, CommandLineOptions.Clo.ProverKillTime); + + // Flush any axioms that came with the program before we start SI on this implementation + prover.AssertAxioms(); + + GenVc(impl, callback); + + prover.Check(); + var outcome = prover.CheckOutcomeCore(handler); + //var outcome = ProverInterface.Outcome.Valid; + + prover.Close(); + + + + //Console.WriteLine("Answer = {0}", outcome); + + return ProverInterfaceOutcomeToConditionGenerationOutcome(outcome); + } + } + +} // namespace VC diff --git a/Source/VCGeneration/VC.cs b/Source/VCGeneration/VC.cs index 8e5c853c..b457b383 100644 --- a/Source/VCGeneration/VC.cs +++ b/Source/VCGeneration/VC.cs @@ -1,3935 +1,3935 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading;
-using System.IO;
-using Microsoft.Boogie;
-using Microsoft.Boogie.GraphUtil;
-using System.Diagnostics.Contracts;
-using Microsoft.Basetypes;
-using Microsoft.Boogie.VCExprAST;
-
-namespace VC {
- using Bpl = Microsoft.Boogie;
- using System.Threading.Tasks;
-
- public class VCGen : ConditionGeneration {
- private const bool _print_time = false;
- /// <summary>
- /// Constructor. Initializes the theorem prover.
- /// </summary>
- [NotDelayed]
- public VCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers)
- : base(program, checkers)
- {
- Contract.Requires(program != null);
- this.appendLogFile = appendLogFile;
- this.logFilePath = logFilePath;
- }
-
- private static AssumeCmd AssertTurnedIntoAssume(AssertCmd assrt) {
- Contract.Requires(assrt != null);
- Contract.Ensures(Contract.Result<AssumeCmd>() != null);
-
- Expr expr = assrt.Expr;
- Contract.Assert(expr != null);
- switch (Wlp.Subsumption(assrt)) {
- case CommandLineOptions.SubsumptionOption.Never:
- expr = Expr.True;
- break;
- case CommandLineOptions.SubsumptionOption.Always:
- break;
- case CommandLineOptions.SubsumptionOption.NotForQuantifiers:
- if (expr is QuantifierExpr) {
- expr = Expr.True;
- }
- break;
- default:
- Contract.Assert(false);
- throw new cce.UnreachableException(); // unexpected case
- }
-
- return new AssumeCmd(assrt.tok, expr);
- }
-
- #region Soundness smoke tester
- class SmokeTester {
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(parent != null);
- Contract.Invariant(impl != null);
- Contract.Invariant(initial != null);
- Contract.Invariant(cce.NonNullDictionaryAndValues(copies));
- Contract.Invariant(cce.NonNull(visited));
- Contract.Invariant(callback != null);
- }
-
- VCGen parent;
- Implementation impl;
- Block initial;
- int id;
- Dictionary<Block, Block> copies = new Dictionary<Block, Block>();
- HashSet<Block> visited = new HashSet<Block>();
- VerifierCallback callback;
-
- internal SmokeTester(VCGen par, Implementation i, VerifierCallback callback) {
- Contract.Requires(par != null);
- Contract.Requires(i != null);
- Contract.Requires(callback != null);
- parent = par;
- impl = i;
- initial = i.Blocks[0];
- this.callback = callback;
- }
-
- internal void Copy() {
- CloneBlock(impl.Blocks[0]);
- initial = GetCopiedBlocks()[0];
- }
-
- internal void Test() {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- DFS(initial);
- }
-
- void TopologicalSortImpl() {
- Graph<Block> dag = new Graph<Block>();
- dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph
- foreach (Block b in impl.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);
- }
- }
- }
- impl.Blocks = new List<Block>();
- foreach (Block b in dag.TopologicalSort()) {
- Contract.Assert(b != null);
- impl.Blocks.Add(b);
- }
- }
-
- void Emit() {
- TopologicalSortImpl();
- EmitImpl(impl, false);
- }
-
- // this one copies forward
- Block CloneBlock(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block fake_res;
- if (copies.TryGetValue(b, out fake_res)) {
- return cce.NonNull(fake_res);
- }
- Block res = new Block(b.tok, b.Label, new List<Cmd>(b.Cmds), null);
- copies[b] = res;
- if (b.TransferCmd is GotoCmd) {
- foreach (Block ch in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) {
- Contract.Assert(ch != null);
- CloneBlock(ch);
- }
- }
- foreach (Block p in b.Predecessors) {
- Contract.Assert(p != null);
- res.Predecessors.Add(CloneBlock(p));
- }
- return res;
- }
-
- // this one copies backwards
- Block CopyBlock(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block fake_res;
- if (copies.TryGetValue(b, out fake_res)) {
- // fake_res should be Block! but the compiler fails
- return cce.NonNull(fake_res);
- }
- Block res;
- List<Cmd> seq = new List<Cmd>();
- foreach (Cmd c in b.Cmds) {
- Contract.Assert(c != null);
- AssertCmd turn = c as AssertCmd;
- if (!turnAssertIntoAssumes || turn == null) {
- seq.Add(c);
- } else {
- seq.Add(AssertTurnedIntoAssume(turn));
- }
- }
- res = new Block(b.tok, b.Label, seq, null);
- copies[b] = res;
- foreach (Block p in b.Predecessors) {
- Contract.Assert(p != null);
- res.Predecessors.Add(CopyBlock(p));
- }
- return res;
- }
-
- List<Block> GetCopiedBlocks() {
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>()));
-
- // the order of nodes in res is random (except for the first one, being the entry)
- List<Block> res = new List<Block>();
- res.Add(copies[initial]);
-
- foreach (KeyValuePair<Block, Block> kv in copies) {
- Contract.Assert(kv.Key != null&&kv.Value!=null);
- GotoCmd go = kv.Key.TransferCmd as GotoCmd;
- ReturnCmd ret = kv.Key.TransferCmd as ReturnCmd;
- if (kv.Key != initial) {
- res.Add(kv.Value);
- }
- if (go != null) {
- GotoCmd copy = new GotoCmd(go.tok, new List<String>(), new List<Block>());
- kv.Value.TransferCmd = copy;
- foreach (Block b in cce.NonNull(go.labelTargets)) {
- Contract.Assert(b != null);
- Block c;
- if (copies.TryGetValue(b, out c)) {
- copy.AddTarget(cce.NonNull(c));
- }
- }
- } else if (ret != null) {
- kv.Value.TransferCmd = ret;
- } else {
- Contract.Assume(false);
- throw new cce.UnreachableException();
- }
- }
-
- copies.Clear();
-
- return res;
- }
-
- // check if e is true, false, !true, !false
- // if so return true and the value of the expression in val
- bool BooleanEval(Expr e, ref bool val) {
- Contract.Requires(e != null);
- LiteralExpr lit = e as LiteralExpr;
- NAryExpr call = e as NAryExpr;
-
- if (lit != null && lit.isBool) {
- val = lit.asBool;
- return true;
- } else if (call != null &&
- call.Fun is UnaryOperator &&
- ((UnaryOperator)call.Fun).Op == UnaryOperator.Opcode.Not &&
- BooleanEval(cce.NonNull(call.Args[0]), ref val)) {
- val = !val;
- return true;
- }
- // this is for the 0bv32 != 0bv32 generated by vcc
- else if (call != null &&
- call.Fun is BinaryOperator &&
- ((BinaryOperator)call.Fun).Op == BinaryOperator.Opcode.Neq &&
- call.Args[0] is LiteralExpr &&
- cce.NonNull(call.Args[0]).Equals(call.Args[1])) {
- val = false;
- return true;
- }
-
- return false;
- }
-
- bool IsFalse(Expr e) {
- Contract.Requires(e != null);
- bool val = false;
- return BooleanEval(e, ref val) && !val;
- }
-
- bool CheckUnreachable(Block cur, List<Cmd> seq)
- {
- Contract.Requires(cur != null);
- Contract.Requires(seq != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- foreach (Cmd cmd in seq)
- {
- AssertCmd assrt = cmd as AssertCmd;
- if (assrt != null && QKeyValue.FindBoolAttribute(assrt.Attributes, "PossiblyUnreachable"))
- return false;
- }
-
- DateTime start = DateTime.UtcNow;
- if (CommandLineOptions.Clo.Trace)
- {
- System.Console.Write(" soundness smoke test #{0} ... ", id);
- }
- callback.OnProgress("smoke", id, id, 0.0);
-
- Token tok = new Token();
- tok.val = "soundness smoke test assertion";
- seq.Add(new AssertCmd(tok, Expr.False));
- Block copy = CopyBlock(cur);
- Contract.Assert(copy != null);
- copy.Cmds = seq;
- List<Block> backup = impl.Blocks;
- Contract.Assert(backup != null);
- impl.Blocks = GetCopiedBlocks();
- copy.TransferCmd = new ReturnCmd(Token.NoToken);
- if (CommandLineOptions.Clo.TraceVerify)
- {
- System.Console.WriteLine();
- System.Console.WriteLine(" --- smoke #{0}, before passify", id);
- Emit();
- }
- parent.CurrentLocalVariables = impl.LocVars;
- ModelViewInfo mvInfo;
- parent.PassifyImpl(impl, out mvInfo);
- Dictionary<int, Absy> label2Absy;
- Checker ch = parent.FindCheckerFor(CommandLineOptions.Clo.SmokeTimeout);
- Contract.Assert(ch != null);
-
- ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined;
- try
- {
- lock (ch)
- {
- var exprGen = ch.TheoremProver.Context.ExprGen;
- VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
-
- VCExpr vc = parent.GenerateVC(impl, controlFlowVariableExpr, out label2Absy, ch.TheoremProver.Context);
- Contract.Assert(vc != null);
-
- if (!CommandLineOptions.Clo.UseLabels)
- {
- VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vc = exprGen.Implies(eqExpr, vc);
- }
-
- impl.Blocks = backup;
-
- if (CommandLineOptions.Clo.TraceVerify)
- {
- System.Console.WriteLine(" --- smoke #{0}, after passify", id);
- Emit();
- }
-
- ch.BeginCheck(cce.NonNull(impl.Name + "_smoke" + id++), vc, new ErrorHandler(label2Absy, this.callback));
- }
-
- ch.ProverTask.Wait();
-
- lock (ch)
- {
- outcome = ch.ReadOutcome();
- }
- }
- finally
- {
- ch.GoBackToIdle();
- }
-
- parent.CurrentLocalVariables = null;
-
- DateTime end = DateTime.UtcNow;
- TimeSpan elapsed = end - start;
- if (CommandLineOptions.Clo.Trace)
- {
- System.Console.WriteLine(" [{0} s] {1}", elapsed.TotalSeconds,
- outcome == ProverInterface.Outcome.Valid ? "OOPS" :
- "OK" + (outcome == ProverInterface.Outcome.Invalid ? "" : " (" + outcome + ")"));
- }
-
- if (outcome == ProverInterface.Outcome.Valid)
- {
- // copy it again, so we get the version with calls, assignments and such
- copy = CopyBlock(cur);
- copy.Cmds = seq;
- impl.Blocks = GetCopiedBlocks();
- TopologicalSortImpl();
- callback.OnUnreachableCode(impl);
- impl.Blocks = backup;
- return true;
- }
- return false;
- }
-
- const bool turnAssertIntoAssumes = false;
-
- void DFS(Block cur) {
- Contract.Requires(cur != null);
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- if (visited.Contains(cur))
- return;
- visited.Add(cur);
-
- List<Cmd> seq = new List<Cmd>();
- foreach (Cmd cmd_ in cur.Cmds) {
- Cmd cmd = cmd_;
- Contract.Assert(cmd != null);
- AssertCmd assrt = cmd as AssertCmd;
- AssumeCmd assm = cmd as AssumeCmd;
- CallCmd call = cmd as CallCmd;
-
- bool assumeFalse = false;
-
- if (assrt != null) {
- // we're not going any further
- // it's clear the user expected unreachable code here
- // it's not clear where did he expect it, maybe it would be right to insert
- // a check just one command before
- if (IsFalse(assrt.Expr))
- return;
-
-#if TURN_ASSERT_INFO_ASSUMES
- if (turnAssertIntoAssumes) {
- cmd = AssertTurnedIntoAssume(assrt);
- }
-#endif
- } else if (assm != null) {
- if (IsFalse(assm.Expr))
- assumeFalse = true;
- } else if (call != null) {
- foreach (Ensures e in (cce.NonNull(call.Proc)).Ensures) {
- Contract.Assert(e != null);
- if (IsFalse(e.Condition))
- assumeFalse = true;
- }
- }
-
- if (assumeFalse) {
- CheckUnreachable(cur, seq);
- return;
- }
-
- seq.Add(cmd);
- }
-
-
- GotoCmd go = cur.TransferCmd as GotoCmd;
- ReturnCmd ret = cur.TransferCmd as ReturnCmd;
-
- Contract.Assume(!(go != null && go.labelTargets == null && go.labelNames != null && go.labelNames.Count > 0));
-
- if (ret != null || (go != null && cce.NonNull(go.labelTargets).Count == 0)) {
- // we end in return, so there will be no more places to check
- CheckUnreachable(cur, seq);
- } else if (go != null) {
- bool needToCheck = true;
- // if all of our children have more than one parent, then
- // we're in the right place to check
- foreach (Block target in cce.NonNull(go.labelTargets)) {
- Contract.Assert(target != null);
- if (target.Predecessors.Count == 1) {
- needToCheck = false;
- }
- }
- if (needToCheck) {
- CheckUnreachable(cur, seq);
- }
- foreach (Block target in go.labelTargets) {
- Contract.Assert(target != null);
- DFS(target);
- }
- }
- }
-
- class ErrorHandler : ProverInterface.ErrorHandler {
- Dictionary<int, Absy> label2Absy;
- VerifierCallback callback;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(label2Absy != null);
- Contract.Invariant(callback != null);
- }
-
-
- public ErrorHandler(Dictionary<int, Absy> label2Absy, VerifierCallback callback) {
- Contract.Requires(label2Absy != null);
- Contract.Requires(callback != null);
- this.label2Absy = label2Absy;
- this.callback = callback;
- }
-
- public override Absy Label2Absy(string label) {
- //Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- return cce.NonNull((Absy)label2Absy[id]);
- }
-
- public override void OnProverWarning(string msg) {
- //Contract.Requires(msg != null);
- this.callback.OnWarning(msg);
- }
- }
- }
-
-
- #endregion
-
- #region Splitter
- class Split {
- class BlockStats {
- public bool big_block;
- public int id;
- public double assertion_cost;
- public double assumption_cost; // before multiplier
- public double incomming_paths;
- public List<Block>/*!>!*/ virtual_successors = new List<Block>();
- public List<Block>/*!>!*/ virtual_predecesors = new List<Block>();
- public HashSet<Block> reachable_blocks;
- public readonly Block block;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(virtual_successors));
- Contract.Invariant(cce.NonNullElements(virtual_predecesors));
- Contract.Invariant(block != null);
- }
-
-
- public BlockStats(Block b, int i) {
- Contract.Requires(b != null);
- block = b;
- assertion_cost = -1;
- id = i;
- }
- }
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(cce.NonNullElements(blocks));
- Contract.Invariant(cce.NonNullElements(big_blocks));
- Contract.Invariant(cce.NonNullDictionaryAndValues(stats));
- Contract.Invariant(cce.NonNullElements(assumized_branches));
- Contract.Invariant(gotoCmdOrigins != null);
- Contract.Invariant(parent != null);
- Contract.Invariant(impl != null);
- Contract.Invariant(copies != null);
- Contract.Invariant(cce.NonNull(protected_from_assert_to_assume));
- Contract.Invariant(cce.NonNull(keep_at_all));
- }
-
-
- readonly List<Block> blocks;
- readonly List<Block> big_blocks = new List<Block>();
- readonly Dictionary<Block/*!*/, BlockStats/*!*/>/*!*/ stats = new Dictionary<Block/*!*/, BlockStats/*!*/>();
- readonly int id;
- static int current_id = -1;
- Block split_block;
- bool assert_to_assume;
- List<Block/*!*/>/*!*/ assumized_branches = new List<Block/*!*/>();
-
- double score;
- bool score_computed;
- double total_cost;
- int assertion_count;
- double assertion_cost; // without multiplication by paths
- Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins;
- readonly public VCGen/*!*/ parent;
- Implementation/*!*/ impl;
-
- Dictionary<Block/*!*/, Block/*!*/>/*!*/ copies = new Dictionary<Block/*!*/, Block/*!*/>();
- bool doing_slice;
- double slice_initial_limit;
- double slice_limit;
- bool slice_pos;
- HashSet<Block/*!*/>/*!*/ protected_from_assert_to_assume = new HashSet<Block/*!*/>();
- HashSet<Block/*!*/>/*!*/ keep_at_all = new HashSet<Block/*!*/>();
-
- // async interface
- private Checker checker;
- private int splitNo;
- internal ErrorReporter reporter;
-
- public Split(List<Block/*!*/>/*!*/ blocks, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par, Implementation/*!*/ impl) {
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(par != null);
- Contract.Requires(impl != null);
- this.blocks = blocks;
- this.gotoCmdOrigins = gotoCmdOrigins;
- this.parent = par;
- this.impl = impl;
- this.id = Interlocked.Increment(ref current_id);
- }
-
- public double Cost {
- get {
- ComputeBestSplit();
- return total_cost;
- }
- }
-
- public bool LastChance {
- get {
- ComputeBestSplit();
- return assertion_count == 1 && score < 0;
- }
- }
-
- public string Stats {
- get {
- ComputeBestSplit();
- return string.Format("(cost:{0:0}/{1:0}{2})", total_cost, assertion_cost, LastChance ? " last" : "");
- }
- }
-
- public void DumpDot(int no) {
- using (System.IO.StreamWriter sw = System.IO.File.CreateText(string.Format("split.{0}.dot", no))) {
- sw.WriteLine("digraph G {");
-
- ComputeBestSplit();
- List<Block> saved = assumized_branches;
- Contract.Assert(saved != null);
- assumized_branches = new List<Block>();
- DoComputeScore(false);
- assumized_branches = saved;
-
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- BlockStats s = GetBlockStats(b);
- foreach (Block t in s.virtual_successors) {
- Contract.Assert(t != null);
- sw.WriteLine("n{0} -> n{1};", s.id, GetBlockStats(t).id);
- }
- sw.WriteLine("n{0} [label=\"{1}:\\n({2:0.0}+{3:0.0})*{4:0.0}\"{5}];",
- s.id, b.Label,
- s.assertion_cost, s.assumption_cost, s.incomming_paths,
- s.assertion_cost > 0 ? ",shape=box" : "");
-
- }
- sw.WriteLine("}");
- sw.Close();
- }
-
- string filename = string.Format("split.{0}.bpl", no);
- using (System.IO.StreamWriter sw = System.IO.File.CreateText(filename)) {
- int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured;
- CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program
- bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings;
- CommandLineOptions.Clo.PrintDesugarings = false;
- List<Block> backup = impl.Blocks;
- Contract.Assert(backup != null);
- impl.Blocks = blocks;
- impl.Emit(new TokenTextWriter(filename, sw, /*setTokens=*/ false, /*pretty=*/ false), 0);
- impl.Blocks = backup;
- CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting;
- CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured;
- }
- }
-
- int bsid;
- BlockStats GetBlockStats(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<BlockStats>() != null);
-
- BlockStats s;
- if (!stats.TryGetValue(b, out s)) {
- s = new BlockStats(b, bsid++);
- stats[b] = s;
- }
- return cce.NonNull(s);
- }
-
- double AssertionCost(PredicateCmd c) {
- return 1.0;
- }
-
- void CountAssertions(Block b) {
- Contract.Requires(b != null);
- BlockStats s = GetBlockStats(b);
- if (s.assertion_cost >= 0)
- return; // already done
- s.big_block = true;
- s.assertion_cost = 0;
- s.assumption_cost = 0;
- foreach (Cmd c in b.Cmds) {
- if (c is AssertCmd) {
- double cost = AssertionCost((AssertCmd)c);
- s.assertion_cost += cost;
- assertion_count++;
- assertion_cost += cost;
- } else if (c is AssumeCmd) {
- s.assumption_cost += AssertionCost((AssumeCmd)c);
- }
- }
- foreach (Block c in Exits(b)) {
- Contract.Assert(c != null);
- s.virtual_successors.Add(c);
- }
- if (s.virtual_successors.Count == 1) {
- Block next = s.virtual_successors[0];
- BlockStats se = GetBlockStats(next);
- CountAssertions(next);
- if (next.Predecessors.Count > 1 || se.virtual_successors.Count != 1)
- return;
- s.virtual_successors[0] = se.virtual_successors[0];
- s.assertion_cost += se.assertion_cost;
- s.assumption_cost += se.assumption_cost;
- se.big_block = false;
- }
- }
-
- HashSet<Block/*!*/>/*!*/ ComputeReachableNodes(Block/*!*/ b) {
- Contract.Requires(b != null);
- Contract.Ensures(cce.NonNull(Contract.Result<HashSet<Block/*!*/>>()));
- BlockStats s = GetBlockStats(b);
- if (s.reachable_blocks != null) {
- return s.reachable_blocks;
- }
- HashSet<Block/*!*/> blocks = new HashSet<Block/*!*/>();
- s.reachable_blocks = blocks;
- blocks.Add(b);
- foreach (Block/*!*/ succ in Exits(b)) {
- Contract.Assert(succ != null);
- foreach (Block r in ComputeReachableNodes(succ)) {
- Contract.Assert(r != null);
- blocks.Add(r);
- }
- }
- return blocks;
- }
-
- double ProverCost(double vc_cost) {
- return vc_cost * vc_cost;
- }
-
- void ComputeBestSplit() {
- if (score_computed)
- return;
- score_computed = true;
-
- assertion_count = 0;
-
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- CountAssertions(b);
- }
-
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- BlockStats bs = GetBlockStats(b);
- if (bs.big_block) {
- big_blocks.Add(b);
- foreach (Block ch in bs.virtual_successors) {
- Contract.Assert(ch != null);
- BlockStats chs = GetBlockStats(ch);
- if (!chs.big_block) {
- Console.WriteLine("non-big {0} accessed from {1}", ch, b);
- DumpDot(-1);
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- chs.virtual_predecesors.Add(b);
- }
- }
- }
-
- assumized_branches.Clear();
- total_cost = ProverCost(DoComputeScore(false));
-
- score = double.PositiveInfinity;
- Block best_split = null;
- List<Block> saved_branches = new List<Block>();
-
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- GotoCmd gt = b.TransferCmd as GotoCmd;
- if (gt == null)
- continue;
- List<Block> targ = cce.NonNull(gt.labelTargets);
- if (targ.Count < 2)
- continue;
- // caution, we only consider two first exits
-
- double left0, right0, left1, right1;
- split_block = b;
-
- assumized_branches.Clear();
- assumized_branches.Add(cce.NonNull(targ[0]));
- left0 = DoComputeScore(true);
- right0 = DoComputeScore(false);
-
- assumized_branches.Clear();
- for (int idx = 1; idx < targ.Count; idx++) {
- assumized_branches.Add(cce.NonNull(targ[idx]));
- }
- left1 = DoComputeScore(true);
- right1 = DoComputeScore(false);
-
- double current_score = ProverCost(left1) + ProverCost(right1);
- double other_score = ProverCost(left0) + ProverCost(right0);
-
- if (other_score < current_score) {
- current_score = other_score;
- assumized_branches.Clear();
- assumized_branches.Add(cce.NonNull(targ[0]));
- }
-
- if (current_score < score) {
- score = current_score;
- best_split = split_block;
- saved_branches.Clear();
- saved_branches.AddRange(assumized_branches);
- }
- }
-
- if (CommandLineOptions.Clo.VcsPathSplitMult * score > total_cost) {
- split_block = null;
- score = -1;
- } else {
- assumized_branches = saved_branches;
- split_block = best_split;
- }
- }
-
- void UpdateIncommingPaths(BlockStats s) {
- Contract.Requires(s != null);
- if (s.incomming_paths < 0.0) {
- int count = 0;
- s.incomming_paths = 0.0;
- if (!keep_at_all.Contains(s.block))
- return;
- foreach (Block b in s.virtual_predecesors) {
- Contract.Assert(b != null);
- BlockStats ch = GetBlockStats(b);
- Contract.Assert(ch != null);
- UpdateIncommingPaths(ch);
- if (ch.incomming_paths > 0.0) {
- s.incomming_paths += ch.incomming_paths;
- count++;
- }
- }
- if (count > 1) {
- s.incomming_paths *= CommandLineOptions.Clo.VcsPathJoinMult;
- }
- }
- }
-
- void ComputeBlockSetsHelper(Block b, bool allow_small) {
- Contract.Requires(b != null);
- if (keep_at_all.Contains(b))
- return;
- keep_at_all.Add(b);
-
- if (allow_small) {
- foreach (Block ch in Exits(b)) {
- Contract.Assert(ch != null);
- if (b == split_block && assumized_branches.Contains(ch))
- continue;
- ComputeBlockSetsHelper(ch, allow_small);
- }
- } else {
- foreach (Block ch in GetBlockStats(b).virtual_successors) {
- Contract.Assert(ch != null);
- if (b == split_block && assumized_branches.Contains(ch))
- continue;
- ComputeBlockSetsHelper(ch, allow_small);
- }
- }
- }
-
- void ComputeBlockSets(bool allow_small) {
- protected_from_assert_to_assume.Clear();
- keep_at_all.Clear();
-
- Debug.Assert(split_block == null || GetBlockStats(split_block).big_block);
- Debug.Assert(GetBlockStats(blocks[0]).big_block);
-
- if (assert_to_assume) {
- foreach (Block b in allow_small ? blocks : big_blocks) {
- Contract.Assert(b != null);
- if (ComputeReachableNodes(b).Contains(cce.NonNull(split_block))) {
- keep_at_all.Add(b);
- }
- }
-
- foreach (Block b in assumized_branches) {
- Contract.Assert(b != null);
- foreach (Block r in ComputeReachableNodes(b)) {
- Contract.Assert(r != null);
- if (allow_small || GetBlockStats(r).big_block) {
- keep_at_all.Add(r);
- protected_from_assert_to_assume.Add(r);
- }
- }
- }
- } else {
- ComputeBlockSetsHelper(blocks[0], allow_small);
- }
- }
-
- bool ShouldAssumize(Block b) {
- Contract.Requires(b != null);
- return assert_to_assume && !protected_from_assert_to_assume.Contains(b);
- }
-
- double DoComputeScore(bool aa) {
- assert_to_assume = aa;
- ComputeBlockSets(false);
-
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- GetBlockStats(b).incomming_paths = -1.0;
- }
-
- GetBlockStats(blocks[0]).incomming_paths = 1.0;
-
- double cost = 0.0;
- foreach (Block b in big_blocks) {
- Contract.Assert(b != null);
- if (keep_at_all.Contains(b)) {
- BlockStats s = GetBlockStats(b);
- UpdateIncommingPaths(s);
- double local = s.assertion_cost;
- if (ShouldAssumize(b)) {
- local = (s.assertion_cost + s.assumption_cost) * CommandLineOptions.Clo.VcsAssumeMult;
- } else {
- local = s.assumption_cost * CommandLineOptions.Clo.VcsAssumeMult + s.assertion_cost;
- }
- local = local + local * s.incomming_paths * CommandLineOptions.Clo.VcsPathCostMult;
- cost += local;
- }
- }
-
- return cost;
- }
-
- List<Cmd> SliceCmds(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<List<Cmd>>() != null);
-
- List<Cmd> seq = b.Cmds;
- Contract.Assert(seq != null);
- if (!doing_slice && !ShouldAssumize(b))
- return seq;
- List<Cmd> res = new List<Cmd>();
- foreach (Cmd c in seq) {
- Contract.Assert(c != null);
- AssertCmd a = c as AssertCmd;
- Cmd the_new = c;
- bool swap = false;
- if (a != null) {
- if (doing_slice) {
- double cost = AssertionCost(a);
- bool first = (slice_limit - cost) >= 0 || slice_initial_limit == slice_limit;
- slice_limit -= cost;
- swap = slice_pos == first;
- } else if (assert_to_assume) {
- swap = true;
- } else {
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
-
- if (swap) {
- the_new = AssertTurnedIntoAssume(a);
- }
- }
- res.Add(the_new);
- }
- return res;
- }
-
- Block CloneBlock(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<Block>() != null);
-
- Block res;
- if (copies.TryGetValue(b, out res)) {
- return cce.NonNull(res);
- }
- res = new Block(b.tok, b.Label, SliceCmds(b), b.TransferCmd);
- GotoCmd gt = b.TransferCmd as GotoCmd;
- copies[b] = res;
- if (gt != null) {
- GotoCmd newGoto = new GotoCmd(gt.tok, new List<String>(), new List<Block>());
- res.TransferCmd = newGoto;
- int pos = 0;
- foreach (Block ch in cce.NonNull(gt.labelTargets)) {
- Contract.Assert(ch != null);
- Contract.Assert(doing_slice ||
- (assert_to_assume || (keep_at_all.Contains(ch) || assumized_branches.Contains(ch))));
- if (doing_slice ||
- ((b != split_block || assumized_branches.Contains(ch) == assert_to_assume) &&
- keep_at_all.Contains(ch))) {
- newGoto.AddTarget(CloneBlock(ch));
- }
- pos++;
- }
- }
- return res;
- }
-
- Split DoSplit() {
- Contract.Ensures(Contract.Result<Split>() != null);
-
- copies.Clear();
- CloneBlock(blocks[0]);
- List<Block> newBlocks = new List<Block>();
- Dictionary<TransferCmd, ReturnCmd> newGotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>();
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- Block tmp;
- if (copies.TryGetValue(b, out tmp)) {
- newBlocks.Add(cce.NonNull(tmp));
- if (gotoCmdOrigins.ContainsKey(b.TransferCmd)) {
- newGotoCmdOrigins[tmp.TransferCmd] = gotoCmdOrigins[b.TransferCmd];
- }
-
- foreach (Block p in b.Predecessors) {
- Contract.Assert(p != null);
- Block tmp2;
- if (copies.TryGetValue(p, out tmp2)) {
- tmp.Predecessors.Add(tmp2);
- }
- }
- }
- }
-
- return new Split(newBlocks, newGotoCmdOrigins, parent, impl);
- }
-
- Split SplitAt(int idx) {
- Contract.Ensures(Contract.Result<Split>() != null);
-
- assert_to_assume = idx == 0;
- doing_slice = false;
- ComputeBlockSets(true);
-
- return DoSplit();
- }
-
- Split SliceAsserts(double limit, bool pos) {
- Contract.Ensures(Contract.Result<Split>() != null);
-
- slice_pos = pos;
- slice_limit = limit;
- slice_initial_limit = limit;
- doing_slice = true;
- Split r = DoSplit();
- /*
- Console.WriteLine("split {0} / {1} -->", limit, pos);
- List<Block!> tmp = impl.Blocks;
- impl.Blocks = r.blocks;
- EmitImpl(impl, false);
- impl.Blocks = tmp;
- */
-
- return r;
- }
-
- void Print() {
- List<Block> tmp = impl.Blocks;
- Contract.Assert(tmp != null);
- impl.Blocks = blocks;
- EmitImpl(impl, false);
- impl.Blocks = tmp;
- }
-
- public Counterexample ToCounterexample(ProverContext context) {
- Contract.Requires(context != null);
- Contract.Ensures(Contract.Result<Counterexample>() != null);
-
- List<Block> trace = new List<Block>();
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- trace.Add(b);
- }
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- foreach (Cmd c in b.Cmds) {
- Contract.Assert(c != null);
- if (c is AssertCmd) {
- return AssertCmdToCounterexample((AssertCmd)c, cce.NonNull(b.TransferCmd), trace, null, null, context);
- }
- }
- }
- Contract.Assume(false);
- throw new cce.UnreachableException();
- }
-
- /// <summary>
- /// Starting from the 0-index "split_here" annotation in begin, verifies until it reaches a subsequent "split_here" annotation
- /// Returns a list of blocks where all code not verified has asserts converted into assumes
- /// </summary>
- /// <param name="blocks">Implementation's collection of blocks</param>
- /// <param name="begin">Block containing the first split_here from which to start verifying</param>
- /// <param name="begin_split_id">0-based ID of the "split_here" annotation within begin at which to start verifying</param>
- /// <param name="blockInternalSplit">True if the entire split is contained within block begin</param>
- /// <param name="endPoints">Set of all blocks containing a "split_here" annotation</param>
- /// <returns></returns>
- // Note: Current implementation may over report errors.
- // For example, if the control flow graph is a diamond (e.g., A -> B, C, B->D, C->D),
- // and there is a split in B and an error in D, then D will be verified twice and hence report the error twice.
- // Best solution may be to memoize blocks that have been fully verified and be sure not to verify them again
- private static List<Block> DoManualSplit(List<Block> blocks, Block begin, int begin_split_id, bool blockInternalSplit, IEnumerable<Block> endPoints) {
- // Compute the set of blocks reachable from begin but not included in endPoints. These will be verified in their entirety.
- var blocksToVerifyEntirely = new HashSet<Block>();
- var reachableEndPoints = new HashSet<Block>(); // Reachable end points will be verified up to their first split point
- var todo = new Stack<Block>();
- todo.Push(begin);
- while (todo.Count > 0) {
- var currentBlock = todo.Pop();
- if (blocksToVerifyEntirely.Contains(currentBlock)) continue;
- blocksToVerifyEntirely.Add(currentBlock);
- var exit = currentBlock.TransferCmd as GotoCmd;
- if (exit != null)
- foreach (Block targetBlock in exit.labelTargets) {
- if (!endPoints.Contains(targetBlock)) {
- todo.Push(targetBlock);
- } else {
- reachableEndPoints.Add(targetBlock);
- }
- }
-
- }
- blocksToVerifyEntirely.Remove(begin);
-
- // Convert assumes to asserts in "unreachable" blocks, including portions of blocks containing "split_here"
- var newBlocks = new List<Block>(blocks.Count()); // Copies of the original blocks
- var duplicator = new Duplicator();
- var oldToNewBlockMap = new Dictionary<Block, Block>(blocks.Count()); // Maps original blocks to their new copies in newBlocks
-
- foreach (var currentBlock in blocks) {
- var newBlock = (Block)duplicator.VisitBlock(currentBlock);
- oldToNewBlockMap[currentBlock] = newBlock;
- newBlocks.Add(newBlock);
-
- if (!blockInternalSplit && blocksToVerifyEntirely.Contains(currentBlock)) continue; // All reachable blocks must be checked in their entirety, so don't change anything
- // Otherwise, we only verify a portion of the current block, so we'll need to look at each of its commands
-
- // !verify -> convert assert to assume
- var verify = (currentBlock == begin && begin_split_id == -1) // -1 tells us to start verifying from the very beginning (i.e., there is no split in the begin block)
- || (reachableEndPoints.Contains(currentBlock) // This endpoint is reachable from begin, so we verify until we hit the first split point
- && !blockInternalSplit); // Don't bother verifying if all of the splitting is within the begin block
- var newCmds = new List<Cmd>();
- var split_here_count = 0;
-
- foreach (Cmd c in currentBlock.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) {
- if (currentBlock == begin) { // Verify everything between the begin_split_id we were given and the next split
- if (split_here_count == begin_split_id) {
- verify = true;
- } else if (split_here_count == begin_split_id + 1) {
- verify = false;
- }
- } else { // We're in an endPoint so we stop verifying as soon as we hit a "split_here"
- verify = false;
- }
- split_here_count++;
- }
-
- var asrt = c as AssertCmd;
- if (verify || asrt == null)
- newCmds.Add(c);
- else
- newCmds.Add(AssertTurnedIntoAssume(asrt));
- }
-
- newBlock.Cmds = newCmds;
- }
-
- // Patch the edges between the new blocks
- foreach (var oldBlock in blocks) {
- if (oldBlock.TransferCmd is ReturnCmd) { continue; }
- var gotoCmd = (GotoCmd)oldBlock.TransferCmd;
- var newLabelTargets = new List<Block>(gotoCmd.labelTargets.Count());
- var newLabelNames = new List<string>(gotoCmd.labelTargets.Count());
- foreach (var target in gotoCmd.labelTargets) {
- newLabelTargets.Add(oldToNewBlockMap[target]);
- newLabelNames.Add(oldToNewBlockMap[target].Label);
- }
- oldToNewBlockMap[oldBlock].TransferCmd = new GotoCmd(gotoCmd.tok, newLabelNames, newLabelTargets);
- }
-
- return newBlocks;
- }
-
- public static List<Split/*!*/> FindManualSplits(Implementation/*!*/ impl, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par) {
- Contract.Requires(impl != null);
- Contract.Ensures(Contract.Result<List<Split>>() == null || cce.NonNullElements(Contract.Result<List<Split>>()));
-
- var splitPoints = new Dictionary<Block,int>();
- foreach (var b in impl.Blocks) {
- foreach (Cmd c in b.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) {
- int count;
- splitPoints.TryGetValue(b, out count);
- splitPoints[b] = count + 1;
- }
- }
- }
-
- if (splitPoints.Count() == 0) { // No manual split points here
- return null;
- }
-
- List<Split> splits = new List<Split>();
- Block entryPoint = impl.Blocks[0];
- var newEntryBlocks = DoManualSplit(impl.Blocks, entryPoint, -1, splitPoints.Keys.Contains(entryPoint), splitPoints.Keys);
- splits.Add(new Split(newEntryBlocks, gotoCmdOrigins, par, impl)); // REVIEW: Does gotoCmdOrigins need to be changed at all?
-
- foreach (KeyValuePair<Block,int> pair in splitPoints) {
- for (int i = 0; i < pair.Value; i++) {
- bool blockInternalSplit = i < pair.Value - 1; // There's at least one more split, after this one, in the current block
- var newBlocks = DoManualSplit(impl.Blocks, pair.Key, i, blockInternalSplit, splitPoints.Keys);
- Split s = new Split(newBlocks, gotoCmdOrigins, par, impl); // REVIEW: Does gotoCmdOrigins need to be changed at all?
- splits.Add(s);
- }
- }
-
- return splits;
- }
-
- public static List<Split/*!*/>/*!*/ DoSplit(Split initial, double max_cost, int max) {
- Contract.Requires(initial != null);
- Contract.Ensures(cce.NonNullElements(Contract.Result<List<Split>>()));
-
- List<Split> res = new List<Split>();
- res.Add(initial);
-
- while (res.Count < max) {
- Split best = null;
- int best_idx = 0, pos = 0;
- foreach (Split s in res) {
- Contract.Assert(s != null);
- s.ComputeBestSplit(); // TODO check total_cost first
- if (s.total_cost > max_cost &&
- (best == null || best.total_cost < s.total_cost) &&
- (s.assertion_count > 1 || s.split_block != null)) {
- best = s;
- best_idx = pos;
- }
- pos++;
- }
-
- if (best == null)
- break; // no split found
-
- Split s0, s1;
-
- bool split_stats = CommandLineOptions.Clo.TraceVerify;
-
- if (split_stats) {
- Console.WriteLine("{0} {1} -->", best.split_block == null ? "SLICE" : ("SPLIT@" + best.split_block.Label), best.Stats);
- if (best.split_block != null) {
- GotoCmd g = best.split_block.TransferCmd as GotoCmd;
- if (g != null) {
- Console.Write(" exits: ");
- foreach (Block b in cce.NonNull(g.labelTargets)) {
- Contract.Assert(b != null);
- Console.Write("{0} ", b.Label);
- }
- Console.WriteLine("");
- Console.Write(" assumized: ");
- foreach (Block b in best.assumized_branches) {
- Contract.Assert(b != null);
- Console.Write("{0} ", b.Label);
- }
- Console.WriteLine("");
- }
- }
- }
-
- if (best.split_block != null) {
- s0 = best.SplitAt(0);
- s1 = best.SplitAt(1);
- } else {
- best.split_block = null;
- s0 = best.SliceAsserts(best.assertion_cost / 2, true);
- s1 = best.SliceAsserts(best.assertion_cost / 2, false);
- }
-
- if (true) {
- List<Block> ss = new List<Block>();
- ss.Add(s0.blocks[0]);
- ss.Add(s1.blocks[0]);
- try {
- best.SoundnessCheck(new HashSet<List<Block>>(new BlockListComparer()), best.blocks[0], ss);
- } catch (System.Exception e) {
- Console.WriteLine(e);
- best.DumpDot(-1);
- s0.DumpDot(-2);
- s1.DumpDot(-3);
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- }
-
- if (split_stats) {
- s0.ComputeBestSplit();
- s1.ComputeBestSplit();
- Console.WriteLine(" --> {0}", s0.Stats);
- Console.WriteLine(" --> {0}", s1.Stats);
- }
-
- if (CommandLineOptions.Clo.TraceVerify) {
- best.Print();
- }
-
- res[best_idx] = s0;
- res.Add(s1);
- }
-
- return res;
- }
-
- class BlockListComparer : IEqualityComparer<List<Block>>
- {
- public bool Equals(List<Block> x, List<Block> y)
- {
- return x == y || x.SequenceEqual(y);
- }
-
- public int GetHashCode(List<Block> obj)
- {
- int h = 0;
- Contract.Assume(obj != null);
- foreach (var b in obj)
- {
- if (b != null)
- {
- h += b.GetHashCode();
- }
- }
- return h;
- }
- }
-
- public Checker Checker {
- get {
- Contract.Ensures(Contract.Result<Checker>() != null);
-
- Contract.Assert(checker != null);
- return checker;
- }
- }
-
- public Task ProverTask {
- get {
- Contract.Assert(checker != null);
- return checker.ProverTask;
- }
- }
-
- public void ReadOutcome(ref Outcome cur_outcome, out bool prover_failed) {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
- ProverInterface.Outcome outcome = cce.NonNull(checker).ReadOutcome();
-
- if (CommandLineOptions.Clo.Trace && splitNo >= 0) {
- System.Console.WriteLine(" --> split #{0} done, [{1} s] {2}", splitNo, checker.ProverRunTime.TotalSeconds, outcome);
- }
-
- if (CommandLineOptions.Clo.VcsDumpSplits) {
- DumpDot(splitNo);
- }
-
- prover_failed = false;
-
- switch (outcome) {
- case ProverInterface.Outcome.Valid:
- return;
- case ProverInterface.Outcome.Invalid:
- cur_outcome = Outcome.Errors;
- return;
- case ProverInterface.Outcome.OutOfMemory:
- prover_failed = true;
- if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive)
- cur_outcome = Outcome.OutOfMemory;
- return;
- case ProverInterface.Outcome.TimeOut:
- prover_failed = true;
- if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive)
- cur_outcome = Outcome.TimedOut;
- return;
- case ProverInterface.Outcome.Undetermined:
- if (cur_outcome != Outcome.Errors)
- cur_outcome = Outcome.Inconclusive;
- return;
- default:
- Contract.Assert(false);
- throw new cce.UnreachableException();
- }
- }
-
- /// <summary>
- /// As a side effect, updates "this.parent.CumulativeAssertionCount".
- /// </summary>
- public void BeginCheck(Checker checker, VerifierCallback callback, ModelViewInfo mvInfo, int no, int timeout)
- {
- Contract.Requires(checker != null);
- Contract.Requires(callback != null);
-
- splitNo = no;
-
- impl.Blocks = blocks;
-
- this.checker = checker;
-
- Dictionary<int, Absy> label2absy = new Dictionary<int, Absy>();
-
- ProverContext ctx = checker.TheoremProver.Context;
- Boogie2VCExprTranslator bet = ctx.BoogieExprTranslator;
- CodeExprConversionClosure cc = new CodeExprConversionClosure(label2absy, ctx);
- bet.SetCodeExprConverter(cc.CodeExprToVerificationCondition);
-
- var exprGen = ctx.ExprGen;
- VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO);
-
- VCExpr vc = parent.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, checker.TheoremProver.Context);
- Contract.Assert(vc != null);
-
- if (!CommandLineOptions.Clo.UseLabels)
- {
- VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO));
- VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId)));
- vc = exprGen.Implies(eqExpr, vc);
- }
-
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local)
- {
- reporter = new ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, cce.NonNull(this.Checker.TheoremProver.Context), parent.program);
- }
- else
- {
- reporter = new ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, this.Checker.TheoremProver.Context, parent.program);
- }
-
- if (CommandLineOptions.Clo.TraceVerify && no >= 0)
- {
- Console.WriteLine("-- after split #{0}", no);
- Print();
- }
-
- string desc = cce.NonNull(impl.Name);
- if (no >= 0)
- desc += "_split" + no;
- checker.BeginCheck(desc, vc, reporter);
- }
-
- private void SoundnessCheck(HashSet<List<Block>/*!*/>/*!*/ cache, Block/*!*/ orig, List<Block/*!*/>/*!*/ copies) {
- Contract.Requires(cce.NonNull(cache));
- Contract.Requires(orig != null);
- Contract.Requires(copies != null);
- {
- var t = new List<Block> { orig };
- foreach (Block b in copies) {
- Contract.Assert(b != null);
- t.Add(b);
- }
- if (cache.Contains(t)) {
- return;
- }
- cache.Add(t);
- }
-
- for (int i = 0; i < orig.Cmds.Count; ++i) {
- Cmd cmd = orig.Cmds[i];
- if (cmd is AssertCmd) {
- int found = 0;
- foreach (Block c in copies) {
- Contract.Assert(c != null);
- if (c.Cmds[i] == cmd) {
- found++;
- }
- }
- if (found == 0) {
- throw new System.Exception(string.Format("missing assertion: {0}({1})", cmd.tok.filename, cmd.tok.line));
- }
- }
- }
-
- foreach (Block exit in Exits(orig)) {
- Contract.Assert(exit != null);
- List<Block> newcopies = new List<Block>();
- foreach (Block c in copies) {
- foreach (Block cexit in Exits(c)) {
- Contract.Assert(cexit != null);
- if (cexit.Label == exit.Label) {
- newcopies.Add(cexit);
- }
- }
- }
- if (newcopies.Count == 0) {
- throw new System.Exception("missing exit " + exit.Label);
- }
- SoundnessCheck(cache, exit, newcopies);
- }
- }
- }
- #endregion
-
-
- public class CodeExprConversionClosure
- {
- Dictionary<int, Absy> label2absy;
- ProverContext ctx;
- public CodeExprConversionClosure(Dictionary<int, Absy> label2absy, ProverContext ctx)
- {
- this.label2absy = label2absy;
- this.ctx = ctx;
- }
-
- public VCExpr CodeExprToVerificationCondition(CodeExpr codeExpr, Hashtable blockVariables, List<VCExprLetBinding> bindings, bool isPositiveContext)
- {
- VCGen vcgen = new VCGen(new Program(), null, false, new List<Checker>());
- vcgen.variable2SequenceNumber = new Dictionary<Variable, int>();
- vcgen.incarnationOriginMap = new Dictionary<Incarnation, Absy>();
- vcgen.CurrentLocalVariables = codeExpr.LocVars;
-
- ResetPredecessors(codeExpr.Blocks);
- vcgen.AddBlocksBetween(codeExpr.Blocks);
- Dictionary<Variable, Expr> gotoCmdOrigins = vcgen.ConvertBlocks2PassiveCmd(codeExpr.Blocks, new List<IdentifierExpr>(), new ModelViewInfo(codeExpr));
- int ac; // computed, but then ignored for this CodeExpr
- VCExpr startCorrect = VCGen.LetVCIterative(codeExpr.Blocks, null, label2absy, ctx, out ac, isPositiveContext);
- VCExpr vce = ctx.ExprGen.Let(bindings, startCorrect);
- if (vcgen.CurrentLocalVariables.Count != 0)
- {
- Boogie2VCExprTranslator translator = ctx.BoogieExprTranslator;
- List<VCExprVar> boundVars = new List<VCExprVar>();
- foreach (Variable v in vcgen.CurrentLocalVariables)
- {
- Contract.Assert(v != null);
- VCExprVar ev = translator.LookupVariable(v);
- Contract.Assert(ev != null);
- boundVars.Add(ev);
- if (v.TypedIdent.Type.Equals(Bpl.Type.Bool))
- {
- // add an antecedent (tickleBool ev) to help the prover find a possible trigger
- vce = ctx.ExprGen.Implies(ctx.ExprGen.Function(VCExpressionGenerator.TickleBoolOp, ev), vce);
- }
- }
- vce = ctx.ExprGen.Forall(boundVars, new List<VCTrigger>(), vce);
- }
- if (isPositiveContext)
- {
- vce = ctx.ExprGen.Not(vce);
- }
- return vce;
- }
- }
-
- public VCExpr GenerateVC(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, out Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext)
- {
- Contract.Requires(impl != null);
- Contract.Requires(proverContext != null);
- Contract.Ensures(Contract.ValueAtReturn(out label2absy) != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- label2absy = new Dictionary<int, Absy>();
- return GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverContext);
- }
-
- public VCExpr GenerateVCAux(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext) {
- Contract.Requires(impl != null);
- Contract.Requires(proverContext != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- TypecheckingContext tc = new TypecheckingContext(null);
- impl.Typecheck(tc);
-
- VCExpr vc;
- int assertionCount;
- switch (CommandLineOptions.Clo.vcVariety) {
- case CommandLineOptions.VCVariety.Structured:
- vc = VCViaStructuredProgram(impl, label2absy, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Block:
- vc = FlatBlockVC(impl, label2absy, false, false, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.BlockReach:
- vc = FlatBlockVC(impl, label2absy, false, true, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Local:
- vc = FlatBlockVC(impl, label2absy, true, false, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.BlockNested:
- vc = NestedBlockVC(impl, label2absy, false, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.BlockNestedReach:
- vc = NestedBlockVC(impl, label2absy, true, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Dag:
- if (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).SupportsDags || CommandLineOptions.Clo.FixedPointEngine != null) {
- vc = DagVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, new Hashtable/*<Block, VCExpr!>*/(), proverContext, out assertionCount);
- } else {
- vc = LetVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, proverContext, out assertionCount);
- }
- break;
- case CommandLineOptions.VCVariety.DagIterative:
- vc = LetVCIterative(impl.Blocks, controlFlowVariableExpr, label2absy, proverContext, out assertionCount);
- break;
- case CommandLineOptions.VCVariety.Doomed:
- vc = FlatBlockVC(impl, label2absy, false, false, true, proverContext, out assertionCount);
- break;
- default:
- Contract.Assert(false);
- throw new cce.UnreachableException(); // unexpected enumeration value
- }
- CumulativeAssertionCount += assertionCount;
- return vc;
- }
-
- void CheckIntAttributeOnImpl(Implementation impl, string name, ref int val) {
- Contract.Requires(impl != null);
- Contract.Requires(name != null);
- if (!(cce.NonNull(impl.Proc).CheckIntAttribute(name, ref val) || !impl.CheckIntAttribute(name, ref val))) {
- Console.WriteLine("ignoring ill-formed {:{0} ...} attribute on {1}, parameter should be an int", name, impl.Name);
- }
- }
-
- public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) {
- Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true);
-
- if (impl.SkipVerification) {
- return Outcome.Inconclusive; // not sure about this one
- }
-
- callback.OnProgress("VCgen", 0, 0, 0.0);
-
- Stopwatch watch = new Stopwatch();
- if (_print_time)
- {
- Console.WriteLine("Checking function {0}", impl.Name);
- watch.Reset();
- watch.Start();
- }
-
- ConvertCFG2DAG(impl);
-
- SmokeTester smoke_tester = null;
- if (CommandLineOptions.Clo.SoundnessSmokeTest) {
- smoke_tester = new SmokeTester(this, impl, callback);
- smoke_tester.Copy();
- }
-
- ModelViewInfo mvInfo;
- var gotoCmdOrigins = PassifyImpl(impl, out mvInfo);
-
- // If "expand" attribute is supplied, expand any assertion of conjunctions into multiple assertions, one per conjunct
- foreach (var b in impl.Blocks)
- {
- List<Cmd> newCmds = new List<Cmd>();
- bool changed = false;
- foreach (var c in b.Cmds)
- {
- var a = c as AssertCmd;
- var ar = c as AssertRequiresCmd;
- var ae = c as AssertEnsuresCmd;
- var ai = c as LoopInitAssertCmd;
- var am = c as LoopInvMaintainedAssertCmd;
- // TODO:
- //use Duplicator and Substituter rather than new
- //nested IToken?
- //document expand attribute (search for {:ignore}, for example)
- //fix up new CallCmd, new Requires, new Ensures in OwickiGries.cs
- Func<Expr,Expr,Expr> withType = (Expr from, Expr to) =>
- {
- NAryExpr nFrom = from as NAryExpr;
- NAryExpr nTo = to as NAryExpr;
- to.Type = from.Type;
- if (nFrom != null && nTo != null) nTo.TypeParameters = nFrom.TypeParameters;
- return to;
- };
-
- Action<int,Expr,Action<Expr>> traverse = null;
- traverse = (depth, e, act) =>
- {
- ForallExpr forall = e as ForallExpr;
- NAryExpr nary = e as NAryExpr;
- if (forall != null)
- {
- traverse(depth, forall.Body, e1 => act(withType(forall,
- new ForallExpr(e1.tok, forall.TypeParameters, forall.Dummies, forall.Attributes, forall.Triggers, e1))));
- return;
- }
- if (nary != null)
- {
- var args = nary.Args;
- IAppliable fun = nary.Fun;
- BinaryOperator bop = fun as BinaryOperator;
- FunctionCall call = fun as FunctionCall;
- if (bop != null)
- {
- switch (bop.Op)
- {
- case BinaryOperator.Opcode.And:
- traverse(depth, args[0], act);
- traverse(depth, args[1], act);
- return;
- case BinaryOperator.Opcode.Imp:
- traverse(depth, args[1], e1 => act(withType(nary,
- new NAryExpr(e1.tok, fun, new List<Expr>() { args[0], e1 }))));
- return;
- }
- }
- if (depth > 0 && call != null && call.Func != null)
- {
- Function cf = call.Func;
- Expr body = cf.Body;
- List<Variable> ins = cf.InParams;
- if (body == null && cf.DefinitionAxiom != null)
- {
- ForallExpr all = cf.DefinitionAxiom.Expr as ForallExpr;
- if (all != null)
- {
- NAryExpr def = all.Body as NAryExpr;
- if (def != null && def.Fun is BinaryOperator && ((BinaryOperator) (def.Fun)).Op == BinaryOperator.Opcode.Iff)
- {
- body = def.Args[1];
- ins = all.Dummies;
- }
- }
- }
- if (body != null)
- {
- Func<Expr,Expr> new_f = e1 =>
- {
- Function f = new Function(cf.tok, "expand<" + cf.Name + ">", cf.TypeParameters, ins, cf.OutParams[0], cf.Comment);
- f.Body = e1;
- Token tok = new Token(e1.tok.line, e1.tok.col);
- tok.filename = e.tok.filename + "(" + e.tok.line + "," + e.tok.col + ") --> " + e1.tok.filename;
- return withType(nary, new NAryExpr(tok, new FunctionCall(f), args));
- };
- traverse(depth - 1, body, e1 => act(new_f(e1)));
- return;
- }
- }
- }
- act(e);
- };
-
- if (a != null)
- {
- var attr = a.Attributes;
- if (ar != null && ar.Requires.Attributes != null) attr = ar.Requires.Attributes;
- if (ar != null && ar.Call.Attributes != null) attr = ar.Call.Attributes;
- if (ae != null && ae.Ensures.Attributes != null) attr = ae.Ensures.Attributes;
- if (QKeyValue.FindExprAttribute(attr, "expand") != null || QKeyValue.FindBoolAttribute(attr, "expand"))
- {
- int depth = QKeyValue.FindIntAttribute(attr, "expand", 100);
- Func<Expr,Expr> fe = e => Expr.Or(a.Expr, e);
- //traverse(depth, a.Expr, e => System.Console.WriteLine(e.GetType() + " :: " + e + " @ " + e.tok.line + ", " + e.tok.col));
- traverse(depth, a.Expr, e =>
- {
- AssertCmd new_c =
- (ar != null) ? new AssertRequiresCmd(ar.Call, new Requires(e.tok, ar.Requires.Free, fe(e), ar.Requires.Comment)) :
- (ae != null) ? new AssertEnsuresCmd(new Ensures(e.tok, ae.Ensures.Free, fe(e), ae.Ensures.Comment)) :
- (ai != null) ? new LoopInitAssertCmd(e.tok, fe(e)) :
- (am != null) ? new LoopInvMaintainedAssertCmd(e.tok, fe(e)) :
- new AssertCmd(e.tok, fe(e));
- new_c.Attributes = new QKeyValue(e.tok, "subsumption", new List<object>() { new LiteralExpr(e.tok, BigNum.FromInt(0)) }, a.Attributes);
- newCmds.Add(new_c);
- });
- }
- newCmds.Add(c);
- changed = true;
- }
- else
- {
- newCmds.Add(c);
- }
- }
- if (changed) b.Cmds = newCmds;
- }
-
- double max_vc_cost = CommandLineOptions.Clo.VcsMaxCost;
- int tmp_max_vc_cost = -1, max_splits = CommandLineOptions.Clo.VcsMaxSplits,
- max_kg_splits = CommandLineOptions.Clo.VcsMaxKeepGoingSplits;
- CheckIntAttributeOnImpl(impl, "vcs_max_cost", ref tmp_max_vc_cost);
- CheckIntAttributeOnImpl(impl, "vcs_max_splits", ref max_splits);
- CheckIntAttributeOnImpl(impl, "vcs_max_keep_going_splits", ref max_kg_splits);
- if (tmp_max_vc_cost >= 0) {
- max_vc_cost = tmp_max_vc_cost;
- }
-
- Outcome outcome = Outcome.Correct;
-
- // Report all recycled failing assertions for this implementation.
- if (impl.RecycledFailingAssertions != null && impl.RecycledFailingAssertions.Any())
- {
- outcome = Outcome.Errors;
- foreach (var a in impl.RecycledFailingAssertions)
- {
- var checksum = a.Checksum;
- var oldCex = impl.ErrorChecksumToCachedError[checksum] as Counterexample;
- if (oldCex != null) {
- if (CommandLineOptions.Clo.VerifySnapshots < 3) {
- callback.OnCounterexample(oldCex, null);
- } else {
- // If possible, we use the old counterexample, but with the location information of "a"
- var cex = AssertCmdToCloneCounterexample(a, oldCex);
- callback.OnCounterexample(cex, null);
- // OnCounterexample may have had side effects on the RequestId and OriginalRequestId fields. We make
- // any such updates available in oldCex. (Is this really a good design? --KRML)
- oldCex.RequestId = cex.RequestId;
- oldCex.OriginalRequestId = cex.OriginalRequestId;
- }
- }
- }
- }
-
- Cores = CommandLineOptions.Clo.VcsCores;
- Stack<Split> work = new Stack<Split>();
- List<Split> currently_running = new List<Split>();
- ResetPredecessors(impl.Blocks);
- List<Split> manual_splits = Split.FindManualSplits(impl, gotoCmdOrigins, this);
- if (manual_splits != null) {
- foreach (var split in manual_splits) {
- work.Push(split);
- }
- } else {
- work.Push(new Split(impl.Blocks, gotoCmdOrigins, this, impl));
- }
-
- bool keep_going = max_kg_splits > 1;
- int total = 0;
- int no = max_splits == 1 && !keep_going ? -1 : 0;
- bool first_round = true;
- bool do_splitting = keep_going || max_splits > 1;
- double remaining_cost = 0.0, proven_cost = 0.0;
-
- if (do_splitting) {
- remaining_cost = work.Peek().Cost;
- }
-
- while (work.Any() || currently_running.Any())
- {
- bool prover_failed = false;
- Split s = null;
- var isWaiting = !work.Any();
-
- if (!isWaiting)
- {
- s = work.Peek();
-
- if (first_round && max_splits > 1)
- {
- prover_failed = true;
- remaining_cost -= s.Cost;
- }
- else
- {
- var timeout = (keep_going && s.LastChance) ? CommandLineOptions.Clo.VcsFinalAssertTimeout :
- keep_going ? CommandLineOptions.Clo.VcsKeepGoingTimeout :
- impl.TimeLimit;
-
- var checker = s.parent.FindCheckerFor(timeout, false);
- try
- {
- if (checker == null)
- {
- isWaiting = true;
- goto waiting;
- }
- else
- {
- s = work.Pop();
- }
-
- if (CommandLineOptions.Clo.Trace && no >= 0)
- {
- System.Console.WriteLine(" checking split {1}/{2}, {3:0.00}%, {0} ...",
- s.Stats, no + 1, total, 100 * proven_cost / (proven_cost + remaining_cost));
- }
- callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost));
-
- Contract.Assert(s.parent == this);
- lock (checker)
- {
- s.BeginCheck(checker, callback, mvInfo, no, timeout);
- }
-
- no++;
-
- currently_running.Add(s);
- }
- catch (Exception)
- {
- checker.GoBackToIdle();
- throw;
- }
- }
- }
-
- waiting:
- if (isWaiting)
- {
- // Wait for one split to terminate.
- var tasks = currently_running.Select(splt => splt.ProverTask).ToArray();
-
- if (tasks.Any())
- {
- try
- {
- int index = Task.WaitAny(tasks);
- s = currently_running[index];
- currently_running.RemoveAt(index);
-
- if (do_splitting)
- {
- remaining_cost -= s.Cost;
- }
-
- lock (s.Checker)
- {
- s.ReadOutcome(ref outcome, out prover_failed);
- }
-
- if (do_splitting)
- {
- if (prover_failed)
- {
- // even if the prover fails, we have learned something, i.e., it is
- // annoying to watch Boogie say Timeout, 0.00% a couple of times
- proven_cost += s.Cost / 100;
- }
- else
- {
- proven_cost += s.Cost;
- }
- }
- callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost));
-
- if (prover_failed && !first_round && s.LastChance)
- {
- string msg = "some timeout";
- if (s.reporter != null && s.reporter.resourceExceededMessage != null)
- {
- msg = s.reporter.resourceExceededMessage;
- }
- callback.OnCounterexample(s.ToCounterexample(s.Checker.TheoremProver.Context), msg);
- outcome = Outcome.Errors;
- break;
- }
- }
- finally
- {
- s.Checker.GoBackToIdle();
- }
-
- Contract.Assert(prover_failed || outcome == Outcome.Correct || outcome == Outcome.Errors || outcome == Outcome.Inconclusive);
- }
- }
-
- if (prover_failed)
- {
- int splits = first_round && max_splits > 1 ? max_splits : max_kg_splits;
-
- if (splits > 1)
- {
- List<Split> tmp = Split.DoSplit(s, max_vc_cost, splits);
- Contract.Assert(tmp != null);
- max_vc_cost = 1.0; // for future
- first_round = false;
- //tmp.Sort(new Comparison<Split!>(Split.Compare));
- foreach (Split a in tmp)
- {
- Contract.Assert(a != null);
- work.Push(a);
- total++;
- remaining_cost += a.Cost;
- }
- if (outcome != Outcome.Errors)
- {
- outcome = Outcome.Correct;
- }
- }
- else
- {
- Contract.Assert(outcome != Outcome.Correct);
- if (outcome == Outcome.TimedOut)
- {
- string msg = "some timeout";
- if (s.reporter != null && s.reporter.resourceExceededMessage != null)
- {
- msg = s.reporter.resourceExceededMessage;
- }
- callback.OnTimeout(msg);
- }
- else if (outcome == Outcome.OutOfMemory)
- {
- string msg = "out of memory";
- if (s.reporter != null && s.reporter.resourceExceededMessage != null)
- {
- msg = s.reporter.resourceExceededMessage;
- }
- callback.OnOutOfMemory(msg);
- }
-
- break;
- }
- }
- }
-
- if (outcome == Outcome.Correct && smoke_tester != null) {
- smoke_tester.Test();
- }
-
- callback.OnProgress("done", 0, 0, 1.0);
-
- if (_print_time)
- {
- watch.Stop();
- Console.WriteLine("Total time for this method: {0}", watch.Elapsed.ToString());
- }
-
- return outcome;
- }
-
- public class ErrorReporter : ProverInterface.ErrorHandler {
- Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins;
- Dictionary<int, Absy>/*!*/ label2absy;
- List<Block/*!*/>/*!*/ blocks;
- protected Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap;
- protected VerifierCallback/*!*/ callback;
- protected ModelViewInfo MvInfo;
- internal string resourceExceededMessage;
- static System.IO.TextWriter modelWriter;
- [ContractInvariantMethod]
- void ObjectInvariant() {
- Contract.Invariant(gotoCmdOrigins != null);
- Contract.Invariant(label2absy != null);
- Contract.Invariant(cce.NonNullElements(blocks));
- Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Invariant(callback != null);
- Contract.Invariant(context != null);
- Contract.Invariant(program != null);
- }
-
-
- public static TextWriter ModelWriter {
- get {
- Contract.Ensures(Contract.Result<TextWriter>() != null);
-
- if (ErrorReporter.modelWriter == null)
- ErrorReporter.modelWriter = CommandLineOptions.Clo.PrintErrorModelFile == null ? Console.Out : new StreamWriter(CommandLineOptions.Clo.PrintErrorModelFile, false);
- return ErrorReporter.modelWriter;
- }
- }
-
- protected ProverContext/*!*/ context;
- Program/*!*/ program;
-
- public ErrorReporter(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins,
- Dictionary<int, Absy>/*!*/ label2absy,
- List<Block/*!*/>/*!*/ blocks,
- Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
- VerifierCallback/*!*/ callback,
- ModelViewInfo mvInfo,
- ProverContext/*!*/ context,
- Program/*!*/ program) {
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Requires(callback != null);
- Contract.Requires(context!=null);
- Contract.Requires(program!=null);
- this.gotoCmdOrigins = gotoCmdOrigins;
- this.label2absy = label2absy;
- this.blocks = blocks;
- this.incarnationOriginMap = incarnationOriginMap;
- this.callback = callback;
- this.MvInfo = mvInfo;
-
- this.context = context;
- this.program = program;
- }
-
- public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
- //Contract.Requires(cce.NonNullElements(labels));
- if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
- if (VC.ConditionGeneration.errorModelList != null)
- {
- VC.ConditionGeneration.errorModelList.Add(model);
- }
-
- model.Write(ErrorReporter.ModelWriter);
- ErrorReporter.ModelWriter.Flush();
- }
-
- Hashtable traceNodes = new Hashtable();
- foreach (string s in labels) {
- Contract.Assert(s != null);
- Absy absy = Label2Absy(s);
- Contract.Assert(absy != null);
- if (traceNodes.ContainsKey(absy))
- System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes");
- else
- traceNodes.Add(absy, null);
- }
-
- List<Block> trace = new List<Block>();
- Block entryBlock = cce.NonNull(this.blocks[0]);
- Contract.Assert(traceNodes.Contains(entryBlock));
- trace.Add(entryBlock);
-
- Counterexample newCounterexample = TraceCounterexample(entryBlock, traceNodes, trace, model, MvInfo, incarnationOriginMap, context, new Dictionary<TraceLocation, CalleeCounterexampleInfo>());
-
- if (newCounterexample == null)
- return;
-
- #region Map passive program errors back to original program errors
- ReturnCounterexample returnExample = newCounterexample as ReturnCounterexample;
- if (returnExample != null) {
- foreach (Block b in returnExample.Trace) {
- Contract.Assert(b != null);
- Contract.Assume(b.TransferCmd != null);
- ReturnCmd cmd = gotoCmdOrigins.ContainsKey(b.TransferCmd) ? gotoCmdOrigins[b.TransferCmd] : null;
- if (cmd != null) {
- returnExample.FailingReturn = cmd;
- break;
- }
- }
- }
- #endregion
- callback.OnCounterexample(newCounterexample, null);
- }
-
- public override Absy Label2Absy(string label) {
- //Contract.Requires(label != null);
- Contract.Ensures(Contract.Result<Absy>() != null);
-
- int id = int.Parse(label);
- return cce.NonNull((Absy)label2absy[id]);
- }
-
- public override void OnResourceExceeded(string msg, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) {
- //Contract.Requires(msg != null);
- resourceExceededMessage = msg;
- if (assertCmds != null)
- {
- foreach (var cmd in assertCmds)
- {
- Counterexample cex = AssertCmdToCounterexample(cmd.Item1, cmd.Item2 , new List<Block>(), null, null, context);
- callback.OnCounterexample(cex, msg);
- }
- }
- }
-
- public override void OnProverWarning(string msg) {
- //Contract.Requires(msg != null);
- callback.OnWarning(msg);
- }
- }
-
- public class ErrorReporterLocal : ErrorReporter {
- public ErrorReporterLocal(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins,
- Dictionary<int, Absy>/*!*/ label2absy,
- List<Block/*!*/>/*!*/ blocks,
- Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
- VerifierCallback/*!*/ callback,
- ModelViewInfo mvInfo,
- ProverContext/*!*/ context,
- Program/*!*/ program)
- : base(gotoCmdOrigins, label2absy, blocks, incarnationOriginMap, callback, mvInfo, context, program) // here for aesthetic purposes //TODO: Maybe nix?
- {
- Contract.Requires(gotoCmdOrigins != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Requires(callback != null);
- Contract.Requires(context != null);
- Contract.Requires(program != null);
- }
-
- public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) {
- //Contract.Requires(cce.NonNullElements(labels));
- // We ignore the error model here for enhanced error message purposes.
- // It is only printed to the command line.
- if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) {
- if (CommandLineOptions.Clo.PrintErrorModelFile != null) {
- model.Write(ErrorReporter.ModelWriter);
- ErrorReporter.ModelWriter.Flush();
- }
- }
- List<Block> traceNodes = new List<Block>();
- List<AssertCmd> assertNodes = new List<AssertCmd>();
- foreach (string s in labels) {
- Contract.Assert(s != null);
- Absy node = Label2Absy(s);
- if (node is Block) {
- Block b = (Block)node;
- traceNodes.Add(b);
- } else {
- AssertCmd a = (AssertCmd)node;
- assertNodes.Add(a);
- }
- }
- Contract.Assert(assertNodes.Count > 0);
- Contract.Assert(traceNodes.Count == assertNodes.Count);
-
- foreach (AssertCmd a in assertNodes) {
- // find the corresponding Block (assertNodes.Count is likely to be 1, or small in any case, so just do a linear search here)
- foreach (Block b in traceNodes) {
- if (b.Cmds.Contains(a)) {
- List<Block> trace = new List<Block>();
- trace.Add(b);
- Counterexample newCounterexample = AssertCmdToCounterexample(a, cce.NonNull(b.TransferCmd), trace, model, MvInfo, context);
- callback.OnCounterexample(newCounterexample, null);
- goto NEXT_ASSERT;
- }
- }
- Contract.Assert(false);
- throw new cce.UnreachableException(); // there was no block that contains the assert
- NEXT_ASSERT: {
- }
- }
- }
- }
-
- private void RecordCutEdge(Dictionary<Block,List<Block>> edgesCut, Block from, Block to){
- if (edgesCut != null)
- {
- if (!edgesCut.ContainsKey(from))
- edgesCut.Add(from, new List<Block>());
- edgesCut[from].Add(to);
- }
- }
-
- public void ConvertCFG2DAG(Implementation impl, Dictionary<Block,List<Block>> edgesCut = null, int taskID = -1)
- {
- Contract.Requires(impl != null);
- impl.PruneUnreachableBlocks(); // This is needed for VCVariety.BlockNested, and is otherwise just an optimization
-
- CurrentLocalVariables = impl.LocVars;
- variable2SequenceNumber = new Dictionary<Variable, int>();
- incarnationOriginMap = new Dictionary<Incarnation, Absy>();
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("original implementation");
- EmitImpl(impl, false);
- }
- #endregion
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after desugaring sugared commands like procedure calls");
- EmitImpl(impl, true);
- }
- #endregion
-
- // Recompute the predecessors, but first insert a dummy start node that is sure not to be the target of any goto (because the cutting of back edges
- // below assumes that the start node has no predecessor)
- impl.Blocks.Insert(0, new Block(new Token(-17, -4), "0", new List<Cmd>(), new GotoCmd(Token.NoToken, new List<String> { impl.Blocks[0].Label }, new List<Block> { impl.Blocks[0] })));
- ResetPredecessors(impl.Blocks);
-
- if(CommandLineOptions.Clo.KInductionDepth < 0) {
- ConvertCFG2DAGStandard(impl, edgesCut, taskID);
- } else {
- ConvertCFG2DAGKInduction(impl, edgesCut, taskID);
- }
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after conversion into a DAG");
- EmitImpl(impl, true);
- }
- #endregion
- }
-
- private void ConvertCFG2DAGStandard(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID)
- {
- #region Convert program CFG into a DAG
-
- #region Use the graph library to figure out where the (natural) loops are
-
- #region Create the graph by adding the source node and each edge
- Graph<Block> g = Program.GraphFromImpl(impl);
- #endregion
-
- //Graph<Block> g = program.ProcessLoops(impl);
-
- g.ComputeLoops(); // this is the call that does all of the processing
- if (!g.Reducible)
- {
- throw new VCGenException("Irreducible flow graphs are unsupported.");
- }
-
- #endregion
-
- #region Cut the backedges, push assert/assume statements from loop header into predecessors, change them all into assume statements at top of loop, introduce havoc statements
- foreach (Block header in cce.NonNull(g.Headers))
- {
- Contract.Assert(header != null);
- IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>();
- foreach (Block b in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(b != null);
- backEdgeNodes.Add(b, null);
- }
-
- #region Find the (possibly empty) prefix of assert commands in the header, replace each assert with an assume of the same condition
- List<Cmd> prefixOfPredicateCmdsInit = new List<Cmd>();
- List<Cmd> prefixOfPredicateCmdsMaintained = new List<Cmd>();
- for (int i = 0, n = header.Cmds.Count; i < n; i++)
- {
- PredicateCmd a = header.Cmds[i] as PredicateCmd;
- if (a != null)
- {
- if (a is AssertCmd)
- {
- AssertCmd c = (AssertCmd)a;
- AssertCmd b = null;
-
- if (CommandLineOptions.Clo.ConcurrentHoudini)
- {
- Contract.Assert(taskID >= 0);
- if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvEntryAssert)
- b = new LoopInitAssertCmd(c.tok, Expr.True);
- else
- b = new LoopInitAssertCmd(c.tok, c.Expr);
- }
- else
- {
- b = new LoopInitAssertCmd(c.tok, c.Expr);
- }
-
- b.Attributes = c.Attributes;
- b.ErrorData = c.ErrorData;
- prefixOfPredicateCmdsInit.Add(b);
-
- if (CommandLineOptions.Clo.ConcurrentHoudini)
- {
- Contract.Assert(taskID >= 0);
- if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvMaintainedAssert)
- b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, Expr.True);
- else
- b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr);
- }
- else
- {
- b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr);
- }
-
- b.Attributes = c.Attributes;
- b.ErrorData = c.ErrorData;
- prefixOfPredicateCmdsMaintained.Add(b);
- header.Cmds[i] = new AssumeCmd(c.tok, c.Expr);
- }
- else
- {
- Contract.Assert(a is AssumeCmd);
- if (Bpl.CommandLineOptions.Clo.AlwaysAssumeFreeLoopInvariants)
- {
- // Usually, "free" stuff, like free loop invariants (and the assume statements
- // that stand for such loop invariants) are ignored on the checking side. This
- // command-line option changes that behavior to always assume the conditions.
- prefixOfPredicateCmdsInit.Add(a);
- prefixOfPredicateCmdsMaintained.Add(a);
- }
- }
- }
- else if (header.Cmds[i] is CommentCmd)
- {
- // ignore
- }
- else
- {
- break; // stop when an assignment statement (or any other non-predicate cmd) is encountered
- }
- }
- #endregion
-
- #region Copy the prefix of predicate commands into each predecessor. Do this *before* cutting the backedge!!
- for (int predIndex = 0, n = header.Predecessors.Count; predIndex < n; predIndex++)
- {
- Block pred = cce.NonNull(header.Predecessors[predIndex]);
-
- // Create a block between header and pred for the predicate commands if pred has more than one successor
- GotoCmd gotocmd = cce.NonNull((GotoCmd)pred.TransferCmd);
- Contract.Assert(gotocmd.labelNames != null); // if "pred" is really a predecessor, it may be a GotoCmd with at least one label
- if (gotocmd.labelNames.Count > 1)
- {
- Block newBlock = CreateBlockBetween(predIndex, header);
- impl.Blocks.Add(newBlock);
-
- // if pred is a back edge node, then now newBlock is the back edge node
- if (backEdgeNodes.ContainsKey(pred))
- {
- backEdgeNodes.Remove(pred);
- backEdgeNodes.Add(newBlock, null);
- }
-
- pred = newBlock;
- }
- // Add the predicate commands
- if (backEdgeNodes.ContainsKey(pred))
- {
- pred.Cmds.AddRange(prefixOfPredicateCmdsMaintained);
- }
- else
- {
- pred.Cmds.AddRange(prefixOfPredicateCmdsInit);
- }
- }
- #endregion
-
- #region Cut the back edge
- foreach (Block backEdgeNode in cce.NonNull(backEdgeNodes.Keys))
- {
- Contract.Assert(backEdgeNode != null);
- Debug.Assert(backEdgeNode.TransferCmd is GotoCmd, "An node was identified as the source for a backedge, but it does not have a goto command.");
- GotoCmd gtc = backEdgeNode.TransferCmd as GotoCmd;
- if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count > 1)
- {
- // then remove the backedge by removing the target block from the list of gotos
- List<Block> remainingTargets = new List<Block>();
- List<String> remainingLabels = new List<String>();
- Contract.Assume(gtc.labelNames != null);
- for (int i = 0, n = gtc.labelTargets.Count; i < n; i++)
- {
- if (gtc.labelTargets[i] != header)
- {
- remainingTargets.Add(gtc.labelTargets[i]);
- remainingLabels.Add(gtc.labelNames[i]);
- }
- else
- RecordCutEdge(edgesCut, backEdgeNode, header);
- }
- gtc.labelTargets = remainingTargets;
- gtc.labelNames = remainingLabels;
- }
- else
- {
- // This backedge is the only out-going edge from this node.
- // Add an "assume false" statement to the end of the statements
- // inside of the block and change the goto command to a return command.
- AssumeCmd ac = new AssumeCmd(Token.NoToken, Expr.False);
- backEdgeNode.Cmds.Add(ac);
- backEdgeNode.TransferCmd = new ReturnCmd(Token.NoToken);
- if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count == 1)
- RecordCutEdge(edgesCut, backEdgeNode, gtc.labelTargets[0]);
- }
- #region Remove the backedge node from the list of predecessor nodes in the header
- List<Block> newPreds = new List<Block>();
- foreach (Block p in header.Predecessors)
- {
- if (p != backEdgeNode)
- newPreds.Add(p);
- }
- header.Predecessors = newPreds;
- #endregion
- }
- #endregion
-
- #region Collect all variables that are assigned to in all of the natural loops for which this is the header
- List<Variable> varsToHavoc = VarsAssignedInLoop(g, header);
- List<IdentifierExpr> havocExprs = new List<IdentifierExpr>();
- foreach (Variable v in varsToHavoc)
- {
- Contract.Assert(v != null);
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v);
- if (!havocExprs.Contains(ie))
- havocExprs.Add(ie);
- }
- // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct
- // the source location for this later on
- HavocCmd hc = new HavocCmd(header.tok, havocExprs);
- List<Cmd> newCmds = new List<Cmd>();
- newCmds.Add(hc);
- foreach (Cmd c in header.Cmds)
- {
- newCmds.Add(c);
- }
- header.Cmds = newCmds;
- #endregion
- }
- #endregion
- #endregion Convert program CFG into a DAG
- }
-
- public static List<Variable> VarsAssignedInLoop(Graph<Block> g, Block header)
- {
- List<Variable> varsToHavoc = new List<Variable>();
- foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(backEdgeNode != null);
- foreach (Block b in g.NaturalLoops(header, backEdgeNode))
- {
- Contract.Assert(b != null);
- foreach (Cmd c in b.Cmds)
- {
- Contract.Assert(c != null);
- c.AddAssignedVariables(varsToHavoc);
- }
- }
- }
- return varsToHavoc;
- }
-
- public static IEnumerable<Variable> VarsReferencedInLoop(Graph<Block> g, Block header)
- {
- HashSet<Variable> referencedVars = new HashSet<Variable>();
- foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(backEdgeNode != null);
- foreach (Block b in g.NaturalLoops(header, backEdgeNode))
- {
- Contract.Assert(b != null);
- foreach (Cmd c in b.Cmds)
- {
- Contract.Assert(c != null);
- var Collector = new VariableCollector();
- Collector.Visit(c);
- foreach(var v in Collector.usedVars) {
- referencedVars.Add(v);
- }
- }
- }
- }
- return referencedVars;
- }
-
- private void ConvertCFG2DAGKInduction(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID) {
-
- // K-induction has not been adapted to be aware of these parameters which standard CFG to DAG transformation uses
- Contract.Requires(edgesCut == null);
- Contract.Requires(taskID == -1);
-
- int inductionK = CommandLineOptions.Clo.KInductionDepth;
- Contract.Assume(inductionK >= 0);
-
- bool contRuleApplication = true;
- while (contRuleApplication) {
- contRuleApplication = false;
-
- #region Use the graph library to figure out where the (natural) loops are
-
- #region Create the graph by adding the source node and each edge
- Graph<Block> g = Program.GraphFromImpl(impl);
- #endregion
-
- g.ComputeLoops(); // this is the call that does all of the processing
- if (!g.Reducible) {
- throw new VCGenException("Irreducible flow graphs are unsupported.");
- }
-
- #endregion
-
- foreach (Block header in cce.NonNull(g.Headers)) {
- Contract.Assert(header != null);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("Applying k-induction rule with k=" + inductionK);
- }
- #endregion
-
- #region generate the step case
- Block newHeader = DuplicateLoop(impl, g, header, null,
- false, false, "_step_assertion");
- for (int i = 0; i < inductionK; ++i)
- {
- newHeader = DuplicateLoop(impl, g, header, newHeader,
- true, true,
- "_step_" + (inductionK - i));
- }
- #endregion
-
- #region havoc variables that can be assigned in the loop
-
- List<Variable> varsToHavoc = VarsAssignedInLoop(g, header);
- List<IdentifierExpr> havocExprs = new List<IdentifierExpr>();
- foreach (Variable v in varsToHavoc)
- {
- Contract.Assert(v != null);
- IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v);
- if (!havocExprs.Contains(ie))
- havocExprs.Add(ie);
- }
- // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct
- // the source location for this later on
- HavocCmd hc = new HavocCmd(newHeader.tok, havocExprs);
- List<Cmd> havocCmds = new List<Cmd>();
- havocCmds.Add(hc);
-
- Block havocBlock = new Block(newHeader.tok, newHeader.Label + "_havoc", havocCmds,
- new GotoCmd (newHeader.tok, new List<Block> { newHeader }));
-
- impl.Blocks.Add(havocBlock);
- newHeader.Predecessors.Add(havocBlock);
- newHeader = havocBlock;
-
- #endregion
-
- #region generate the base case loop copies
- for (int i = 0; i < inductionK; ++i)
- {
- newHeader = DuplicateLoop(impl, g, header, newHeader,
- false, false,
- "_base_" + (inductionK - i));
- }
- #endregion
-
- #region redirect into the new loop copies and remove the original loop (but don't redirect back-edges)
-
- IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>();
- foreach (Block b in cce.NonNull(g.BackEdgeNodes(header))) { Contract.Assert(b != null); backEdgeNodes.Add(b, null); }
-
- for (int predIndex = 0, n = header.Predecessors.Count(); predIndex < n; predIndex++)
- {
- Block pred = cce.NonNull(header.Predecessors[predIndex]);
- if (!backEdgeNodes.ContainsKey(pred))
- {
- GotoCmd gc = pred.TransferCmd as GotoCmd;
- Contract.Assert(gc != null);
- for (int i = 0; i < gc.labelTargets.Count(); ++i)
- {
- if (gc.labelTargets[i] == header)
- {
- gc.labelTargets[i] = newHeader;
- gc.labelNames[i] = newHeader.Label;
- newHeader.Predecessors.Add(pred);
- }
- }
- }
- }
- impl.PruneUnreachableBlocks();
-
- #endregion
-
- contRuleApplication = true;
- break;
- }
-
- }
-
- ResetPredecessors(impl.Blocks);
- impl.FreshenCaptureStates();
-
- }
-
- private Block DuplicateLoop(Implementation impl, Graph<Block> g,
- Block header, Block nextHeader, bool cutExits,
- bool toAssumptions, string suffix)
- {
- IDictionary<Block, Block> ori2CopiedBlocks = new Dictionary<Block, Block>();
- Duplicator duplicator = new Duplicator();
-
- #region create copies of all blocks in the loop
- foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header)))
- {
- Contract.Assert(backEdgeNode != null);
- foreach (Block b in g.NaturalLoops(header, backEdgeNode))
- {
- Contract.Assert(b != null);
- if (!ori2CopiedBlocks.ContainsKey(b))
- {
- Block copy = (Block)duplicator.Visit(b);
- copy.Cmds = new List<Cmd>(copy.Cmds); // Philipp Ruemmer commented that this was necessary due to a bug in the Duplicator. That was a long time; worth checking whether this has been fixed
- copy.Predecessors = new List<Block>();
- copy.Label = copy.Label + suffix;
-
- #region turn asserts into assumptions
- if (toAssumptions)
- {
- for (int i = 0; i < copy.Cmds.Count(); ++i)
- {
- AssertCmd ac = copy.Cmds[i] as AssertCmd;
- if (ac != null)
- {
- copy.Cmds[i] = new AssumeCmd(ac.tok, ac.Expr);
- }
- }
- }
- #endregion
-
- impl.Blocks.Add(copy);
- ori2CopiedBlocks.Add(b, copy);
- }
- }
- }
- #endregion
-
- #region adjust the transfer commands of the newly created blocks
- foreach (KeyValuePair<Block, Block> pair in ori2CopiedBlocks)
- {
- Block copy = pair.Value;
- GotoCmd gc = copy.TransferCmd as GotoCmd;
- if (gc != null)
- {
- List<Block> newTargets = new List<Block>();
- List<string> newLabels = new List<string>();
-
- for (int i = 0; i < gc.labelTargets.Count(); ++i)
- {
- Block newTarget;
- if (gc.labelTargets[i] == header)
- {
- if (nextHeader != null)
- {
- newTargets.Add(nextHeader);
- newLabels.Add(nextHeader.Label);
- nextHeader.Predecessors.Add(copy);
- }
- }
- else if (ori2CopiedBlocks.TryGetValue(gc.labelTargets[i], out newTarget))
- {
- newTargets.Add(newTarget);
- newLabels.Add(newTarget.Label);
- newTarget.Predecessors.Add(copy);
- }
- else if (!cutExits)
- {
- newTargets.Add(gc.labelTargets[i]);
- newLabels.Add(gc.labelNames[i]);
- gc.labelTargets[i].Predecessors.Add(copy);
- }
- }
-
- if (newTargets.Count() == 0)
- {
- // if no targets are left, we assume false and return
- copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
- copy.TransferCmd = new ReturnCmd(Token.NoToken);
- }
- else
- {
- copy.TransferCmd = new GotoCmd(gc.tok, newLabels, newTargets);
- }
- }
- else if (cutExits && (copy.TransferCmd is ReturnCmd))
- {
- // because return is a kind of exit from the loop, we
- // assume false to cut this path
- copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False));
- }
- }
- #endregion
-
- return ori2CopiedBlocks[header];
- }
-
- public void DesugarCalls(Implementation impl) {
- foreach (Block block in impl.Blocks) {
- List<Cmd> newCmds = new List<Cmd>();
- foreach (Cmd cmd in block.Cmds) {
- SugaredCmd sugaredCmd = cmd as SugaredCmd;
- if (sugaredCmd != null) {
- StateCmd stateCmd = sugaredCmd.Desugaring as StateCmd;
- foreach (Variable v in stateCmd.Locals) {
- impl.LocVars.Add(v);
- }
- newCmds.AddRange(stateCmd.Cmds);
- }
- else {
- newCmds.Add(cmd);
- }
- }
- block.Cmds = newCmds;
- }
- }
-
- public Dictionary<TransferCmd, ReturnCmd> PassifyImpl(Implementation impl, out ModelViewInfo mvInfo)
- {
- Contract.Requires(impl != null);
- Contract.Requires(program != null);
- Contract.Ensures(Contract.Result<Dictionary<TransferCmd, ReturnCmd>>() != null);
-
- Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>();
- Block exitBlock = GenerateUnifiedExit(impl, gotoCmdOrigins);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after creating a unified exit block");
- EmitImpl(impl, true);
- }
- #endregion
-
- #region Insert pre- and post-conditions and where clauses as assume and assert statements
- {
- List<Cmd> cc = new List<Cmd>();
- // where clauses of global variables
- lock (program.TopLevelDeclarations)
- {
- foreach (var gvar in program.GlobalVariables)
- {
- if (gvar != null && gvar.TypedIdent.WhereExpr != null)
- {
- Cmd c = new AssumeCmd(gvar.tok, gvar.TypedIdent.WhereExpr);
- cc.Add(c);
- }
- }
- }
- // where clauses of in- and out-parameters
- cc.AddRange(GetParamWhereClauses(impl));
- // where clauses of local variables
- foreach (Variable lvar in impl.LocVars) {Contract.Assert(lvar != null);
- if (lvar.TypedIdent.WhereExpr != null) {
- Cmd c = new AssumeCmd(lvar.tok, lvar.TypedIdent.WhereExpr);
- cc.Add(c);
- } else if (QKeyValue.FindBoolAttribute(lvar.Attributes, "assumption")) {
- cc.Add(new AssumeCmd(lvar.tok, new IdentifierExpr(lvar.tok, lvar), new QKeyValue(lvar.tok, "assumption_variable_initialization", new List<object>(), null)));
- }
- }
- // add cc and the preconditions to new blocks preceding impl.Blocks[0]
- InjectPreconditions(impl, cc);
-
- // append postconditions, starting in exitBlock and continuing into other blocks, if needed
- InjectPostConditions(impl, exitBlock, gotoCmdOrigins);
- }
- #endregion
-
- #region Support for stratified inlining
- addExitAssert(impl.Name, exitBlock);
- #endregion
-
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after inserting pre- and post-conditions");
- EmitImpl(impl, true);
- }
- #endregion
-
- AddBlocksBetween(impl.Blocks);
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after adding empty blocks as needed to catch join assumptions");
- EmitImpl(impl, true);
- }
- #endregion
-
- if (CommandLineOptions.Clo.LiveVariableAnalysis > 0) {
- Microsoft.Boogie.LiveVariableAnalysis.ComputeLiveVariables(impl);
- }
-
- mvInfo = new ModelViewInfo(program, impl);
- Convert2PassiveCmd(impl, mvInfo);
-
- #region Peep-hole optimizations
- if (CommandLineOptions.Clo.RemoveEmptyBlocks){
- #region Get rid of empty blocks
- {
- RemoveEmptyBlocksIterative(impl.Blocks);
- impl.PruneUnreachableBlocks();
- }
- #endregion Get rid of empty blocks
-
- #region Debug Tracing
- if (CommandLineOptions.Clo.TraceVerify)
- {
- Console.WriteLine("after peep-hole optimizations");
- EmitImpl(impl, true);
- }
- #endregion
- }
- #endregion Peep-hole optimizations
-
- HandleSelectiveChecking(impl);
-
-
-// #region Constant Folding
-// #endregion
-// #region Debug Tracing
-// if (CommandLineOptions.Clo.TraceVerify)
-// {
-// Console.WriteLine("after constant folding");
-// EmitImpl(impl, true);
-// }
-// #endregion
-
- return gotoCmdOrigins;
- }
-
- private static void HandleSelectiveChecking(Implementation impl)
- {
- if (QKeyValue.FindBoolAttribute(impl.Attributes, "selective_checking") ||
- QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "selective_checking")) {
-
- var startPoints = new List<Block>();
- foreach (var b in impl.Blocks) {
- foreach (Cmd c in b.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here")) {
- startPoints.Add(b);
- break;
- }
- }
- }
-
- // Compute the set of blocks reachable from blocks containing "start_checking_here"
- var blocksToCheck = new HashSet<Block>();
- foreach (var b in startPoints) {
- var todo = new Stack<Block>();
- var wasThere = blocksToCheck.Contains(b);
- todo.Push(b);
- while (todo.Count > 0) {
- var x = todo.Pop();
- if (blocksToCheck.Contains(x)) continue;
- blocksToCheck.Add(x);
- var ex = x.TransferCmd as GotoCmd;
- if (ex != null)
- foreach (Block e in ex.labelTargets)
- todo.Push(e);
- }
- if (!wasThere) blocksToCheck.Remove(b);
- }
-
- // Convert asserts to assumes in "unreachable" blocks, as well as in portions of blocks before we reach "start_checking_here"
- foreach (var b in impl.Blocks) {
- if (blocksToCheck.Contains(b)) continue; // All reachable blocks must be checked in their entirety, so don't change anything
- var newCmds = new List<Cmd>();
- var copyMode = false;
- foreach (Cmd c in b.Cmds) {
- var p = c as PredicateCmd;
- if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here"))
- copyMode = true;
- var asrt = c as AssertCmd;
- if (copyMode || asrt == null)
- newCmds.Add(c);
- else
- newCmds.Add(AssertTurnedIntoAssume(asrt));
- }
-
- b.Cmds = newCmds;
- }
- }
- }
-
- // Used by stratified inlining
- protected virtual void addExitAssert(string implName, Block exitBlock)
- {
- }
-
- public virtual Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- // Construct the set of inlined procs in the original program
- var inlinedProcs = new HashSet<string>();
- foreach (var proc in program.Procedures)
- {
- if (!(proc is LoopProcedure))
- {
- inlinedProcs.Add(proc.Name);
- }
- }
-
- return extractLoopTraceRec(
- new CalleeCounterexampleInfo(cex, new List<object>()),
- mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample;
- }
-
- protected CalleeCounterexampleInfo extractLoopTraceRec(
- CalleeCounterexampleInfo cexInfo, string currProc,
- HashSet<string> inlinedProcs,
- Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- Contract.Requires(currProc != null);
- if (cexInfo.counterexample == null) return cexInfo;
-
- var cex = cexInfo.counterexample;
- // Go through all blocks in the trace, map them back to blocks in the original program (if there is one)
- var ret = cex.Clone();
- ret.Trace = new List<Block>();
- ret.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>();
-
- for (int numBlock = 0; numBlock < cex.Trace.Count; numBlock ++ )
- {
- Block block = cex.Trace[numBlock];
- var origBlock = elGetBlock(currProc, block, extractLoopMappingInfo);
- if (origBlock != null) ret.Trace.Add(origBlock);
- var callCnt = 1;
- for (int numInstr = 0; numInstr < block.Cmds.Count; numInstr ++) {
- Cmd cmd = block.Cmds[numInstr];
- var loc = new TraceLocation(numBlock, numInstr);
- if (!cex.calleeCounterexamples.ContainsKey(loc))
- {
- if (getCallee(cex.getTraceCmd(loc), inlinedProcs) != null) callCnt++;
- continue;
- }
- string callee = cex.getCalledProcName(cex.getTraceCmd(loc));
- Contract.Assert(callee != null);
- var calleeTrace = cex.calleeCounterexamples[loc];
- Debug.Assert(calleeTrace != null);
-
- var origTrace = extractLoopTraceRec(calleeTrace, callee, inlinedProcs, extractLoopMappingInfo);
-
- if (elIsLoop(callee))
- {
- // Absorb the trace into the current trace
-
- int currLen = ret.Trace.Count;
- ret.Trace.AddRange(origTrace.counterexample.Trace);
-
- foreach (var kvp in origTrace.counterexample.calleeCounterexamples)
- {
- var newloc = new TraceLocation(kvp.Key.numBlock + currLen, kvp.Key.numInstr);
- ret.calleeCounterexamples.Add(newloc, kvp.Value);
- }
-
- }
- else
- {
- var origLoc = new TraceLocation(ret.Trace.Count - 1, getCallCmdPosition(origBlock, callCnt, inlinedProcs, callee));
- ret.calleeCounterexamples.Add(origLoc, origTrace);
- callCnt++;
- }
- }
- }
- return new CalleeCounterexampleInfo(ret, cexInfo.args);
- }
-
- // return the position of the i^th CallCmd in the block (count only those Calls that call a procedure in inlinedProcs).
- // Assert failure if there isn't any.
- // Assert that the CallCmd found calls "callee"
- private int getCallCmdPosition(Block block, int i, HashSet<string> inlinedProcs, string callee)
- {
- Debug.Assert(i >= 1);
- for (int pos = 0; pos < block.Cmds.Count; pos++)
- {
- Cmd cmd = block.Cmds[pos];
- string procCalled = getCallee(cmd, inlinedProcs);
-
- if (procCalled != null)
- {
- if (i == 1)
- {
- Debug.Assert(procCalled == callee);
- return pos;
- }
- i--;
- }
- }
-
- Debug.Assert(false, "Didn't find the i^th call cmd");
- return -1;
- }
-
- private string getCallee(Cmd cmd, HashSet<string> inlinedProcs)
- {
- string procCalled = null;
- if (cmd is CallCmd)
- {
- var cc = (CallCmd)cmd;
- if (inlinedProcs.Contains(cc.Proc.Name))
- {
- procCalled = cc.Proc.Name;
- }
- }
-
- if (cmd is AssumeCmd)
- {
- var expr = (cmd as AssumeCmd).Expr as NAryExpr;
- if (expr != null)
- {
- if (inlinedProcs.Contains(expr.Fun.FunctionName))
- {
- procCalled = expr.Fun.FunctionName;
- }
- }
- }
- return procCalled;
- }
-
- protected virtual bool elIsLoop(string procname)
- {
- return false;
- }
-
- private Block elGetBlock(string procname, Block block, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo)
- {
- Contract.Requires(procname != null);
-
- if (!extractLoopMappingInfo.ContainsKey(procname))
- return block;
-
- if (!extractLoopMappingInfo[procname].ContainsKey(block.Label))
- return null;
-
- return extractLoopMappingInfo[procname][block.Label];
- }
-
- static Counterexample TraceCounterexample(
- Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace, Model errModel, ModelViewInfo mvInfo,
- Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap,
- ProverContext/*!*/ context,
- Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples)
- {
- Contract.Requires(b != null);
- Contract.Requires(traceNodes != null);
- Contract.Requires(trace != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap));
- Contract.Requires(context != null);
- Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples));
- // After translation, all potential errors come from asserts.
-
- while (true)
- {
- List<Cmd> cmds = b.Cmds;
- Contract.Assert(cmds != null);
- TransferCmd transferCmd = cce.NonNull(b.TransferCmd);
- for (int i = 0; i < cmds.Count; i++)
- {
- Cmd cmd = cce.NonNull(cmds[i]);
-
- // Skip if 'cmd' not contained in the trace or not an assert
- if (cmd is AssertCmd && traceNodes.Contains(cmd))
- {
- Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context);
- Contract.Assert(newCounterexample != null);
- newCounterexample.AddCalleeCounterexample(calleeCounterexamples);
- return newCounterexample;
- }
- }
-
- GotoCmd gotoCmd = transferCmd as GotoCmd;
- if (gotoCmd == null) return null;
- Block foundBlock = null;
- foreach (Block bb in cce.NonNull(gotoCmd.labelTargets))
- {
- Contract.Assert(bb != null);
- if (traceNodes.Contains(bb))
- {
- foundBlock = bb;
- break;
- }
- }
- if (foundBlock == null) return null;
- trace.Add(foundBlock);
- b = foundBlock;
- }
- }
-
- public static Counterexample AssertCmdToCounterexample(AssertCmd cmd, TransferCmd transferCmd, List<Block> trace, Model errModel, ModelViewInfo mvInfo, ProverContext context)
- {
- Contract.Requires(cmd != null);
- Contract.Requires(transferCmd != null);
- Contract.Requires(trace != null);
- Contract.Requires(context != null);
- Contract.Ensures(Contract.Result<Counterexample>() != null);
-
- List<string> relatedInformation = new List<string>();
-
- // See if it is a special assert inserted in translation
- if (cmd is AssertRequiresCmd)
- {
- AssertRequiresCmd assertCmd = (AssertRequiresCmd)cmd;
- Contract.Assert(assertCmd != null);
- CallCounterexample cc = new CallCounterexample(trace, assertCmd.Call, assertCmd.Requires, errModel, mvInfo, context, assertCmd.Checksum);
- cc.relatedInformation = relatedInformation;
- return cc;
- }
- else if (cmd is AssertEnsuresCmd)
- {
- AssertEnsuresCmd assertCmd = (AssertEnsuresCmd)cmd;
- Contract.Assert(assertCmd != null);
- ReturnCounterexample rc = new ReturnCounterexample(trace, transferCmd, assertCmd.Ensures, errModel, mvInfo, context, cmd.Checksum);
- rc.relatedInformation = relatedInformation;
- return rc;
- }
- else
- {
- AssertCounterexample ac = new AssertCounterexample(trace, (AssertCmd)cmd, errModel, mvInfo, context);
- ac.relatedInformation = relatedInformation;
- return ac;
- }
- }
-
- /// <summary>
- /// Returns a clone of "cex", but with the location stored in "cex" replaced by those from "assrt".
- /// </summary>
- public static Counterexample AssertCmdToCloneCounterexample(AssertCmd assrt, Counterexample cex) {
- Contract.Requires(assrt != null);
- Contract.Requires(cex != null);
- Contract.Ensures(Contract.Result<Counterexample>() != null);
-
- List<string> relatedInformation = new List<string>();
-
- Counterexample cc;
- if (assrt is AssertRequiresCmd) {
- var aa = (AssertRequiresCmd)assrt;
- cc = new CallCounterexample(cex.Trace, aa.Call, aa.Requires, cex.Model, cex.MvInfo, cex.Context, aa.Checksum);
- } else if (assrt is AssertEnsuresCmd && cex is ReturnCounterexample) {
- var aa = (AssertEnsuresCmd)assrt;
- var oldCex = (ReturnCounterexample)cex;
- cc = new ReturnCounterexample(cex.Trace, oldCex.FailingReturn, aa.Ensures, cex.Model, cex.MvInfo, cex.Context, aa.Checksum);
- } else {
- cc = new AssertCounterexample(cex.Trace, assrt, cex.Model, cex.MvInfo, cex.Context);
- }
- cc.relatedInformation = relatedInformation;
- return cc;
- }
-
- static VCExpr LetVC(Block startBlock,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- ProverContext proverCtxt,
- out int assertionCount) {
- Contract.Requires(startBlock != null);
- Contract.Requires(proverCtxt != null);
-
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/();
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- VCExpr startCorrect = LetVC(startBlock, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out assertionCount);
- return proverCtxt.ExprGen.Let(bindings, startCorrect);
- }
-
- static VCExpr LetVCIterative(List<Block> blocks,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- ProverContext proverCtxt,
- out int assertionCount,
- bool isPositiveContext = true)
- {
- Contract.Requires(blocks != null);
- Contract.Requires(proverCtxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- assertionCount = 0;
-
- Graph<Block> dag = new Graph<Block>();
- dag.AddSource(blocks[0]);
- 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(dest, b);
- }
- }
- }
- IEnumerable sortedNodes = dag.TopologicalSort();
- Contract.Assert(sortedNodes != null);
-
- Dictionary<Block, VCExprVar> blockVariables = new Dictionary<Block, VCExprVar>();
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- foreach (Block block in sortedNodes) {
- VCExpr SuccCorrect;
- GotoCmd gotocmd = block.TransferCmd as GotoCmd;
- if (gotocmd == null) {
- ReturnExprCmd re = block.TransferCmd as ReturnExprCmd;
- if (re == null) {
- SuccCorrect = VCExpressionGenerator.True;
- }
- else {
- SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr);
- if (isPositiveContext)
- {
- SuccCorrect = gen.Not(SuccCorrect);
- }
- }
- }
- else {
- Contract.Assert(gotocmd.labelTargets != null);
- List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count);
- foreach (Block successor in gotocmd.labelTargets) {
- Contract.Assert(successor != null);
- VCExpr s = blockVariables[successor];
- if (controlFlowVariableExpr != null) {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
- s = gen.Implies(controlTransferExpr, s);
- }
- SuccCorrectVars.Add(s);
- }
- SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars);
- }
-
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr, isPositiveContext);
- VCExpr vc = Wlp.Block(block, SuccCorrect, context);
- assertionCount += context.AssertionCount;
-
- VCExprVar v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool);
- bindings.Add(gen.LetBinding(v, vc));
- blockVariables.Add(block, v);
- }
-
- return proverCtxt.ExprGen.Let(bindings, blockVariables[blocks[0]]);
- }
-
- static VCExpr LetVC(Block block,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- Hashtable/*<Block, VCExprVar!>*/ blockVariables,
- List<VCExprLetBinding/*!*/>/*!*/ bindings,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(block != null);
- Contract.Requires(blockVariables!= null);
- Contract.Requires(cce.NonNullElements(bindings));
- Contract.Requires(proverCtxt != null);
-
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- assertionCount = 0;
-
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- VCExprVar v = (VCExprVar)blockVariables[block];
- if (v == null) {
- /*
- * For block A (= block), generate:
- * LET_binding A_correct = wp(A_body, (/\ S \in Successors(A) :: S_correct))
- * with the side effect of adding the let bindings to "bindings" for any
- * successor not yet visited.
- */
- VCExpr SuccCorrect;
- GotoCmd gotocmd = block.TransferCmd as GotoCmd;
- if (gotocmd == null) {
- ReturnExprCmd re = block.TransferCmd as ReturnExprCmd;
- if (re == null) {
- SuccCorrect = VCExpressionGenerator.True;
- } else {
- SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr);
- }
- } else {
- Contract.Assert( gotocmd.labelTargets != null);
- List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count);
- foreach (Block successor in gotocmd.labelTargets) {
- Contract.Assert(successor != null);
- int ac;
- VCExpr s = LetVC(successor, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out ac);
- assertionCount += ac;
- if (controlFlowVariableExpr != null)
- {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
- s = gen.Implies(controlTransferExpr, s);
- }
- SuccCorrectVars.Add(s);
- }
- SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars);
- }
-
-
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
- VCExpr vc = Wlp.Block(block, SuccCorrect, context);
- assertionCount += context.AssertionCount;
-
- v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool);
- bindings.Add(gen.LetBinding(v, vc));
- blockVariables.Add(block, v);
- }
- return v;
- }
-
- static VCExpr DagVC(Block block,
- VCExpr controlFlowVariableExpr,
- Dictionary<int, Absy> label2absy,
- Hashtable/*<Block, VCExpr!>*/ blockEquations,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(block != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(blockEquations != null);
- Contract.Requires(proverCtxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- assertionCount = 0;
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- VCExpr vc = (VCExpr)blockEquations[block];
- if (vc != null) {
- return vc;
- }
-
- /*
- * For block A (= block), generate:
- * wp(A_body, (/\ S \in Successors(A) :: DagVC(S)))
- */
- VCExpr SuccCorrect = null;
- GotoCmd gotocmd = block.TransferCmd as GotoCmd;
- if (gotocmd != null)
- {
- foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
- Contract.Assert(successor != null);
- int ac;
- VCExpr c = DagVC(successor, controlFlowVariableExpr, label2absy, blockEquations, proverCtxt, out ac);
- assertionCount += ac;
- if (controlFlowVariableExpr != null) {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId)));
- VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId)));
- c = gen.Implies(controlTransferExpr, c);
- }
- SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c);
- }
- }
- if (SuccCorrect == null) {
- SuccCorrect = VCExpressionGenerator.True;
- }
-
- VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr);
- vc = Wlp.Block(block, SuccCorrect, context);
- assertionCount += context.AssertionCount;
-
- // gen.MarkAsSharedFormula(vc); PR: don't know yet what to do with this guy
-
- blockEquations.Add(block, vc);
- return vc;
- }
-
- static VCExpr FlatBlockVC(Implementation impl,
- Dictionary<int, Absy> label2absy,
- bool local, bool reach, bool doomed,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(impl != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(proverCtxt != null);
- Contract.Requires( !local || !reach); // "reach" must be false for local
-
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen);
- Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null;
-
- List<Block> blocks = impl.Blocks;
- Contract.Assert(blocks != null);
- // block sorting is now done on the VCExpr
- // if (!local && (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) {
- // blocks = SortBlocks(blocks);
- // }
-
- VCExpr proofObligation;
- if (!local) {
- proofObligation = cce.NonNull((VCExprVar)BlkCorrect[impl.Blocks[0]]);
- } else {
- List<VCExpr> conjuncts = new List<VCExpr>(blocks.Count);
- foreach (Block b in blocks) {Contract.Assert(b != null);
- VCExpr v = cce.NonNull((VCExprVar)BlkCorrect[b]);
- conjuncts.Add(v);
- }
- proofObligation = gen.NAry(VCExpressionGenerator.AndOp, conjuncts);
- }
-
- VCContext context = new VCContext(label2absy, proverCtxt);
- Contract.Assert(context != null);
-
- List<VCExprLetBinding> programSemantics = new List<VCExprLetBinding>(blocks.Count);
- foreach (Block b in blocks) {Contract.Assert(b != null);
- /*
- * In block mode,
- * For a return block A, generate:
- * A_correct <== wp(A_body, true) [post-condition has been translated into an assert]
- * For all other blocks, generate:
- * A_correct <== wp(A_body, (/\ S \in Successors(A) :: S_correct))
- *
- * In doomed mode, proceed as in block mode, except for a return block A, generate:
- * A_correct <== wp(A_body, false) [post-condition has been translated into an assert]
- *
- * In block reach mode, the wp(A_body,...) in the equations above change to:
- * A_reached ==> wp(A_body,...)
- * and the conjunction above changes to:
- * (/\ S \in Successors(A) :: S_correct \/ (\/ T \in Successors(A) && T != S :: T_reached))
- *
- * In local mode, generate:
- * A_correct <== wp(A_body, true)
- */
- VCExpr SuccCorrect;
- if (local) {
- SuccCorrect = VCExpressionGenerator.True;
- } else {
- SuccCorrect = SuccessorsCorrect(b, BlkCorrect, BlkReached, doomed, gen);
- }
-
- VCExpr wlp = Wlp.Block(b, SuccCorrect, context);
- if (BlkReached != null) {
- wlp = gen.Implies(cce.NonNull((VCExprVar)BlkReached[b]), wlp);
- }
-
- VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]);
- VCExprLetBinding binding = gen.LetBinding(okVar, wlp);
- programSemantics.Add(binding);
- }
-
- assertionCount = context.AssertionCount;
- return gen.Let(programSemantics, proofObligation);
- }
-
- private static Hashtable/* Block --> VCExprVar */ BlockVariableMap(List<Block/*!*/>/*!*/ blocks, string suffix,
- Microsoft.Boogie.VCExpressionGenerator gen) {
- Contract.Requires(cce.NonNullElements(blocks));
- Contract.Requires(suffix != null);
- Contract.Requires(gen != null);
- Contract.Ensures(Contract.Result<Hashtable>() != null);
-
- Hashtable/* Block --> VCExprVar */ map = new Hashtable/* Block --> (Let)Variable */();
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- VCExprVar v = gen.Variable(b.Label + suffix, Bpl.Type.Bool);
- Contract.Assert(v != null);
- map.Add(b, v);
- }
- return map;
- }
-
- private static VCExpr SuccessorsCorrect(
- Block b,
- Hashtable/* Block --> VCExprVar */ BlkCorrect,
- Hashtable/* Block --> VCExprVar */ BlkReached,
- bool doomed,
- Microsoft.Boogie.VCExpressionGenerator gen) {
- Contract.Requires(b != null);
- Contract.Requires(BlkCorrect != null);
- Contract.Requires(gen != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpr SuccCorrect = null;
- GotoCmd gotocmd = b.TransferCmd as GotoCmd;
- if (gotocmd != null) {
- foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) {
- Contract.Assert(successor != null);
- // c := S_correct
- VCExpr c = (VCExprVar)BlkCorrect[successor];
- Contract.Assert(c != null);
- if (BlkReached != null) {
- // c := S_correct \/ Sibling0_reached \/ Sibling1_reached \/ ...;
- foreach (Block successorSibling in gotocmd.labelTargets) {
- Contract.Assert(successorSibling != null);
- if (successorSibling != successor) {
- c = gen.Or(c, cce.NonNull((VCExprVar)BlkReached[successorSibling]));
- }
- }
- }
- SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c);
- }
- }
- if (SuccCorrect == null) {
- return VCExpressionGenerator.True;
- } else if (doomed) {
- return VCExpressionGenerator.False;
- } else {
- return SuccCorrect;
- }
- }
-
- static VCExpr NestedBlockVC(Implementation impl,
- Dictionary<int, Absy> label2absy,
- bool reach,
- ProverContext proverCtxt,
- out int assertionCount){
- Contract.Requires(impl != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(proverCtxt != null);
- Contract.Requires( impl.Blocks.Count != 0);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpressionGenerator gen = proverCtxt.ExprGen;
- Contract.Assert(gen != null);
- Graph<Block> g = Program.GraphFromImpl(impl);
-
- Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen);
- Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null;
-
- Block startBlock = cce.NonNull( impl.Blocks[0]);
- VCExpr proofObligation = (VCExprVar)BlkCorrect[startBlock];
- Contract.Assert(proofObligation != null);
- VCContext context = new VCContext(label2absy, proverCtxt);
-
- Hashtable/*Block->int*/ totalOrder = new Hashtable/*Block->int*/();
- {
- List<Block> blocks = impl.Blocks;
-
- // block sorting is now done on the VCExpr
- // if (((!)CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) {
- // blocks = SortBlocks(blocks);
- // }
- int i = 0;
- foreach (Block b in blocks) {
- Contract.Assert(b != null);
- totalOrder[b] = i;
- i++;
- }
- }
-
- VCExprLetBinding programSemantics = NestedBlockEquation(cce.NonNull(impl.Blocks[0]), BlkCorrect, BlkReached, totalOrder, context, g, gen);
- List<VCExprLetBinding> ps = new List<VCExprLetBinding>(1);
- ps.Add(programSemantics);
-
- assertionCount = context.AssertionCount;
- return gen.Let(ps, proofObligation);
- }
-
- private static VCExprLetBinding NestedBlockEquation(Block b,
- Hashtable/*Block-->VCExprVar*/ BlkCorrect,
- Hashtable/*Block-->VCExprVar*/ BlkReached,
- Hashtable/*Block->int*/ totalOrder,
- VCContext context,
- Graph<Block> g,
- Microsoft.Boogie.VCExpressionGenerator gen) {
- Contract.Requires(b != null);
- Contract.Requires(BlkCorrect != null);
- Contract.Requires(totalOrder != null);
- Contract.Requires(g != null);
- Contract.Requires(context != null);
-
- Contract.Ensures(Contract.Result<VCExprLetBinding>() != null);
-
- /*
- * For a block b, return:
- * LET_BINDING b_correct = wp(b_body, X)
- * where X is:
- * LET (THOSE d \in DirectDominates(b) :: BlockEquation(d))
- * IN (/\ s \in Successors(b) :: s_correct)
- *
- * When the VC-expression generator does not support LET expresions, this
- * will eventually turn into:
- * b_correct <== wp(b_body, X)
- * where X is:
- * (/\ s \in Successors(b) :: s_correct)
- * <==
- * (/\ d \in DirectDominatees(b) :: BlockEquation(d))
- *
- * In both cases above, if BlkReached is non-null, then the wp expression
- * is instead:
- * b_reached ==> wp(b_body, X)
- */
-
- VCExpr SuccCorrect = SuccessorsCorrect(b, BlkCorrect, null, false, gen);
- Contract.Assert(SuccCorrect != null);
-
- List<VCExprLetBinding> bindings = new List<VCExprLetBinding>();
- foreach (Block dominee in GetSortedBlocksImmediatelyDominatedBy(g, b, totalOrder)) {
- Contract.Assert(dominee != null);
- VCExprLetBinding c = NestedBlockEquation(dominee, BlkCorrect, BlkReached, totalOrder, context, g, gen);
- bindings.Add(c);
- }
-
- VCExpr X = gen.Let(bindings, SuccCorrect);
- VCExpr wlp = Wlp.Block(b, X, context);
- if (BlkReached != null) {
- wlp = gen.Implies((VCExprVar)BlkReached[b], wlp);
- Contract.Assert(wlp != null);
- }
- VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]);
- return gen.LetBinding(okVar, wlp);
- }
-
- /// <summary>
- /// Returns a list of g.ImmediatelyDominatedBy(b), but in a sorted order, hoping to steer around
- /// the nondeterminism problems we've been seeing by using just this call.
- /// </summary>
- static List<Block/*!*/>/*!*/ GetSortedBlocksImmediatelyDominatedBy(Graph<Block>/*!*/ g, Block/*!*/ b, Hashtable/*Block->int*//*!*/ totalOrder) {
- Contract.Requires(g != null);
- Contract.Requires(b != null);
- Contract.Requires(totalOrder != null);
- Contract.Ensures(Contract.Result<List<Block>>() != null);
-
- List<Block> list = new List<Block>();
- foreach (Block dominee in g.ImmediatelyDominatedBy(b)) {
- Contract.Assert(dominee != null);
- list.Add(dominee);
- }
- list.Sort(new Comparison<Block>(delegate(Block x, Block y) {
- return (int)cce.NonNull(totalOrder[x]) - (int)cce.NonNull(totalOrder[y]);
- }));
- return list;
- }
-
- static VCExpr VCViaStructuredProgram
- (Implementation impl, Dictionary<int, Absy> label2absy,
- ProverContext proverCtxt,
- out int assertionCount)
- {
- Contract.Requires(impl != null);
- Contract.Requires(label2absy != null);
- Contract.Requires(proverCtxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- #region Convert block structure back to a "regular expression"
- RE r = DAG2RE.Transform(cce.NonNull(impl.Blocks[0]));
- Contract.Assert(r != null);
- #endregion
-
- VCContext ctxt = new VCContext(label2absy, proverCtxt);
- Contract.Assert(ctxt != null);
- #region Send wlp(program,true) to Simplify
- var vcexp = Wlp.RegExpr(r, VCExpressionGenerator.True, ctxt);
- assertionCount = ctxt.AssertionCount;
- return vcexp;
- #endregion
- }
-
- /// <summary>
- /// Remove empty blocks reachable from the startBlock of the CFG
- /// </summary>
- static void RemoveEmptyBlocksIterative(List<Block> blocks) {
- // postorder traversal of cfg
- // noting loop heads in [keep] and
- // generating token information in [renameInfo]
- Block startBlock = blocks[0];
- var postorder = new List<Block>();
- var keep = new HashSet<Block>();
- var visited = new HashSet<Block>();
- var grey = new HashSet<Block>();
- var stack = new Stack<Block>();
- Dictionary<Block, Block> renameInfo = new Dictionary<Block, Block>();
-
- stack.Push(startBlock);
- visited.Add(startBlock);
- while (stack.Count != 0) {
- var curr = stack.Pop();
- if (grey.Contains(curr)) {
- postorder.Add(curr);
-
- // generate renameInfoForStartBlock
- GotoCmd gtc = curr.TransferCmd as GotoCmd;
- renameInfo[curr] = null;
- if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) {
- if (curr.Cmds.Count == 0 && curr.tok.IsValid) {
- renameInfo[curr] = curr;
- }
- } else {
- if (curr.Cmds.Count == 0 || curr == startBlock) {
- if (curr.tok.IsValid) {
- renameInfo[curr] = curr;
- } else {
- HashSet<Block> successorRenameInfo = new HashSet<Block>();
- foreach (Block s in gtc.labelTargets) {
- if (keep.Contains(s)) {
- successorRenameInfo.Add(null);
- } else {
- successorRenameInfo.Add(renameInfo[s]);
- }
- }
- if (successorRenameInfo.Count == 1) {
- renameInfo[curr] = successorRenameInfo.Single();
- }
- }
- }
- }
- // end generate renameInfoForStartBlock
-
- } else {
- grey.Add(curr);
- stack.Push(curr);
- GotoCmd gtc = curr.TransferCmd as GotoCmd;
- if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) continue;
- foreach (Block s in gtc.labelTargets) {
- if (!visited.Contains(s)) {
- visited.Add(s);
- stack.Push(s);
- } else if (grey.Contains(s) && !postorder.Contains(s)) { // s is a loop head
- keep.Add(s);
- }
- }
- }
- }
- keep.Add(startBlock);
-
- foreach (Block b in postorder) {
- if (!keep.Contains(b) && b.Cmds.Count == 0) {
- GotoCmd bGtc = b.TransferCmd as GotoCmd;
- foreach (Block p in b.Predecessors) {
- GotoCmd pGtc = p.TransferCmd as GotoCmd;
- Contract.Assert(pGtc != null);
- pGtc.labelTargets.Remove(b);
- pGtc.labelNames.Remove(b.Label);
- }
- if (bGtc == null || bGtc.labelTargets == null || bGtc.labelTargets.Count == 0) {
- continue;
- }
-
- List<Block> successors = bGtc.labelTargets;
-
- // Try to push token information if possible
- if (b.tok.IsValid && successors.Count == 1 && b != renameInfo[startBlock]) {
- var s = successors.Single();
- if (!s.tok.IsValid) {
- foreach (Block p in s.Predecessors) {
- if (p != b) {
- GotoCmd pGtc = p.TransferCmd as GotoCmd;
- Contract.Assert(pGtc != null);
- pGtc.labelTargets.Remove(s);
- pGtc.labelNames.Remove(s.Label);
- pGtc.labelTargets.Add(s);
- pGtc.labelNames.Add(b.Label);
- }
- }
- s.tok = b.tok;
- s.Label = b.Label;
- }
- }
-
- foreach (Block p in b.Predecessors) {
- GotoCmd pGtc = p.TransferCmd as GotoCmd;
- Contract.Assert(pGtc != null);
- foreach (Block s in successors) {
- if (!pGtc.labelTargets.Contains(s)) {
- pGtc.labelTargets.Add(s);
- pGtc.labelNames.Add(s.Label);
- }
- }
- }
- }
- }
-
- if (!startBlock.tok.IsValid && startBlock.Cmds.All(c => c is AssumeCmd)) {
- if (renameInfo[startBlock] != null) {
- startBlock.tok = renameInfo[startBlock].tok;
- startBlock.Label = renameInfo[startBlock].Label;
- }
- }
-
- }
-
- /// <summary>
- /// Remove the empty blocks reachable from the block.
- /// It changes the visiting state of the blocks, so that if you want to visit again the blocks, you have to reset them...
- /// </summary>
- static List<Block> RemoveEmptyBlocks(Block b) {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.Result<List<Block>>() != null);
-
- Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit);
- Block renameInfo;
- List<Block> retVal = removeEmptyBlocksWorker(b, true, out renameInfo);
- if (renameInfo != null && !b.tok.IsValid) {
- bool onlyAssumes = true;
- foreach (Cmd c in b.Cmds) {
- if (!(c is AssumeCmd)) {
- onlyAssumes = false;
- break;
- }
- }
- if (onlyAssumes) {
- b.tok = renameInfo.tok;
- b.Label = renameInfo.Label;
- }
- }
- return retVal;
- }
-
- /// <summary>
- /// For every not-yet-visited block n reachable from b, change n's successors to skip empty nodes.
- /// Return the *set* of blocks reachable from b without passing through a nonempty block.
- /// The target of any backedge is counted as a nonempty block.
- /// If renameInfoForStartBlock is non-null, it denotes an empty block with location information, and that
- /// information would be appropriate to display
- /// </summary>
- private static List<Block> removeEmptyBlocksWorker(Block b, bool startNode, out Block renameInfoForStartBlock)
- {
- Contract.Requires(b != null);
- Contract.Ensures(Contract.ValueAtReturn(out renameInfoForStartBlock) == null || Contract.ValueAtReturn(out renameInfoForStartBlock).tok.IsValid);
- // ensures: b in result ==> renameInfoForStartBlock == null;
-
- renameInfoForStartBlock = null;
- List<Block> bs = new List<Block>();
- GotoCmd gtc = b.TransferCmd as GotoCmd;
-
- // b has no successors
- if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0)
- {
- if (b.Cmds.Count != 0){ // only empty blocks are removed...
- bs.Add(b);
- } else if (b.tok.IsValid) {
- renameInfoForStartBlock = b;
- }
- return bs;
- }
- else if (b.TraversingStatus == Block.VisitState.ToVisit) // if b has some successors and we have not seen it so far...
- {
- b.TraversingStatus = Block.VisitState.BeingVisited;
-
- // Before recursing down to successors, make a sobering observation:
- // If b has no commands and is not the start node, then it will see
- // extinction (because it will not be included in the "return setOfSuccessors"
- // statement below). In that case, if b has a location, then the location
- // information would be lost. Hence, make an attempt to save the location
- // by pushing the location onto b's successor. This can be done if (0) b has
- // exactly one successor, (1) that successor has no location of its own, and
- // (2) that successor has no other predecessors.
- if (b.Cmds.Count == 0 && !startNode) {
- // b is about to become extinct; try to save its name and location, if possible
- if (b.tok.IsValid && gtc.labelTargets.Count == 1) {
- Block succ = cce.NonNull(gtc.labelTargets[0]);
- if (!succ.tok.IsValid && succ.Predecessors.Count == 1) {
- succ.tok = b.tok;
- succ.Label = b.Label;
- }
- }
- }
-
- // recursively call this method on each successor
- // merge result into a *set* of blocks
- HashSet<Block> mergedSuccessors = new HashSet<Block>();
- int m = 0; // in the following loop, set renameInfoForStartBlock to the value that all recursive calls agree on, if possible; otherwise, null
- foreach (Block dest in gtc.labelTargets){Contract.Assert(dest != null);
- Block renameInfo;
- List<Block> ys = removeEmptyBlocksWorker(dest, false, out renameInfo);
- Contract.Assert(ys != null);
- if (m == 0) {
- renameInfoForStartBlock = renameInfo;
- } else if (renameInfoForStartBlock != renameInfo) {
- renameInfoForStartBlock = null;
- }
- foreach (Block successor in ys){
- if (!mergedSuccessors.Contains(successor))
- mergedSuccessors.Add(successor);
- }
- m++;
- }
- b.TraversingStatus = Block.VisitState.AlreadyVisited;
-
- List<Block> setOfSuccessors = new List<Block>();
- foreach (Block d in mergedSuccessors)
- setOfSuccessors.Add(d);
- if (b.Cmds.Count == 0 && !startNode) {
- // b is about to become extinct
- if (b.tok.IsValid) {
- renameInfoForStartBlock = b;
- }
- return setOfSuccessors;
- }
- // otherwise, update the list of successors of b to be the blocks in setOfSuccessors
- gtc.labelTargets = setOfSuccessors;
- gtc.labelNames = new List<String>();
- foreach (Block d in setOfSuccessors){
- Contract.Assert(d != null);
- gtc.labelNames.Add(d.Label);}
- if (!startNode) {
- renameInfoForStartBlock = null;
- }
- return new List<Block> { b };
- }
- else // b has some successors, but we are already visiting it, or we have already visited it...
- {
- return new List<Block> { b };
- }
- }
-
- static void DumpMap(Hashtable /*Variable->Expr*/ map) {
- Contract.Requires(map != null);
- foreach (DictionaryEntry de in map) {
- Variable v = (Variable)de.Key;
- Contract.Assert(v != null);
- Expr e = (Expr)de.Value;
- Contract.Assert(e != null);
- Console.Write(" ");
- v.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0);
- Console.Write(" --> ");
- e.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false));
- Console.WriteLine();
- }
- }
- }
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.IO; +using Microsoft.Boogie; +using Microsoft.Boogie.GraphUtil; +using System.Diagnostics.Contracts; +using Microsoft.Basetypes; +using Microsoft.Boogie.VCExprAST; + +namespace VC { + using Bpl = Microsoft.Boogie; + using System.Threading.Tasks; + + public class VCGen : ConditionGeneration { + private const bool _print_time = false; + /// <summary> + /// Constructor. Initializes the theorem prover. + /// </summary> + [NotDelayed] + public VCGen(Program program, string/*?*/ logFilePath, bool appendLogFile, List<Checker> checkers) + : base(program, checkers) + { + Contract.Requires(program != null); + this.appendLogFile = appendLogFile; + this.logFilePath = logFilePath; + } + + private static AssumeCmd AssertTurnedIntoAssume(AssertCmd assrt) { + Contract.Requires(assrt != null); + Contract.Ensures(Contract.Result<AssumeCmd>() != null); + + Expr expr = assrt.Expr; + Contract.Assert(expr != null); + switch (Wlp.Subsumption(assrt)) { + case CommandLineOptions.SubsumptionOption.Never: + expr = Expr.True; + break; + case CommandLineOptions.SubsumptionOption.Always: + break; + case CommandLineOptions.SubsumptionOption.NotForQuantifiers: + if (expr is QuantifierExpr) { + expr = Expr.True; + } + break; + default: + Contract.Assert(false); + throw new cce.UnreachableException(); // unexpected case + } + + return new AssumeCmd(assrt.tok, expr); + } + + #region Soundness smoke tester + class SmokeTester { + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(parent != null); + Contract.Invariant(impl != null); + Contract.Invariant(initial != null); + Contract.Invariant(cce.NonNullDictionaryAndValues(copies)); + Contract.Invariant(cce.NonNull(visited)); + Contract.Invariant(callback != null); + } + + VCGen parent; + Implementation impl; + Block initial; + int id; + Dictionary<Block, Block> copies = new Dictionary<Block, Block>(); + HashSet<Block> visited = new HashSet<Block>(); + VerifierCallback callback; + + internal SmokeTester(VCGen par, Implementation i, VerifierCallback callback) { + Contract.Requires(par != null); + Contract.Requires(i != null); + Contract.Requires(callback != null); + parent = par; + impl = i; + initial = i.Blocks[0]; + this.callback = callback; + } + + internal void Copy() { + CloneBlock(impl.Blocks[0]); + initial = GetCopiedBlocks()[0]; + } + + internal void Test() { + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + + DFS(initial); + } + + void TopologicalSortImpl() { + Graph<Block> dag = new Graph<Block>(); + dag.AddSource(cce.NonNull(impl.Blocks[0])); // there is always at least one node in the graph + foreach (Block b in impl.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); + } + } + } + impl.Blocks = new List<Block>(); + foreach (Block b in dag.TopologicalSort()) { + Contract.Assert(b != null); + impl.Blocks.Add(b); + } + } + + void Emit() { + TopologicalSortImpl(); + EmitImpl(impl, false); + } + + // this one copies forward + Block CloneBlock(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<Block>() != null); + + Block fake_res; + if (copies.TryGetValue(b, out fake_res)) { + return cce.NonNull(fake_res); + } + Block res = new Block(b.tok, b.Label, new List<Cmd>(b.Cmds), null); + copies[b] = res; + if (b.TransferCmd is GotoCmd) { + foreach (Block ch in cce.NonNull((GotoCmd)b.TransferCmd).labelTargets) { + Contract.Assert(ch != null); + CloneBlock(ch); + } + } + foreach (Block p in b.Predecessors) { + Contract.Assert(p != null); + res.Predecessors.Add(CloneBlock(p)); + } + return res; + } + + // this one copies backwards + Block CopyBlock(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<Block>() != null); + + Block fake_res; + if (copies.TryGetValue(b, out fake_res)) { + // fake_res should be Block! but the compiler fails + return cce.NonNull(fake_res); + } + Block res; + List<Cmd> seq = new List<Cmd>(); + foreach (Cmd c in b.Cmds) { + Contract.Assert(c != null); + AssertCmd turn = c as AssertCmd; + if (!turnAssertIntoAssumes || turn == null) { + seq.Add(c); + } else { + seq.Add(AssertTurnedIntoAssume(turn)); + } + } + res = new Block(b.tok, b.Label, seq, null); + copies[b] = res; + foreach (Block p in b.Predecessors) { + Contract.Assert(p != null); + res.Predecessors.Add(CopyBlock(p)); + } + return res; + } + + List<Block> GetCopiedBlocks() { + Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>())); + + // the order of nodes in res is random (except for the first one, being the entry) + List<Block> res = new List<Block>(); + res.Add(copies[initial]); + + foreach (KeyValuePair<Block, Block> kv in copies) { + Contract.Assert(kv.Key != null&&kv.Value!=null); + GotoCmd go = kv.Key.TransferCmd as GotoCmd; + ReturnCmd ret = kv.Key.TransferCmd as ReturnCmd; + if (kv.Key != initial) { + res.Add(kv.Value); + } + if (go != null) { + GotoCmd copy = new GotoCmd(go.tok, new List<String>(), new List<Block>()); + kv.Value.TransferCmd = copy; + foreach (Block b in cce.NonNull(go.labelTargets)) { + Contract.Assert(b != null); + Block c; + if (copies.TryGetValue(b, out c)) { + copy.AddTarget(cce.NonNull(c)); + } + } + } else if (ret != null) { + kv.Value.TransferCmd = ret; + } else { + Contract.Assume(false); + throw new cce.UnreachableException(); + } + } + + copies.Clear(); + + return res; + } + + // check if e is true, false, !true, !false + // if so return true and the value of the expression in val + bool BooleanEval(Expr e, ref bool val) { + Contract.Requires(e != null); + LiteralExpr lit = e as LiteralExpr; + NAryExpr call = e as NAryExpr; + + if (lit != null && lit.isBool) { + val = lit.asBool; + return true; + } else if (call != null && + call.Fun is UnaryOperator && + ((UnaryOperator)call.Fun).Op == UnaryOperator.Opcode.Not && + BooleanEval(cce.NonNull(call.Args[0]), ref val)) { + val = !val; + return true; + } + // this is for the 0bv32 != 0bv32 generated by vcc + else if (call != null && + call.Fun is BinaryOperator && + ((BinaryOperator)call.Fun).Op == BinaryOperator.Opcode.Neq && + call.Args[0] is LiteralExpr && + cce.NonNull(call.Args[0]).Equals(call.Args[1])) { + val = false; + return true; + } + + return false; + } + + bool IsFalse(Expr e) { + Contract.Requires(e != null); + bool val = false; + return BooleanEval(e, ref val) && !val; + } + + bool CheckUnreachable(Block cur, List<Cmd> seq) + { + Contract.Requires(cur != null); + Contract.Requires(seq != null); + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + foreach (Cmd cmd in seq) + { + AssertCmd assrt = cmd as AssertCmd; + if (assrt != null && QKeyValue.FindBoolAttribute(assrt.Attributes, "PossiblyUnreachable")) + return false; + } + + DateTime start = DateTime.UtcNow; + if (CommandLineOptions.Clo.Trace) + { + System.Console.Write(" soundness smoke test #{0} ... ", id); + } + callback.OnProgress("smoke", id, id, 0.0); + + Token tok = new Token(); + tok.val = "soundness smoke test assertion"; + seq.Add(new AssertCmd(tok, Expr.False)); + Block copy = CopyBlock(cur); + Contract.Assert(copy != null); + copy.Cmds = seq; + List<Block> backup = impl.Blocks; + Contract.Assert(backup != null); + impl.Blocks = GetCopiedBlocks(); + copy.TransferCmd = new ReturnCmd(Token.NoToken); + if (CommandLineOptions.Clo.TraceVerify) + { + System.Console.WriteLine(); + System.Console.WriteLine(" --- smoke #{0}, before passify", id); + Emit(); + } + parent.CurrentLocalVariables = impl.LocVars; + ModelViewInfo mvInfo; + parent.PassifyImpl(impl, out mvInfo); + Dictionary<int, Absy> label2Absy; + Checker ch = parent.FindCheckerFor(CommandLineOptions.Clo.SmokeTimeout); + Contract.Assert(ch != null); + + ProverInterface.Outcome outcome = ProverInterface.Outcome.Undetermined; + try + { + lock (ch) + { + var exprGen = ch.TheoremProver.Context.ExprGen; + VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO); + + VCExpr vc = parent.GenerateVC(impl, controlFlowVariableExpr, out label2Absy, ch.TheoremProver.Context); + Contract.Assert(vc != null); + + if (!CommandLineOptions.Clo.UseLabels) + { + VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO)); + VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId))); + vc = exprGen.Implies(eqExpr, vc); + } + + impl.Blocks = backup; + + if (CommandLineOptions.Clo.TraceVerify) + { + System.Console.WriteLine(" --- smoke #{0}, after passify", id); + Emit(); + } + + ch.BeginCheck(cce.NonNull(impl.Name + "_smoke" + id++), vc, new ErrorHandler(label2Absy, this.callback)); + } + + ch.ProverTask.Wait(); + + lock (ch) + { + outcome = ch.ReadOutcome(); + } + } + finally + { + ch.GoBackToIdle(); + } + + parent.CurrentLocalVariables = null; + + DateTime end = DateTime.UtcNow; + TimeSpan elapsed = end - start; + if (CommandLineOptions.Clo.Trace) + { + System.Console.WriteLine(" [{0} s] {1}", elapsed.TotalSeconds, + outcome == ProverInterface.Outcome.Valid ? "OOPS" : + "OK" + (outcome == ProverInterface.Outcome.Invalid ? "" : " (" + outcome + ")")); + } + + if (outcome == ProverInterface.Outcome.Valid) + { + // copy it again, so we get the version with calls, assignments and such + copy = CopyBlock(cur); + copy.Cmds = seq; + impl.Blocks = GetCopiedBlocks(); + TopologicalSortImpl(); + callback.OnUnreachableCode(impl); + impl.Blocks = backup; + return true; + } + return false; + } + + const bool turnAssertIntoAssumes = false; + + void DFS(Block cur) { + Contract.Requires(cur != null); + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + if (visited.Contains(cur)) + return; + visited.Add(cur); + + List<Cmd> seq = new List<Cmd>(); + foreach (Cmd cmd_ in cur.Cmds) { + Cmd cmd = cmd_; + Contract.Assert(cmd != null); + AssertCmd assrt = cmd as AssertCmd; + AssumeCmd assm = cmd as AssumeCmd; + CallCmd call = cmd as CallCmd; + + bool assumeFalse = false; + + if (assrt != null) { + // we're not going any further + // it's clear the user expected unreachable code here + // it's not clear where did he expect it, maybe it would be right to insert + // a check just one command before + if (IsFalse(assrt.Expr)) + return; + +#if TURN_ASSERT_INFO_ASSUMES + if (turnAssertIntoAssumes) { + cmd = AssertTurnedIntoAssume(assrt); + } +#endif + } else if (assm != null) { + if (IsFalse(assm.Expr)) + assumeFalse = true; + } else if (call != null) { + foreach (Ensures e in (cce.NonNull(call.Proc)).Ensures) { + Contract.Assert(e != null); + if (IsFalse(e.Condition)) + assumeFalse = true; + } + } + + if (assumeFalse) { + CheckUnreachable(cur, seq); + return; + } + + seq.Add(cmd); + } + + + GotoCmd go = cur.TransferCmd as GotoCmd; + ReturnCmd ret = cur.TransferCmd as ReturnCmd; + + Contract.Assume(!(go != null && go.labelTargets == null && go.labelNames != null && go.labelNames.Count > 0)); + + if (ret != null || (go != null && cce.NonNull(go.labelTargets).Count == 0)) { + // we end in return, so there will be no more places to check + CheckUnreachable(cur, seq); + } else if (go != null) { + bool needToCheck = true; + // if all of our children have more than one parent, then + // we're in the right place to check + foreach (Block target in cce.NonNull(go.labelTargets)) { + Contract.Assert(target != null); + if (target.Predecessors.Count == 1) { + needToCheck = false; + } + } + if (needToCheck) { + CheckUnreachable(cur, seq); + } + foreach (Block target in go.labelTargets) { + Contract.Assert(target != null); + DFS(target); + } + } + } + + class ErrorHandler : ProverInterface.ErrorHandler { + Dictionary<int, Absy> label2Absy; + VerifierCallback callback; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(label2Absy != null); + Contract.Invariant(callback != null); + } + + + public ErrorHandler(Dictionary<int, Absy> label2Absy, VerifierCallback callback) { + Contract.Requires(label2Absy != null); + Contract.Requires(callback != null); + this.label2Absy = label2Absy; + this.callback = callback; + } + + public override Absy Label2Absy(string label) { + //Contract.Requires(label != null); + Contract.Ensures(Contract.Result<Absy>() != null); + + int id = int.Parse(label); + return cce.NonNull((Absy)label2Absy[id]); + } + + public override void OnProverWarning(string msg) { + //Contract.Requires(msg != null); + this.callback.OnWarning(msg); + } + } + } + + + #endregion + + #region Splitter + class Split { + class BlockStats { + public bool big_block; + public int id; + public double assertion_cost; + public double assumption_cost; // before multiplier + public double incomming_paths; + public List<Block>/*!>!*/ virtual_successors = new List<Block>(); + public List<Block>/*!>!*/ virtual_predecesors = new List<Block>(); + public HashSet<Block> reachable_blocks; + public readonly Block block; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(virtual_successors)); + Contract.Invariant(cce.NonNullElements(virtual_predecesors)); + Contract.Invariant(block != null); + } + + + public BlockStats(Block b, int i) { + Contract.Requires(b != null); + block = b; + assertion_cost = -1; + id = i; + } + } + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(cce.NonNullElements(blocks)); + Contract.Invariant(cce.NonNullElements(big_blocks)); + Contract.Invariant(cce.NonNullDictionaryAndValues(stats)); + Contract.Invariant(cce.NonNullElements(assumized_branches)); + Contract.Invariant(gotoCmdOrigins != null); + Contract.Invariant(parent != null); + Contract.Invariant(impl != null); + Contract.Invariant(copies != null); + Contract.Invariant(cce.NonNull(protected_from_assert_to_assume)); + Contract.Invariant(cce.NonNull(keep_at_all)); + } + + + readonly List<Block> blocks; + readonly List<Block> big_blocks = new List<Block>(); + readonly Dictionary<Block/*!*/, BlockStats/*!*/>/*!*/ stats = new Dictionary<Block/*!*/, BlockStats/*!*/>(); + readonly int id; + static int current_id = -1; + Block split_block; + bool assert_to_assume; + List<Block/*!*/>/*!*/ assumized_branches = new List<Block/*!*/>(); + + double score; + bool score_computed; + double total_cost; + int assertion_count; + double assertion_cost; // without multiplication by paths + Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins; + readonly public VCGen/*!*/ parent; + Implementation/*!*/ impl; + + Dictionary<Block/*!*/, Block/*!*/>/*!*/ copies = new Dictionary<Block/*!*/, Block/*!*/>(); + bool doing_slice; + double slice_initial_limit; + double slice_limit; + bool slice_pos; + HashSet<Block/*!*/>/*!*/ protected_from_assert_to_assume = new HashSet<Block/*!*/>(); + HashSet<Block/*!*/>/*!*/ keep_at_all = new HashSet<Block/*!*/>(); + + // async interface + private Checker checker; + private int splitNo; + internal ErrorReporter reporter; + + public Split(List<Block/*!*/>/*!*/ blocks, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par, Implementation/*!*/ impl) { + Contract.Requires(cce.NonNullElements(blocks)); + Contract.Requires(gotoCmdOrigins != null); + Contract.Requires(par != null); + Contract.Requires(impl != null); + this.blocks = blocks; + this.gotoCmdOrigins = gotoCmdOrigins; + this.parent = par; + this.impl = impl; + this.id = Interlocked.Increment(ref current_id); + } + + public double Cost { + get { + ComputeBestSplit(); + return total_cost; + } + } + + public bool LastChance { + get { + ComputeBestSplit(); + return assertion_count == 1 && score < 0; + } + } + + public string Stats { + get { + ComputeBestSplit(); + return string.Format("(cost:{0:0}/{1:0}{2})", total_cost, assertion_cost, LastChance ? " last" : ""); + } + } + + public void DumpDot(int no) { + using (System.IO.StreamWriter sw = System.IO.File.CreateText(string.Format("split.{0}.dot", no))) { + sw.WriteLine("digraph G {"); + + ComputeBestSplit(); + List<Block> saved = assumized_branches; + Contract.Assert(saved != null); + assumized_branches = new List<Block>(); + DoComputeScore(false); + assumized_branches = saved; + + foreach (Block b in big_blocks) { + Contract.Assert(b != null); + BlockStats s = GetBlockStats(b); + foreach (Block t in s.virtual_successors) { + Contract.Assert(t != null); + sw.WriteLine("n{0} -> n{1};", s.id, GetBlockStats(t).id); + } + sw.WriteLine("n{0} [label=\"{1}:\\n({2:0.0}+{3:0.0})*{4:0.0}\"{5}];", + s.id, b.Label, + s.assertion_cost, s.assumption_cost, s.incomming_paths, + s.assertion_cost > 0 ? ",shape=box" : ""); + + } + sw.WriteLine("}"); + sw.Close(); + } + + string filename = string.Format("split.{0}.bpl", no); + using (System.IO.StreamWriter sw = System.IO.File.CreateText(filename)) { + int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured; + CommandLineOptions.Clo.PrintUnstructured = 2; // print only the unstructured program + bool oldPrintDesugaringSetting = CommandLineOptions.Clo.PrintDesugarings; + CommandLineOptions.Clo.PrintDesugarings = false; + List<Block> backup = impl.Blocks; + Contract.Assert(backup != null); + impl.Blocks = blocks; + impl.Emit(new TokenTextWriter(filename, sw, /*setTokens=*/ false, /*pretty=*/ false), 0); + impl.Blocks = backup; + CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaringSetting; + CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured; + } + } + + int bsid; + BlockStats GetBlockStats(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<BlockStats>() != null); + + BlockStats s; + if (!stats.TryGetValue(b, out s)) { + s = new BlockStats(b, bsid++); + stats[b] = s; + } + return cce.NonNull(s); + } + + double AssertionCost(PredicateCmd c) { + return 1.0; + } + + void CountAssertions(Block b) { + Contract.Requires(b != null); + BlockStats s = GetBlockStats(b); + if (s.assertion_cost >= 0) + return; // already done + s.big_block = true; + s.assertion_cost = 0; + s.assumption_cost = 0; + foreach (Cmd c in b.Cmds) { + if (c is AssertCmd) { + double cost = AssertionCost((AssertCmd)c); + s.assertion_cost += cost; + assertion_count++; + assertion_cost += cost; + } else if (c is AssumeCmd) { + s.assumption_cost += AssertionCost((AssumeCmd)c); + } + } + foreach (Block c in Exits(b)) { + Contract.Assert(c != null); + s.virtual_successors.Add(c); + } + if (s.virtual_successors.Count == 1) { + Block next = s.virtual_successors[0]; + BlockStats se = GetBlockStats(next); + CountAssertions(next); + if (next.Predecessors.Count > 1 || se.virtual_successors.Count != 1) + return; + s.virtual_successors[0] = se.virtual_successors[0]; + s.assertion_cost += se.assertion_cost; + s.assumption_cost += se.assumption_cost; + se.big_block = false; + } + } + + HashSet<Block/*!*/>/*!*/ ComputeReachableNodes(Block/*!*/ b) { + Contract.Requires(b != null); + Contract.Ensures(cce.NonNull(Contract.Result<HashSet<Block/*!*/>>())); + BlockStats s = GetBlockStats(b); + if (s.reachable_blocks != null) { + return s.reachable_blocks; + } + HashSet<Block/*!*/> blocks = new HashSet<Block/*!*/>(); + s.reachable_blocks = blocks; + blocks.Add(b); + foreach (Block/*!*/ succ in Exits(b)) { + Contract.Assert(succ != null); + foreach (Block r in ComputeReachableNodes(succ)) { + Contract.Assert(r != null); + blocks.Add(r); + } + } + return blocks; + } + + double ProverCost(double vc_cost) { + return vc_cost * vc_cost; + } + + void ComputeBestSplit() { + if (score_computed) + return; + score_computed = true; + + assertion_count = 0; + + foreach (Block b in blocks) { + Contract.Assert(b != null); + CountAssertions(b); + } + + foreach (Block b in blocks) { + Contract.Assert(b != null); + BlockStats bs = GetBlockStats(b); + if (bs.big_block) { + big_blocks.Add(b); + foreach (Block ch in bs.virtual_successors) { + Contract.Assert(ch != null); + BlockStats chs = GetBlockStats(ch); + if (!chs.big_block) { + Console.WriteLine("non-big {0} accessed from {1}", ch, b); + DumpDot(-1); + Contract.Assert(false); + throw new cce.UnreachableException(); + } + chs.virtual_predecesors.Add(b); + } + } + } + + assumized_branches.Clear(); + total_cost = ProverCost(DoComputeScore(false)); + + score = double.PositiveInfinity; + Block best_split = null; + List<Block> saved_branches = new List<Block>(); + + foreach (Block b in big_blocks) { + Contract.Assert(b != null); + GotoCmd gt = b.TransferCmd as GotoCmd; + if (gt == null) + continue; + List<Block> targ = cce.NonNull(gt.labelTargets); + if (targ.Count < 2) + continue; + // caution, we only consider two first exits + + double left0, right0, left1, right1; + split_block = b; + + assumized_branches.Clear(); + assumized_branches.Add(cce.NonNull(targ[0])); + left0 = DoComputeScore(true); + right0 = DoComputeScore(false); + + assumized_branches.Clear(); + for (int idx = 1; idx < targ.Count; idx++) { + assumized_branches.Add(cce.NonNull(targ[idx])); + } + left1 = DoComputeScore(true); + right1 = DoComputeScore(false); + + double current_score = ProverCost(left1) + ProverCost(right1); + double other_score = ProverCost(left0) + ProverCost(right0); + + if (other_score < current_score) { + current_score = other_score; + assumized_branches.Clear(); + assumized_branches.Add(cce.NonNull(targ[0])); + } + + if (current_score < score) { + score = current_score; + best_split = split_block; + saved_branches.Clear(); + saved_branches.AddRange(assumized_branches); + } + } + + if (CommandLineOptions.Clo.VcsPathSplitMult * score > total_cost) { + split_block = null; + score = -1; + } else { + assumized_branches = saved_branches; + split_block = best_split; + } + } + + void UpdateIncommingPaths(BlockStats s) { + Contract.Requires(s != null); + if (s.incomming_paths < 0.0) { + int count = 0; + s.incomming_paths = 0.0; + if (!keep_at_all.Contains(s.block)) + return; + foreach (Block b in s.virtual_predecesors) { + Contract.Assert(b != null); + BlockStats ch = GetBlockStats(b); + Contract.Assert(ch != null); + UpdateIncommingPaths(ch); + if (ch.incomming_paths > 0.0) { + s.incomming_paths += ch.incomming_paths; + count++; + } + } + if (count > 1) { + s.incomming_paths *= CommandLineOptions.Clo.VcsPathJoinMult; + } + } + } + + void ComputeBlockSetsHelper(Block b, bool allow_small) { + Contract.Requires(b != null); + if (keep_at_all.Contains(b)) + return; + keep_at_all.Add(b); + + if (allow_small) { + foreach (Block ch in Exits(b)) { + Contract.Assert(ch != null); + if (b == split_block && assumized_branches.Contains(ch)) + continue; + ComputeBlockSetsHelper(ch, allow_small); + } + } else { + foreach (Block ch in GetBlockStats(b).virtual_successors) { + Contract.Assert(ch != null); + if (b == split_block && assumized_branches.Contains(ch)) + continue; + ComputeBlockSetsHelper(ch, allow_small); + } + } + } + + void ComputeBlockSets(bool allow_small) { + protected_from_assert_to_assume.Clear(); + keep_at_all.Clear(); + + Debug.Assert(split_block == null || GetBlockStats(split_block).big_block); + Debug.Assert(GetBlockStats(blocks[0]).big_block); + + if (assert_to_assume) { + foreach (Block b in allow_small ? blocks : big_blocks) { + Contract.Assert(b != null); + if (ComputeReachableNodes(b).Contains(cce.NonNull(split_block))) { + keep_at_all.Add(b); + } + } + + foreach (Block b in assumized_branches) { + Contract.Assert(b != null); + foreach (Block r in ComputeReachableNodes(b)) { + Contract.Assert(r != null); + if (allow_small || GetBlockStats(r).big_block) { + keep_at_all.Add(r); + protected_from_assert_to_assume.Add(r); + } + } + } + } else { + ComputeBlockSetsHelper(blocks[0], allow_small); + } + } + + bool ShouldAssumize(Block b) { + Contract.Requires(b != null); + return assert_to_assume && !protected_from_assert_to_assume.Contains(b); + } + + double DoComputeScore(bool aa) { + assert_to_assume = aa; + ComputeBlockSets(false); + + foreach (Block b in big_blocks) { + Contract.Assert(b != null); + GetBlockStats(b).incomming_paths = -1.0; + } + + GetBlockStats(blocks[0]).incomming_paths = 1.0; + + double cost = 0.0; + foreach (Block b in big_blocks) { + Contract.Assert(b != null); + if (keep_at_all.Contains(b)) { + BlockStats s = GetBlockStats(b); + UpdateIncommingPaths(s); + double local = s.assertion_cost; + if (ShouldAssumize(b)) { + local = (s.assertion_cost + s.assumption_cost) * CommandLineOptions.Clo.VcsAssumeMult; + } else { + local = s.assumption_cost * CommandLineOptions.Clo.VcsAssumeMult + s.assertion_cost; + } + local = local + local * s.incomming_paths * CommandLineOptions.Clo.VcsPathCostMult; + cost += local; + } + } + + return cost; + } + + List<Cmd> SliceCmds(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<List<Cmd>>() != null); + + List<Cmd> seq = b.Cmds; + Contract.Assert(seq != null); + if (!doing_slice && !ShouldAssumize(b)) + return seq; + List<Cmd> res = new List<Cmd>(); + foreach (Cmd c in seq) { + Contract.Assert(c != null); + AssertCmd a = c as AssertCmd; + Cmd the_new = c; + bool swap = false; + if (a != null) { + if (doing_slice) { + double cost = AssertionCost(a); + bool first = (slice_limit - cost) >= 0 || slice_initial_limit == slice_limit; + slice_limit -= cost; + swap = slice_pos == first; + } else if (assert_to_assume) { + swap = true; + } else { + Contract.Assert(false); + throw new cce.UnreachableException(); + } + + if (swap) { + the_new = AssertTurnedIntoAssume(a); + } + } + res.Add(the_new); + } + return res; + } + + Block CloneBlock(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<Block>() != null); + + Block res; + if (copies.TryGetValue(b, out res)) { + return cce.NonNull(res); + } + res = new Block(b.tok, b.Label, SliceCmds(b), b.TransferCmd); + GotoCmd gt = b.TransferCmd as GotoCmd; + copies[b] = res; + if (gt != null) { + GotoCmd newGoto = new GotoCmd(gt.tok, new List<String>(), new List<Block>()); + res.TransferCmd = newGoto; + int pos = 0; + foreach (Block ch in cce.NonNull(gt.labelTargets)) { + Contract.Assert(ch != null); + Contract.Assert(doing_slice || + (assert_to_assume || (keep_at_all.Contains(ch) || assumized_branches.Contains(ch)))); + if (doing_slice || + ((b != split_block || assumized_branches.Contains(ch) == assert_to_assume) && + keep_at_all.Contains(ch))) { + newGoto.AddTarget(CloneBlock(ch)); + } + pos++; + } + } + return res; + } + + Split DoSplit() { + Contract.Ensures(Contract.Result<Split>() != null); + + copies.Clear(); + CloneBlock(blocks[0]); + List<Block> newBlocks = new List<Block>(); + Dictionary<TransferCmd, ReturnCmd> newGotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>(); + foreach (Block b in blocks) { + Contract.Assert(b != null); + Block tmp; + if (copies.TryGetValue(b, out tmp)) { + newBlocks.Add(cce.NonNull(tmp)); + if (gotoCmdOrigins.ContainsKey(b.TransferCmd)) { + newGotoCmdOrigins[tmp.TransferCmd] = gotoCmdOrigins[b.TransferCmd]; + } + + foreach (Block p in b.Predecessors) { + Contract.Assert(p != null); + Block tmp2; + if (copies.TryGetValue(p, out tmp2)) { + tmp.Predecessors.Add(tmp2); + } + } + } + } + + return new Split(newBlocks, newGotoCmdOrigins, parent, impl); + } + + Split SplitAt(int idx) { + Contract.Ensures(Contract.Result<Split>() != null); + + assert_to_assume = idx == 0; + doing_slice = false; + ComputeBlockSets(true); + + return DoSplit(); + } + + Split SliceAsserts(double limit, bool pos) { + Contract.Ensures(Contract.Result<Split>() != null); + + slice_pos = pos; + slice_limit = limit; + slice_initial_limit = limit; + doing_slice = true; + Split r = DoSplit(); + /* + Console.WriteLine("split {0} / {1} -->", limit, pos); + List<Block!> tmp = impl.Blocks; + impl.Blocks = r.blocks; + EmitImpl(impl, false); + impl.Blocks = tmp; + */ + + return r; + } + + void Print() { + List<Block> tmp = impl.Blocks; + Contract.Assert(tmp != null); + impl.Blocks = blocks; + EmitImpl(impl, false); + impl.Blocks = tmp; + } + + public Counterexample ToCounterexample(ProverContext context) { + Contract.Requires(context != null); + Contract.Ensures(Contract.Result<Counterexample>() != null); + + List<Block> trace = new List<Block>(); + foreach (Block b in blocks) { + Contract.Assert(b != null); + trace.Add(b); + } + foreach (Block b in blocks) { + Contract.Assert(b != null); + foreach (Cmd c in b.Cmds) { + Contract.Assert(c != null); + if (c is AssertCmd) { + return AssertCmdToCounterexample((AssertCmd)c, cce.NonNull(b.TransferCmd), trace, null, null, context); + } + } + } + Contract.Assume(false); + throw new cce.UnreachableException(); + } + + /// <summary> + /// Starting from the 0-index "split_here" annotation in begin, verifies until it reaches a subsequent "split_here" annotation + /// Returns a list of blocks where all code not verified has asserts converted into assumes + /// </summary> + /// <param name="blocks">Implementation's collection of blocks</param> + /// <param name="begin">Block containing the first split_here from which to start verifying</param> + /// <param name="begin_split_id">0-based ID of the "split_here" annotation within begin at which to start verifying</param> + /// <param name="blockInternalSplit">True if the entire split is contained within block begin</param> + /// <param name="endPoints">Set of all blocks containing a "split_here" annotation</param> + /// <returns></returns> + // Note: Current implementation may over report errors. + // For example, if the control flow graph is a diamond (e.g., A -> B, C, B->D, C->D), + // and there is a split in B and an error in D, then D will be verified twice and hence report the error twice. + // Best solution may be to memoize blocks that have been fully verified and be sure not to verify them again + private static List<Block> DoManualSplit(List<Block> blocks, Block begin, int begin_split_id, bool blockInternalSplit, IEnumerable<Block> endPoints) { + // Compute the set of blocks reachable from begin but not included in endPoints. These will be verified in their entirety. + var blocksToVerifyEntirely = new HashSet<Block>(); + var reachableEndPoints = new HashSet<Block>(); // Reachable end points will be verified up to their first split point + var todo = new Stack<Block>(); + todo.Push(begin); + while (todo.Count > 0) { + var currentBlock = todo.Pop(); + if (blocksToVerifyEntirely.Contains(currentBlock)) continue; + blocksToVerifyEntirely.Add(currentBlock); + var exit = currentBlock.TransferCmd as GotoCmd; + if (exit != null) + foreach (Block targetBlock in exit.labelTargets) { + if (!endPoints.Contains(targetBlock)) { + todo.Push(targetBlock); + } else { + reachableEndPoints.Add(targetBlock); + } + } + + } + blocksToVerifyEntirely.Remove(begin); + + // Convert assumes to asserts in "unreachable" blocks, including portions of blocks containing "split_here" + var newBlocks = new List<Block>(blocks.Count()); // Copies of the original blocks + var duplicator = new Duplicator(); + var oldToNewBlockMap = new Dictionary<Block, Block>(blocks.Count()); // Maps original blocks to their new copies in newBlocks + + foreach (var currentBlock in blocks) { + var newBlock = (Block)duplicator.VisitBlock(currentBlock); + oldToNewBlockMap[currentBlock] = newBlock; + newBlocks.Add(newBlock); + + if (!blockInternalSplit && blocksToVerifyEntirely.Contains(currentBlock)) continue; // All reachable blocks must be checked in their entirety, so don't change anything + // Otherwise, we only verify a portion of the current block, so we'll need to look at each of its commands + + // !verify -> convert assert to assume + var verify = (currentBlock == begin && begin_split_id == -1) // -1 tells us to start verifying from the very beginning (i.e., there is no split in the begin block) + || (reachableEndPoints.Contains(currentBlock) // This endpoint is reachable from begin, so we verify until we hit the first split point + && !blockInternalSplit); // Don't bother verifying if all of the splitting is within the begin block + var newCmds = new List<Cmd>(); + var split_here_count = 0; + + foreach (Cmd c in currentBlock.Cmds) { + var p = c as PredicateCmd; + if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) { + if (currentBlock == begin) { // Verify everything between the begin_split_id we were given and the next split + if (split_here_count == begin_split_id) { + verify = true; + } else if (split_here_count == begin_split_id + 1) { + verify = false; + } + } else { // We're in an endPoint so we stop verifying as soon as we hit a "split_here" + verify = false; + } + split_here_count++; + } + + var asrt = c as AssertCmd; + if (verify || asrt == null) + newCmds.Add(c); + else + newCmds.Add(AssertTurnedIntoAssume(asrt)); + } + + newBlock.Cmds = newCmds; + } + + // Patch the edges between the new blocks + foreach (var oldBlock in blocks) { + if (oldBlock.TransferCmd is ReturnCmd) { continue; } + var gotoCmd = (GotoCmd)oldBlock.TransferCmd; + var newLabelTargets = new List<Block>(gotoCmd.labelTargets.Count()); + var newLabelNames = new List<string>(gotoCmd.labelTargets.Count()); + foreach (var target in gotoCmd.labelTargets) { + newLabelTargets.Add(oldToNewBlockMap[target]); + newLabelNames.Add(oldToNewBlockMap[target].Label); + } + oldToNewBlockMap[oldBlock].TransferCmd = new GotoCmd(gotoCmd.tok, newLabelNames, newLabelTargets); + } + + return newBlocks; + } + + public static List<Split/*!*/> FindManualSplits(Implementation/*!*/ impl, Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, VCGen/*!*/ par) { + Contract.Requires(impl != null); + Contract.Ensures(Contract.Result<List<Split>>() == null || cce.NonNullElements(Contract.Result<List<Split>>())); + + var splitPoints = new Dictionary<Block,int>(); + foreach (var b in impl.Blocks) { + foreach (Cmd c in b.Cmds) { + var p = c as PredicateCmd; + if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "split_here")) { + int count; + splitPoints.TryGetValue(b, out count); + splitPoints[b] = count + 1; + } + } + } + + if (splitPoints.Count() == 0) { // No manual split points here + return null; + } + + List<Split> splits = new List<Split>(); + Block entryPoint = impl.Blocks[0]; + var newEntryBlocks = DoManualSplit(impl.Blocks, entryPoint, -1, splitPoints.Keys.Contains(entryPoint), splitPoints.Keys); + splits.Add(new Split(newEntryBlocks, gotoCmdOrigins, par, impl)); // REVIEW: Does gotoCmdOrigins need to be changed at all? + + foreach (KeyValuePair<Block,int> pair in splitPoints) { + for (int i = 0; i < pair.Value; i++) { + bool blockInternalSplit = i < pair.Value - 1; // There's at least one more split, after this one, in the current block + var newBlocks = DoManualSplit(impl.Blocks, pair.Key, i, blockInternalSplit, splitPoints.Keys); + Split s = new Split(newBlocks, gotoCmdOrigins, par, impl); // REVIEW: Does gotoCmdOrigins need to be changed at all? + splits.Add(s); + } + } + + return splits; + } + + public static List<Split/*!*/>/*!*/ DoSplit(Split initial, double max_cost, int max) { + Contract.Requires(initial != null); + Contract.Ensures(cce.NonNullElements(Contract.Result<List<Split>>())); + + List<Split> res = new List<Split>(); + res.Add(initial); + + while (res.Count < max) { + Split best = null; + int best_idx = 0, pos = 0; + foreach (Split s in res) { + Contract.Assert(s != null); + s.ComputeBestSplit(); // TODO check total_cost first + if (s.total_cost > max_cost && + (best == null || best.total_cost < s.total_cost) && + (s.assertion_count > 1 || s.split_block != null)) { + best = s; + best_idx = pos; + } + pos++; + } + + if (best == null) + break; // no split found + + Split s0, s1; + + bool split_stats = CommandLineOptions.Clo.TraceVerify; + + if (split_stats) { + Console.WriteLine("{0} {1} -->", best.split_block == null ? "SLICE" : ("SPLIT@" + best.split_block.Label), best.Stats); + if (best.split_block != null) { + GotoCmd g = best.split_block.TransferCmd as GotoCmd; + if (g != null) { + Console.Write(" exits: "); + foreach (Block b in cce.NonNull(g.labelTargets)) { + Contract.Assert(b != null); + Console.Write("{0} ", b.Label); + } + Console.WriteLine(""); + Console.Write(" assumized: "); + foreach (Block b in best.assumized_branches) { + Contract.Assert(b != null); + Console.Write("{0} ", b.Label); + } + Console.WriteLine(""); + } + } + } + + if (best.split_block != null) { + s0 = best.SplitAt(0); + s1 = best.SplitAt(1); + } else { + best.split_block = null; + s0 = best.SliceAsserts(best.assertion_cost / 2, true); + s1 = best.SliceAsserts(best.assertion_cost / 2, false); + } + + if (true) { + List<Block> ss = new List<Block>(); + ss.Add(s0.blocks[0]); + ss.Add(s1.blocks[0]); + try { + best.SoundnessCheck(new HashSet<List<Block>>(new BlockListComparer()), best.blocks[0], ss); + } catch (System.Exception e) { + Console.WriteLine(e); + best.DumpDot(-1); + s0.DumpDot(-2); + s1.DumpDot(-3); + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + + if (split_stats) { + s0.ComputeBestSplit(); + s1.ComputeBestSplit(); + Console.WriteLine(" --> {0}", s0.Stats); + Console.WriteLine(" --> {0}", s1.Stats); + } + + if (CommandLineOptions.Clo.TraceVerify) { + best.Print(); + } + + res[best_idx] = s0; + res.Add(s1); + } + + return res; + } + + class BlockListComparer : IEqualityComparer<List<Block>> + { + public bool Equals(List<Block> x, List<Block> y) + { + return x == y || x.SequenceEqual(y); + } + + public int GetHashCode(List<Block> obj) + { + int h = 0; + Contract.Assume(obj != null); + foreach (var b in obj) + { + if (b != null) + { + h += b.GetHashCode(); + } + } + return h; + } + } + + public Checker Checker { + get { + Contract.Ensures(Contract.Result<Checker>() != null); + + Contract.Assert(checker != null); + return checker; + } + } + + public Task ProverTask { + get { + Contract.Assert(checker != null); + return checker.ProverTask; + } + } + + public void ReadOutcome(ref Outcome cur_outcome, out bool prover_failed) { + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + ProverInterface.Outcome outcome = cce.NonNull(checker).ReadOutcome(); + + if (CommandLineOptions.Clo.Trace && splitNo >= 0) { + System.Console.WriteLine(" --> split #{0} done, [{1} s] {2}", splitNo, checker.ProverRunTime.TotalSeconds, outcome); + } + + if (CommandLineOptions.Clo.VcsDumpSplits) { + DumpDot(splitNo); + } + + prover_failed = false; + + switch (outcome) { + case ProverInterface.Outcome.Valid: + return; + case ProverInterface.Outcome.Invalid: + cur_outcome = Outcome.Errors; + return; + case ProverInterface.Outcome.OutOfMemory: + prover_failed = true; + if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive) + cur_outcome = Outcome.OutOfMemory; + return; + case ProverInterface.Outcome.TimeOut: + prover_failed = true; + if (cur_outcome != Outcome.Errors && cur_outcome != Outcome.Inconclusive) + cur_outcome = Outcome.TimedOut; + return; + case ProverInterface.Outcome.Undetermined: + if (cur_outcome != Outcome.Errors) + cur_outcome = Outcome.Inconclusive; + return; + default: + Contract.Assert(false); + throw new cce.UnreachableException(); + } + } + + /// <summary> + /// As a side effect, updates "this.parent.CumulativeAssertionCount". + /// </summary> + public void BeginCheck(Checker checker, VerifierCallback callback, ModelViewInfo mvInfo, int no, int timeout) + { + Contract.Requires(checker != null); + Contract.Requires(callback != null); + + splitNo = no; + + impl.Blocks = blocks; + + this.checker = checker; + + Dictionary<int, Absy> label2absy = new Dictionary<int, Absy>(); + + ProverContext ctx = checker.TheoremProver.Context; + Boogie2VCExprTranslator bet = ctx.BoogieExprTranslator; + CodeExprConversionClosure cc = new CodeExprConversionClosure(label2absy, ctx); + bet.SetCodeExprConverter(cc.CodeExprToVerificationCondition); + + var exprGen = ctx.ExprGen; + VCExpr controlFlowVariableExpr = CommandLineOptions.Clo.UseLabels ? null : exprGen.Integer(BigNum.ZERO); + + VCExpr vc = parent.GenerateVCAux(impl, controlFlowVariableExpr, label2absy, checker.TheoremProver.Context); + Contract.Assert(vc != null); + + if (!CommandLineOptions.Clo.UseLabels) + { + VCExpr controlFlowFunctionAppl = exprGen.ControlFlowFunctionApplication(exprGen.Integer(BigNum.ZERO), exprGen.Integer(BigNum.ZERO)); + VCExpr eqExpr = exprGen.Eq(controlFlowFunctionAppl, exprGen.Integer(BigNum.FromInt(impl.Blocks[0].UniqueId))); + vc = exprGen.Implies(eqExpr, vc); + } + + if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Local) + { + reporter = new ErrorReporterLocal(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, cce.NonNull(this.Checker.TheoremProver.Context), parent.program); + } + else + { + reporter = new ErrorReporter(gotoCmdOrigins, label2absy, impl.Blocks, parent.incarnationOriginMap, callback, mvInfo, this.Checker.TheoremProver.Context, parent.program); + } + + if (CommandLineOptions.Clo.TraceVerify && no >= 0) + { + Console.WriteLine("-- after split #{0}", no); + Print(); + } + + string desc = cce.NonNull(impl.Name); + if (no >= 0) + desc += "_split" + no; + checker.BeginCheck(desc, vc, reporter); + } + + private void SoundnessCheck(HashSet<List<Block>/*!*/>/*!*/ cache, Block/*!*/ orig, List<Block/*!*/>/*!*/ copies) { + Contract.Requires(cce.NonNull(cache)); + Contract.Requires(orig != null); + Contract.Requires(copies != null); + { + var t = new List<Block> { orig }; + foreach (Block b in copies) { + Contract.Assert(b != null); + t.Add(b); + } + if (cache.Contains(t)) { + return; + } + cache.Add(t); + } + + for (int i = 0; i < orig.Cmds.Count; ++i) { + Cmd cmd = orig.Cmds[i]; + if (cmd is AssertCmd) { + int found = 0; + foreach (Block c in copies) { + Contract.Assert(c != null); + if (c.Cmds[i] == cmd) { + found++; + } + } + if (found == 0) { + throw new System.Exception(string.Format("missing assertion: {0}({1})", cmd.tok.filename, cmd.tok.line)); + } + } + } + + foreach (Block exit in Exits(orig)) { + Contract.Assert(exit != null); + List<Block> newcopies = new List<Block>(); + foreach (Block c in copies) { + foreach (Block cexit in Exits(c)) { + Contract.Assert(cexit != null); + if (cexit.Label == exit.Label) { + newcopies.Add(cexit); + } + } + } + if (newcopies.Count == 0) { + throw new System.Exception("missing exit " + exit.Label); + } + SoundnessCheck(cache, exit, newcopies); + } + } + } + #endregion + + + public class CodeExprConversionClosure + { + Dictionary<int, Absy> label2absy; + ProverContext ctx; + public CodeExprConversionClosure(Dictionary<int, Absy> label2absy, ProverContext ctx) + { + this.label2absy = label2absy; + this.ctx = ctx; + } + + public VCExpr CodeExprToVerificationCondition(CodeExpr codeExpr, Hashtable blockVariables, List<VCExprLetBinding> bindings, bool isPositiveContext) + { + VCGen vcgen = new VCGen(new Program(), null, false, new List<Checker>()); + vcgen.variable2SequenceNumber = new Dictionary<Variable, int>(); + vcgen.incarnationOriginMap = new Dictionary<Incarnation, Absy>(); + vcgen.CurrentLocalVariables = codeExpr.LocVars; + + ResetPredecessors(codeExpr.Blocks); + vcgen.AddBlocksBetween(codeExpr.Blocks); + Dictionary<Variable, Expr> gotoCmdOrigins = vcgen.ConvertBlocks2PassiveCmd(codeExpr.Blocks, new List<IdentifierExpr>(), new ModelViewInfo(codeExpr)); + int ac; // computed, but then ignored for this CodeExpr + VCExpr startCorrect = VCGen.LetVCIterative(codeExpr.Blocks, null, label2absy, ctx, out ac, isPositiveContext); + VCExpr vce = ctx.ExprGen.Let(bindings, startCorrect); + if (vcgen.CurrentLocalVariables.Count != 0) + { + Boogie2VCExprTranslator translator = ctx.BoogieExprTranslator; + List<VCExprVar> boundVars = new List<VCExprVar>(); + foreach (Variable v in vcgen.CurrentLocalVariables) + { + Contract.Assert(v != null); + VCExprVar ev = translator.LookupVariable(v); + Contract.Assert(ev != null); + boundVars.Add(ev); + if (v.TypedIdent.Type.Equals(Bpl.Type.Bool)) + { + // add an antecedent (tickleBool ev) to help the prover find a possible trigger + vce = ctx.ExprGen.Implies(ctx.ExprGen.Function(VCExpressionGenerator.TickleBoolOp, ev), vce); + } + } + vce = ctx.ExprGen.Forall(boundVars, new List<VCTrigger>(), vce); + } + if (isPositiveContext) + { + vce = ctx.ExprGen.Not(vce); + } + return vce; + } + } + + public VCExpr GenerateVC(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, out Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext) + { + Contract.Requires(impl != null); + Contract.Requires(proverContext != null); + Contract.Ensures(Contract.ValueAtReturn(out label2absy) != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + label2absy = new Dictionary<int, Absy>(); + return GenerateVCAux(impl, controlFlowVariableExpr, label2absy, proverContext); + } + + public VCExpr GenerateVCAux(Implementation/*!*/ impl, VCExpr controlFlowVariableExpr, Dictionary<int, Absy>/*!*/ label2absy, ProverContext proverContext) { + Contract.Requires(impl != null); + Contract.Requires(proverContext != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + TypecheckingContext tc = new TypecheckingContext(null); + impl.Typecheck(tc); + + VCExpr vc; + int assertionCount; + switch (CommandLineOptions.Clo.vcVariety) { + case CommandLineOptions.VCVariety.Structured: + vc = VCViaStructuredProgram(impl, label2absy, proverContext, out assertionCount); + break; + case CommandLineOptions.VCVariety.Block: + vc = FlatBlockVC(impl, label2absy, false, false, false, proverContext, out assertionCount); + break; + case CommandLineOptions.VCVariety.BlockReach: + vc = FlatBlockVC(impl, label2absy, false, true, false, proverContext, out assertionCount); + break; + case CommandLineOptions.VCVariety.Local: + vc = FlatBlockVC(impl, label2absy, true, false, false, proverContext, out assertionCount); + break; + case CommandLineOptions.VCVariety.BlockNested: + vc = NestedBlockVC(impl, label2absy, false, proverContext, out assertionCount); + break; + case CommandLineOptions.VCVariety.BlockNestedReach: + vc = NestedBlockVC(impl, label2absy, true, proverContext, out assertionCount); + break; + case CommandLineOptions.VCVariety.Dag: + if (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).SupportsDags || CommandLineOptions.Clo.FixedPointEngine != null) { + vc = DagVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, new Hashtable/*<Block, VCExpr!>*/(), proverContext, out assertionCount); + } else { + vc = LetVC(cce.NonNull(impl.Blocks[0]), controlFlowVariableExpr, label2absy, proverContext, out assertionCount); + } + break; + case CommandLineOptions.VCVariety.DagIterative: + vc = LetVCIterative(impl.Blocks, controlFlowVariableExpr, label2absy, proverContext, out assertionCount); + break; + case CommandLineOptions.VCVariety.Doomed: + vc = FlatBlockVC(impl, label2absy, false, false, true, proverContext, out assertionCount); + break; + default: + Contract.Assert(false); + throw new cce.UnreachableException(); // unexpected enumeration value + } + CumulativeAssertionCount += assertionCount; + return vc; + } + + void CheckIntAttributeOnImpl(Implementation impl, string name, ref int val) { + Contract.Requires(impl != null); + Contract.Requires(name != null); + if (!(cce.NonNull(impl.Proc).CheckIntAttribute(name, ref val) || !impl.CheckIntAttribute(name, ref val))) { + Console.WriteLine("ignoring ill-formed {:{0} ...} attribute on {1}, parameter should be an int", name, impl.Name); + } + } + + public override Outcome VerifyImplementation(Implementation/*!*/ impl, VerifierCallback/*!*/ callback) { + Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); + + if (impl.SkipVerification) { + return Outcome.Inconclusive; // not sure about this one + } + + callback.OnProgress("VCgen", 0, 0, 0.0); + + Stopwatch watch = new Stopwatch(); + if (_print_time) + { + Console.WriteLine("Checking function {0}", impl.Name); + watch.Reset(); + watch.Start(); + } + + ConvertCFG2DAG(impl); + + SmokeTester smoke_tester = null; + if (CommandLineOptions.Clo.SoundnessSmokeTest) { + smoke_tester = new SmokeTester(this, impl, callback); + smoke_tester.Copy(); + } + + ModelViewInfo mvInfo; + var gotoCmdOrigins = PassifyImpl(impl, out mvInfo); + + // If "expand" attribute is supplied, expand any assertion of conjunctions into multiple assertions, one per conjunct + foreach (var b in impl.Blocks) + { + List<Cmd> newCmds = new List<Cmd>(); + bool changed = false; + foreach (var c in b.Cmds) + { + var a = c as AssertCmd; + var ar = c as AssertRequiresCmd; + var ae = c as AssertEnsuresCmd; + var ai = c as LoopInitAssertCmd; + var am = c as LoopInvMaintainedAssertCmd; + // TODO: + //use Duplicator and Substituter rather than new + //nested IToken? + //document expand attribute (search for {:ignore}, for example) + //fix up new CallCmd, new Requires, new Ensures in OwickiGries.cs + Func<Expr,Expr,Expr> withType = (Expr from, Expr to) => + { + NAryExpr nFrom = from as NAryExpr; + NAryExpr nTo = to as NAryExpr; + to.Type = from.Type; + if (nFrom != null && nTo != null) nTo.TypeParameters = nFrom.TypeParameters; + return to; + }; + + Action<int,Expr,Action<Expr>> traverse = null; + traverse = (depth, e, act) => + { + ForallExpr forall = e as ForallExpr; + NAryExpr nary = e as NAryExpr; + if (forall != null) + { + traverse(depth, forall.Body, e1 => act(withType(forall, + new ForallExpr(e1.tok, forall.TypeParameters, forall.Dummies, forall.Attributes, forall.Triggers, e1)))); + return; + } + if (nary != null) + { + var args = nary.Args; + IAppliable fun = nary.Fun; + BinaryOperator bop = fun as BinaryOperator; + FunctionCall call = fun as FunctionCall; + if (bop != null) + { + switch (bop.Op) + { + case BinaryOperator.Opcode.And: + traverse(depth, args[0], act); + traverse(depth, args[1], act); + return; + case BinaryOperator.Opcode.Imp: + traverse(depth, args[1], e1 => act(withType(nary, + new NAryExpr(e1.tok, fun, new List<Expr>() { args[0], e1 })))); + return; + } + } + if (depth > 0 && call != null && call.Func != null) + { + Function cf = call.Func; + Expr body = cf.Body; + List<Variable> ins = cf.InParams; + if (body == null && cf.DefinitionAxiom != null) + { + ForallExpr all = cf.DefinitionAxiom.Expr as ForallExpr; + if (all != null) + { + NAryExpr def = all.Body as NAryExpr; + if (def != null && def.Fun is BinaryOperator && ((BinaryOperator) (def.Fun)).Op == BinaryOperator.Opcode.Iff) + { + body = def.Args[1]; + ins = all.Dummies; + } + } + } + if (body != null) + { + Func<Expr,Expr> new_f = e1 => + { + Function f = new Function(cf.tok, "expand<" + cf.Name + ">", cf.TypeParameters, ins, cf.OutParams[0], cf.Comment); + f.Body = e1; + Token tok = new Token(e1.tok.line, e1.tok.col); + tok.filename = e.tok.filename + "(" + e.tok.line + "," + e.tok.col + ") --> " + e1.tok.filename; + return withType(nary, new NAryExpr(tok, new FunctionCall(f), args)); + }; + traverse(depth - 1, body, e1 => act(new_f(e1))); + return; + } + } + } + act(e); + }; + + if (a != null) + { + var attr = a.Attributes; + if (ar != null && ar.Requires.Attributes != null) attr = ar.Requires.Attributes; + if (ar != null && ar.Call.Attributes != null) attr = ar.Call.Attributes; + if (ae != null && ae.Ensures.Attributes != null) attr = ae.Ensures.Attributes; + if (QKeyValue.FindExprAttribute(attr, "expand") != null || QKeyValue.FindBoolAttribute(attr, "expand")) + { + int depth = QKeyValue.FindIntAttribute(attr, "expand", 100); + Func<Expr,Expr> fe = e => Expr.Or(a.Expr, e); + //traverse(depth, a.Expr, e => System.Console.WriteLine(e.GetType() + " :: " + e + " @ " + e.tok.line + ", " + e.tok.col)); + traverse(depth, a.Expr, e => + { + AssertCmd new_c = + (ar != null) ? new AssertRequiresCmd(ar.Call, new Requires(e.tok, ar.Requires.Free, fe(e), ar.Requires.Comment)) : + (ae != null) ? new AssertEnsuresCmd(new Ensures(e.tok, ae.Ensures.Free, fe(e), ae.Ensures.Comment)) : + (ai != null) ? new LoopInitAssertCmd(e.tok, fe(e)) : + (am != null) ? new LoopInvMaintainedAssertCmd(e.tok, fe(e)) : + new AssertCmd(e.tok, fe(e)); + new_c.Attributes = new QKeyValue(e.tok, "subsumption", new List<object>() { new LiteralExpr(e.tok, BigNum.FromInt(0)) }, a.Attributes); + newCmds.Add(new_c); + }); + } + newCmds.Add(c); + changed = true; + } + else + { + newCmds.Add(c); + } + } + if (changed) b.Cmds = newCmds; + } + + double max_vc_cost = CommandLineOptions.Clo.VcsMaxCost; + int tmp_max_vc_cost = -1, max_splits = CommandLineOptions.Clo.VcsMaxSplits, + max_kg_splits = CommandLineOptions.Clo.VcsMaxKeepGoingSplits; + CheckIntAttributeOnImpl(impl, "vcs_max_cost", ref tmp_max_vc_cost); + CheckIntAttributeOnImpl(impl, "vcs_max_splits", ref max_splits); + CheckIntAttributeOnImpl(impl, "vcs_max_keep_going_splits", ref max_kg_splits); + if (tmp_max_vc_cost >= 0) { + max_vc_cost = tmp_max_vc_cost; + } + + Outcome outcome = Outcome.Correct; + + // Report all recycled failing assertions for this implementation. + if (impl.RecycledFailingAssertions != null && impl.RecycledFailingAssertions.Any()) + { + outcome = Outcome.Errors; + foreach (var a in impl.RecycledFailingAssertions) + { + var checksum = a.Checksum; + var oldCex = impl.ErrorChecksumToCachedError[checksum] as Counterexample; + if (oldCex != null) { + if (CommandLineOptions.Clo.VerifySnapshots < 3) { + callback.OnCounterexample(oldCex, null); + } else { + // If possible, we use the old counterexample, but with the location information of "a" + var cex = AssertCmdToCloneCounterexample(a, oldCex); + callback.OnCounterexample(cex, null); + // OnCounterexample may have had side effects on the RequestId and OriginalRequestId fields. We make + // any such updates available in oldCex. (Is this really a good design? --KRML) + oldCex.RequestId = cex.RequestId; + oldCex.OriginalRequestId = cex.OriginalRequestId; + } + } + } + } + + Cores = CommandLineOptions.Clo.VcsCores; + Stack<Split> work = new Stack<Split>(); + List<Split> currently_running = new List<Split>(); + ResetPredecessors(impl.Blocks); + List<Split> manual_splits = Split.FindManualSplits(impl, gotoCmdOrigins, this); + if (manual_splits != null) { + foreach (var split in manual_splits) { + work.Push(split); + } + } else { + work.Push(new Split(impl.Blocks, gotoCmdOrigins, this, impl)); + } + + bool keep_going = max_kg_splits > 1; + int total = 0; + int no = max_splits == 1 && !keep_going ? -1 : 0; + bool first_round = true; + bool do_splitting = keep_going || max_splits > 1; + double remaining_cost = 0.0, proven_cost = 0.0; + + if (do_splitting) { + remaining_cost = work.Peek().Cost; + } + + while (work.Any() || currently_running.Any()) + { + bool prover_failed = false; + Split s = null; + var isWaiting = !work.Any(); + + if (!isWaiting) + { + s = work.Peek(); + + if (first_round && max_splits > 1) + { + prover_failed = true; + remaining_cost -= s.Cost; + } + else + { + var timeout = (keep_going && s.LastChance) ? CommandLineOptions.Clo.VcsFinalAssertTimeout : + keep_going ? CommandLineOptions.Clo.VcsKeepGoingTimeout : + impl.TimeLimit; + + var checker = s.parent.FindCheckerFor(timeout, false); + try + { + if (checker == null) + { + isWaiting = true; + goto waiting; + } + else + { + s = work.Pop(); + } + + if (CommandLineOptions.Clo.Trace && no >= 0) + { + System.Console.WriteLine(" checking split {1}/{2}, {3:0.00}%, {0} ...", + s.Stats, no + 1, total, 100 * proven_cost / (proven_cost + remaining_cost)); + } + callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost)); + + Contract.Assert(s.parent == this); + lock (checker) + { + s.BeginCheck(checker, callback, mvInfo, no, timeout); + } + + no++; + + currently_running.Add(s); + } + catch (Exception) + { + checker.GoBackToIdle(); + throw; + } + } + } + + waiting: + if (isWaiting) + { + // Wait for one split to terminate. + var tasks = currently_running.Select(splt => splt.ProverTask).ToArray(); + + if (tasks.Any()) + { + try + { + int index = Task.WaitAny(tasks); + s = currently_running[index]; + currently_running.RemoveAt(index); + + if (do_splitting) + { + remaining_cost -= s.Cost; + } + + lock (s.Checker) + { + s.ReadOutcome(ref outcome, out prover_failed); + } + + if (do_splitting) + { + if (prover_failed) + { + // even if the prover fails, we have learned something, i.e., it is + // annoying to watch Boogie say Timeout, 0.00% a couple of times + proven_cost += s.Cost / 100; + } + else + { + proven_cost += s.Cost; + } + } + callback.OnProgress("VCprove", no < 0 ? 0 : no, total, proven_cost / (remaining_cost + proven_cost)); + + if (prover_failed && !first_round && s.LastChance) + { + string msg = "some timeout"; + if (s.reporter != null && s.reporter.resourceExceededMessage != null) + { + msg = s.reporter.resourceExceededMessage; + } + callback.OnCounterexample(s.ToCounterexample(s.Checker.TheoremProver.Context), msg); + outcome = Outcome.Errors; + break; + } + } + finally + { + s.Checker.GoBackToIdle(); + } + + Contract.Assert(prover_failed || outcome == Outcome.Correct || outcome == Outcome.Errors || outcome == Outcome.Inconclusive); + } + } + + if (prover_failed) + { + int splits = first_round && max_splits > 1 ? max_splits : max_kg_splits; + + if (splits > 1) + { + List<Split> tmp = Split.DoSplit(s, max_vc_cost, splits); + Contract.Assert(tmp != null); + max_vc_cost = 1.0; // for future + first_round = false; + //tmp.Sort(new Comparison<Split!>(Split.Compare)); + foreach (Split a in tmp) + { + Contract.Assert(a != null); + work.Push(a); + total++; + remaining_cost += a.Cost; + } + if (outcome != Outcome.Errors) + { + outcome = Outcome.Correct; + } + } + else + { + Contract.Assert(outcome != Outcome.Correct); + if (outcome == Outcome.TimedOut) + { + string msg = "some timeout"; + if (s.reporter != null && s.reporter.resourceExceededMessage != null) + { + msg = s.reporter.resourceExceededMessage; + } + callback.OnTimeout(msg); + } + else if (outcome == Outcome.OutOfMemory) + { + string msg = "out of memory"; + if (s.reporter != null && s.reporter.resourceExceededMessage != null) + { + msg = s.reporter.resourceExceededMessage; + } + callback.OnOutOfMemory(msg); + } + + break; + } + } + } + + if (outcome == Outcome.Correct && smoke_tester != null) { + smoke_tester.Test(); + } + + callback.OnProgress("done", 0, 0, 1.0); + + if (_print_time) + { + watch.Stop(); + Console.WriteLine("Total time for this method: {0}", watch.Elapsed.ToString()); + } + + return outcome; + } + + public class ErrorReporter : ProverInterface.ErrorHandler { + Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins; + Dictionary<int, Absy>/*!*/ label2absy; + List<Block/*!*/>/*!*/ blocks; + protected Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap; + protected VerifierCallback/*!*/ callback; + protected ModelViewInfo MvInfo; + internal string resourceExceededMessage; + static System.IO.TextWriter modelWriter; + [ContractInvariantMethod] + void ObjectInvariant() { + Contract.Invariant(gotoCmdOrigins != null); + Contract.Invariant(label2absy != null); + Contract.Invariant(cce.NonNullElements(blocks)); + Contract.Invariant(cce.NonNullDictionaryAndValues(incarnationOriginMap)); + Contract.Invariant(callback != null); + Contract.Invariant(context != null); + Contract.Invariant(program != null); + } + + + public static TextWriter ModelWriter { + get { + Contract.Ensures(Contract.Result<TextWriter>() != null); + + if (ErrorReporter.modelWriter == null) + ErrorReporter.modelWriter = CommandLineOptions.Clo.PrintErrorModelFile == null ? Console.Out : new StreamWriter(CommandLineOptions.Clo.PrintErrorModelFile, false); + return ErrorReporter.modelWriter; + } + } + + protected ProverContext/*!*/ context; + Program/*!*/ program; + + public ErrorReporter(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, + Dictionary<int, Absy>/*!*/ label2absy, + List<Block/*!*/>/*!*/ blocks, + Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap, + VerifierCallback/*!*/ callback, + ModelViewInfo mvInfo, + ProverContext/*!*/ context, + Program/*!*/ program) { + Contract.Requires(gotoCmdOrigins != null); + Contract.Requires(label2absy != null); + Contract.Requires(cce.NonNullElements(blocks)); + Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap)); + Contract.Requires(callback != null); + Contract.Requires(context!=null); + Contract.Requires(program!=null); + this.gotoCmdOrigins = gotoCmdOrigins; + this.label2absy = label2absy; + this.blocks = blocks; + this.incarnationOriginMap = incarnationOriginMap; + this.callback = callback; + this.MvInfo = mvInfo; + + this.context = context; + this.program = program; + } + + public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) { + //Contract.Requires(cce.NonNullElements(labels)); + if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) { + if (VC.ConditionGeneration.errorModelList != null) + { + VC.ConditionGeneration.errorModelList.Add(model); + } + + model.Write(ErrorReporter.ModelWriter); + ErrorReporter.ModelWriter.Flush(); + } + + Hashtable traceNodes = new Hashtable(); + foreach (string s in labels) { + Contract.Assert(s != null); + Absy absy = Label2Absy(s); + Contract.Assert(absy != null); + if (traceNodes.ContainsKey(absy)) + System.Console.WriteLine("Warning: duplicate label: " + s + " read while tracing nodes"); + else + traceNodes.Add(absy, null); + } + + List<Block> trace = new List<Block>(); + Block entryBlock = cce.NonNull(this.blocks[0]); + Contract.Assert(traceNodes.Contains(entryBlock)); + trace.Add(entryBlock); + + Counterexample newCounterexample = TraceCounterexample(entryBlock, traceNodes, trace, model, MvInfo, incarnationOriginMap, context, new Dictionary<TraceLocation, CalleeCounterexampleInfo>()); + + if (newCounterexample == null) + return; + + #region Map passive program errors back to original program errors + ReturnCounterexample returnExample = newCounterexample as ReturnCounterexample; + if (returnExample != null) { + foreach (Block b in returnExample.Trace) { + Contract.Assert(b != null); + Contract.Assume(b.TransferCmd != null); + ReturnCmd cmd = gotoCmdOrigins.ContainsKey(b.TransferCmd) ? gotoCmdOrigins[b.TransferCmd] : null; + if (cmd != null) { + returnExample.FailingReturn = cmd; + break; + } + } + } + #endregion + callback.OnCounterexample(newCounterexample, null); + } + + public override Absy Label2Absy(string label) { + //Contract.Requires(label != null); + Contract.Ensures(Contract.Result<Absy>() != null); + + int id = int.Parse(label); + return cce.NonNull((Absy)label2absy[id]); + } + + public override void OnResourceExceeded(string msg, IEnumerable<Tuple<AssertCmd, TransferCmd>> assertCmds = null) { + //Contract.Requires(msg != null); + resourceExceededMessage = msg; + if (assertCmds != null) + { + foreach (var cmd in assertCmds) + { + Counterexample cex = AssertCmdToCounterexample(cmd.Item1, cmd.Item2 , new List<Block>(), null, null, context); + callback.OnCounterexample(cex, msg); + } + } + } + + public override void OnProverWarning(string msg) { + //Contract.Requires(msg != null); + callback.OnWarning(msg); + } + } + + public class ErrorReporterLocal : ErrorReporter { + public ErrorReporterLocal(Dictionary<TransferCmd, ReturnCmd>/*!*/ gotoCmdOrigins, + Dictionary<int, Absy>/*!*/ label2absy, + List<Block/*!*/>/*!*/ blocks, + Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap, + VerifierCallback/*!*/ callback, + ModelViewInfo mvInfo, + ProverContext/*!*/ context, + Program/*!*/ program) + : base(gotoCmdOrigins, label2absy, blocks, incarnationOriginMap, callback, mvInfo, context, program) // here for aesthetic purposes //TODO: Maybe nix? + { + Contract.Requires(gotoCmdOrigins != null); + Contract.Requires(label2absy != null); + Contract.Requires(cce.NonNullElements(blocks)); + Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap)); + Contract.Requires(callback != null); + Contract.Requires(context != null); + Contract.Requires(program != null); + } + + public override void OnModel(IList<string/*!*/>/*!*/ labels, Model model, ProverInterface.Outcome proverOutcome) { + //Contract.Requires(cce.NonNullElements(labels)); + // We ignore the error model here for enhanced error message purposes. + // It is only printed to the command line. + if (CommandLineOptions.Clo.PrintErrorModel >= 1 && model != null) { + if (CommandLineOptions.Clo.PrintErrorModelFile != null) { + model.Write(ErrorReporter.ModelWriter); + ErrorReporter.ModelWriter.Flush(); + } + } + List<Block> traceNodes = new List<Block>(); + List<AssertCmd> assertNodes = new List<AssertCmd>(); + foreach (string s in labels) { + Contract.Assert(s != null); + Absy node = Label2Absy(s); + if (node is Block) { + Block b = (Block)node; + traceNodes.Add(b); + } else { + AssertCmd a = (AssertCmd)node; + assertNodes.Add(a); + } + } + Contract.Assert(assertNodes.Count > 0); + Contract.Assert(traceNodes.Count == assertNodes.Count); + + foreach (AssertCmd a in assertNodes) { + // find the corresponding Block (assertNodes.Count is likely to be 1, or small in any case, so just do a linear search here) + foreach (Block b in traceNodes) { + if (b.Cmds.Contains(a)) { + List<Block> trace = new List<Block>(); + trace.Add(b); + Counterexample newCounterexample = AssertCmdToCounterexample(a, cce.NonNull(b.TransferCmd), trace, model, MvInfo, context); + callback.OnCounterexample(newCounterexample, null); + goto NEXT_ASSERT; + } + } + Contract.Assert(false); + throw new cce.UnreachableException(); // there was no block that contains the assert + NEXT_ASSERT: { + } + } + } + } + + private void RecordCutEdge(Dictionary<Block,List<Block>> edgesCut, Block from, Block to){ + if (edgesCut != null) + { + if (!edgesCut.ContainsKey(from)) + edgesCut.Add(from, new List<Block>()); + edgesCut[from].Add(to); + } + } + + public void ConvertCFG2DAG(Implementation impl, Dictionary<Block,List<Block>> edgesCut = null, int taskID = -1) + { + Contract.Requires(impl != null); + impl.PruneUnreachableBlocks(); // This is needed for VCVariety.BlockNested, and is otherwise just an optimization + + CurrentLocalVariables = impl.LocVars; + variable2SequenceNumber = new Dictionary<Variable, int>(); + incarnationOriginMap = new Dictionary<Incarnation, Absy>(); + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("original implementation"); + EmitImpl(impl, false); + } + #endregion + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("after desugaring sugared commands like procedure calls"); + EmitImpl(impl, true); + } + #endregion + + // Recompute the predecessors, but first insert a dummy start node that is sure not to be the target of any goto (because the cutting of back edges + // below assumes that the start node has no predecessor) + impl.Blocks.Insert(0, new Block(new Token(-17, -4), "0", new List<Cmd>(), new GotoCmd(Token.NoToken, new List<String> { impl.Blocks[0].Label }, new List<Block> { impl.Blocks[0] }))); + ResetPredecessors(impl.Blocks); + + if(CommandLineOptions.Clo.KInductionDepth < 0) { + ConvertCFG2DAGStandard(impl, edgesCut, taskID); + } else { + ConvertCFG2DAGKInduction(impl, edgesCut, taskID); + } + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("after conversion into a DAG"); + EmitImpl(impl, true); + } + #endregion + } + + private void ConvertCFG2DAGStandard(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID) + { + #region Convert program CFG into a DAG + + #region Use the graph library to figure out where the (natural) loops are + + #region Create the graph by adding the source node and each edge + Graph<Block> g = Program.GraphFromImpl(impl); + #endregion + + //Graph<Block> g = program.ProcessLoops(impl); + + g.ComputeLoops(); // this is the call that does all of the processing + if (!g.Reducible) + { + throw new VCGenException("Irreducible flow graphs are unsupported."); + } + + #endregion + + #region Cut the backedges, push assert/assume statements from loop header into predecessors, change them all into assume statements at top of loop, introduce havoc statements + foreach (Block header in cce.NonNull(g.Headers)) + { + Contract.Assert(header != null); + IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>(); + foreach (Block b in cce.NonNull(g.BackEdgeNodes(header))) + { + Contract.Assert(b != null); + backEdgeNodes.Add(b, null); + } + + #region Find the (possibly empty) prefix of assert commands in the header, replace each assert with an assume of the same condition + List<Cmd> prefixOfPredicateCmdsInit = new List<Cmd>(); + List<Cmd> prefixOfPredicateCmdsMaintained = new List<Cmd>(); + for (int i = 0, n = header.Cmds.Count; i < n; i++) + { + PredicateCmd a = header.Cmds[i] as PredicateCmd; + if (a != null) + { + if (a is AssertCmd) + { + AssertCmd c = (AssertCmd)a; + AssertCmd b = null; + + if (CommandLineOptions.Clo.ConcurrentHoudini) + { + Contract.Assert(taskID >= 0); + if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvEntryAssert) + b = new LoopInitAssertCmd(c.tok, Expr.True); + else + b = new LoopInitAssertCmd(c.tok, c.Expr); + } + else + { + b = new LoopInitAssertCmd(c.tok, c.Expr); + } + + b.Attributes = c.Attributes; + b.ErrorData = c.ErrorData; + prefixOfPredicateCmdsInit.Add(b); + + if (CommandLineOptions.Clo.ConcurrentHoudini) + { + Contract.Assert(taskID >= 0); + if (CommandLineOptions.Clo.Cho[taskID].DisableLoopInvMaintainedAssert) + b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, Expr.True); + else + b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr); + } + else + { + b = new Bpl.LoopInvMaintainedAssertCmd(c.tok, c.Expr); + } + + b.Attributes = c.Attributes; + b.ErrorData = c.ErrorData; + prefixOfPredicateCmdsMaintained.Add(b); + header.Cmds[i] = new AssumeCmd(c.tok, c.Expr); + } + else + { + Contract.Assert(a is AssumeCmd); + if (Bpl.CommandLineOptions.Clo.AlwaysAssumeFreeLoopInvariants) + { + // Usually, "free" stuff, like free loop invariants (and the assume statements + // that stand for such loop invariants) are ignored on the checking side. This + // command-line option changes that behavior to always assume the conditions. + prefixOfPredicateCmdsInit.Add(a); + prefixOfPredicateCmdsMaintained.Add(a); + } + } + } + else if (header.Cmds[i] is CommentCmd) + { + // ignore + } + else + { + break; // stop when an assignment statement (or any other non-predicate cmd) is encountered + } + } + #endregion + + #region Copy the prefix of predicate commands into each predecessor. Do this *before* cutting the backedge!! + for (int predIndex = 0, n = header.Predecessors.Count; predIndex < n; predIndex++) + { + Block pred = cce.NonNull(header.Predecessors[predIndex]); + + // Create a block between header and pred for the predicate commands if pred has more than one successor + GotoCmd gotocmd = cce.NonNull((GotoCmd)pred.TransferCmd); + Contract.Assert(gotocmd.labelNames != null); // if "pred" is really a predecessor, it may be a GotoCmd with at least one label + if (gotocmd.labelNames.Count > 1) + { + Block newBlock = CreateBlockBetween(predIndex, header); + impl.Blocks.Add(newBlock); + + // if pred is a back edge node, then now newBlock is the back edge node + if (backEdgeNodes.ContainsKey(pred)) + { + backEdgeNodes.Remove(pred); + backEdgeNodes.Add(newBlock, null); + } + + pred = newBlock; + } + // Add the predicate commands + if (backEdgeNodes.ContainsKey(pred)) + { + pred.Cmds.AddRange(prefixOfPredicateCmdsMaintained); + } + else + { + pred.Cmds.AddRange(prefixOfPredicateCmdsInit); + } + } + #endregion + + #region Cut the back edge + foreach (Block backEdgeNode in cce.NonNull(backEdgeNodes.Keys)) + { + Contract.Assert(backEdgeNode != null); + Debug.Assert(backEdgeNode.TransferCmd is GotoCmd, "An node was identified as the source for a backedge, but it does not have a goto command."); + GotoCmd gtc = backEdgeNode.TransferCmd as GotoCmd; + if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count > 1) + { + // then remove the backedge by removing the target block from the list of gotos + List<Block> remainingTargets = new List<Block>(); + List<String> remainingLabels = new List<String>(); + Contract.Assume(gtc.labelNames != null); + for (int i = 0, n = gtc.labelTargets.Count; i < n; i++) + { + if (gtc.labelTargets[i] != header) + { + remainingTargets.Add(gtc.labelTargets[i]); + remainingLabels.Add(gtc.labelNames[i]); + } + else + RecordCutEdge(edgesCut, backEdgeNode, header); + } + gtc.labelTargets = remainingTargets; + gtc.labelNames = remainingLabels; + } + else + { + // This backedge is the only out-going edge from this node. + // Add an "assume false" statement to the end of the statements + // inside of the block and change the goto command to a return command. + AssumeCmd ac = new AssumeCmd(Token.NoToken, Expr.False); + backEdgeNode.Cmds.Add(ac); + backEdgeNode.TransferCmd = new ReturnCmd(Token.NoToken); + if (gtc != null && gtc.labelTargets != null && gtc.labelTargets.Count == 1) + RecordCutEdge(edgesCut, backEdgeNode, gtc.labelTargets[0]); + } + #region Remove the backedge node from the list of predecessor nodes in the header + List<Block> newPreds = new List<Block>(); + foreach (Block p in header.Predecessors) + { + if (p != backEdgeNode) + newPreds.Add(p); + } + header.Predecessors = newPreds; + #endregion + } + #endregion + + #region Collect all variables that are assigned to in all of the natural loops for which this is the header + List<Variable> varsToHavoc = VarsAssignedInLoop(g, header); + List<IdentifierExpr> havocExprs = new List<IdentifierExpr>(); + foreach (Variable v in varsToHavoc) + { + Contract.Assert(v != null); + IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v); + if (!havocExprs.Contains(ie)) + havocExprs.Add(ie); + } + // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct + // the source location for this later on + HavocCmd hc = new HavocCmd(header.tok, havocExprs); + List<Cmd> newCmds = new List<Cmd>(); + newCmds.Add(hc); + foreach (Cmd c in header.Cmds) + { + newCmds.Add(c); + } + header.Cmds = newCmds; + #endregion + } + #endregion + #endregion Convert program CFG into a DAG + } + + public static List<Variable> VarsAssignedInLoop(Graph<Block> g, Block header) + { + List<Variable> varsToHavoc = new List<Variable>(); + foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header))) + { + Contract.Assert(backEdgeNode != null); + foreach (Block b in g.NaturalLoops(header, backEdgeNode)) + { + Contract.Assert(b != null); + foreach (Cmd c in b.Cmds) + { + Contract.Assert(c != null); + c.AddAssignedVariables(varsToHavoc); + } + } + } + return varsToHavoc; + } + + public static IEnumerable<Variable> VarsReferencedInLoop(Graph<Block> g, Block header) + { + HashSet<Variable> referencedVars = new HashSet<Variable>(); + foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header))) + { + Contract.Assert(backEdgeNode != null); + foreach (Block b in g.NaturalLoops(header, backEdgeNode)) + { + Contract.Assert(b != null); + foreach (Cmd c in b.Cmds) + { + Contract.Assert(c != null); + var Collector = new VariableCollector(); + Collector.Visit(c); + foreach(var v in Collector.usedVars) { + referencedVars.Add(v); + } + } + } + } + return referencedVars; + } + + private void ConvertCFG2DAGKInduction(Implementation impl, Dictionary<Block, List<Block>> edgesCut, int taskID) { + + // K-induction has not been adapted to be aware of these parameters which standard CFG to DAG transformation uses + Contract.Requires(edgesCut == null); + Contract.Requires(taskID == -1); + + int inductionK = CommandLineOptions.Clo.KInductionDepth; + Contract.Assume(inductionK >= 0); + + bool contRuleApplication = true; + while (contRuleApplication) { + contRuleApplication = false; + + #region Use the graph library to figure out where the (natural) loops are + + #region Create the graph by adding the source node and each edge + Graph<Block> g = Program.GraphFromImpl(impl); + #endregion + + g.ComputeLoops(); // this is the call that does all of the processing + if (!g.Reducible) { + throw new VCGenException("Irreducible flow graphs are unsupported."); + } + + #endregion + + foreach (Block header in cce.NonNull(g.Headers)) { + Contract.Assert(header != null); + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("Applying k-induction rule with k=" + inductionK); + } + #endregion + + #region generate the step case + Block newHeader = DuplicateLoop(impl, g, header, null, + false, false, "_step_assertion"); + for (int i = 0; i < inductionK; ++i) + { + newHeader = DuplicateLoop(impl, g, header, newHeader, + true, true, + "_step_" + (inductionK - i)); + } + #endregion + + #region havoc variables that can be assigned in the loop + + List<Variable> varsToHavoc = VarsAssignedInLoop(g, header); + List<IdentifierExpr> havocExprs = new List<IdentifierExpr>(); + foreach (Variable v in varsToHavoc) + { + Contract.Assert(v != null); + IdentifierExpr ie = new IdentifierExpr(Token.NoToken, v); + if (!havocExprs.Contains(ie)) + havocExprs.Add(ie); + } + // pass the token of the enclosing loop header to the HavocCmd so we can reconstruct + // the source location for this later on + HavocCmd hc = new HavocCmd(newHeader.tok, havocExprs); + List<Cmd> havocCmds = new List<Cmd>(); + havocCmds.Add(hc); + + Block havocBlock = new Block(newHeader.tok, newHeader.Label + "_havoc", havocCmds, + new GotoCmd (newHeader.tok, new List<Block> { newHeader })); + + impl.Blocks.Add(havocBlock); + newHeader.Predecessors.Add(havocBlock); + newHeader = havocBlock; + + #endregion + + #region generate the base case loop copies + for (int i = 0; i < inductionK; ++i) + { + newHeader = DuplicateLoop(impl, g, header, newHeader, + false, false, + "_base_" + (inductionK - i)); + } + #endregion + + #region redirect into the new loop copies and remove the original loop (but don't redirect back-edges) + + IDictionary<Block, object> backEdgeNodes = new Dictionary<Block, object>(); + foreach (Block b in cce.NonNull(g.BackEdgeNodes(header))) { Contract.Assert(b != null); backEdgeNodes.Add(b, null); } + + for (int predIndex = 0, n = header.Predecessors.Count(); predIndex < n; predIndex++) + { + Block pred = cce.NonNull(header.Predecessors[predIndex]); + if (!backEdgeNodes.ContainsKey(pred)) + { + GotoCmd gc = pred.TransferCmd as GotoCmd; + Contract.Assert(gc != null); + for (int i = 0; i < gc.labelTargets.Count(); ++i) + { + if (gc.labelTargets[i] == header) + { + gc.labelTargets[i] = newHeader; + gc.labelNames[i] = newHeader.Label; + newHeader.Predecessors.Add(pred); + } + } + } + } + impl.PruneUnreachableBlocks(); + + #endregion + + contRuleApplication = true; + break; + } + + } + + ResetPredecessors(impl.Blocks); + impl.FreshenCaptureStates(); + + } + + private Block DuplicateLoop(Implementation impl, Graph<Block> g, + Block header, Block nextHeader, bool cutExits, + bool toAssumptions, string suffix) + { + IDictionary<Block, Block> ori2CopiedBlocks = new Dictionary<Block, Block>(); + Duplicator duplicator = new Duplicator(); + + #region create copies of all blocks in the loop + foreach (Block backEdgeNode in cce.NonNull(g.BackEdgeNodes(header))) + { + Contract.Assert(backEdgeNode != null); + foreach (Block b in g.NaturalLoops(header, backEdgeNode)) + { + Contract.Assert(b != null); + if (!ori2CopiedBlocks.ContainsKey(b)) + { + Block copy = (Block)duplicator.Visit(b); + copy.Cmds = new List<Cmd>(copy.Cmds); // Philipp Ruemmer commented that this was necessary due to a bug in the Duplicator. That was a long time; worth checking whether this has been fixed + copy.Predecessors = new List<Block>(); + copy.Label = copy.Label + suffix; + + #region turn asserts into assumptions + if (toAssumptions) + { + for (int i = 0; i < copy.Cmds.Count(); ++i) + { + AssertCmd ac = copy.Cmds[i] as AssertCmd; + if (ac != null) + { + copy.Cmds[i] = new AssumeCmd(ac.tok, ac.Expr); + } + } + } + #endregion + + impl.Blocks.Add(copy); + ori2CopiedBlocks.Add(b, copy); + } + } + } + #endregion + + #region adjust the transfer commands of the newly created blocks + foreach (KeyValuePair<Block, Block> pair in ori2CopiedBlocks) + { + Block copy = pair.Value; + GotoCmd gc = copy.TransferCmd as GotoCmd; + if (gc != null) + { + List<Block> newTargets = new List<Block>(); + List<string> newLabels = new List<string>(); + + for (int i = 0; i < gc.labelTargets.Count(); ++i) + { + Block newTarget; + if (gc.labelTargets[i] == header) + { + if (nextHeader != null) + { + newTargets.Add(nextHeader); + newLabels.Add(nextHeader.Label); + nextHeader.Predecessors.Add(copy); + } + } + else if (ori2CopiedBlocks.TryGetValue(gc.labelTargets[i], out newTarget)) + { + newTargets.Add(newTarget); + newLabels.Add(newTarget.Label); + newTarget.Predecessors.Add(copy); + } + else if (!cutExits) + { + newTargets.Add(gc.labelTargets[i]); + newLabels.Add(gc.labelNames[i]); + gc.labelTargets[i].Predecessors.Add(copy); + } + } + + if (newTargets.Count() == 0) + { + // if no targets are left, we assume false and return + copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); + copy.TransferCmd = new ReturnCmd(Token.NoToken); + } + else + { + copy.TransferCmd = new GotoCmd(gc.tok, newLabels, newTargets); + } + } + else if (cutExits && (copy.TransferCmd is ReturnCmd)) + { + // because return is a kind of exit from the loop, we + // assume false to cut this path + copy.Cmds.Add(new AssumeCmd(Token.NoToken, Expr.False)); + } + } + #endregion + + return ori2CopiedBlocks[header]; + } + + public void DesugarCalls(Implementation impl) { + foreach (Block block in impl.Blocks) { + List<Cmd> newCmds = new List<Cmd>(); + foreach (Cmd cmd in block.Cmds) { + SugaredCmd sugaredCmd = cmd as SugaredCmd; + if (sugaredCmd != null) { + StateCmd stateCmd = sugaredCmd.Desugaring as StateCmd; + foreach (Variable v in stateCmd.Locals) { + impl.LocVars.Add(v); + } + newCmds.AddRange(stateCmd.Cmds); + } + else { + newCmds.Add(cmd); + } + } + block.Cmds = newCmds; + } + } + + public Dictionary<TransferCmd, ReturnCmd> PassifyImpl(Implementation impl, out ModelViewInfo mvInfo) + { + Contract.Requires(impl != null); + Contract.Requires(program != null); + Contract.Ensures(Contract.Result<Dictionary<TransferCmd, ReturnCmd>>() != null); + + Dictionary<TransferCmd, ReturnCmd> gotoCmdOrigins = new Dictionary<TransferCmd, ReturnCmd>(); + Block exitBlock = GenerateUnifiedExit(impl, gotoCmdOrigins); + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("after creating a unified exit block"); + EmitImpl(impl, true); + } + #endregion + + #region Insert pre- and post-conditions and where clauses as assume and assert statements + { + List<Cmd> cc = new List<Cmd>(); + // where clauses of global variables + lock (program.TopLevelDeclarations) + { + foreach (var gvar in program.GlobalVariables) + { + if (gvar != null && gvar.TypedIdent.WhereExpr != null) + { + Cmd c = new AssumeCmd(gvar.tok, gvar.TypedIdent.WhereExpr); + cc.Add(c); + } + } + } + // where clauses of in- and out-parameters + cc.AddRange(GetParamWhereClauses(impl)); + // where clauses of local variables + foreach (Variable lvar in impl.LocVars) {Contract.Assert(lvar != null); + if (lvar.TypedIdent.WhereExpr != null) { + Cmd c = new AssumeCmd(lvar.tok, lvar.TypedIdent.WhereExpr); + cc.Add(c); + } else if (QKeyValue.FindBoolAttribute(lvar.Attributes, "assumption")) { + cc.Add(new AssumeCmd(lvar.tok, new IdentifierExpr(lvar.tok, lvar), new QKeyValue(lvar.tok, "assumption_variable_initialization", new List<object>(), null))); + } + } + // add cc and the preconditions to new blocks preceding impl.Blocks[0] + InjectPreconditions(impl, cc); + + // append postconditions, starting in exitBlock and continuing into other blocks, if needed + InjectPostConditions(impl, exitBlock, gotoCmdOrigins); + } + #endregion + + #region Support for stratified inlining + addExitAssert(impl.Name, exitBlock); + #endregion + + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("after inserting pre- and post-conditions"); + EmitImpl(impl, true); + } + #endregion + + AddBlocksBetween(impl.Blocks); + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("after adding empty blocks as needed to catch join assumptions"); + EmitImpl(impl, true); + } + #endregion + + if (CommandLineOptions.Clo.LiveVariableAnalysis > 0) { + Microsoft.Boogie.LiveVariableAnalysis.ComputeLiveVariables(impl); + } + + mvInfo = new ModelViewInfo(program, impl); + Convert2PassiveCmd(impl, mvInfo); + + #region Peep-hole optimizations + if (CommandLineOptions.Clo.RemoveEmptyBlocks){ + #region Get rid of empty blocks + { + RemoveEmptyBlocksIterative(impl.Blocks); + impl.PruneUnreachableBlocks(); + } + #endregion Get rid of empty blocks + + #region Debug Tracing + if (CommandLineOptions.Clo.TraceVerify) + { + Console.WriteLine("after peep-hole optimizations"); + EmitImpl(impl, true); + } + #endregion + } + #endregion Peep-hole optimizations + + HandleSelectiveChecking(impl); + + +// #region Constant Folding +// #endregion +// #region Debug Tracing +// if (CommandLineOptions.Clo.TraceVerify) +// { +// Console.WriteLine("after constant folding"); +// EmitImpl(impl, true); +// } +// #endregion + + return gotoCmdOrigins; + } + + private static void HandleSelectiveChecking(Implementation impl) + { + if (QKeyValue.FindBoolAttribute(impl.Attributes, "selective_checking") || + QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "selective_checking")) { + + var startPoints = new List<Block>(); + foreach (var b in impl.Blocks) { + foreach (Cmd c in b.Cmds) { + var p = c as PredicateCmd; + if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here")) { + startPoints.Add(b); + break; + } + } + } + + // Compute the set of blocks reachable from blocks containing "start_checking_here" + var blocksToCheck = new HashSet<Block>(); + foreach (var b in startPoints) { + var todo = new Stack<Block>(); + var wasThere = blocksToCheck.Contains(b); + todo.Push(b); + while (todo.Count > 0) { + var x = todo.Pop(); + if (blocksToCheck.Contains(x)) continue; + blocksToCheck.Add(x); + var ex = x.TransferCmd as GotoCmd; + if (ex != null) + foreach (Block e in ex.labelTargets) + todo.Push(e); + } + if (!wasThere) blocksToCheck.Remove(b); + } + + // Convert asserts to assumes in "unreachable" blocks, as well as in portions of blocks before we reach "start_checking_here" + foreach (var b in impl.Blocks) { + if (blocksToCheck.Contains(b)) continue; // All reachable blocks must be checked in their entirety, so don't change anything + var newCmds = new List<Cmd>(); + var copyMode = false; + foreach (Cmd c in b.Cmds) { + var p = c as PredicateCmd; + if (p != null && QKeyValue.FindBoolAttribute(p.Attributes, "start_checking_here")) + copyMode = true; + var asrt = c as AssertCmd; + if (copyMode || asrt == null) + newCmds.Add(c); + else + newCmds.Add(AssertTurnedIntoAssume(asrt)); + } + + b.Cmds = newCmds; + } + } + } + + // Used by stratified inlining + protected virtual void addExitAssert(string implName, Block exitBlock) + { + } + + public virtual Counterexample extractLoopTrace(Counterexample cex, string mainProcName, Program program, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) + { + // Construct the set of inlined procs in the original program + var inlinedProcs = new HashSet<string>(); + foreach (var proc in program.Procedures) + { + if (!(proc is LoopProcedure)) + { + inlinedProcs.Add(proc.Name); + } + } + + return extractLoopTraceRec( + new CalleeCounterexampleInfo(cex, new List<object>()), + mainProcName, inlinedProcs, extractLoopMappingInfo).counterexample; + } + + protected CalleeCounterexampleInfo extractLoopTraceRec( + CalleeCounterexampleInfo cexInfo, string currProc, + HashSet<string> inlinedProcs, + Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) + { + Contract.Requires(currProc != null); + if (cexInfo.counterexample == null) return cexInfo; + + var cex = cexInfo.counterexample; + // Go through all blocks in the trace, map them back to blocks in the original program (if there is one) + var ret = cex.Clone(); + ret.Trace = new List<Block>(); + ret.calleeCounterexamples = new Dictionary<TraceLocation, CalleeCounterexampleInfo>(); + + for (int numBlock = 0; numBlock < cex.Trace.Count; numBlock ++ ) + { + Block block = cex.Trace[numBlock]; + var origBlock = elGetBlock(currProc, block, extractLoopMappingInfo); + if (origBlock != null) ret.Trace.Add(origBlock); + var callCnt = 1; + for (int numInstr = 0; numInstr < block.Cmds.Count; numInstr ++) { + Cmd cmd = block.Cmds[numInstr]; + var loc = new TraceLocation(numBlock, numInstr); + if (!cex.calleeCounterexamples.ContainsKey(loc)) + { + if (getCallee(cex.getTraceCmd(loc), inlinedProcs) != null) callCnt++; + continue; + } + string callee = cex.getCalledProcName(cex.getTraceCmd(loc)); + Contract.Assert(callee != null); + var calleeTrace = cex.calleeCounterexamples[loc]; + Debug.Assert(calleeTrace != null); + + var origTrace = extractLoopTraceRec(calleeTrace, callee, inlinedProcs, extractLoopMappingInfo); + + if (elIsLoop(callee)) + { + // Absorb the trace into the current trace + + int currLen = ret.Trace.Count; + ret.Trace.AddRange(origTrace.counterexample.Trace); + + foreach (var kvp in origTrace.counterexample.calleeCounterexamples) + { + var newloc = new TraceLocation(kvp.Key.numBlock + currLen, kvp.Key.numInstr); + ret.calleeCounterexamples.Add(newloc, kvp.Value); + } + + } + else + { + var origLoc = new TraceLocation(ret.Trace.Count - 1, getCallCmdPosition(origBlock, callCnt, inlinedProcs, callee)); + ret.calleeCounterexamples.Add(origLoc, origTrace); + callCnt++; + } + } + } + return new CalleeCounterexampleInfo(ret, cexInfo.args); + } + + // return the position of the i^th CallCmd in the block (count only those Calls that call a procedure in inlinedProcs). + // Assert failure if there isn't any. + // Assert that the CallCmd found calls "callee" + private int getCallCmdPosition(Block block, int i, HashSet<string> inlinedProcs, string callee) + { + Debug.Assert(i >= 1); + for (int pos = 0; pos < block.Cmds.Count; pos++) + { + Cmd cmd = block.Cmds[pos]; + string procCalled = getCallee(cmd, inlinedProcs); + + if (procCalled != null) + { + if (i == 1) + { + Debug.Assert(procCalled == callee); + return pos; + } + i--; + } + } + + Debug.Assert(false, "Didn't find the i^th call cmd"); + return -1; + } + + private string getCallee(Cmd cmd, HashSet<string> inlinedProcs) + { + string procCalled = null; + if (cmd is CallCmd) + { + var cc = (CallCmd)cmd; + if (inlinedProcs.Contains(cc.Proc.Name)) + { + procCalled = cc.Proc.Name; + } + } + + if (cmd is AssumeCmd) + { + var expr = (cmd as AssumeCmd).Expr as NAryExpr; + if (expr != null) + { + if (inlinedProcs.Contains(expr.Fun.FunctionName)) + { + procCalled = expr.Fun.FunctionName; + } + } + } + return procCalled; + } + + protected virtual bool elIsLoop(string procname) + { + return false; + } + + private Block elGetBlock(string procname, Block block, Dictionary<string, Dictionary<string, Block>> extractLoopMappingInfo) + { + Contract.Requires(procname != null); + + if (!extractLoopMappingInfo.ContainsKey(procname)) + return block; + + if (!extractLoopMappingInfo[procname].ContainsKey(block.Label)) + return null; + + return extractLoopMappingInfo[procname][block.Label]; + } + + static Counterexample TraceCounterexample( + Block/*!*/ b, Hashtable/*!*/ traceNodes, List<Block>/*!*/ trace, Model errModel, ModelViewInfo mvInfo, + Dictionary<Incarnation, Absy/*!*/>/*!*/ incarnationOriginMap, + ProverContext/*!*/ context, + Dictionary<TraceLocation/*!*/, CalleeCounterexampleInfo/*!*/>/*!*/ calleeCounterexamples) + { + Contract.Requires(b != null); + Contract.Requires(traceNodes != null); + Contract.Requires(trace != null); + Contract.Requires(cce.NonNullDictionaryAndValues(incarnationOriginMap)); + Contract.Requires(context != null); + Contract.Requires(cce.NonNullDictionaryAndValues(calleeCounterexamples)); + // After translation, all potential errors come from asserts. + + while (true) + { + List<Cmd> cmds = b.Cmds; + Contract.Assert(cmds != null); + TransferCmd transferCmd = cce.NonNull(b.TransferCmd); + for (int i = 0; i < cmds.Count; i++) + { + Cmd cmd = cce.NonNull(cmds[i]); + + // Skip if 'cmd' not contained in the trace or not an assert + if (cmd is AssertCmd && traceNodes.Contains(cmd)) + { + Counterexample newCounterexample = AssertCmdToCounterexample((AssertCmd)cmd, transferCmd, trace, errModel, mvInfo, context); + Contract.Assert(newCounterexample != null); + newCounterexample.AddCalleeCounterexample(calleeCounterexamples); + return newCounterexample; + } + } + + GotoCmd gotoCmd = transferCmd as GotoCmd; + if (gotoCmd == null) return null; + Block foundBlock = null; + foreach (Block bb in cce.NonNull(gotoCmd.labelTargets)) + { + Contract.Assert(bb != null); + if (traceNodes.Contains(bb)) + { + foundBlock = bb; + break; + } + } + if (foundBlock == null) return null; + trace.Add(foundBlock); + b = foundBlock; + } + } + + public static Counterexample AssertCmdToCounterexample(AssertCmd cmd, TransferCmd transferCmd, List<Block> trace, Model errModel, ModelViewInfo mvInfo, ProverContext context) + { + Contract.Requires(cmd != null); + Contract.Requires(transferCmd != null); + Contract.Requires(trace != null); + Contract.Requires(context != null); + Contract.Ensures(Contract.Result<Counterexample>() != null); + + List<string> relatedInformation = new List<string>(); + + // See if it is a special assert inserted in translation + if (cmd is AssertRequiresCmd) + { + AssertRequiresCmd assertCmd = (AssertRequiresCmd)cmd; + Contract.Assert(assertCmd != null); + CallCounterexample cc = new CallCounterexample(trace, assertCmd.Call, assertCmd.Requires, errModel, mvInfo, context, assertCmd.Checksum); + cc.relatedInformation = relatedInformation; + return cc; + } + else if (cmd is AssertEnsuresCmd) + { + AssertEnsuresCmd assertCmd = (AssertEnsuresCmd)cmd; + Contract.Assert(assertCmd != null); + ReturnCounterexample rc = new ReturnCounterexample(trace, transferCmd, assertCmd.Ensures, errModel, mvInfo, context, cmd.Checksum); + rc.relatedInformation = relatedInformation; + return rc; + } + else + { + AssertCounterexample ac = new AssertCounterexample(trace, (AssertCmd)cmd, errModel, mvInfo, context); + ac.relatedInformation = relatedInformation; + return ac; + } + } + + /// <summary> + /// Returns a clone of "cex", but with the location stored in "cex" replaced by those from "assrt". + /// </summary> + public static Counterexample AssertCmdToCloneCounterexample(AssertCmd assrt, Counterexample cex) { + Contract.Requires(assrt != null); + Contract.Requires(cex != null); + Contract.Ensures(Contract.Result<Counterexample>() != null); + + List<string> relatedInformation = new List<string>(); + + Counterexample cc; + if (assrt is AssertRequiresCmd) { + var aa = (AssertRequiresCmd)assrt; + cc = new CallCounterexample(cex.Trace, aa.Call, aa.Requires, cex.Model, cex.MvInfo, cex.Context, aa.Checksum); + } else if (assrt is AssertEnsuresCmd && cex is ReturnCounterexample) { + var aa = (AssertEnsuresCmd)assrt; + var oldCex = (ReturnCounterexample)cex; + cc = new ReturnCounterexample(cex.Trace, oldCex.FailingReturn, aa.Ensures, cex.Model, cex.MvInfo, cex.Context, aa.Checksum); + } else { + cc = new AssertCounterexample(cex.Trace, assrt, cex.Model, cex.MvInfo, cex.Context); + } + cc.relatedInformation = relatedInformation; + return cc; + } + + static VCExpr LetVC(Block startBlock, + VCExpr controlFlowVariableExpr, + Dictionary<int, Absy> label2absy, + ProverContext proverCtxt, + out int assertionCount) { + Contract.Requires(startBlock != null); + Contract.Requires(proverCtxt != null); + + Contract.Ensures(Contract.Result<VCExpr>() != null); + + Hashtable/*<Block, LetVariable!>*/ blockVariables = new Hashtable/*<Block, LetVariable!!>*/(); + List<VCExprLetBinding> bindings = new List<VCExprLetBinding>(); + VCExpr startCorrect = LetVC(startBlock, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out assertionCount); + return proverCtxt.ExprGen.Let(bindings, startCorrect); + } + + static VCExpr LetVCIterative(List<Block> blocks, + VCExpr controlFlowVariableExpr, + Dictionary<int, Absy> label2absy, + ProverContext proverCtxt, + out int assertionCount, + bool isPositiveContext = true) + { + Contract.Requires(blocks != null); + Contract.Requires(proverCtxt != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + assertionCount = 0; + + Graph<Block> dag = new Graph<Block>(); + dag.AddSource(blocks[0]); + 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(dest, b); + } + } + } + IEnumerable sortedNodes = dag.TopologicalSort(); + Contract.Assert(sortedNodes != null); + + Dictionary<Block, VCExprVar> blockVariables = new Dictionary<Block, VCExprVar>(); + List<VCExprLetBinding> bindings = new List<VCExprLetBinding>(); + VCExpressionGenerator gen = proverCtxt.ExprGen; + Contract.Assert(gen != null); + foreach (Block block in sortedNodes) { + VCExpr SuccCorrect; + GotoCmd gotocmd = block.TransferCmd as GotoCmd; + if (gotocmd == null) { + ReturnExprCmd re = block.TransferCmd as ReturnExprCmd; + if (re == null) { + SuccCorrect = VCExpressionGenerator.True; + } + else { + SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr); + if (isPositiveContext) + { + SuccCorrect = gen.Not(SuccCorrect); + } + } + } + else { + Contract.Assert(gotocmd.labelTargets != null); + List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count); + foreach (Block successor in gotocmd.labelTargets) { + Contract.Assert(successor != null); + VCExpr s = blockVariables[successor]; + if (controlFlowVariableExpr != null) { + VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId))); + VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId))); + s = gen.Implies(controlTransferExpr, s); + } + SuccCorrectVars.Add(s); + } + SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars); + } + + VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr, isPositiveContext); + VCExpr vc = Wlp.Block(block, SuccCorrect, context); + assertionCount += context.AssertionCount; + + VCExprVar v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool); + bindings.Add(gen.LetBinding(v, vc)); + blockVariables.Add(block, v); + } + + return proverCtxt.ExprGen.Let(bindings, blockVariables[blocks[0]]); + } + + static VCExpr LetVC(Block block, + VCExpr controlFlowVariableExpr, + Dictionary<int, Absy> label2absy, + Hashtable/*<Block, VCExprVar!>*/ blockVariables, + List<VCExprLetBinding/*!*/>/*!*/ bindings, + ProverContext proverCtxt, + out int assertionCount) + { + Contract.Requires(block != null); + Contract.Requires(blockVariables!= null); + Contract.Requires(cce.NonNullElements(bindings)); + Contract.Requires(proverCtxt != null); + + Contract.Ensures(Contract.Result<VCExpr>() != null); + + assertionCount = 0; + + VCExpressionGenerator gen = proverCtxt.ExprGen; + Contract.Assert(gen != null); + VCExprVar v = (VCExprVar)blockVariables[block]; + if (v == null) { + /* + * For block A (= block), generate: + * LET_binding A_correct = wp(A_body, (/\ S \in Successors(A) :: S_correct)) + * with the side effect of adding the let bindings to "bindings" for any + * successor not yet visited. + */ + VCExpr SuccCorrect; + GotoCmd gotocmd = block.TransferCmd as GotoCmd; + if (gotocmd == null) { + ReturnExprCmd re = block.TransferCmd as ReturnExprCmd; + if (re == null) { + SuccCorrect = VCExpressionGenerator.True; + } else { + SuccCorrect = proverCtxt.BoogieExprTranslator.Translate(re.Expr); + } + } else { + Contract.Assert( gotocmd.labelTargets != null); + List<VCExpr> SuccCorrectVars = new List<VCExpr>(gotocmd.labelTargets.Count); + foreach (Block successor in gotocmd.labelTargets) { + Contract.Assert(successor != null); + int ac; + VCExpr s = LetVC(successor, controlFlowVariableExpr, label2absy, blockVariables, bindings, proverCtxt, out ac); + assertionCount += ac; + if (controlFlowVariableExpr != null) + { + VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId))); + VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId))); + s = gen.Implies(controlTransferExpr, s); + } + SuccCorrectVars.Add(s); + } + SuccCorrect = gen.NAry(VCExpressionGenerator.AndOp, SuccCorrectVars); + } + + + VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr); + VCExpr vc = Wlp.Block(block, SuccCorrect, context); + assertionCount += context.AssertionCount; + + v = gen.Variable(block.Label + "_correct", Bpl.Type.Bool); + bindings.Add(gen.LetBinding(v, vc)); + blockVariables.Add(block, v); + } + return v; + } + + static VCExpr DagVC(Block block, + VCExpr controlFlowVariableExpr, + Dictionary<int, Absy> label2absy, + Hashtable/*<Block, VCExpr!>*/ blockEquations, + ProverContext proverCtxt, + out int assertionCount) + { + Contract.Requires(block != null); + Contract.Requires(label2absy != null); + Contract.Requires(blockEquations != null); + Contract.Requires(proverCtxt != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + assertionCount = 0; + VCExpressionGenerator gen = proverCtxt.ExprGen; + Contract.Assert(gen != null); + VCExpr vc = (VCExpr)blockEquations[block]; + if (vc != null) { + return vc; + } + + /* + * For block A (= block), generate: + * wp(A_body, (/\ S \in Successors(A) :: DagVC(S))) + */ + VCExpr SuccCorrect = null; + GotoCmd gotocmd = block.TransferCmd as GotoCmd; + if (gotocmd != null) + { + foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) { + Contract.Assert(successor != null); + int ac; + VCExpr c = DagVC(successor, controlFlowVariableExpr, label2absy, blockEquations, proverCtxt, out ac); + assertionCount += ac; + if (controlFlowVariableExpr != null) { + VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(controlFlowVariableExpr, gen.Integer(BigNum.FromInt(block.UniqueId))); + VCExpr controlTransferExpr = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(successor.UniqueId))); + c = gen.Implies(controlTransferExpr, c); + } + SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c); + } + } + if (SuccCorrect == null) { + SuccCorrect = VCExpressionGenerator.True; + } + + VCContext context = new VCContext(label2absy, proverCtxt, controlFlowVariableExpr); + vc = Wlp.Block(block, SuccCorrect, context); + assertionCount += context.AssertionCount; + + // gen.MarkAsSharedFormula(vc); PR: don't know yet what to do with this guy + + blockEquations.Add(block, vc); + return vc; + } + + static VCExpr FlatBlockVC(Implementation impl, + Dictionary<int, Absy> label2absy, + bool local, bool reach, bool doomed, + ProverContext proverCtxt, + out int assertionCount) + { + Contract.Requires(impl != null); + Contract.Requires(label2absy != null); + Contract.Requires(proverCtxt != null); + Contract.Requires( !local || !reach); // "reach" must be false for local + + VCExpressionGenerator gen = proverCtxt.ExprGen; + Contract.Assert(gen != null); + Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen); + Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null; + + List<Block> blocks = impl.Blocks; + Contract.Assert(blocks != null); + // block sorting is now done on the VCExpr + // if (!local && (cce.NonNull(CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) { + // blocks = SortBlocks(blocks); + // } + + VCExpr proofObligation; + if (!local) { + proofObligation = cce.NonNull((VCExprVar)BlkCorrect[impl.Blocks[0]]); + } else { + List<VCExpr> conjuncts = new List<VCExpr>(blocks.Count); + foreach (Block b in blocks) {Contract.Assert(b != null); + VCExpr v = cce.NonNull((VCExprVar)BlkCorrect[b]); + conjuncts.Add(v); + } + proofObligation = gen.NAry(VCExpressionGenerator.AndOp, conjuncts); + } + + VCContext context = new VCContext(label2absy, proverCtxt); + Contract.Assert(context != null); + + List<VCExprLetBinding> programSemantics = new List<VCExprLetBinding>(blocks.Count); + foreach (Block b in blocks) {Contract.Assert(b != null); + /* + * In block mode, + * For a return block A, generate: + * A_correct <== wp(A_body, true) [post-condition has been translated into an assert] + * For all other blocks, generate: + * A_correct <== wp(A_body, (/\ S \in Successors(A) :: S_correct)) + * + * In doomed mode, proceed as in block mode, except for a return block A, generate: + * A_correct <== wp(A_body, false) [post-condition has been translated into an assert] + * + * In block reach mode, the wp(A_body,...) in the equations above change to: + * A_reached ==> wp(A_body,...) + * and the conjunction above changes to: + * (/\ S \in Successors(A) :: S_correct \/ (\/ T \in Successors(A) && T != S :: T_reached)) + * + * In local mode, generate: + * A_correct <== wp(A_body, true) + */ + VCExpr SuccCorrect; + if (local) { + SuccCorrect = VCExpressionGenerator.True; + } else { + SuccCorrect = SuccessorsCorrect(b, BlkCorrect, BlkReached, doomed, gen); + } + + VCExpr wlp = Wlp.Block(b, SuccCorrect, context); + if (BlkReached != null) { + wlp = gen.Implies(cce.NonNull((VCExprVar)BlkReached[b]), wlp); + } + + VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]); + VCExprLetBinding binding = gen.LetBinding(okVar, wlp); + programSemantics.Add(binding); + } + + assertionCount = context.AssertionCount; + return gen.Let(programSemantics, proofObligation); + } + + private static Hashtable/* Block --> VCExprVar */ BlockVariableMap(List<Block/*!*/>/*!*/ blocks, string suffix, + Microsoft.Boogie.VCExpressionGenerator gen) { + Contract.Requires(cce.NonNullElements(blocks)); + Contract.Requires(suffix != null); + Contract.Requires(gen != null); + Contract.Ensures(Contract.Result<Hashtable>() != null); + + Hashtable/* Block --> VCExprVar */ map = new Hashtable/* Block --> (Let)Variable */(); + foreach (Block b in blocks) { + Contract.Assert(b != null); + VCExprVar v = gen.Variable(b.Label + suffix, Bpl.Type.Bool); + Contract.Assert(v != null); + map.Add(b, v); + } + return map; + } + + private static VCExpr SuccessorsCorrect( + Block b, + Hashtable/* Block --> VCExprVar */ BlkCorrect, + Hashtable/* Block --> VCExprVar */ BlkReached, + bool doomed, + Microsoft.Boogie.VCExpressionGenerator gen) { + Contract.Requires(b != null); + Contract.Requires(BlkCorrect != null); + Contract.Requires(gen != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpr SuccCorrect = null; + GotoCmd gotocmd = b.TransferCmd as GotoCmd; + if (gotocmd != null) { + foreach (Block successor in cce.NonNull(gotocmd.labelTargets)) { + Contract.Assert(successor != null); + // c := S_correct + VCExpr c = (VCExprVar)BlkCorrect[successor]; + Contract.Assert(c != null); + if (BlkReached != null) { + // c := S_correct \/ Sibling0_reached \/ Sibling1_reached \/ ...; + foreach (Block successorSibling in gotocmd.labelTargets) { + Contract.Assert(successorSibling != null); + if (successorSibling != successor) { + c = gen.Or(c, cce.NonNull((VCExprVar)BlkReached[successorSibling])); + } + } + } + SuccCorrect = SuccCorrect == null ? c : gen.And(SuccCorrect, c); + } + } + if (SuccCorrect == null) { + return VCExpressionGenerator.True; + } else if (doomed) { + return VCExpressionGenerator.False; + } else { + return SuccCorrect; + } + } + + static VCExpr NestedBlockVC(Implementation impl, + Dictionary<int, Absy> label2absy, + bool reach, + ProverContext proverCtxt, + out int assertionCount){ + Contract.Requires(impl != null); + Contract.Requires(label2absy != null); + Contract.Requires(proverCtxt != null); + Contract.Requires( impl.Blocks.Count != 0); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpressionGenerator gen = proverCtxt.ExprGen; + Contract.Assert(gen != null); + Graph<Block> g = Program.GraphFromImpl(impl); + + Hashtable/* Block --> VCExprVar */ BlkCorrect = BlockVariableMap(impl.Blocks, "_correct", gen); + Hashtable/* Block --> VCExprVar */ BlkReached = reach ? BlockVariableMap(impl.Blocks, "_reached", gen) : null; + + Block startBlock = cce.NonNull( impl.Blocks[0]); + VCExpr proofObligation = (VCExprVar)BlkCorrect[startBlock]; + Contract.Assert(proofObligation != null); + VCContext context = new VCContext(label2absy, proverCtxt); + + Hashtable/*Block->int*/ totalOrder = new Hashtable/*Block->int*/(); + { + List<Block> blocks = impl.Blocks; + + // block sorting is now done on the VCExpr + // if (((!)CommandLineOptions.Clo.TheProverFactory).NeedsBlockSorting) { + // blocks = SortBlocks(blocks); + // } + int i = 0; + foreach (Block b in blocks) { + Contract.Assert(b != null); + totalOrder[b] = i; + i++; + } + } + + VCExprLetBinding programSemantics = NestedBlockEquation(cce.NonNull(impl.Blocks[0]), BlkCorrect, BlkReached, totalOrder, context, g, gen); + List<VCExprLetBinding> ps = new List<VCExprLetBinding>(1); + ps.Add(programSemantics); + + assertionCount = context.AssertionCount; + return gen.Let(ps, proofObligation); + } + + private static VCExprLetBinding NestedBlockEquation(Block b, + Hashtable/*Block-->VCExprVar*/ BlkCorrect, + Hashtable/*Block-->VCExprVar*/ BlkReached, + Hashtable/*Block->int*/ totalOrder, + VCContext context, + Graph<Block> g, + Microsoft.Boogie.VCExpressionGenerator gen) { + Contract.Requires(b != null); + Contract.Requires(BlkCorrect != null); + Contract.Requires(totalOrder != null); + Contract.Requires(g != null); + Contract.Requires(context != null); + + Contract.Ensures(Contract.Result<VCExprLetBinding>() != null); + + /* + * For a block b, return: + * LET_BINDING b_correct = wp(b_body, X) + * where X is: + * LET (THOSE d \in DirectDominates(b) :: BlockEquation(d)) + * IN (/\ s \in Successors(b) :: s_correct) + * + * When the VC-expression generator does not support LET expresions, this + * will eventually turn into: + * b_correct <== wp(b_body, X) + * where X is: + * (/\ s \in Successors(b) :: s_correct) + * <== + * (/\ d \in DirectDominatees(b) :: BlockEquation(d)) + * + * In both cases above, if BlkReached is non-null, then the wp expression + * is instead: + * b_reached ==> wp(b_body, X) + */ + + VCExpr SuccCorrect = SuccessorsCorrect(b, BlkCorrect, null, false, gen); + Contract.Assert(SuccCorrect != null); + + List<VCExprLetBinding> bindings = new List<VCExprLetBinding>(); + foreach (Block dominee in GetSortedBlocksImmediatelyDominatedBy(g, b, totalOrder)) { + Contract.Assert(dominee != null); + VCExprLetBinding c = NestedBlockEquation(dominee, BlkCorrect, BlkReached, totalOrder, context, g, gen); + bindings.Add(c); + } + + VCExpr X = gen.Let(bindings, SuccCorrect); + VCExpr wlp = Wlp.Block(b, X, context); + if (BlkReached != null) { + wlp = gen.Implies((VCExprVar)BlkReached[b], wlp); + Contract.Assert(wlp != null); + } + VCExprVar okVar = cce.NonNull((VCExprVar)BlkCorrect[b]); + return gen.LetBinding(okVar, wlp); + } + + /// <summary> + /// Returns a list of g.ImmediatelyDominatedBy(b), but in a sorted order, hoping to steer around + /// the nondeterminism problems we've been seeing by using just this call. + /// </summary> + static List<Block/*!*/>/*!*/ GetSortedBlocksImmediatelyDominatedBy(Graph<Block>/*!*/ g, Block/*!*/ b, Hashtable/*Block->int*//*!*/ totalOrder) { + Contract.Requires(g != null); + Contract.Requires(b != null); + Contract.Requires(totalOrder != null); + Contract.Ensures(Contract.Result<List<Block>>() != null); + + List<Block> list = new List<Block>(); + foreach (Block dominee in g.ImmediatelyDominatedBy(b)) { + Contract.Assert(dominee != null); + list.Add(dominee); + } + list.Sort(new Comparison<Block>(delegate(Block x, Block y) { + return (int)cce.NonNull(totalOrder[x]) - (int)cce.NonNull(totalOrder[y]); + })); + return list; + } + + static VCExpr VCViaStructuredProgram + (Implementation impl, Dictionary<int, Absy> label2absy, + ProverContext proverCtxt, + out int assertionCount) + { + Contract.Requires(impl != null); + Contract.Requires(label2absy != null); + Contract.Requires(proverCtxt != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + #region Convert block structure back to a "regular expression" + RE r = DAG2RE.Transform(cce.NonNull(impl.Blocks[0])); + Contract.Assert(r != null); + #endregion + + VCContext ctxt = new VCContext(label2absy, proverCtxt); + Contract.Assert(ctxt != null); + #region Send wlp(program,true) to Simplify + var vcexp = Wlp.RegExpr(r, VCExpressionGenerator.True, ctxt); + assertionCount = ctxt.AssertionCount; + return vcexp; + #endregion + } + + /// <summary> + /// Remove empty blocks reachable from the startBlock of the CFG + /// </summary> + static void RemoveEmptyBlocksIterative(List<Block> blocks) { + // postorder traversal of cfg + // noting loop heads in [keep] and + // generating token information in [renameInfo] + Block startBlock = blocks[0]; + var postorder = new List<Block>(); + var keep = new HashSet<Block>(); + var visited = new HashSet<Block>(); + var grey = new HashSet<Block>(); + var stack = new Stack<Block>(); + Dictionary<Block, Block> renameInfo = new Dictionary<Block, Block>(); + + stack.Push(startBlock); + visited.Add(startBlock); + while (stack.Count != 0) { + var curr = stack.Pop(); + if (grey.Contains(curr)) { + postorder.Add(curr); + + // generate renameInfoForStartBlock + GotoCmd gtc = curr.TransferCmd as GotoCmd; + renameInfo[curr] = null; + if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) { + if (curr.Cmds.Count == 0 && curr.tok.IsValid) { + renameInfo[curr] = curr; + } + } else { + if (curr.Cmds.Count == 0 || curr == startBlock) { + if (curr.tok.IsValid) { + renameInfo[curr] = curr; + } else { + HashSet<Block> successorRenameInfo = new HashSet<Block>(); + foreach (Block s in gtc.labelTargets) { + if (keep.Contains(s)) { + successorRenameInfo.Add(null); + } else { + successorRenameInfo.Add(renameInfo[s]); + } + } + if (successorRenameInfo.Count == 1) { + renameInfo[curr] = successorRenameInfo.Single(); + } + } + } + } + // end generate renameInfoForStartBlock + + } else { + grey.Add(curr); + stack.Push(curr); + GotoCmd gtc = curr.TransferCmd as GotoCmd; + if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) continue; + foreach (Block s in gtc.labelTargets) { + if (!visited.Contains(s)) { + visited.Add(s); + stack.Push(s); + } else if (grey.Contains(s) && !postorder.Contains(s)) { // s is a loop head + keep.Add(s); + } + } + } + } + keep.Add(startBlock); + + foreach (Block b in postorder) { + if (!keep.Contains(b) && b.Cmds.Count == 0) { + GotoCmd bGtc = b.TransferCmd as GotoCmd; + foreach (Block p in b.Predecessors) { + GotoCmd pGtc = p.TransferCmd as GotoCmd; + Contract.Assert(pGtc != null); + pGtc.labelTargets.Remove(b); + pGtc.labelNames.Remove(b.Label); + } + if (bGtc == null || bGtc.labelTargets == null || bGtc.labelTargets.Count == 0) { + continue; + } + + List<Block> successors = bGtc.labelTargets; + + // Try to push token information if possible + if (b.tok.IsValid && successors.Count == 1 && b != renameInfo[startBlock]) { + var s = successors.Single(); + if (!s.tok.IsValid) { + foreach (Block p in s.Predecessors) { + if (p != b) { + GotoCmd pGtc = p.TransferCmd as GotoCmd; + Contract.Assert(pGtc != null); + pGtc.labelTargets.Remove(s); + pGtc.labelNames.Remove(s.Label); + pGtc.labelTargets.Add(s); + pGtc.labelNames.Add(b.Label); + } + } + s.tok = b.tok; + s.Label = b.Label; + } + } + + foreach (Block p in b.Predecessors) { + GotoCmd pGtc = p.TransferCmd as GotoCmd; + Contract.Assert(pGtc != null); + foreach (Block s in successors) { + if (!pGtc.labelTargets.Contains(s)) { + pGtc.labelTargets.Add(s); + pGtc.labelNames.Add(s.Label); + } + } + } + } + } + + if (!startBlock.tok.IsValid && startBlock.Cmds.All(c => c is AssumeCmd)) { + if (renameInfo[startBlock] != null) { + startBlock.tok = renameInfo[startBlock].tok; + startBlock.Label = renameInfo[startBlock].Label; + } + } + + } + + /// <summary> + /// Remove the empty blocks reachable from the block. + /// It changes the visiting state of the blocks, so that if you want to visit again the blocks, you have to reset them... + /// </summary> + static List<Block> RemoveEmptyBlocks(Block b) { + Contract.Requires(b != null); + Contract.Ensures(Contract.Result<List<Block>>() != null); + + Contract.Assert(b.TraversingStatus == Block.VisitState.ToVisit); + Block renameInfo; + List<Block> retVal = removeEmptyBlocksWorker(b, true, out renameInfo); + if (renameInfo != null && !b.tok.IsValid) { + bool onlyAssumes = true; + foreach (Cmd c in b.Cmds) { + if (!(c is AssumeCmd)) { + onlyAssumes = false; + break; + } + } + if (onlyAssumes) { + b.tok = renameInfo.tok; + b.Label = renameInfo.Label; + } + } + return retVal; + } + + /// <summary> + /// For every not-yet-visited block n reachable from b, change n's successors to skip empty nodes. + /// Return the *set* of blocks reachable from b without passing through a nonempty block. + /// The target of any backedge is counted as a nonempty block. + /// If renameInfoForStartBlock is non-null, it denotes an empty block with location information, and that + /// information would be appropriate to display + /// </summary> + private static List<Block> removeEmptyBlocksWorker(Block b, bool startNode, out Block renameInfoForStartBlock) + { + Contract.Requires(b != null); + Contract.Ensures(Contract.ValueAtReturn(out renameInfoForStartBlock) == null || Contract.ValueAtReturn(out renameInfoForStartBlock).tok.IsValid); + // ensures: b in result ==> renameInfoForStartBlock == null; + + renameInfoForStartBlock = null; + List<Block> bs = new List<Block>(); + GotoCmd gtc = b.TransferCmd as GotoCmd; + + // b has no successors + if (gtc == null || gtc.labelTargets == null || gtc.labelTargets.Count == 0) + { + if (b.Cmds.Count != 0){ // only empty blocks are removed... + bs.Add(b); + } else if (b.tok.IsValid) { + renameInfoForStartBlock = b; + } + return bs; + } + else if (b.TraversingStatus == Block.VisitState.ToVisit) // if b has some successors and we have not seen it so far... + { + b.TraversingStatus = Block.VisitState.BeingVisited; + + // Before recursing down to successors, make a sobering observation: + // If b has no commands and is not the start node, then it will see + // extinction (because it will not be included in the "return setOfSuccessors" + // statement below). In that case, if b has a location, then the location + // information would be lost. Hence, make an attempt to save the location + // by pushing the location onto b's successor. This can be done if (0) b has + // exactly one successor, (1) that successor has no location of its own, and + // (2) that successor has no other predecessors. + if (b.Cmds.Count == 0 && !startNode) { + // b is about to become extinct; try to save its name and location, if possible + if (b.tok.IsValid && gtc.labelTargets.Count == 1) { + Block succ = cce.NonNull(gtc.labelTargets[0]); + if (!succ.tok.IsValid && succ.Predecessors.Count == 1) { + succ.tok = b.tok; + succ.Label = b.Label; + } + } + } + + // recursively call this method on each successor + // merge result into a *set* of blocks + HashSet<Block> mergedSuccessors = new HashSet<Block>(); + int m = 0; // in the following loop, set renameInfoForStartBlock to the value that all recursive calls agree on, if possible; otherwise, null + foreach (Block dest in gtc.labelTargets){Contract.Assert(dest != null); + Block renameInfo; + List<Block> ys = removeEmptyBlocksWorker(dest, false, out renameInfo); + Contract.Assert(ys != null); + if (m == 0) { + renameInfoForStartBlock = renameInfo; + } else if (renameInfoForStartBlock != renameInfo) { + renameInfoForStartBlock = null; + } + foreach (Block successor in ys){ + if (!mergedSuccessors.Contains(successor)) + mergedSuccessors.Add(successor); + } + m++; + } + b.TraversingStatus = Block.VisitState.AlreadyVisited; + + List<Block> setOfSuccessors = new List<Block>(); + foreach (Block d in mergedSuccessors) + setOfSuccessors.Add(d); + if (b.Cmds.Count == 0 && !startNode) { + // b is about to become extinct + if (b.tok.IsValid) { + renameInfoForStartBlock = b; + } + return setOfSuccessors; + } + // otherwise, update the list of successors of b to be the blocks in setOfSuccessors + gtc.labelTargets = setOfSuccessors; + gtc.labelNames = new List<String>(); + foreach (Block d in setOfSuccessors){ + Contract.Assert(d != null); + gtc.labelNames.Add(d.Label);} + if (!startNode) { + renameInfoForStartBlock = null; + } + return new List<Block> { b }; + } + else // b has some successors, but we are already visiting it, or we have already visited it... + { + return new List<Block> { b }; + } + } + + static void DumpMap(Hashtable /*Variable->Expr*/ map) { + Contract.Requires(map != null); + foreach (DictionaryEntry de in map) { + Variable v = (Variable)de.Key; + Contract.Assert(v != null); + Expr e = (Expr)de.Value; + Contract.Assert(e != null); + Console.Write(" "); + v.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false), 0); + Console.Write(" --> "); + e.Emit(new TokenTextWriter("<console>", Console.Out, /*setTokens=*/ false, /*pretty=*/ false)); + Console.WriteLine(); + } + } + } +} diff --git a/Source/VCGeneration/VCGeneration.csproj b/Source/VCGeneration/VCGeneration.csproj index 74e1eef8..9bd3fb1a 100644 --- a/Source/VCGeneration/VCGeneration.csproj +++ b/Source/VCGeneration/VCGeneration.csproj @@ -1,230 +1,230 @@ -<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>9.0.21022</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</ProjectGuid>
- <OutputType>Library</OutputType>
- <AppDesignerFolder>Properties</AppDesignerFolder>
- <RootNamespace>VCGeneration</RootNamespace>
- <AssemblyName>VCGeneration</AssemblyName>
- <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
- <FileAlignment>512</FileAlignment>
- <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode>
- <SignAssembly>true</SignAssembly>
- <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile>
- <FileUpgradeFlags>
- </FileUpgradeFlags>
- <OldToolsVersion>3.5</OldToolsVersion>
- <UpgradeBackupLocation />
- <PublishUrl>publish\</PublishUrl>
- <Install>true</Install>
- <InstallFrom>Disk</InstallFrom>
- <UpdateEnabled>false</UpdateEnabled>
- <UpdateMode>Foreground</UpdateMode>
- <UpdateInterval>7</UpdateInterval>
- <UpdateIntervalUnits>Days</UpdateIntervalUnits>
- <UpdatePeriodically>false</UpdatePeriodically>
- <UpdateRequired>false</UpdateRequired>
- <MapFileExtensions>true</MapFileExtensions>
- <ApplicationRevision>0</ApplicationRevision>
- <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
- <IsWebBootstrapper>false</IsWebBootstrapper>
- <UseApplicationTrust>false</UseApplicationTrust>
- <BootstrapperEnabled>true</BootstrapperEnabled>
- <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'" >Client</TargetFrameworkProfile>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly>
- </CodeContractsCustomRewriterAssembly>
- <CodeContractsCustomRewriterClass>
- </CodeContractsCustomRewriterClass>
- <CodeContractsLibPaths>
- </CodeContractsLibPaths>
- <CodeContractsExtraRewriteOptions>
- </CodeContractsExtraRewriteOptions>
- <CodeContractsExtraAnalysisOptions>
- </CodeContractsExtraAnalysisOptions>
- <CodeContractsBaseLineFile>
- </CodeContractsBaseLineFile>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugType>pdbonly</DebugType>
- <Optimize>true</Optimize>
- <OutputPath>bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <ErrorReport>prompt</ErrorReport>
- <WarningLevel>4</WarningLevel>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\z3apidebug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisRuleAssemblies>
- </CodeAnalysisRuleAssemblies>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>Migrated rules for VCGeneration.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
- <WarningLevel>4</WarningLevel>
- <Optimize>false</Optimize>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\Checked\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <CodeAnalysisLogFile>bin\Debug\VCGeneration.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile>
- <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression>
- <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories>
- <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
- <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking>
- <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface>
- <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure>
- <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires>
- <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers>
- <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis>
- <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations>
- <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations>
- <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations>
- <CodeContractsEnumObligations>False</CodeContractsEnumObligations>
- <CodeContractsPointerObligations>False</CodeContractsPointerObligations>
- <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions>
- <CodeContractsRunInBackground>True</CodeContractsRunInBackground>
- <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies>
- <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine>
- <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs>
- <CodeContractsCustomRewriterAssembly />
- <CodeContractsCustomRewriterClass />
- <CodeContractsLibPaths />
- <CodeContractsExtraRewriteOptions />
- <CodeContractsExtraAnalysisOptions />
- <CodeContractsBaseLineFile />
- <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults>
- <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
- <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
- <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
- <WarningLevel>4</WarningLevel>
- <Optimize>false</Optimize>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'">
- <DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\QED\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- <DebugType>full</DebugType>
- <PlatformTarget>AnyCPU</PlatformTarget>
- <ErrorReport>prompt</ErrorReport>
- <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="Check.cs" />
- <Compile Include="ConditionGeneration.cs" />
- <Compile Include="Context.cs" />
- <Compile Include="ExprExtensions.cs" />
- <Compile Include="FixedpointVC.cs" />
- <Compile Include="OrderingAxioms.cs" />
- <Compile Include="RPFP.cs" />
- <Compile Include="StratifiedVC.cs" />
- <Compile Include="VC.cs" />
- <Compile Include="..\version.cs" />
- <Compile Include="Wlp.cs" />
- </ItemGroup>
- <ItemGroup>
- <ProjectReference Include="..\Basetypes\Basetypes.csproj">
- <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project>
- <Name>Basetypes</Name>
- </ProjectReference>
- <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj">
- <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project>
- <Name>CodeContractsExtender</Name>
- </ProjectReference>
- <ProjectReference Include="..\Core\Core.csproj">
- <Project>{B230A69C-C466-4065-B9C1-84D80E76D802}</Project>
- <Name>Core</Name>
- </ProjectReference>
- <ProjectReference Include="..\Graph\Graph.csproj">
- <Project>{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}</Project>
- <Name>Graph</Name>
- </ProjectReference>
- <ProjectReference Include="..\Model\Model.csproj">
- <Project>{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}</Project>
- <Name>Model</Name>
- </ProjectReference>
- <ProjectReference Include="..\ParserHelper\ParserHelper.csproj">
- <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project>
- <Name>ParserHelper</Name>
- </ProjectReference>
- <ProjectReference Include="..\VCExpr\VCExpr.csproj">
- <Project>{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}</Project>
- <Name>VCExpr</Name>
- </ProjectReference>
- </ItemGroup>
- <ItemGroup>
- <Folder Include="Properties\" />
- </ItemGroup>
- <ItemGroup>
- <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
- <Install>false</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
- <Visible>False</Visible>
- <ProductName>.NET Framework 3.5 SP1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
- <Visible>False</Visible>
- <ProductName>Windows Installer 3.1</ProductName>
- <Install>true</Install>
- </BootstrapperPackage>
- </ItemGroup>
- <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProductVersion>9.0.21022</ProductVersion> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{E1F10180-C7B9-4147-B51F-FA1B701966DC}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>VCGeneration</RootNamespace> + <AssemblyName>VCGeneration</AssemblyName> + <TargetFrameworkVersion>v4.0</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <CodeContractsAssemblyMode>1</CodeContractsAssemblyMode> + <SignAssembly>true</SignAssembly> + <AssemblyOriginatorKeyFile>..\InterimKey.snk</AssemblyOriginatorKeyFile> + <FileUpgradeFlags> + </FileUpgradeFlags> + <OldToolsVersion>3.5</OldToolsVersion> + <UpgradeBackupLocation /> + <PublishUrl>publish\</PublishUrl> + <Install>true</Install> + <InstallFrom>Disk</InstallFrom> + <UpdateEnabled>false</UpdateEnabled> + <UpdateMode>Foreground</UpdateMode> + <UpdateInterval>7</UpdateInterval> + <UpdateIntervalUnits>Days</UpdateIntervalUnits> + <UpdatePeriodically>false</UpdatePeriodically> + <UpdateRequired>false</UpdateRequired> + <MapFileExtensions>true</MapFileExtensions> + <ApplicationRevision>0</ApplicationRevision> + <ApplicationVersion>1.0.0.%2a</ApplicationVersion> + <IsWebBootstrapper>false</IsWebBootstrapper> + <UseApplicationTrust>false</UseApplicationTrust> + <BootstrapperEnabled>true</BootstrapperEnabled> + <TargetFrameworkProfile Condition=" '$(OS)' == 'Windows_NT'" >Client</TargetFrameworkProfile> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <CodeContractsEnableRuntimeChecking>False</CodeContractsEnableRuntimeChecking> + <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface> + <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure> + <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires> + <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis> + <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations> + <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations> + <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations> + <CodeContractsPointerObligations>False</CodeContractsPointerObligations> + <CodeContractsContainerAnalysis>False</CodeContractsContainerAnalysis> + <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions> + <CodeContractsRunInBackground>True</CodeContractsRunInBackground> + <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies> + <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine> + <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs> + <CodeContractsCustomRewriterAssembly> + </CodeContractsCustomRewriterAssembly> + <CodeContractsCustomRewriterClass> + </CodeContractsCustomRewriterClass> + <CodeContractsLibPaths> + </CodeContractsLibPaths> + <CodeContractsExtraRewriteOptions> + </CodeContractsExtraRewriteOptions> + <CodeContractsExtraAnalysisOptions> + </CodeContractsExtraAnalysisOptions> + <CodeContractsBaseLineFile> + </CodeContractsBaseLineFile> + <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel> + <CodeContractsReferenceAssembly>%28none%29</CodeContractsReferenceAssembly> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'z3apidebug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\z3apidebug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>AnyCPU</PlatformTarget> + <CodeAnalysisRuleAssemblies> + </CodeAnalysisRuleAssemblies> + <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression> + <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>Migrated rules for VCGeneration.ruleset</CodeAnalysisRuleSet> + <CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules> + <WarningLevel>4</WarningLevel> + <Optimize>false</Optimize> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Checked|AnyCPU'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\Checked\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>AnyCPU</PlatformTarget> + <CodeAnalysisLogFile>bin\Debug\VCGeneration.dll.CodeAnalysisLog.xml</CodeAnalysisLogFile> + <CodeAnalysisUseTypeNameInSuppression>true</CodeAnalysisUseTypeNameInSuppression> + <CodeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</CodeAnalysisModuleSuppressionsFile> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + <CodeAnalysisRuleSetDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets</CodeAnalysisRuleSetDirectories> + <CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories> + <CodeContractsEnableRuntimeChecking>True</CodeContractsEnableRuntimeChecking> + <CodeContractsRuntimeOnlyPublicSurface>False</CodeContractsRuntimeOnlyPublicSurface> + <CodeContractsRuntimeThrowOnFailure>True</CodeContractsRuntimeThrowOnFailure> + <CodeContractsRuntimeCallSiteRequires>False</CodeContractsRuntimeCallSiteRequires> + <CodeContractsRuntimeSkipQuantifiers>False</CodeContractsRuntimeSkipQuantifiers> + <CodeContractsRunCodeAnalysis>False</CodeContractsRunCodeAnalysis> + <CodeContractsNonNullObligations>False</CodeContractsNonNullObligations> + <CodeContractsBoundsObligations>False</CodeContractsBoundsObligations> + <CodeContractsArithmeticObligations>False</CodeContractsArithmeticObligations> + <CodeContractsEnumObligations>False</CodeContractsEnumObligations> + <CodeContractsPointerObligations>False</CodeContractsPointerObligations> + <CodeContractsRedundantAssumptions>False</CodeContractsRedundantAssumptions> + <CodeContractsRunInBackground>True</CodeContractsRunInBackground> + <CodeContractsShowSquigglies>False</CodeContractsShowSquigglies> + <CodeContractsUseBaseLine>False</CodeContractsUseBaseLine> + <CodeContractsEmitXMLDocs>False</CodeContractsEmitXMLDocs> + <CodeContractsCustomRewriterAssembly /> + <CodeContractsCustomRewriterClass /> + <CodeContractsLibPaths /> + <CodeContractsExtraRewriteOptions /> + <CodeContractsExtraAnalysisOptions /> + <CodeContractsBaseLineFile /> + <CodeContractsCacheAnalysisResults>False</CodeContractsCacheAnalysisResults> + <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel> + <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly> + <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel> + <WarningLevel>4</WarningLevel> + <Optimize>false</Optimize> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'QED|AnyCPU'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\QED\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>AnyCPU</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet> + </PropertyGroup> + <ItemGroup> + <Reference Include="System" /> + <Reference Include="System.Data" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Check.cs" /> + <Compile Include="ConditionGeneration.cs" /> + <Compile Include="Context.cs" /> + <Compile Include="ExprExtensions.cs" /> + <Compile Include="FixedpointVC.cs" /> + <Compile Include="OrderingAxioms.cs" /> + <Compile Include="RPFP.cs" /> + <Compile Include="StratifiedVC.cs" /> + <Compile Include="VC.cs" /> + <Compile Include="..\version.cs" /> + <Compile Include="Wlp.cs" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Basetypes\Basetypes.csproj"> + <Project>{43DFAD18-3E35-4558-9BE2-CAFF6B5BA8A0}</Project> + <Name>Basetypes</Name> + </ProjectReference> + <ProjectReference Include="..\CodeContractsExtender\CodeContractsExtender.csproj"> + <Project>{ACCC0156-0921-43ED-8F67-AD8BDC8CDE31}</Project> + <Name>CodeContractsExtender</Name> + </ProjectReference> + <ProjectReference Include="..\Core\Core.csproj"> + <Project>{B230A69C-C466-4065-B9C1-84D80E76D802}</Project> + <Name>Core</Name> + </ProjectReference> + <ProjectReference Include="..\Graph\Graph.csproj"> + <Project>{69A2B0B8-BCAC-4101-AE7A-556FCC58C06E}</Project> + <Name>Graph</Name> + </ProjectReference> + <ProjectReference Include="..\Model\Model.csproj"> + <Project>{ACEF88D5-DADD-46DA-BAE1-2144D63F4C83}</Project> + <Name>Model</Name> + </ProjectReference> + <ProjectReference Include="..\ParserHelper\ParserHelper.csproj"> + <Project>{FCD3AC7F-9DFD-46C8-AB1E-09F0B0F16DC5}</Project> + <Name>ParserHelper</Name> + </ProjectReference> + <ProjectReference Include="..\VCExpr\VCExpr.csproj"> + <Project>{56FFDBCA-7D14-43B8-A6CA-22A20E417EE1}</Project> + <Name>VCExpr</Name> + </ProjectReference> + </ItemGroup> + <ItemGroup> + <Folder Include="Properties\" /> + </ItemGroup> + <ItemGroup> + <BootstrapperPackage Include="Microsoft.Net.Client.3.5"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName> + <Install>false</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1"> + <Visible>False</Visible> + <ProductName>.NET Framework 3.5 SP1</ProductName> + <Install>true</Install> + </BootstrapperPackage> + <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1"> + <Visible>False</Visible> + <ProductName>Windows Installer 3.1</ProductName> + <Install>true</Install> + </BootstrapperPackage> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <!-- To modify your build process, add your task inside one of the targets below and uncomment it. Other similar extension points exist, see Microsoft.Common.targets. <Target Name="BeforeBuild"> </Target> <Target Name="AfterBuild"> </Target> - -->
+ --> </Project> diff --git a/Source/VCGeneration/Wlp.cs b/Source/VCGeneration/Wlp.cs index 82d3b607..b4ee4c09 100644 --- a/Source/VCGeneration/Wlp.cs +++ b/Source/VCGeneration/Wlp.cs @@ -1,255 +1,255 @@ -//-----------------------------------------------------------------------------
-//
-// Copyright (C) Microsoft Corporation. All Rights Reserved.
-//
-//-----------------------------------------------------------------------------
-using System;
-using System.Collections;
-using Microsoft.Boogie;
-using Microsoft.Boogie.VCExprAST;
-using System.Diagnostics.Contracts;
-using System.Collections.Generic;
-using Microsoft.Basetypes;
-
-namespace VC {
- public class VCContext
- {
- [ContractInvariantMethod]
- void ObjectInvariant()
- {
- Contract.Invariant(Ctxt != null);
- }
-
- [Rep] public readonly Dictionary<int, Absy> Label2absy;
- [Rep] public readonly ProverContext Ctxt;
- public readonly VCExpr ControlFlowVariableExpr;
- public int AssertionCount; // counts the number of assertions for which Wlp has been computed
- public bool isPositiveContext;
-
- public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, bool isPositiveContext = true)
- {
- Contract.Requires(ctxt != null);
- this.Label2absy = label2absy;
- this.Ctxt = ctxt;
- this.isPositiveContext = isPositiveContext;
- }
-
- public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, VCExpr controlFlowVariableExpr, bool isPositiveContext = true)
- {
- Contract.Requires(ctxt != null);
- this.Label2absy = label2absy;
- this.Ctxt = ctxt;
- this.ControlFlowVariableExpr = controlFlowVariableExpr;
- this.isPositiveContext = isPositiveContext;
- }
- }
-
- #region A class to compute wlp of a passive command program
-
- public class Wlp
- {
- public static VCExpr Block(Block b, VCExpr N, VCContext ctxt)
- //modifies ctxt.*;
- {
- Contract.Requires(b != null);
- Contract.Requires(N != null);
- Contract.Requires(ctxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpressionGenerator gen = ctxt.Ctxt.ExprGen;
- Contract.Assert(gen != null);
-
- VCExpr res = N;
-
- for (int i = b.Cmds.Count; --i >= 0; )
- {
- res = Cmd(b, cce.NonNull( b.Cmds[i]), res, ctxt);
- }
-
- int id = b.UniqueId;
- if (ctxt.Label2absy != null) {
- ctxt.Label2absy[id] = b;
- }
-
- try {
- cce.BeginExpose(ctxt);
- if (ctxt.Label2absy == null) {
- return res;
- }
- else {
- return gen.Implies(gen.LabelPos(cce.NonNull(id.ToString()), VCExpressionGenerator.True), res);
- }
- } finally {
- cce.EndExpose();
- }
- }
-
- /// <summary>
- /// Computes the wlp for an assert or assume command "cmd".
- /// </summary>
- public static VCExpr Cmd(Block b, Cmd cmd, VCExpr N, VCContext ctxt) {
- Contract.Requires(cmd != null);
- Contract.Requires(N != null);
- Contract.Requires(ctxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- VCExpressionGenerator gen = ctxt.Ctxt.ExprGen;
- Contract.Assert(gen != null);
- if (cmd is AssertCmd) {
- AssertCmd ac = (AssertCmd)cmd;
-
- var isFullyVerified = false;
- if (ac.VerifiedUnder != null)
- {
- var litExpr = ac.VerifiedUnder as LiteralExpr;
- isFullyVerified = litExpr != null && litExpr.IsTrue;
- }
-
- if (!isFullyVerified)
- {
- ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext;
- }
-
- VCExpr C = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr);
-
- VCExpr VU = null;
- if (!isFullyVerified)
- {
- if (ac.VerifiedUnder != null)
- {
- VU = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.VerifiedUnder);
-
- if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout)
- {
- ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd);
- VU = gen.Or(VU, gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++))));
- }
- }
- else if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout)
- {
- ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd);
- VU = gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++)));
- }
- ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext;
- }
-
- VCExpr R = null;
- if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) {
- R = gen.Implies(C, N);
- } else {
- var subsumption = Subsumption(ac);
- if (subsumption == CommandLineOptions.SubsumptionOption.Always
- || (subsumption == CommandLineOptions.SubsumptionOption.NotForQuantifiers && !(C is VCExprQuantifier)))
- {
- N = gen.ImpliesSimp(C, N, false);
- }
-
- if (isFullyVerified)
- {
- return N;
- }
- else if (VU != null)
- {
- C = gen.OrSimp(VU, C);
- }
-
- int id = ac.UniqueId;
- if (ctxt.Label2absy != null)
- {
- ctxt.Label2absy[id] = ac;
- }
-
- ctxt.AssertionCount++;
-
- if (ctxt.ControlFlowVariableExpr == null) {
- Contract.Assert(ctxt.Label2absy != null);
- R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), C), N);
- } else {
- VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(ctxt.ControlFlowVariableExpr, gen.Integer(BigNum.FromInt(b.UniqueId)));
- Contract.Assert(controlFlowFunctionAppl != null);
- VCExpr assertFailure = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(-ac.UniqueId)));
- if (ctxt.Label2absy == null) {
- R = gen.AndSimp(gen.Implies(assertFailure, C), N);
- } else {
- R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), gen.Implies(assertFailure, C)), N);
- }
- }
- }
- return R;
- } else if (cmd is AssumeCmd) {
- AssumeCmd ac = (AssumeCmd)cmd;
-
- if (CommandLineOptions.Clo.StratifiedInlining > 0) {
- // Label the assume if it is a procedure call
- NAryExpr naryExpr = ac.Expr as NAryExpr;
- if (naryExpr != null) {
- if (naryExpr.Fun is FunctionCall) {
- int id = ac.UniqueId;
- ctxt.Label2absy[id] = ac;
- return gen.ImpliesSimp(gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr)), N);
- }
- }
- }
- return gen.ImpliesSimp(ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr), N);
- } else {
- Console.WriteLine(cmd.ToString());
- Contract.Assert(false); throw new cce.UnreachableException(); // unexpected command
- }
- }
-
- public static CommandLineOptions.SubsumptionOption Subsumption(AssertCmd ac) {
- Contract.Requires(ac != null);
- int n = QKeyValue.FindIntAttribute(ac.Attributes, "subsumption", -1);
- switch (n) {
- case 0: return CommandLineOptions.SubsumptionOption.Never;
- case 1: return CommandLineOptions.SubsumptionOption.NotForQuantifiers;
- case 2: return CommandLineOptions.SubsumptionOption.Always;
- default: return CommandLineOptions.Clo.UseSubsumption;
- }
- }
-
- public static VCExpr RegExpr(RE r, VCExpr N, VCContext ctxt)
- {
- Contract.Requires(r != null);
- Contract.Requires(N != null);
- Contract.Requires(ctxt != null);
- Contract.Ensures(Contract.Result<VCExpr>() != null);
-
- if ( r is AtomicRE )
- {
- AtomicRE ar = (AtomicRE) r;
- return Block(ar.b, N, ctxt);
- }
- else if ( r is Sequential )
- {
- Sequential s = (Sequential) r;
- return RegExpr(s.first, RegExpr(s.second, N, ctxt), ctxt);
- }
- else if ( r is Choice )
- {
- Choice ch = (Choice) r;
- VCExpr res;
- if (ch.rs == null || ch.rs.Count==0)
- {
- res = N;
- }
- else
- {
- VCExpr currentWLP = RegExpr(cce.NonNull(ch.rs[0]), N, ctxt);
- for (int i = 1, n = ch.rs.Count; i < n; i++)
- {
- currentWLP = ctxt.Ctxt.ExprGen.And(currentWLP, RegExpr(cce.NonNull(ch.rs[i]), N, ctxt));
- }
- res = currentWLP;
- }
- return res;
- }
- else
- {
- Contract.Assert(false);throw new cce.UnreachableException(); // unexpected RE subtype
- }
- }
- }
- #endregion
-
-}
+//----------------------------------------------------------------------------- +// +// Copyright (C) Microsoft Corporation. All Rights Reserved. +// +//----------------------------------------------------------------------------- +using System; +using System.Collections; +using Microsoft.Boogie; +using Microsoft.Boogie.VCExprAST; +using System.Diagnostics.Contracts; +using System.Collections.Generic; +using Microsoft.Basetypes; + +namespace VC { + public class VCContext + { + [ContractInvariantMethod] + void ObjectInvariant() + { + Contract.Invariant(Ctxt != null); + } + + [Rep] public readonly Dictionary<int, Absy> Label2absy; + [Rep] public readonly ProverContext Ctxt; + public readonly VCExpr ControlFlowVariableExpr; + public int AssertionCount; // counts the number of assertions for which Wlp has been computed + public bool isPositiveContext; + + public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, bool isPositiveContext = true) + { + Contract.Requires(ctxt != null); + this.Label2absy = label2absy; + this.Ctxt = ctxt; + this.isPositiveContext = isPositiveContext; + } + + public VCContext(Dictionary<int, Absy> label2absy, ProverContext ctxt, VCExpr controlFlowVariableExpr, bool isPositiveContext = true) + { + Contract.Requires(ctxt != null); + this.Label2absy = label2absy; + this.Ctxt = ctxt; + this.ControlFlowVariableExpr = controlFlowVariableExpr; + this.isPositiveContext = isPositiveContext; + } + } + + #region A class to compute wlp of a passive command program + + public class Wlp + { + public static VCExpr Block(Block b, VCExpr N, VCContext ctxt) + //modifies ctxt.*; + { + Contract.Requires(b != null); + Contract.Requires(N != null); + Contract.Requires(ctxt != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpressionGenerator gen = ctxt.Ctxt.ExprGen; + Contract.Assert(gen != null); + + VCExpr res = N; + + for (int i = b.Cmds.Count; --i >= 0; ) + { + res = Cmd(b, cce.NonNull( b.Cmds[i]), res, ctxt); + } + + int id = b.UniqueId; + if (ctxt.Label2absy != null) { + ctxt.Label2absy[id] = b; + } + + try { + cce.BeginExpose(ctxt); + if (ctxt.Label2absy == null) { + return res; + } + else { + return gen.Implies(gen.LabelPos(cce.NonNull(id.ToString()), VCExpressionGenerator.True), res); + } + } finally { + cce.EndExpose(); + } + } + + /// <summary> + /// Computes the wlp for an assert or assume command "cmd". + /// </summary> + public static VCExpr Cmd(Block b, Cmd cmd, VCExpr N, VCContext ctxt) { + Contract.Requires(cmd != null); + Contract.Requires(N != null); + Contract.Requires(ctxt != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + VCExpressionGenerator gen = ctxt.Ctxt.ExprGen; + Contract.Assert(gen != null); + if (cmd is AssertCmd) { + AssertCmd ac = (AssertCmd)cmd; + + var isFullyVerified = false; + if (ac.VerifiedUnder != null) + { + var litExpr = ac.VerifiedUnder as LiteralExpr; + isFullyVerified = litExpr != null && litExpr.IsTrue; + } + + if (!isFullyVerified) + { + ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext; + } + + VCExpr C = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr); + + VCExpr VU = null; + if (!isFullyVerified) + { + if (ac.VerifiedUnder != null) + { + VU = ctxt.Ctxt.BoogieExprTranslator.Translate(ac.VerifiedUnder); + + if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout) + { + ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd); + VU = gen.Or(VU, gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++)))); + } + } + else if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout) + { + ctxt.Ctxt.TimeoutDiagnosticIDToAssertion[ctxt.Ctxt.TimoutDiagnosticsCount] = new Tuple<AssertCmd,TransferCmd>(ac, b.TransferCmd); + VU = gen.Function(VCExpressionGenerator.TimeoutDiagnosticsOp, gen.Integer(BigNum.FromInt(ctxt.Ctxt.TimoutDiagnosticsCount++))); + } + ctxt.Ctxt.BoogieExprTranslator.isPositiveContext = !ctxt.Ctxt.BoogieExprTranslator.isPositiveContext; + } + + VCExpr R = null; + if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { + R = gen.Implies(C, N); + } else { + var subsumption = Subsumption(ac); + if (subsumption == CommandLineOptions.SubsumptionOption.Always + || (subsumption == CommandLineOptions.SubsumptionOption.NotForQuantifiers && !(C is VCExprQuantifier))) + { + N = gen.ImpliesSimp(C, N, false); + } + + if (isFullyVerified) + { + return N; + } + else if (VU != null) + { + C = gen.OrSimp(VU, C); + } + + int id = ac.UniqueId; + if (ctxt.Label2absy != null) + { + ctxt.Label2absy[id] = ac; + } + + ctxt.AssertionCount++; + + if (ctxt.ControlFlowVariableExpr == null) { + Contract.Assert(ctxt.Label2absy != null); + R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), C), N); + } else { + VCExpr controlFlowFunctionAppl = gen.ControlFlowFunctionApplication(ctxt.ControlFlowVariableExpr, gen.Integer(BigNum.FromInt(b.UniqueId))); + Contract.Assert(controlFlowFunctionAppl != null); + VCExpr assertFailure = gen.Eq(controlFlowFunctionAppl, gen.Integer(BigNum.FromInt(-ac.UniqueId))); + if (ctxt.Label2absy == null) { + R = gen.AndSimp(gen.Implies(assertFailure, C), N); + } else { + R = gen.AndSimp(gen.LabelNeg(cce.NonNull(id.ToString()), gen.Implies(assertFailure, C)), N); + } + } + } + return R; + } else if (cmd is AssumeCmd) { + AssumeCmd ac = (AssumeCmd)cmd; + + if (CommandLineOptions.Clo.StratifiedInlining > 0) { + // Label the assume if it is a procedure call + NAryExpr naryExpr = ac.Expr as NAryExpr; + if (naryExpr != null) { + if (naryExpr.Fun is FunctionCall) { + int id = ac.UniqueId; + ctxt.Label2absy[id] = ac; + return gen.ImpliesSimp(gen.LabelPos(cce.NonNull("si_fcall_" + id.ToString()), ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr)), N); + } + } + } + return gen.ImpliesSimp(ctxt.Ctxt.BoogieExprTranslator.Translate(ac.Expr), N); + } else { + Console.WriteLine(cmd.ToString()); + Contract.Assert(false); throw new cce.UnreachableException(); // unexpected command + } + } + + public static CommandLineOptions.SubsumptionOption Subsumption(AssertCmd ac) { + Contract.Requires(ac != null); + int n = QKeyValue.FindIntAttribute(ac.Attributes, "subsumption", -1); + switch (n) { + case 0: return CommandLineOptions.SubsumptionOption.Never; + case 1: return CommandLineOptions.SubsumptionOption.NotForQuantifiers; + case 2: return CommandLineOptions.SubsumptionOption.Always; + default: return CommandLineOptions.Clo.UseSubsumption; + } + } + + public static VCExpr RegExpr(RE r, VCExpr N, VCContext ctxt) + { + Contract.Requires(r != null); + Contract.Requires(N != null); + Contract.Requires(ctxt != null); + Contract.Ensures(Contract.Result<VCExpr>() != null); + + if ( r is AtomicRE ) + { + AtomicRE ar = (AtomicRE) r; + return Block(ar.b, N, ctxt); + } + else if ( r is Sequential ) + { + Sequential s = (Sequential) r; + return RegExpr(s.first, RegExpr(s.second, N, ctxt), ctxt); + } + else if ( r is Choice ) + { + Choice ch = (Choice) r; + VCExpr res; + if (ch.rs == null || ch.rs.Count==0) + { + res = N; + } + else + { + VCExpr currentWLP = RegExpr(cce.NonNull(ch.rs[0]), N, ctxt); + for (int i = 1, n = ch.rs.Count; i < n; i++) + { + currentWLP = ctxt.Ctxt.ExprGen.And(currentWLP, RegExpr(cce.NonNull(ch.rs[i]), N, ctxt)); + } + res = currentWLP; + } + return res; + } + else + { + Contract.Assert(false);throw new cce.UnreachableException(); // unexpected RE subtype + } + } + } + #endregion + +} diff --git a/Source/VCGeneration/cce.cs b/Source/VCGeneration/cce.cs index 23d79815..42cabfcb 100644 --- a/Source/VCGeneration/cce.cs +++ b/Source/VCGeneration/cce.cs @@ -1,105 +1,105 @@ -
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.Contracts;
-using System.Text;
-using Microsoft.Boogie;
-
- /// <summary>
- /// A class containing static methods to extend the functionality of Code Contracts
- /// </summary>
-
-public static class cce {
- [Pure]
- public static T NonNull<T>(T t) {
- Contract.Assert(t != null);
- return t;
- }
- [Pure]
- public static bool NonNullElements<T>(IEnumerable<T> collection) {
- return collection != null && Contract.ForAll(collection, c => c != null);
- }
- [Pure]
- public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> collection) {
- return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values);
- }
- [Pure]
- public static bool NonNullElements(VariableSeq collection) {
- return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null);
- }
- [Pure]
- public static void BeginExpose(object o) {
- }
- [Pure]
- public static void EndExpose() {
- }
- [Pure]
- public static bool IsPeerConsistent(object o) {
- return true;
- }
- [Pure]
- public static bool IsConsistent(object o) {
- return true;
- }
- [Pure]
- public static bool IsExposable(object o) {
- return true;
- }
- [Pure]
- public static bool IsExposed(object o) {
- return true;
- }
- public static class Owner {
- [Pure]
- public static bool Same(object o, object p) {
- return true;
- }
- [Pure]
- public static void AssignSame(object o, object p) {
- }
- [Pure]
- public static object ElementProxy(object o) {
- return o;
- }
- [Pure]
- public static bool None(object o) {
- return true;
- }
- }
- [Pure]
- public static void LoopInvariant(bool p) {
- Contract.Assert(p);
- }
-
- public class UnreachableException : Exception {
- public UnreachableException() {
- }
- }
-}
-
-public class PeerAttribute : System.Attribute {
-}
-public class RepAttribute : System.Attribute {
-}
-public class CapturedAttribute : System.Attribute {
-}
-public class NotDelayedAttribute : System.Attribute {
-}
-public class NoDefaultContractAttribute : System.Attribute {
-}
-public class VerifyAttribute : System.Attribute {
- public VerifyAttribute(bool b) {
-
- }
-}
-public class StrictReadonlyAttribute : System.Attribute {
- }
-public class AdditiveAttribute : System.Attribute {
-}
-public class ReadsAttribute : System.Attribute {
- public enum Reads {
- Nothing,
- };
- public ReadsAttribute(object o) {
- }
-}
+ +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Text; +using Microsoft.Boogie; + + /// <summary> + /// A class containing static methods to extend the functionality of Code Contracts + /// </summary> + +public static class cce { + [Pure] + public static T NonNull<T>(T t) { + Contract.Assert(t != null); + return t; + } + [Pure] + public static bool NonNullElements<T>(IEnumerable<T> collection) { + return collection != null && Contract.ForAll(collection, c => c != null); + } + [Pure] + public static bool NonNullElements<TKey, TValue>(IDictionary<TKey, TValue> collection) { + return collection != null && NonNullElements(collection.Keys) && NonNullElements(collection.Values); + } + [Pure] + public static bool NonNullElements(VariableSeq collection) { + return collection != null && Contract.ForAll(0, collection.Length, i => collection[i] != null); + } + [Pure] + public static void BeginExpose(object o) { + } + [Pure] + public static void EndExpose() { + } + [Pure] + public static bool IsPeerConsistent(object o) { + return true; + } + [Pure] + public static bool IsConsistent(object o) { + return true; + } + [Pure] + public static bool IsExposable(object o) { + return true; + } + [Pure] + public static bool IsExposed(object o) { + return true; + } + public static class Owner { + [Pure] + public static bool Same(object o, object p) { + return true; + } + [Pure] + public static void AssignSame(object o, object p) { + } + [Pure] + public static object ElementProxy(object o) { + return o; + } + [Pure] + public static bool None(object o) { + return true; + } + } + [Pure] + public static void LoopInvariant(bool p) { + Contract.Assert(p); + } + + public class UnreachableException : Exception { + public UnreachableException() { + } + } +} + +public class PeerAttribute : System.Attribute { +} +public class RepAttribute : System.Attribute { +} +public class CapturedAttribute : System.Attribute { +} +public class NotDelayedAttribute : System.Attribute { +} +public class NoDefaultContractAttribute : System.Attribute { +} +public class VerifyAttribute : System.Attribute { + public VerifyAttribute(bool b) { + + } +} +public class StrictReadonlyAttribute : System.Attribute { + } +public class AdditiveAttribute : System.Attribute { +} +public class ReadsAttribute : System.Attribute { + public enum Reads { + Nothing, + }; + public ReadsAttribute(object o) { + } +} |