public override Outcome CheckOutcomeCore(ErrorHandler handler, int taskID = -1) { Contract.EnsuresOnThrow<UnexpectedProverOutputException>(true); var result = Outcome.Undetermined; if (Process == null) return result; try { currentErrorHandler = handler; FlushProverWarnings(); int errorLimit; if (CommandLineOptions.Clo.ConcurrentHoudini) { Contract.Assert(taskID >= 0); errorLimit = CommandLineOptions.Clo.Cho[taskID].ProverCCLimit; } else { errorLimit = CommandLineOptions.Clo.ProverCCLimit; } if (errorLimit < 1) errorLimit = 1; int errorsLeft = errorLimit; var globalResult = Outcome.Undetermined; while (true) { string[] labels = null; bool popLater = false; try { errorsLeft--; result = GetResponse(); var reporter = handler as VC.VCGen.ErrorReporter; // TODO(wuestholz): Is the reporter ever null? if (usingUnsatCore && result == Outcome.Valid && reporter != null && 0 < NamedAssumes.Count) { if (usingUnsatCore) { UsedNamedAssumes = new HashSet<string>(); SendThisVC("(get-unsat-core)"); var resp = Process.GetProverResponse(); if (resp.Name != "") { UsedNamedAssumes.Add(resp.Name); if (CommandLineOptions.Clo.PrintNecessaryAssumes) { reporter.AddNecessaryAssume(resp.Name.Substring("aux$$assume$$".Length)); } } foreach (var arg in resp.Arguments) { UsedNamedAssumes.Add(arg.Name); if (CommandLineOptions.Clo.PrintNecessaryAssumes) { reporter.AddNecessaryAssume(arg.Name.Substring("aux$$assume$$".Length)); } } } else { UsedNamedAssumes = null; } } if (CommandLineOptions.Clo.RunDiagnosticsOnTimeout && result == Outcome.TimeOut) { #region Run timeout diagnostics if (CommandLineOptions.Clo.TraceDiagnosticsOnTimeout) { Console.Out.WriteLine("Starting timeout diagnostics with initial time limit {0}.", options.TimeLimit); } SendThisVC("; begin timeout diagnostics"); var start = DateTime.UtcNow; var unverified = new SortedSet<int>(ctx.TimeoutDiagnosticIDToAssertion.Keys); var timedOut = new SortedSet<int>(); int frac = 2; int queries = 0; int timeLimitPerAssertion = 0 < options.TimeLimit ? (options.TimeLimit / 100) * CommandLineOptions.Clo.TimeLimitPerAssertionInPercent : 1000; while (true) { int rem = unverified.Count; if (rem == 0) { if (0 < timedOut.Count) { result = CheckSplit(timedOut, ref popLater, options.TimeLimit, timeLimitPerAssertion, ref queries); if (result == Outcome.Valid) { timedOut.Clear(); } else if (result == Outcome.TimeOut) { // Give up and report which assertions were not verified. var cmds = timedOut.Select(id => ctx.TimeoutDiagnosticIDToAssertion[id]); if (cmds.Any()) { handler.OnResourceExceeded("timeout after running diagnostics", cmds); } } } else { result = Outcome.Valid; } break; } // TODO(wuestholz): Try out different ways for splitting up the work (e.g., randomly). var cnt = Math.Max(1, rem / frac); // It seems like assertions later in the control flow have smaller indexes. var split = new SortedSet<int>(unverified.Where((val, idx) => (rem - idx - 1) < cnt)); Contract.Assert(0 < split.Count); var splitRes = CheckSplit(split, ref popLater, timeLimitPerAssertion, timeLimitPerAssertion, ref queries); if (splitRes == Outcome.Valid) { unverified.ExceptWith(split); frac = 1; } else if (splitRes == Outcome.Invalid) { result = splitRes; break; } else if (splitRes == Outcome.TimeOut) { if (2 <= frac && (4 <= (rem / frac))) { frac *= 4; } else if (2 <= (rem / frac)) { frac *= 2; } else { timedOut.UnionWith(split); unverified.ExceptWith(split); frac = 1; } } else { break; } } unverified.UnionWith(timedOut); var end = DateTime.UtcNow; SendThisVC("; end timeout diagnostics"); if (CommandLineOptions.Clo.TraceDiagnosticsOnTimeout) { Console.Out.WriteLine("Terminated timeout diagnostics after {0:F0} ms and {1} prover queries.", end.Subtract(start).TotalMilliseconds, queries); Console.Out.WriteLine("Outcome: {0}", result); Console.Out.WriteLine("Unverified assertions: {0} (of {1})", unverified.Count, ctx.TimeoutDiagnosticIDToAssertion.Keys.Count); string filename = "unknown"; var assertion = ctx.TimeoutDiagnosticIDToAssertion.Values.Select(t => t.Item1).FirstOrDefault(a => a.tok != null && a.tok != Token.NoToken && a.tok.filename != null); if (assertion != null) { filename = assertion.tok.filename; } File.AppendAllText("timeouts.csv", string.Format(";{0};{1};{2:F0};{3};{4};{5};{6}\n", filename, options.TimeLimit, end.Subtract(start).TotalMilliseconds, queries, result, unverified.Count, ctx.TimeoutDiagnosticIDToAssertion.Keys.Count)); } #endregion } if (globalResult == Outcome.Undetermined) globalResult = result; if (result == Outcome.Invalid || result == Outcome.TimeOut || result == Outcome.OutOfMemory) { IList<string> xlabels; if (CommandLineOptions.Clo.UseLabels) { labels = GetLabelsInfo(); if (labels == null) { xlabels = new string[] { }; } else { xlabels = labels.Select(a => a.Replace("@", "").Replace("+", "")).ToList(); } } else if(CommandLineOptions.Clo.SIBoolControlVC) { labels = new string[0]; xlabels = labels; } else { labels = CalculatePath(handler.StartingProcId()); xlabels = labels; } Model model = (result == Outcome.TimeOut || result == Outcome.OutOfMemory) ? null : GetErrorModel(); handler.OnModel(xlabels, model, result); } if (labels == null || !labels.Any() || errorsLeft == 0) break; } finally { if (popLater) { SendThisVC("(pop 1)"); } } if (CommandLineOptions.Clo.UseLabels) { var negLabels = labels.Where(l => l.StartsWith("@")).ToArray(); var posLabels = labels.Where(l => !l.StartsWith("@")); Func<string, string> lbl = (s) => SMTLibNamer.QuoteId(SMTLibNamer.LabelVar(s)); if (!options.MultiTraces) posLabels = Enumerable.Empty<string>(); var conjuncts = posLabels.Select(s => "(not " + lbl(s) + ")").Concat(negLabels.Select(lbl)).ToArray(); string expr = conjuncts.Length == 1 ? conjuncts[0] : ("(or " + conjuncts.Concat(" ") + ")"); ; if (!conjuncts.Any()) { expr = "false"; } SendThisVC("(assert " + expr + ")"); SendCheckSat(); } else { string source = labels[labels.Length - 2]; string target = labels[labels.Length - 1]; SendThisVC("(assert (not (= (ControlFlow 0 " + source + ") (- " + target + "))))"); SendCheckSat(); } } FlushLogFile(); if (CommandLineOptions.Clo.RestartProverPerVC && Process != null) Process.NeedsRestart = true; return globalResult; } finally { currentErrorHandler = null; } }