using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.IO; using System.Linq; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using VC; using BoogiePL = Microsoft.Boogie; using System.Diagnostics; using System.Runtime.Caching; namespace Microsoft.Boogie { #region Output printing public interface OutputPrinter { void ErrorWriteLine(TextWriter tw, string s); void ErrorWriteLine(TextWriter tw, string format, params object[] args); void AdvisoryWriteLine(string format, params object[] args); void Inform(string s, TextWriter tw); void WriteTrailer(PipelineStatistics stats); void WriteErrorInformation(ErrorInformation errorInfo, TextWriter tw, bool skipExecutionTrace = true); void ReportBplError(IToken tok, string message, bool error, TextWriter tw, string category = null); } public class ConsolePrinter : OutputPrinter { public void ErrorWriteLine(TextWriter tw, string s) { Contract.Requires(s != null); if (!s.Contains("Error: ") && !s.Contains("Error BP")) { tw.WriteLine(s); return; } // split the string up into its first line and the remaining lines string remaining = null; int i = s.IndexOf('\r'); if (0 <= i) { remaining = s.Substring(i + 1); if (remaining.StartsWith("\n")) { remaining = remaining.Substring(1); } s = s.Substring(0, i); } ConsoleColor col = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; tw.WriteLine(s); Console.ForegroundColor = col; if (remaining != null) { tw.WriteLine(remaining); } } public void ErrorWriteLine(TextWriter tw, string format, params object[] args) { Contract.Requires(format != null); string s = string.Format(format, args); ErrorWriteLine(tw, s); } public void AdvisoryWriteLine(string format, params object[] args) { Contract.Requires(format != null); ConsoleColor col = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(format, args); Console.ForegroundColor = col; } /// /// Inform the user about something and proceed with translation normally. /// Print newline after the message. /// public void Inform(string s, TextWriter tw) { if (CommandLineOptions.Clo.Trace || CommandLineOptions.Clo.TraceProofObligations) { tw.WriteLine(s); } } public void WriteTrailer(PipelineStatistics stats) { Contract.Requires(stats != null); Contract.Requires(0 <= stats.VerifiedCount && 0 <= stats.ErrorCount && 0 <= stats.InconclusiveCount && 0 <= stats.TimeoutCount && 0 <= stats.OutOfMemoryCount); Console.WriteLine(); if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { Console.Write("{0} finished with {1} credible, {2} doomed{3}", CommandLineOptions.Clo.DescriptiveToolName, stats.VerifiedCount, stats.ErrorCount, stats.ErrorCount == 1 ? "" : "s"); } else { Console.Write("{0} finished with {1} verified, {2} error{3}", CommandLineOptions.Clo.DescriptiveToolName, stats.VerifiedCount, stats.ErrorCount, stats.ErrorCount == 1 ? "" : "s"); } if (stats.InconclusiveCount != 0) { Console.Write(", {0} inconclusive{1}", stats.InconclusiveCount, stats.InconclusiveCount == 1 ? "" : "s"); } if (stats.TimeoutCount != 0) { Console.Write(", {0} time out{1}", stats.TimeoutCount, stats.TimeoutCount == 1 ? "" : "s"); } if (stats.OutOfMemoryCount != 0) { Console.Write(", {0} out of memory", stats.OutOfMemoryCount); } Console.WriteLine(); Console.Out.Flush(); } public void WriteErrorInformation(ErrorInformation errorInfo, TextWriter tw, bool skipExecutionTrace = true) { Contract.Requires(errorInfo != null); ReportBplError(errorInfo.Tok, errorInfo.FullMsg, true, tw); foreach (var e in errorInfo.Aux) { if (!(skipExecutionTrace && e.Category != null && e.Category.Contains("Execution trace"))) { ReportBplError(e.Tok, e.FullMsg, false, tw); } } tw.Write(errorInfo.Out.ToString()); tw.Write(errorInfo.Model.ToString()); tw.Flush(); } public virtual void ReportBplError(IToken tok, string message, bool error, TextWriter tw, string category = null) { Contract.Requires(message != null); if (category != null) { message = string.Format("{0}: {1}", category, message); } string s; if (tok != null) { s = string.Format("{0}({1},{2}): {3}", ExecutionEngine.GetFileNameForConsole(tok.filename), tok.line, tok.col, message); } else { s = message; } if (error) { ErrorWriteLine(tw, s); } else { tw.WriteLine(s); } } } #endregion public enum PipelineOutcome { Done, ResolutionError, TypeCheckingError, ResolvedAndTypeChecked, FatalError, VerificationCompleted } public class PipelineStatistics { public int ErrorCount; public int VerifiedCount; public int InconclusiveCount; public int TimeoutCount; public int OutOfMemoryCount; public long[] CachingActionCounts; public int CachedErrorCount; public int CachedVerifiedCount; public int CachedInconclusiveCount; public int CachedTimeoutCount; public int CachedOutOfMemoryCount; } #region Error reporting public delegate void ErrorReporterDelegate(ErrorInformation errInfo); public enum ErrorKind { Assertion, Precondition, Postcondition, InvariantEntry, InvariantMaintainance } public class ErrorInformationFactory { public virtual ErrorInformation CreateErrorInformation(IToken tok, string msg, string requestId = null, string originalRequestId = null, string category = null) { Contract.Requires(1 <= tok.line && 1 <= tok.col); Contract.Requires(msg != null); return ErrorInformation.CreateErrorInformation(tok, msg, requestId, originalRequestId, category); } } public class ErrorInformation { public readonly IToken Tok; public string Msg; public string Category { get; set; } public string BoogieErrorCode { get; set; } public readonly List Aux = new List(); public string OriginalRequestId { get; set; } public string RequestId { get; set; } public ErrorKind Kind { get; set; } public string ImplementationName { get; set; } public TextWriter Out = new StringWriter(); public TextWriter Model = new StringWriter(); public string FullMsg { get { var prefix = Category; if (BoogieErrorCode != null) { prefix = prefix == null ? BoogieErrorCode : prefix + " " + BoogieErrorCode; } return prefix != null ? string.Format("{0}: {1}", prefix, Msg) : Msg; } } public struct AuxErrorInfo { public readonly IToken Tok; public readonly string Msg; public readonly string Category; public string FullMsg { get { return Category != null ? string.Format("{0}: {1}", Category, Msg) : Msg; } } public AuxErrorInfo(IToken tok, string msg, string category = null) { Tok = tok; Msg = CleanUp(msg); Category = category; } } protected ErrorInformation(IToken tok, string msg) { Contract.Requires(tok != null); Contract.Requires(1 <= tok.line && 1 <= tok.col); Contract.Requires(msg != null); Tok = tok; Msg = CleanUp(msg); } internal static ErrorInformation CreateErrorInformation(IToken tok, string msg, string requestId = null, string originalRequestId = null, string category = null) { var result = new ErrorInformation(tok, msg); result.RequestId = requestId; result.OriginalRequestId = originalRequestId; result.Category = category; return result; } public virtual void AddAuxInfo(IToken tok, string msg, string category = null) { Contract.Requires(tok != null); Contract.Requires(1 <= tok.line && 1 <= tok.col); Contract.Requires(msg != null); Aux.Add(new AuxErrorInfo(tok, msg, category)); } protected static string CleanUp(string msg) { if (msg.ToLower().StartsWith("error: ")) { return msg.Substring(7); } else { return msg; } } } #endregion public sealed class VerificationResult { public readonly string RequestId; public readonly string Checksum; public readonly string DependeciesChecksum; public readonly string ImplementationName; public readonly IToken ImplementationToken; public readonly string ProgramId; public DateTime Start { get; set; } public DateTime End { get; set; } public int ProofObligationCount { get { return ProofObligationCountAfter - ProofObligationCountBefore; } } public int ProofObligationCountBefore { get; set; } public int ProofObligationCountAfter { get; set; } public ConditionGeneration.Outcome Outcome { get; set; } public List Errors; public ISet AssertionChecksums { get; private set; } public VerificationResult(string requestId, Implementation implementation, string programId = null) { Checksum = implementation.Checksum; DependeciesChecksum = implementation.DependencyChecksum; RequestId = requestId; ImplementationName = implementation.Name; ImplementationToken = implementation.tok; ProgramId = programId; AssertionChecksums = implementation.AssertionChecksums; } } public class PolymorphismChecker : ReadOnlyVisitor { bool isMonomorphic = true; public override DeclWithFormals VisitDeclWithFormals(DeclWithFormals node) { if (node.TypeParameters.Count > 0) isMonomorphic = false; return base.VisitDeclWithFormals(node); } public override BinderExpr VisitBinderExpr(BinderExpr node) { if (node.TypeParameters.Count > 0) isMonomorphic = false; return base.VisitBinderExpr(node); } public override MapType VisitMapType(MapType node) { if (node.TypeParameters.Count > 0) isMonomorphic = false; return base.VisitMapType(node); } public override Expr VisitNAryExpr(NAryExpr node) { BinaryOperator op = node.Fun as BinaryOperator; if (op != null && op.Op == BinaryOperator.Opcode.Subtype) isMonomorphic = false; return base.VisitNAryExpr(node); } public static bool IsMonomorphic(Program program) { var checker = new PolymorphismChecker(); checker.VisitProgram(program); return checker.isMonomorphic; } } public class ExecutionEngine { public static OutputPrinter printer; public static ErrorInformationFactory errorInformationFactory = new ErrorInformationFactory(); static int autoRequestIdCount; static readonly string AutoRequestIdPrefix = "auto_request_id_"; public static string FreshRequestId() { var id = Interlocked.Increment(ref autoRequestIdCount); return AutoRequestIdPrefix + id; } public static int AutoRequestId(string id) { if (id.StartsWith(AutoRequestIdPrefix)) { int result; if (int.TryParse(id.Substring(AutoRequestIdPrefix.Length), out result)) { return result; } } return -1; } public readonly static VerificationResultCache Cache = new VerificationResultCache(); static readonly MemoryCache programCache = new MemoryCache("ProgramCache"); static readonly CacheItemPolicy policy = new CacheItemPolicy { SlidingExpiration = new TimeSpan(0, 10, 0), Priority = CacheItemPriority.Default }; public static Program CachedProgram(string programId) { var result = programCache.Get(programId) as Program; return result; } static List Checkers = new List(); static DateTime FirstRequestStart; static readonly ConcurrentDictionary TimePerRequest = new ConcurrentDictionary(); static readonly ConcurrentDictionary StatisticsPerRequest = new ConcurrentDictionary(); static readonly ConcurrentDictionary ImplIdToCancellationTokenSource = new ConcurrentDictionary(); static readonly ConcurrentDictionary RequestIdToCancellationTokenSource = new ConcurrentDictionary(); static ThreadTaskScheduler Scheduler = new ThreadTaskScheduler(16 * 1024 * 1024); public static void ProcessFiles(List fileNames, bool lookForSnapshots = true, string programId = null) { Contract.Requires(cce.NonNullElements(fileNames)); if (programId == null) { programId = "main_program_id"; } if (CommandLineOptions.Clo.VerifySeparately && 1 < fileNames.Count) { foreach (var f in fileNames) { ProcessFiles(new List { f }, lookForSnapshots, f); } return; } if (0 <= CommandLineOptions.Clo.VerifySnapshots && lookForSnapshots) { var snapshotsByVersion = LookForSnapshots(fileNames); foreach (var s in snapshotsByVersion) { ProcessFiles(new List(s), false, programId); } return; } using (XmlFileScope xf = new XmlFileScope(CommandLineOptions.Clo.XmlSink, fileNames[fileNames.Count - 1])) { Program program = ParseBoogieProgram(fileNames, false); if (program == null) return; if (CommandLineOptions.Clo.PrintFile != null) { PrintBplFile(CommandLineOptions.Clo.PrintFile, program, false, true, CommandLineOptions.Clo.PrettyPrint); } LinearTypeChecker linearTypeChecker; CivlTypeChecker civlTypeChecker; PipelineOutcome oc = ResolveAndTypecheck(program, fileNames[fileNames.Count - 1], out linearTypeChecker, out civlTypeChecker); if (oc != PipelineOutcome.ResolvedAndTypeChecked) return; if (CommandLineOptions.Clo.PrintCFGPrefix != null) { foreach (var impl in program.Implementations) { using (StreamWriter sw = new StreamWriter(CommandLineOptions.Clo.PrintCFGPrefix + "." + impl.Name + ".dot")) { sw.Write(program.ProcessLoops(impl).ToDot()); } } } if (CommandLineOptions.Clo.StratifiedInlining == 0) { Concurrency.Transform(linearTypeChecker, civlTypeChecker); (new LinearEraser()).VisitProgram(program); if (CommandLineOptions.Clo.CivlDesugaredFile != null) { int oldPrintUnstructured = CommandLineOptions.Clo.PrintUnstructured; CommandLineOptions.Clo.PrintUnstructured = 1; PrintBplFile(CommandLineOptions.Clo.CivlDesugaredFile, program, false, false, CommandLineOptions.Clo.PrettyPrint); CommandLineOptions.Clo.PrintUnstructured = oldPrintUnstructured; } } EliminateDeadVariables(program); CoalesceBlocks(program); Inline(program); var stats = new PipelineStatistics(); oc = InferAndVerify(program, stats, 1 < CommandLineOptions.Clo.VerifySnapshots ? programId : null); switch (oc) { case PipelineOutcome.Done: case PipelineOutcome.VerificationCompleted: printer.WriteTrailer(stats); break; default: break; } } } public static IList> LookForSnapshots(IList fileNames) { Contract.Requires(fileNames != null); var result = new List>(); for (int version = 0; true; version++) { var nextSnapshot = new List(); foreach (var name in fileNames) { var versionedName = name.Replace(Path.GetExtension(name), ".v" + version + Path.GetExtension(name)); if (File.Exists(versionedName)) { nextSnapshot.Add(versionedName); } } if (nextSnapshot.Any()) { result.Add(nextSnapshot); } else { break; } } return result; } public static void CoalesceBlocks(Program program) { if (CommandLineOptions.Clo.CoalesceBlocks) { if (CommandLineOptions.Clo.Trace) Console.WriteLine("Coalescing blocks..."); Microsoft.Boogie.BlockCoalescer.CoalesceBlocks(program); } } public static void CollectModSets(Program program) { if (CommandLineOptions.Clo.DoModSetAnalysis) { new ModSetCollector().DoModSetAnalysis(program); } } public static void EliminateDeadVariables(Program program) { Microsoft.Boogie.UnusedVarEliminator.Eliminate(program); } public static void PrintBplFile(string filename, Program program, bool allowPrintDesugaring, bool setTokens = true, bool pretty = false) { Contract.Requires(program != null); Contract.Requires(filename != null); bool oldPrintDesugaring = CommandLineOptions.Clo.PrintDesugarings; if (!allowPrintDesugaring) { CommandLineOptions.Clo.PrintDesugarings = false; } using (TokenTextWriter writer = filename == "-" ? new TokenTextWriter("", Console.Out, setTokens, pretty) : new TokenTextWriter(filename, setTokens, pretty)) { if (CommandLineOptions.Clo.ShowEnv != CommandLineOptions.ShowEnvironment.Never) { writer.WriteLine("// " + CommandLineOptions.Clo.Version); writer.WriteLine("// " + CommandLineOptions.Clo.Environment); } writer.WriteLine(); program.Emit(writer); } CommandLineOptions.Clo.PrintDesugarings = oldPrintDesugaring; } /// /// Parse the given files into one Boogie program. If an I/O or parse error occurs, an error will be printed /// and null will be returned. On success, a non-null program is returned. /// public static Program ParseBoogieProgram(List fileNames, bool suppressTraceOutput) { Contract.Requires(cce.NonNullElements(fileNames)); Program program = null; bool okay = true; for (int fileId = 0; fileId < fileNames.Count; fileId++) { string bplFileName = fileNames[fileId]; if (!suppressTraceOutput) { if (CommandLineOptions.Clo.XmlSink != null) { CommandLineOptions.Clo.XmlSink.WriteFileFragment(bplFileName); } if (CommandLineOptions.Clo.Trace) { Console.WriteLine("Parsing " + GetFileNameForConsole(bplFileName)); } } Program programSnippet; int errorCount; try { var defines = new List() { "FILE_" + fileId }; errorCount = Parser.Parse(bplFileName, defines, out programSnippet, CommandLineOptions.Clo.UseBaseNameForFileName); if (programSnippet == null || errorCount != 0) { Console.WriteLine("{0} parse errors detected in {1}", errorCount, GetFileNameForConsole(bplFileName)); okay = false; continue; } } catch (IOException e) { printer.ErrorWriteLine(Console.Out, "Error opening file \"{0}\": {1}", GetFileNameForConsole(bplFileName), e.Message); okay = false; continue; } if (program == null) { program = programSnippet; } else if (programSnippet != null) { program.AddTopLevelDeclarations(programSnippet.TopLevelDeclarations); } } if (!okay) { return null; } else if (program == null) { return new Program(); } else { return program; } } internal static string GetFileNameForConsole(string filename) { return (CommandLineOptions.Clo.UseBaseNameForFileName && !string.IsNullOrEmpty(filename) && filename != "") ? System.IO.Path.GetFileName(filename) : filename; } /// /// Resolves and type checks the given Boogie program. Any errors are reported to the /// console. Returns: /// - Done if no errors occurred, and command line specified no resolution or no type checking. /// - ResolutionError if a resolution error occurred /// - TypeCheckingError if a type checking error occurred /// - ResolvedAndTypeChecked if both resolution and type checking succeeded /// public static PipelineOutcome ResolveAndTypecheck(Program program, string bplFileName, out LinearTypeChecker linearTypeChecker, out CivlTypeChecker civlTypeChecker) { Contract.Requires(program != null); Contract.Requires(bplFileName != null); linearTypeChecker = null; civlTypeChecker = null; // ---------- Resolve ------------------------------------------------------------ if (CommandLineOptions.Clo.NoResolve) { return PipelineOutcome.Done; } int errorCount = program.Resolve(); if (errorCount != 0) { Console.WriteLine("{0} name resolution errors detected in {1}", errorCount, GetFileNameForConsole(bplFileName)); return PipelineOutcome.ResolutionError; } // ---------- Type check ------------------------------------------------------------ if (CommandLineOptions.Clo.NoTypecheck) { return PipelineOutcome.Done; } errorCount = program.Typecheck(); if (errorCount != 0) { Console.WriteLine("{0} type checking errors detected in {1}", errorCount, GetFileNameForConsole(bplFileName)); return PipelineOutcome.TypeCheckingError; } if (PolymorphismChecker.IsMonomorphic(program)) { CommandLineOptions.Clo.TypeEncodingMethod = CommandLineOptions.TypeEncoding.Monomorphic; } CollectModSets(program); civlTypeChecker = new CivlTypeChecker(program); civlTypeChecker.TypeCheck(); if (civlTypeChecker.errorCount != 0) { Console.WriteLine("{0} type checking errors detected in {1}", civlTypeChecker.errorCount, GetFileNameForConsole(bplFileName)); return PipelineOutcome.TypeCheckingError; } linearTypeChecker = new LinearTypeChecker(program); linearTypeChecker.TypeCheck(); if (linearTypeChecker.errorCount == 0) { linearTypeChecker.Transform(); } else { Console.WriteLine("{0} type checking errors detected in {1}", linearTypeChecker.errorCount, GetFileNameForConsole(bplFileName)); return PipelineOutcome.TypeCheckingError; } if (CommandLineOptions.Clo.PrintFile != null && CommandLineOptions.Clo.PrintDesugarings) { // if PrintDesugaring option is engaged, print the file here, after resolution and type checking PrintBplFile(CommandLineOptions.Clo.PrintFile, program, true, true, CommandLineOptions.Clo.PrettyPrint); } return PipelineOutcome.ResolvedAndTypeChecked; } public static void Inline(Program program) { Contract.Requires(program != null); if (CommandLineOptions.Clo.Trace) Console.WriteLine("Inlining..."); // Inline var TopLevelDeclarations = cce.NonNull(program.TopLevelDeclarations); if (CommandLineOptions.Clo.ProcedureInlining != CommandLineOptions.Inlining.None) { bool inline = false; foreach (var d in TopLevelDeclarations) { if ((d is Procedure || d is Implementation) && d.FindExprAttribute("inline") != null) { inline = true; } } if (inline) { foreach (var impl in TopLevelDeclarations.OfType()) { impl.OriginalBlocks = impl.Blocks; impl.OriginalLocVars = impl.LocVars; } foreach (var impl in TopLevelDeclarations.OfType()) { if (CommandLineOptions.Clo.UserWantsToCheckRoutine(impl.Name) && !impl.SkipVerification) { Inliner.ProcessImplementation(program, impl); } } foreach (var impl in TopLevelDeclarations.OfType()) { impl.OriginalBlocks = null; impl.OriginalLocVars = null; } } } } /// /// Given a resolved and type checked Boogie program, infers invariants for the program /// and then attempts to verify it. Returns: /// - Done if command line specified no verification /// - FatalError if a fatal error occurred, in which case an error has been printed to console /// - VerificationCompleted if inference and verification completed, in which the out /// parameters contain meaningful values /// public static PipelineOutcome InferAndVerify(Program program, PipelineStatistics stats, string programId = null, ErrorReporterDelegate er = null, string requestId = null) { Contract.Requires(program != null); Contract.Requires(stats != null); Contract.Ensures(0 <= Contract.ValueAtReturn(out stats.InconclusiveCount) && 0 <= Contract.ValueAtReturn(out stats.TimeoutCount)); if (requestId == null) { requestId = FreshRequestId(); } var start = DateTime.UtcNow; #region Do some pre-abstract-interpretation preprocessing on the program // Doing lambda expansion before abstract interpretation means that the abstract interpreter // never needs to see any lambda expressions. (On the other hand, if it were useful for it // to see lambdas, then it would be better to more lambda expansion until after infererence.) if (CommandLineOptions.Clo.ExpandLambdas) { LambdaHelper.ExpandLambdas(program); //PrintBplFile ("-", program, true); } #endregion #region Infer invariants using Abstract Interpretation // Always use (at least) intervals, if not specified otherwise (e.g. with the "/noinfer" switch) if (CommandLineOptions.Clo.UseAbstractInterpretation) { if (!CommandLineOptions.Clo.Ai.J_Intervals && !CommandLineOptions.Clo.Ai.J_Trivial) { // use /infer:j as the default CommandLineOptions.Clo.Ai.J_Intervals = true; } } Microsoft.Boogie.AbstractInterpretation.NativeAbstractInterpretation.RunAbstractInterpretation(program); #endregion #region Do some post-abstract-interpretation preprocessing on the program (e.g., loop unrolling) if (CommandLineOptions.Clo.LoopUnrollCount != -1) { program.UnrollLoops(CommandLineOptions.Clo.LoopUnrollCount, CommandLineOptions.Clo.SoundLoopUnrolling); } Dictionary> extractLoopMappingInfo = null; if (CommandLineOptions.Clo.ExtractLoops) { extractLoopMappingInfo = program.ExtractLoops(); } if (CommandLineOptions.Clo.PrintInstrumented) { program.Emit(new TokenTextWriter(Console.Out, CommandLineOptions.Clo.PrettyPrint)); } #endregion if (!CommandLineOptions.Clo.Verify) { return PipelineOutcome.Done; } #region Run Houdini and verify if (CommandLineOptions.Clo.ContractInfer) { return RunHoudini(program, stats, er); } #endregion #region Select and prioritize implementations that should be verified var impls = program.Implementations.Where( impl => impl != null && CommandLineOptions.Clo.UserWantsToCheckRoutine(cce.NonNull(impl.Name)) && !impl.SkipVerification); // operate on a stable copy, in case it gets updated while we're running Implementation[] stablePrioritizedImpls = null; if (0 < CommandLineOptions.Clo.VerifySnapshots) { OtherDefinitionAxiomsCollector.Collect(program.Axioms); DependencyCollector.Collect(program); stablePrioritizedImpls = impls.OrderByDescending( impl => impl.Priority != 1 ? impl.Priority : Cache.VerificationPriority(impl)).ToArray(); } else { stablePrioritizedImpls = impls.OrderByDescending(impl => impl.Priority).ToArray(); } #endregion if (1 < CommandLineOptions.Clo.VerifySnapshots) { CachedVerificationResultInjector.Inject(program, stablePrioritizedImpls, requestId, programId, out stats.CachingActionCounts); } #region Verify each implementation var outputCollector = new OutputCollector(stablePrioritizedImpls); var outcome = PipelineOutcome.VerificationCompleted; try { var cts = new CancellationTokenSource(); RequestIdToCancellationTokenSource.AddOrUpdate(requestId, cts, (k, ov) => cts); var tasks = new Task[stablePrioritizedImpls.Length]; // We use this semaphore to limit the number of tasks that are currently executing. var semaphore = new SemaphoreSlim(CommandLineOptions.Clo.VcsCores); // Create a task per implementation. for (int i = 0; i < stablePrioritizedImpls.Length; i++) { var taskIndex = i; var id = stablePrioritizedImpls[taskIndex].Id; CancellationTokenSource old; if (ImplIdToCancellationTokenSource.TryGetValue(id, out old)) { old.Cancel(); } ImplIdToCancellationTokenSource.AddOrUpdate(id, cts, (k, ov) => cts); var t = new Task((dummy) => { try { if (outcome == PipelineOutcome.FatalError) { return; } if (cts.Token.IsCancellationRequested) { cts.Token.ThrowIfCancellationRequested(); } VerifyImplementation(program, stats, er, requestId, extractLoopMappingInfo, stablePrioritizedImpls, taskIndex, outputCollector, Checkers, programId); ImplIdToCancellationTokenSource.TryRemove(id, out old); } finally { semaphore.Release(); } }, cts.Token, TaskCreationOptions.None); tasks[taskIndex] = t; } // Execute the tasks. int j = 0; for (; j < stablePrioritizedImpls.Length && outcome != PipelineOutcome.FatalError; j++) { try { semaphore.Wait(cts.Token); } catch (OperationCanceledException) { break; } tasks[j].Start(Scheduler); } // Don't wait for tasks that haven't been started yet. tasks = tasks.Take(j).ToArray(); Task.WaitAll(tasks); } catch (AggregateException ae) { ae.Handle(e => { var pe = e as ProverException; if (pe != null) { printer.ErrorWriteLine(Console.Out, "Fatal Error: ProverException: {0}", e); outcome = PipelineOutcome.FatalError; return true; } var oce = e as OperationCanceledException; if (oce != null) { return true; } return false; }); } finally { CleanupCheckers(requestId); } if (CommandLineOptions.Clo.PrintNecessaryAssumes && program.NecessaryAssumes.Any()) { Console.WriteLine("Necessary assume command(s): {0}", string.Join(", ", program.NecessaryAssumes)); } cce.NonNull(CommandLineOptions.Clo.TheProverFactory).Close(); outputCollector.WriteMoreOutput(); if (1 < CommandLineOptions.Clo.VerifySnapshots && programId != null) { program.FreezeTopLevelDeclarations(); programCache.Set(programId, program, policy); } if (0 <= CommandLineOptions.Clo.VerifySnapshots && CommandLineOptions.Clo.TraceCachingForBenchmarking) { var end = DateTime.UtcNow; if (TimePerRequest.Count == 0) { FirstRequestStart = start; } TimePerRequest[requestId] = end.Subtract(start); StatisticsPerRequest[requestId] = stats; var printTimes = true; Console.Out.WriteLine(CachedVerificationResultInjector.Statistics.Output(printTimes)); Console.Out.WriteLine("Statistics per request as CSV:"); var actions = string.Join(", ", Enum.GetNames(typeof(VC.ConditionGeneration.CachingAction))); Console.Out.WriteLine("Request ID{0}, Error, E (C), Inconclusive, I (C), Out of Memory, OoM (C), Timeout, T (C), Verified, V (C), {1}", printTimes ? ", Time (ms)" : "", actions); foreach (var kv in TimePerRequest.OrderBy(kv => ExecutionEngine.AutoRequestId(kv.Key))) { var s = StatisticsPerRequest[kv.Key]; var cacs = s.CachingActionCounts; var c = cacs != null ? ", " + cacs.Select(ac => string.Format("{0,3}", ac)).Concat(", ") : ""; var t = printTimes ? string.Format(", {0,8:F0}", kv.Value.TotalMilliseconds) : ""; Console.Out.WriteLine("{0,-19}{1}, {2,2}, {3,2}, {4,2}, {5,2}, {6,2}, {7,2}, {8,2}, {9,2}, {10,2}, {11,2}{12}", kv.Key, t, s.ErrorCount, s.CachedErrorCount, s.InconclusiveCount, s.CachedInconclusiveCount, s.OutOfMemoryCount, s.CachedOutOfMemoryCount, s.TimeoutCount, s.CachedTimeoutCount, s.VerifiedCount, s.CachedVerifiedCount, c); } if (printTimes) { Console.Out.WriteLine(); Console.Out.WriteLine("Total time (ms) since first request: {0:F0}", end.Subtract(FirstRequestStart).TotalMilliseconds); } } #endregion if (SecureVCGen.outfile != null) SecureVCGen.outfile.Close(); return outcome; } public static void CancelRequest(string requestId) { Contract.Requires(requestId != null); CancellationTokenSource cts; if (RequestIdToCancellationTokenSource.TryGetValue(requestId, out cts)) { cts.Cancel(); CleanupCheckers(requestId); } } private static void CleanupCheckers(string requestId) { if (requestId != null) { CancellationTokenSource old; RequestIdToCancellationTokenSource.TryRemove(requestId, out old); } lock (RequestIdToCancellationTokenSource) { if (RequestIdToCancellationTokenSource.IsEmpty) { lock (Checkers) { foreach (Checker checker in Checkers) { Contract.Assert(checker != null); checker.Close(); } } } } } private static void VerifyImplementation(Program program, PipelineStatistics stats, ErrorReporterDelegate er, string requestId, Dictionary> extractLoopMappingInfo, Implementation[] stablePrioritizedImpls, int index, OutputCollector outputCollector, List checkers, string programId) { Implementation impl = stablePrioritizedImpls[index]; VerificationResult verificationResult = null; var output = new StringWriter(); printer.Inform("", output); // newline printer.Inform(string.Format("Verifying {0} ...", impl.Name), output); int priority = 0; var wasCached = false; if (0 < CommandLineOptions.Clo.VerifySnapshots) { var cachedResults = Cache.Lookup(impl, out priority); if (cachedResults != null && priority == Priority.SKIP) { if (CommandLineOptions.Clo.XmlSink != null) { CommandLineOptions.Clo.XmlSink.WriteStartMethod(impl.Name, cachedResults.Start); } printer.Inform(string.Format("Retrieving cached verification result for implementation {0}...", impl.Name), output); if (CommandLineOptions.Clo.VerifySnapshots < 3 || cachedResults.Outcome == ConditionGeneration.Outcome.Correct) { verificationResult = cachedResults; wasCached = true; } } } if (!wasCached) { #region Verify the implementation verificationResult = new VerificationResult(requestId, impl, programId); using (var vcgen = CreateVCGen(program, checkers)) { vcgen.CachingActionCounts = stats.CachingActionCounts; verificationResult.ProofObligationCountBefore = vcgen.CumulativeAssertionCount; verificationResult.Start = DateTime.UtcNow; if (CommandLineOptions.Clo.XmlSink != null) { CommandLineOptions.Clo.XmlSink.WriteStartMethod(impl.Name, verificationResult.Start); } try { if (CommandLineOptions.Clo.inferLeastForUnsat != null) { var svcgen = vcgen as VC.StratifiedVCGen; Contract.Assert(svcgen != null); var ss = new HashSet(); foreach (var c in program.Constants) { if (!c.Name.StartsWith(CommandLineOptions.Clo.inferLeastForUnsat)) continue; ss.Add(c.Name); } verificationResult.Outcome = svcgen.FindLeastToVerify(impl, ref ss); verificationResult.Errors = new List(); output.WriteLine("Result: {0}", string.Join(" ", ss)); } else { verificationResult.Outcome = vcgen.VerifyImplementation(impl, out verificationResult.Errors, requestId); if (CommandLineOptions.Clo.ExtractLoops && verificationResult.Errors != null) { var vcg = vcgen as VCGen; if (vcg != null) { for (int i = 0; i < verificationResult.Errors.Count; i++) { verificationResult.Errors[i] = vcg.extractLoopTrace(verificationResult.Errors[i], impl.Name, program, extractLoopMappingInfo); } } } } } catch (VCGenException e) { var errorInfo = errorInformationFactory.CreateErrorInformation(impl.tok, String.Format("{0} (encountered in implementation {1}).", e.Message, impl.Name), requestId, "Error"); errorInfo.BoogieErrorCode = "BP5010"; errorInfo.ImplementationName = impl.Name; printer.WriteErrorInformation(errorInfo, output); if (er != null) { lock (er) { er(errorInfo); } } verificationResult.Errors = null; verificationResult.Outcome = VCGen.Outcome.Inconclusive; } catch (UnexpectedProverOutputException upo) { printer.AdvisoryWriteLine("Advisory: {0} SKIPPED because of internal error: unexpected prover output: {1}", impl.Name, upo.Message); verificationResult.Errors = null; verificationResult.Outcome = VCGen.Outcome.Inconclusive; } verificationResult.ProofObligationCountAfter = vcgen.CumulativeAssertionCount; verificationResult.End = DateTime.UtcNow; } #endregion #region Cache the verification result if (0 < CommandLineOptions.Clo.VerifySnapshots && !string.IsNullOrEmpty(impl.Checksum)) { Cache.Insert(impl, verificationResult); } #endregion } #region Process the verification results and statistics ProcessOutcome(verificationResult.Outcome, verificationResult.Errors, TimeIndication(verificationResult), stats, output, impl.TimeLimit, er, verificationResult.ImplementationName, verificationResult.ImplementationToken, verificationResult.RequestId, wasCached); ProcessErrors(verificationResult.Errors, verificationResult.Outcome, output, er, impl); if (CommandLineOptions.Clo.XmlSink != null) { CommandLineOptions.Clo.XmlSink.WriteEndMethod(verificationResult.Outcome.ToString().ToLowerInvariant(), verificationResult.End, verificationResult.End - verificationResult.Start); } outputCollector.Add(index, output); outputCollector.WriteMoreOutput(); if (verificationResult.Outcome == VCGen.Outcome.Errors || CommandLineOptions.Clo.Trace) { Console.Out.Flush(); } #endregion } class OutputCollector { StringWriter[] outputs; int nextPrintableIndex = 0; public OutputCollector(Implementation[] implementations) { outputs = new StringWriter[implementations.Length]; } public void WriteMoreOutput() { lock (outputs) { for (; nextPrintableIndex < outputs.Length && outputs[nextPrintableIndex] != null; nextPrintableIndex++) { Console.Write(outputs[nextPrintableIndex].ToString()); outputs[nextPrintableIndex] = null; Console.Out.Flush(); } } } public void Add(int index, StringWriter output) { Contract.Requires(0 <= index && index < outputs.Length); Contract.Requires(output != null); lock (this) { outputs[index] = output; } } } private static ConditionGeneration CreateVCGen(Program program, List checkers) { ConditionGeneration vcgen = null; if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { vcgen = new DCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, checkers); } else if (CommandLineOptions.Clo.FixedPointEngine != null) { vcgen = new FixedpointVC(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, checkers); } else if (CommandLineOptions.Clo.StratifiedInlining > 0) { vcgen = new StratifiedVCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, checkers); } else if (CommandLineOptions.Clo.SecureVcGen != null) { vcgen = new SecureVCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, checkers); } else { vcgen = new VCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, checkers); } return vcgen; } #region Houdini private static PipelineOutcome RunHoudini(Program program, PipelineStatistics stats, ErrorReporterDelegate er) { Contract.Requires(stats != null); if (CommandLineOptions.Clo.AbstractHoudini != null) { return RunAbstractHoudini(program, stats, er); } if (CommandLineOptions.Clo.StagedHoudini != null) { return RunStagedHoudini(program, stats, er); } Houdini.HoudiniSession.HoudiniStatistics houdiniStats = new Houdini.HoudiniSession.HoudiniStatistics(); Houdini.Houdini houdini = new Houdini.Houdini(program, houdiniStats); Houdini.HoudiniOutcome outcome = houdini.PerformHoudiniInference(); houdini.Close(); if (CommandLineOptions.Clo.PrintAssignment) { Console.WriteLine("Assignment computed by Houdini:"); foreach (var x in outcome.assignment) { Console.WriteLine(x.Key + " = " + x.Value); } } if (CommandLineOptions.Clo.Trace) { int numTrueAssigns = 0; foreach (var x in outcome.assignment) { if (x.Value) numTrueAssigns++; } Console.WriteLine("Number of true assignments = " + numTrueAssigns); Console.WriteLine("Number of false assignments = " + (outcome.assignment.Count - numTrueAssigns)); Console.WriteLine("Prover time = " + houdiniStats.proverTime.ToString("F2")); Console.WriteLine("Unsat core prover time = " + houdiniStats.unsatCoreProverTime.ToString("F2")); Console.WriteLine("Number of prover queries = " + houdiniStats.numProverQueries); Console.WriteLine("Number of unsat core prover queries = " + houdiniStats.numUnsatCoreProverQueries); Console.WriteLine("Number of unsat core prunings = " + houdiniStats.numUnsatCorePrunings); } foreach (Houdini.VCGenOutcome x in outcome.implementationOutcomes.Values) { ProcessOutcome(x.outcome, x.errors, "", stats, Console.Out, CommandLineOptions.Clo.ProverKillTime, er); ProcessErrors(x.errors, x.outcome, Console.Out, er); } return PipelineOutcome.Done; } public static Program ProgramFromFile(string filename) { Program p = ParseBoogieProgram(new List { filename }, false); System.Diagnostics.Debug.Assert(p != null); LinearTypeChecker linearTypeChecker; CivlTypeChecker civlTypeChecker; PipelineOutcome oc = ExecutionEngine.ResolveAndTypecheck(p, filename, out linearTypeChecker, out civlTypeChecker); System.Diagnostics.Debug.Assert(oc == PipelineOutcome.ResolvedAndTypeChecked); return p; } private static PipelineOutcome RunStagedHoudini(Program program, PipelineStatistics stats, ErrorReporterDelegate er) { Houdini.HoudiniSession.HoudiniStatistics houdiniStats = new Houdini.HoudiniSession.HoudiniStatistics(); Houdini.StagedHoudini stagedHoudini = new Houdini.StagedHoudini(program, houdiniStats, ProgramFromFile); Houdini.HoudiniOutcome outcome = stagedHoudini.PerformStagedHoudiniInference(); if (CommandLineOptions.Clo.PrintAssignment) { Console.WriteLine("Assignment computed by Houdini:"); foreach (var x in outcome.assignment) { Console.WriteLine(x.Key + " = " + x.Value); } } if (CommandLineOptions.Clo.Trace) { int numTrueAssigns = 0; foreach (var x in outcome.assignment) { if (x.Value) numTrueAssigns++; } Console.WriteLine("Number of true assignments = " + numTrueAssigns); Console.WriteLine("Number of false assignments = " + (outcome.assignment.Count - numTrueAssigns)); Console.WriteLine("Prover time = " + houdiniStats.proverTime.ToString("F2")); Console.WriteLine("Unsat core prover time = " + houdiniStats.unsatCoreProverTime.ToString("F2")); Console.WriteLine("Number of prover queries = " + houdiniStats.numProverQueries); Console.WriteLine("Number of unsat core prover queries = " + houdiniStats.numUnsatCoreProverQueries); Console.WriteLine("Number of unsat core prunings = " + houdiniStats.numUnsatCorePrunings); } foreach (Houdini.VCGenOutcome x in outcome.implementationOutcomes.Values) { ProcessOutcome(x.outcome, x.errors, "", stats, Console.Out, CommandLineOptions.Clo.ProverKillTime, er); ProcessErrors(x.errors, x.outcome, Console.Out, er); } return PipelineOutcome.Done; } private static PipelineOutcome RunAbstractHoudini(Program program, PipelineStatistics stats, ErrorReporterDelegate er) { Contract.Requires(stats != null); //CommandLineOptions.Clo.PrintErrorModel = 1; CommandLineOptions.Clo.UseProverEvaluate = true; CommandLineOptions.Clo.ModelViewFile = "z3model"; CommandLineOptions.Clo.UseArrayTheory = true; CommandLineOptions.Clo.TypeEncodingMethod = CommandLineOptions.TypeEncoding.Monomorphic; Houdini.AbstractDomainFactory.Initialize(program); var domain = Houdini.AbstractDomainFactory.GetInstance(CommandLineOptions.Clo.AbstractHoudini); // Run Abstract Houdini var abs = new Houdini.AbsHoudini(program, domain); var absout = abs.ComputeSummaries(); ProcessOutcome(absout.outcome, absout.errors, "", stats, Console.Out, CommandLineOptions.Clo.ProverKillTime, er); ProcessErrors(absout.errors, absout.outcome, Console.Out, er); //Houdini.PredicateAbs.Initialize(program); //var abs = new Houdini.AbstractHoudini(program); //abs.computeSummaries(new Houdini.PredicateAbs(program.TopLevelDeclarations.OfType().First().Name)); return PipelineOutcome.Done; } #endregion private static string TimeIndication(VerificationResult verificationResult) { var result = ""; if (CommandLineOptions.Clo.Trace) { result = string.Format(" [{0:F3} s, {1} proof obligation{2}] ", (verificationResult.End - verificationResult.Start).TotalSeconds, verificationResult.ProofObligationCount, verificationResult.ProofObligationCount == 1 ? "" : "s"); } else if (CommandLineOptions.Clo.TraceProofObligations) { result = string.Format(" [{0} proof obligation{1}] ", verificationResult.ProofObligationCount, verificationResult.ProofObligationCount == 1 ? "" : "s"); } return result; } private static void ProcessOutcome(VC.VCGen.Outcome outcome, List errors, string timeIndication, PipelineStatistics stats, TextWriter tw, int timeLimit, ErrorReporterDelegate er = null, string implName = null, IToken implTok = null, string requestId = null, bool wasCached = false) { Contract.Requires(stats != null); UpdateStatistics(stats, outcome, errors, wasCached); printer.Inform(timeIndication + OutcomeIndication(outcome, errors), tw); ReportOutcome(outcome, er, implName, implTok, requestId, tw, timeLimit, errors); } private static void ReportOutcome(VC.VCGen.Outcome outcome, ErrorReporterDelegate er, string implName, IToken implTok, string requestId, TextWriter tw, int timeLimit, List errors) { ErrorInformation errorInfo = null; switch (outcome) { case VCGen.Outcome.ReachedBound: tw.WriteLine(string.Format("Stratified Inlining: Reached recursion bound of {0}", CommandLineOptions.Clo.RecursionBound)); break; case VCGen.Outcome.Errors: case VCGen.Outcome.TimedOut: if (implName != null && implTok != null) { if (outcome == ConditionGeneration.Outcome.TimedOut || (errors != null && errors.Any(e => e.IsAuxiliaryCexForDiagnosingTimeouts))) { errorInfo = errorInformationFactory.CreateErrorInformation(implTok, string.Format("Verification of '{1}' timed out after {0} seconds", timeLimit, implName), requestId); } // Report timed out assertions as auxiliary info. if (errors != null) { var cmpr = new CounterexampleComparer(); var timedOutAssertions = errors.Where(e => e.IsAuxiliaryCexForDiagnosingTimeouts).Distinct(cmpr).ToList(); timedOutAssertions.Sort(cmpr); if (0 < timedOutAssertions.Count) { errorInfo.Msg += string.Format(" with {0} check(s) that timed out individually", timedOutAssertions.Count); } foreach (Counterexample error in timedOutAssertions) { var callError = error as CallCounterexample; var returnError = error as ReturnCounterexample; var assertError = error as AssertCounterexample; IToken tok = null; string msg = null; if (callError != null) { tok = callError.FailingCall.tok; msg = callError.FailingCall.ErrorData as string ?? "A precondition for this call might not hold."; } else if (returnError != null) { tok = returnError.FailingReturn.tok; msg = "A postcondition might not hold on this return path."; } else { tok = assertError.FailingAssert.tok; if (assertError.FailingAssert is LoopInitAssertCmd) { msg = "This loop invariant might not hold on entry."; } else if (assertError.FailingAssert is LoopInvMaintainedAssertCmd) { msg = "This loop invariant might not be maintained by the loop."; } else { msg = assertError.FailingAssert.ErrorData as string; if (!CommandLineOptions.Clo.ForceBplErrors && assertError.FailingAssert.ErrorMessage != null) { msg = assertError.FailingAssert.ErrorMessage; } if (msg == null) { msg = "This assertion might not hold."; } } } errorInfo.AddAuxInfo(tok, msg, "Unverified check due to timeout"); } } } break; case VCGen.Outcome.OutOfMemory: if (implName != null && implTok != null) { errorInfo = errorInformationFactory.CreateErrorInformation(implTok, "Verification out of memory (" + implName + ")", requestId); } break; case VCGen.Outcome.Inconclusive: if (implName != null && implTok != null) { errorInfo = errorInformationFactory.CreateErrorInformation(implTok, "Verification inconclusive (" + implName + ")", requestId); } break; } if (errorInfo != null) { errorInfo.ImplementationName = implName; if (er != null) { lock (er) { er(errorInfo); } } else { printer.WriteErrorInformation(errorInfo, tw); } } } private static string OutcomeIndication(VC.VCGen.Outcome outcome, List errors) { string traceOutput = ""; switch (outcome) { default: Contract.Assert(false); // unexpected outcome throw new cce.UnreachableException(); case VCGen.Outcome.ReachedBound: traceOutput = "verified"; break; case VCGen.Outcome.Correct: traceOutput = (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed ? "credible" : "verified"); break; case VCGen.Outcome.TimedOut: traceOutput = "timed out"; break; case VCGen.Outcome.OutOfMemory: traceOutput = "out of memory"; break; case VCGen.Outcome.Inconclusive: traceOutput = "inconclusive"; break; case VCGen.Outcome.Errors: Contract.Assert(errors != null); traceOutput = (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed ? "doomed" : string.Format("error{0}", errors.Count == 1 ? "" : "s")); break; } return traceOutput; } private static void UpdateStatistics(PipelineStatistics stats, VC.VCGen.Outcome outcome, List errors, bool wasCached) { Contract.Requires(stats != null); switch (outcome) { default: Contract.Assert(false); // unexpected outcome throw new cce.UnreachableException(); case VCGen.Outcome.ReachedBound: Interlocked.Increment(ref stats.VerifiedCount); if (wasCached) { Interlocked.Increment(ref stats.CachedVerifiedCount); } break; case VCGen.Outcome.Correct: Interlocked.Increment(ref stats.VerifiedCount); if (wasCached) { Interlocked.Increment(ref stats.CachedVerifiedCount); } break; case VCGen.Outcome.TimedOut: Interlocked.Increment(ref stats.TimeoutCount); if (wasCached) { Interlocked.Increment(ref stats.CachedTimeoutCount); } break; case VCGen.Outcome.OutOfMemory: Interlocked.Increment(ref stats.OutOfMemoryCount); if (wasCached) { Interlocked.Increment(ref stats.CachedOutOfMemoryCount); } break; case VCGen.Outcome.Inconclusive: Interlocked.Increment(ref stats.InconclusiveCount); if (wasCached) { Interlocked.Increment(ref stats.CachedInconclusiveCount); } break; case VCGen.Outcome.Errors: if (CommandLineOptions.Clo.vcVariety == CommandLineOptions.VCVariety.Doomed) { Interlocked.Increment(ref stats.ErrorCount); if (wasCached) { Interlocked.Increment(ref stats.CachedErrorCount); } } else { int cnt = errors.Where(e => !e.IsAuxiliaryCexForDiagnosingTimeouts).Count(); Interlocked.Add(ref stats.ErrorCount, cnt); if (wasCached) { Interlocked.Add(ref stats.CachedErrorCount, cnt); } } break; } } private static void ProcessErrors(List errors, VC.VCGen.Outcome outcome, TextWriter tw, ErrorReporterDelegate er, Implementation impl = null) { var implName = impl != null ? impl.Name : null; if (errors != null) { errors.Sort(new CounterexampleComparer()); foreach (Counterexample error in errors) { if (error.IsAuxiliaryCexForDiagnosingTimeouts) { continue; } var errorInfo = CreateErrorInformation(error, outcome); errorInfo.ImplementationName = implName; if (CommandLineOptions.Clo.XmlSink != null) { WriteErrorInformationToXmlSink(errorInfo, error.Trace); } if (CommandLineOptions.Clo.EnhancedErrorMessages == 1) { foreach (string info in error.relatedInformation) { Contract.Assert(info != null); errorInfo.Out.WriteLine(" " + info); } } if (CommandLineOptions.Clo.ErrorTrace > 0) { errorInfo.Out.WriteLine("Execution trace:"); error.Print(4, errorInfo.Out, b => { errorInfo.AddAuxInfo(b.tok, b.Label, "Execution trace"); }); } if (CommandLineOptions.Clo.ModelViewFile != null) { error.PrintModel(errorInfo.Model); } printer.WriteErrorInformation(errorInfo, tw); if (er != null) { lock (er) { er(errorInfo); } } } } } private static ErrorInformation CreateErrorInformation(Counterexample error, VC.VCGen.Outcome outcome) { // BP1xxx: Parsing errors // BP2xxx: Name resolution errors // BP3xxx: Typechecking errors // BP4xxx: Abstract interpretation errors (Is there such a thing?) // BP5xxx: Verification errors ErrorInformation errorInfo; var cause = "Error"; if (outcome == VCGen.Outcome.TimedOut) { cause = "Timed out on"; } else if (outcome == VCGen.Outcome.OutOfMemory) { cause = "Out of memory on"; } var callError = error as CallCounterexample; var returnError = error as ReturnCounterexample; var assertError = error as AssertCounterexample; if (callError != null) { errorInfo = errorInformationFactory.CreateErrorInformation(callError.FailingCall.tok, callError.FailingCall.ErrorData as string ?? "A precondition for this call might not hold.", callError.RequestId, callError.OriginalRequestId, cause); errorInfo.BoogieErrorCode = "BP5002"; errorInfo.Kind = ErrorKind.Precondition; errorInfo.AddAuxInfo(callError.FailingRequires.tok, callError.FailingRequires.ErrorData as string ?? "This is the precondition that might not hold.", "Related location"); if (!CommandLineOptions.Clo.ForceBplErrors && callError.FailingRequires.ErrorMessage != null) { errorInfo = errorInformationFactory.CreateErrorInformation(null, callError.FailingRequires.ErrorMessage, callError.RequestId, callError.OriginalRequestId, cause); } } else if (returnError != null) { errorInfo = errorInformationFactory.CreateErrorInformation(returnError.FailingReturn.tok, "A postcondition might not hold on this return path.", returnError.RequestId, returnError.OriginalRequestId, cause); errorInfo.BoogieErrorCode = "BP5003"; errorInfo.Kind = ErrorKind.Postcondition; errorInfo.AddAuxInfo(returnError.FailingEnsures.tok, returnError.FailingEnsures.ErrorData as string ?? "This is the postcondition that might not hold.", "Related location"); if (!CommandLineOptions.Clo.ForceBplErrors && returnError.FailingEnsures.ErrorMessage != null) { errorInfo = errorInformationFactory.CreateErrorInformation(null, returnError.FailingEnsures.ErrorMessage, returnError.RequestId, returnError.OriginalRequestId, cause); } } else // error is AssertCounterexample { if (assertError.FailingAssert is LoopInitAssertCmd) { errorInfo = errorInformationFactory.CreateErrorInformation(assertError.FailingAssert.tok, "This loop invariant might not hold on entry.", assertError.RequestId, assertError.OriginalRequestId, cause); errorInfo.BoogieErrorCode = "BP5004"; errorInfo.Kind = ErrorKind.InvariantEntry; } else if (assertError.FailingAssert is LoopInvMaintainedAssertCmd) { errorInfo = errorInformationFactory.CreateErrorInformation(assertError.FailingAssert.tok, "This loop invariant might not be maintained by the loop.", assertError.RequestId, assertError.OriginalRequestId, cause); errorInfo.BoogieErrorCode = "BP5005"; errorInfo.Kind = ErrorKind.InvariantMaintainance; } else { var msg = assertError.FailingAssert.ErrorData as string; var tok = assertError.FailingAssert.tok; if (!CommandLineOptions.Clo.ForceBplErrors && assertError.FailingAssert.ErrorMessage != null) { msg = assertError.FailingAssert.ErrorMessage; tok = null; if (cause == "Error") { cause = null; } } string bec = null; if (msg == null) { msg = "This assertion might not hold."; bec = "BP5001"; } errorInfo = errorInformationFactory.CreateErrorInformation(tok, msg, assertError.RequestId, assertError.OriginalRequestId, cause); errorInfo.BoogieErrorCode = bec; errorInfo.Kind = ErrorKind.Assertion; } } return errorInfo; } private static void WriteErrorInformationToXmlSink(ErrorInformation errorInfo, List trace) { var msg = "assertion violation"; switch (errorInfo.Kind) { case ErrorKind.Precondition: msg = "precondition violation"; break; case ErrorKind.Postcondition: msg = "postcondition violation"; break; case ErrorKind.InvariantEntry: msg = "loop invariant entry violation"; break; case ErrorKind.InvariantMaintainance: msg = "loop invariant maintenance violation"; break; } var relatedError = errorInfo.Aux.FirstOrDefault(); CommandLineOptions.Clo.XmlSink.WriteError(msg, errorInfo.Tok, relatedError.Tok, trace); } } }