// Assumptions: // - Program has no recursion public static HashSet <string> FindLeastToVerify(Program program, HashSet <string> boolVars) { Debug.Assert(program != null); RemoveAsserts(program); if (options.printProg) { BoogieUtil.PrintProgram(program, options.progFileName); } //// ---------- Verify ---------------------------------------------------------------- Debug.Assert(CommandLineOptions.Clo.StratifiedInlining > 0); VC.StratifiedVCGenBase vcgen = null; try { if (options.newStratifiedInlining) { vcgen = new CoreLib.StratifiedInlining(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, null); } else { vcgen = new VC.StratifiedVCGen(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, new List <Checker>()); } } catch (ProverException) { Log.WriteLine(Log.Error, "ProverException: {0}"); return(new HashSet <string>()); } var mains = program.TopLevelDeclarations .OfType <Implementation>() .Where(impl => QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint")); if (mains.Count() != 1) { throw new InternalError("Wrong number of entrypoints for FindLeastToverify"); } var main = mains.First(); VC.VCGen.Outcome outcome; //HashSet<string> minVars = new HashSet<string>(); try { var start = DateTime.Now; outcome = vcgen.FindLeastToVerify(main, ref boolVars); var end = DateTime.Now; TimeSpan elapsed = end - start; Log.WriteLine(Log.Debug, string.Format(" [{0} s] ", elapsed.TotalSeconds)); verificationTime += elapsed; if (recordTempTime) { tempTime += elapsed; } } catch (VC.VCGenException e) { throw new InternalError("VCGenException: " + e.Message); //errors = null; //outcome = VC.VCGen.Outcome.Inconclusive; } catch (UnexpectedProverOutputException upo) { throw new InternalError("Unexpected prover output: " + upo.Message); //errors = null; //outcome = VC.VCGen.Outcome.Inconclusive; } switch (outcome) { case VC.VCGen.Outcome.Correct: break; case VC.VCGen.Outcome.Errors: Debug.Assert(false); break; case VC.VCGen.Outcome.ReachedBound: Debug.Assert(false); break; case VC.VCGen.Outcome.Inconclusive: throw new InternalError("z3 says inconclusive"); case VC.VCGen.Outcome.OutOfMemory: throw new InternalError("z3 out of memory"); case VC.VCGen.Outcome.TimedOut: throw new InternalError("z3 timed out"); default: throw new InternalError("z3 unknown response"); } Debug.Assert(outcome == VC.VCGen.Outcome.Correct); vcgen.Close(); CommandLineOptions.Clo.TheProverFactory.Close(); return(boolVars); }
public static ReturnStatus Verify(Program program, bool needErrorTraces, out List <BoogieErrorTrace> allErrors, out List <string> timedOut, bool isCBA = false) { ReturnStatus ret = ReturnStatus.OK; allErrors = new List <BoogieErrorTrace>(); timedOut = new List <string>(); Debug.Assert(program != null); // Make a copy of the input program var duper = new FixedDuplicator(true); var origProg = new Dictionary <string, Implementation>(); if (needErrorTraces) { foreach (var decl in program.TopLevelDeclarations) { if (decl is Implementation) { var origImpl = duper.VisitImplementation(decl as Implementation); origProg.Add(origImpl.Name, origImpl); } } } if (removeAsserts) { RemoveAsserts(program); } // Set options options.Set(); // save RB var rb = CommandLineOptions.Clo.RecursionBound; if (BoogieVerify.irreducibleLoopUnroll >= 0) { CommandLineOptions.Clo.RecursionBound = BoogieVerify.irreducibleLoopUnroll; } // Do loop extraction var extractionInfo = program.ExtractLoops(); // restore RB CommandLineOptions.Clo.RecursionBound = rb; // set bounds if (options.extraRecBound != null) { options.extraRecBound.Iter(tup => { var impl = BoogieUtil.findProcedureImpl(program.TopLevelDeclarations, tup.Key); if (impl != null) { impl.AddAttribute(BoogieVerify.ExtraRecBoundAttr, Expr.Literal(tup.Value)); } }); } #region Save program to disk if (shuffleProgram) { BoogieUtil.PrintProgram(program, "last_query.bpl"); program = BoogieUtil.ReadAndResolve("last_query.bpl"); } if (options.printProg) { Debug.Assert(options.progFileName != null, "Invalid options"); BoogieUtil.PrintProgram(program, options.progFileName); } #endregion var origBlocks = new Dictionary <string, Tuple <Block, Implementation> >(); // ---------- Infer invariants -------------------------------------------------------- // Abstract interpretation -> Always use (at least) intervals, if not specified otherwise (e.g. with the "/noinfer" switch) //Microsoft.Boogie.AbstractInterpretation.AbstractInterpretation.RunAbstractInterpretation(program); //// ---------- Verify ---------------------------------------------------------------- var mains = new List <Implementation>( program.TopLevelDeclarations .OfType <Implementation>() .Where(impl => QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint"))); VC.VCGen vcgen = null; try { Debug.Assert(CommandLineOptions.Clo.vcVariety != CommandLineOptions.VCVariety.Doomed); Debug.Assert(CommandLineOptions.Clo.StratifiedInlining > 0); if (options.newStratifiedInlining) { if (options.newStratifiedInliningAlgo.ToLower() == "duality") { Microsoft.Boogie.SMTLib.Factory.UseInterpolation = true; } vcgen = new CoreLib.StratifiedInlining(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, null); } else // vcgen = new VC.StratifiedVCGen(options.CallTree != null, options.CallTree, options.procsToSkip, options.extraRecBound, program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, new List<Checker>()); if (!useDuality || !isCBA || !needErrorTraces || options.StratifiedInlining > 1 || mains.Count > 1) { vcgen = new VC.StratifiedVCGen(options.CallTree != null, options.CallTree, program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, new List <Checker>()); } else { CommandLineOptions.Clo.FixedPointMode = CommandLineOptions.FixedPointInferenceMode.Corral; CommandLineOptions.Clo.FixedPointEngine = "duality"; vcgen = new Microsoft.Boogie.FixedpointVC(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, new List <Checker>(), options.extraRecBound); } } catch (ProverException e) { Log.WriteLine(Log.Error, "ProverException: {0}", e.Message); return(ReturnStatus.OK); } if (!mains.Any()) { throw new InternalError("No entrypoint found"); } if (mains.Count > 1) { Console.WriteLine("Verifying {0} impls", mains.Count); } foreach (var impl in mains) { if (PrintImplsBeingVerified) { Log.WriteLine(Log.Verbose, "Verifying implementation " + impl.Name); } List <Counterexample> errors; VC.VCGen.Outcome outcome; try { var start = DateTime.Now; outcome = vcgen.VerifyImplementation(impl, out errors); var end = DateTime.Now; TimeSpan elapsed = end - start; Log.WriteLine(Log.Debug, string.Format(" [{0} s] ", elapsed.TotalSeconds)); verificationTime += elapsed; if (recordTempTime) { tempTime += elapsed; } } catch (VC.VCGenException e) { throw new InternalError("VCGenException: " + e.Message); //errors = null; //outcome = VC.VCGen.Outcome.Inconclusive; } catch (UnexpectedProverOutputException upo) { throw new InternalError("Unexpected prover output: " + upo.Message); //errors = null; //outcome = VC.VCGen.Outcome.Inconclusive; } switch (outcome) { case VC.VCGen.Outcome.Correct: break; case VC.VCGen.Outcome.Errors: break; case VC.VCGen.Outcome.ReachedBound: ret = ReturnStatus.ReachedBound; break; case VC.VCGen.Outcome.Inconclusive: throw new InternalError("z3 says inconclusive"); case VC.VCGen.Outcome.OutOfMemory: // wipe out any counterexamples timedOut.Add(impl.Name); errors = new List <Counterexample>(); break; case VC.VCGen.Outcome.TimedOut: // wipe out any counterexamples timedOut.Add(impl.Name); errors = new List <Counterexample>(); break; default: throw new InternalError("z3 unknown response"); } Log.WriteLine(Log.Debug, outcome.ToString()); Log.WriteLine(Log.Debug, (errors == null ? 0 : errors.Count) + " counterexamples."); if (errors != null) { ret = ReturnStatus.NOK; } // Print model if (errors != null && errors.Count > 0 && errors[0].Model != null && CommandLineOptions.Clo.ModelViewFile != null) { var model = errors[0].Model; var cnt = 0; model.States.Iter(st => { if (st.Name.StartsWith("corral")) { st.ChangeName(st.Name + "_" + cnt.ToString()); cnt++; } }); using (var wr = new StreamWriter(CommandLineOptions.Clo.ModelViewFile, false)) { model.Write(wr); } } if (errors != null && needErrorTraces) { for (int i = 0; i < errors.Count; i++) { //errors[i].Print(1, Console.Out); // Map the trace across loop extraction if (vcgen is VC.VCGen) { errors[i] = (vcgen as VC.VCGen).extractLoopTrace(errors[i], impl.Name, program, extractionInfo); } if (errors[i] is AssertCounterexample) { // Special treatment for assert counterexamples for CBA: Reconstruct // trace in the input program. ReconstructImperativeTrace(errors[i], impl.Name, origProg); allErrors.Add(new BoogieAssertErrorTrace(errors[i] as AssertCounterexample, origProg[impl.Name], program)); } else { allErrors.Add(new BoogieErrorTrace(errors[i], origProg[impl.Name], program)); } } } } //PutBackAsserts(program); if (vcgen is StratifiedVCGen) { CallTreeSize = (vcgen as StratifiedVCGen).numInlined; vcSize = (vcgen as StratifiedVCGen).vcsize; if (options.CallTree != null) { options.CallTree = VC.StratifiedVCGen.callTree; VC.StratifiedVCGen.callTree = null; } } else if (vcgen is CoreLib.StratifiedInlining) { procsHitRecBound = (vcgen as CoreLib.StratifiedInlining).procsHitRecBound; CallTreeSize = (vcgen as CoreLib.StratifiedInlining).stats.numInlined; vcSize = (vcgen as CoreLib.StratifiedInlining).stats.vcSize; if (options.CallTree != null) { options.CallTree = (vcgen as CoreLib.StratifiedInlining).GetCallTree(); } } else { CallTreeSize = 0; } vcgen.Close(); CommandLineOptions.Clo.TheProverFactory.Close(); return(ret); }