// Verify that the trace is a valid counterexample (i.e., it returns an assertion-failure counterexample // upon verification. // Returns a program that consists of a single implementation with a single basic // block that contains the trace. public bool verifyTrace(out Program newProg) { // Currently, this only works for intraprocedural traces Debug.Assert(acex.calleeCounterexamples.Count == 0); HashSet <string> calledProcs; Implementation traceImpl = getImplementation(out calledProcs); newProg = new Program(); // The set of called procedures should only be ones // that do not have an implementation foreach (Declaration decl in prog.TopLevelDeclarations) { if (decl is GlobalVariable) { newProg.AddTopLevelDeclaration(decl); } else if (decl is Procedure) { Procedure tmp = decl as Procedure; if (calledProcs.Contains(tmp.Name)) { newProg.AddTopLevelDeclaration(decl); } else if (tmp.Name == impl.Name) { Procedure pex = new Procedure(Token.NoToken, tmp.Name + "_cex", tmp.TypeParameters, tmp.InParams, tmp.OutParams, tmp.Requires, tmp.Modifies, tmp.Ensures, tmp.Attributes); newProg.AddTopLevelDeclaration(pex); } } else if (decl is Implementation) { Implementation tmp = decl as Implementation; Debug.Assert(!calledProcs.Contains(tmp.Name)); } else { // Just add the other guys (axioms, functions, etc.) newProg.AddTopLevelDeclaration(decl); } } newProg.AddTopLevelDeclaration(traceImpl); newProg = BoogieUtil.ReResolve(newProg, "cex.bpl"); Program newProgCopy = BoogieUtil.ReadAndResolve("cex.bpl"); // (We need to create a copy because Boogie.Verify changes the input program) var errors = new List <BoogieErrorTrace>(); var ret = BoogieVerify.Verify(newProgCopy, out errors); if (ret != BoogieVerify.ReturnStatus.NOK) { return(false); } return(true); }
// Prune away non-candidates, verify using the rest static BoogieVerify.ReturnStatus PruneAndRun(PersistentProgram inp, HashSet <string> candidates, out HashSet <string> assignment, ref int inlined) { var program = inp.getProgram(); program.Typecheck(); program = BoogieUtil.ReResolve(program); // Remove non-candidates CoreLib.HoudiniInlining.InstrumentHoudiniAssignment(program, candidates, true); program.RemoveTopLevelDeclarations(decl => (decl is Constant) && QKeyValue.FindBoolAttribute(decl.Attributes, "existential") && !candidates.Contains((decl as Constant).Name)); //BoogieUtil.PrintProgram(program, "hi_query" + IterCnt + ".bpl"); // Run Houdini var ot = CommandLineOptions.Clo.ProverKillTime; CommandLineOptions.Clo.ProverKillTime = HoudiniTimeout; assignment = CoreLib.HoudiniInlining.RunHoudini(program, true); CommandLineOptions.Clo.ProverKillTime = ot; //Console.WriteLine(" >> Contracts: {0}", assignment.Count); // Read the program again, add contracts program = inp.getProgram(); program.Typecheck(); CoreLib.HoudiniInlining.InstrumentHoudiniAssignment(program, assignment); //BoogieUtil.PrintProgram(program, "si_query" + IterCnt + ".bpl"); // Run SI var err = new List <BoogieErrorTrace>(); // Set bound BoogieVerify.options.maxInlinedBound = 0; if (inlined != 0) { BoogieVerify.options.maxInlinedBound = PerfMetric(inlined); } var rstatus = BoogieVerify.Verify(program, out err, true); //Console.WriteLine(string.Format(" >> Procedures Inlined: {0}", BoogieVerify.CallTreeSize)); //Console.WriteLine(string.Format("Boogie verification time: {0} s", BoogieVerify.verificationTime.TotalSeconds.ToString("F2"))); inlined = BoogieVerify.CallTreeSize + 1; BoogieVerify.options.CallTree = new HashSet <string>(); BoogieVerify.CallTreeSize = 0; BoogieVerify.verificationTime = TimeSpan.Zero; return(rstatus); }
static Program Process(Program program) { // Get rid of Synonyms RemoveTypeSynonyms.Remove(program); //BoogieUtil.PrintProgram(program, "tt.bpl"); program = BoogieUtil.ReResolve(program); // add "allocator" to malloc program.TopLevelDeclarations.OfType <Procedure>() .Where(p => MallocNames.Contains(p.Name)) .Iter(p => p.AddAttribute("allocator")); // Create "null" var nil = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "NULL", btype.Int), false); nil.AddAttribute("allocated"); // axiom NULL == 0; var ax = new Axiom(Token.NoToken, Expr.Eq(Expr.Ident(nil), Expr.Literal(0))); // Convert 0 to NULL in the program ConvertToNull.Convert(program, nil); program.AddTopLevelDeclaration(nil); program.AddTopLevelDeclaration(ax); // Add "assert !aliasQ(e, NULL)" for each expression M[e] appearing in the program InstrumentMemoryAccesses.Instrument(program, nil); // Put {:scalar} {:AllocatorVar} on $CurrAddr var alloc = program.TopLevelDeclarations.OfType <GlobalVariable>().Where(g => g.Name == allocVar) .FirstOrDefault(); if (alloc != null) { alloc.AddAttribute("scalar"); alloc.AddAttribute(AvUtil.AvnAnnotations.AllocatorVarAttr); } else { Console.WriteLine("Warning: Global variable $CurrAddr not found"); } if (initMem) { InitMemory(program); } return(program); }
static IEnumerable <Function> DoInference(Program program, InferenceMode mode, string annotatedFileName, string expandedFileName) { var tmpFileName = "og__tmp_di.bpl"; if (mode == InferenceMode.SEQUENTIAL) { // remove yields program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Blocks .Iter(blk => blk.Cmds = new List <Cmd>(blk.Cmds.Filter(c => !(c is YieldCmd))))); } // Run OG if (dbg) { Console.WriteLine("Running OG: {0}", expandedFileName); } LinearTypeChecker linearTypechecker; CivlTypeChecker moverTypeChecker; var oc = ExecutionEngine.ResolveAndTypecheck(program, annotatedFileName, out linearTypechecker, out moverTypeChecker); if (oc != PipelineOutcome.ResolvedAndTypeChecked) { throw new Exception(string.Format("{0} type checking errors detected in {1}", linearTypechecker.errorCount, annotatedFileName)); } Concurrency.Transform(linearTypechecker, moverTypeChecker); var eraser = new LinearEraser(); eraser.VisitProgram(program); //var stats = new PipelineStatistics(); //ExecutionEngine.EliminateDeadVariablesAndInline(program); //var ret = ExecutionEngine.InferAndVerify(program, stats); //ExecutionEngine.printer.WriteTrailer(stats); //return; program = BoogieUtil.ReResolve(program, dbg ? expandedFileName : tmpFileName); // Run Abs if (dbg) { Console.WriteLine("Running abs houdini on {0}", expandedFileName); } ExecutionEngine.EliminateDeadVariables(program); ExecutionEngine.Inline(program); var domain = Microsoft.Boogie.Houdini.AbstractDomainFactory.GetInstance(absDomain); var abs = new Microsoft.Boogie.Houdini.AbsHoudini(program, domain); var outcome = abs.ComputeSummaries(); if (outcome.outcome != VC.ConditionGeneration.Outcome.Correct) { Console.WriteLine("Some assert failed while running AbsHoudini, aborting"); outcome.errors.Iter(error => og.PrintError(error)); } return(abs.GetAssignment()); }
static void Main(string[] args) { con = new Context(); string inFileName = null, unrolledFileName = null, tidRewrittenFileName = null, expandedFileName = null, annotatedFileName = null, splitFileName = null, yieldedFileName = null, instantiatedFileName = null, finalFileName = null, mhpFileName = null, hmifFileName = null; dbg = false; inFileName = parseCommandLine(args); string[] parts = inFileName.Split('.'); if (parts.Count() == 1) { unrolledFileName = inFileName + "_unrolled"; hmifFileName = inFileName + "_hmif"; expandedFileName = inFileName + "_expanded"; tidRewrittenFileName = inFileName + "_tidRewritten"; annotatedFileName = inFileName + "_annotated"; splitFileName = inFileName + "_split"; yieldedFileName = inFileName + "_yielded"; finalFileName = inFileName + "_final"; mhpFileName = inFileName + "_mhp"; instantiatedFileName = inFileName + "_inst"; } else { string name = parts[0]; unrolledFileName = name + "_unrolled"; hmifFileName = name + "_hmif"; expandedFileName = name + "_expanded"; annotatedFileName = name + "_annotated"; splitFileName = name + "_split"; yieldedFileName = name + "_yielded"; finalFileName = name + "_final"; mhpFileName = name + "_mhp"; instantiatedFileName = name + "_inst"; tidRewrittenFileName = name + "_tidRewritten"; for (int i = 1; i < parts.Count(); ++i) { unrolledFileName += "." + parts[i]; hmifFileName += "." + parts[i]; expandedFileName += "." + parts[i]; annotatedFileName += "." + parts[i]; splitFileName += "." + parts[i]; yieldedFileName += "." + parts[i]; finalFileName += "." + parts[i]; tidRewrittenFileName += "." + parts[i]; mhpFileName += "." + parts[i]; instantiatedFileName += "." + parts[i]; } } var tmpFileName = "og__tmp.bpl"; ExecutionEngine.printer = new ConsolePrinter(); //CommanLineOptions will control how boogie parses the program and gives us the IR CommandLineOptions.Install(new CommandLineOptions()); CommandLineOptions.Clo.Parse(new string[] { }); CommandLineOptions.Clo.PrintInstrumented = true; CommandLineOptions.Clo.StratifiedInliningVerbose = 2; CommandLineOptions.Clo.UseArrayTheory = true; CommandLineOptions.Clo.TypeEncodingMethod = CommandLineOptions.TypeEncoding.Monomorphic; Program program; program = BoogieUtil.ReadAndOnlyResolve(inFileName); // TODO: assert that no procedure can be called in both sync and async mode! // Find entrypoint and initialize con var entry = program.TopLevelDeclarations.OfType <Procedure>() .Where(proc => QKeyValue.FindBoolAttribute(proc.Attributes, "entrypoint")) .FirstOrDefault(); if (entry == null) { Console.WriteLine("Warning: No entrypoint given"); con.entryFunc = null; } else { con.entryFunc = entry.Name; } // Remove unreachable procedures BoogieUtil.pruneProcs(program, con.entryFunc); // Extract loops if (extractLoops) { program.ExtractLoops(); } BoogieUtil.DoModSetAnalysis(program); if (pruneAsserts) { program = og.GuardAsserts(program); } if (injectYields) { program = og.InsertYields(program); } if (instantiateTemplates) { var inst = new TemplateInstantiator(program); inst.Instantiate(program); program = BoogieUtil.ReResolve(program, dbg ? instantiatedFileName : tmpFileName); } var sp = new SplitThreads(con, dbg); var hmif = new HowManyInstanceFinder(con, dbg); var split = new Converter <Program, Program>(sp.split); var findHowManyInstances = new Converter <Program, Program>(hmif.Compute); if (entry != null && splitThreads) { if (dbg) { Console.WriteLine("Splitting procedures on thread entry: {0}", splitFileName); } program = split(program); program = BoogieUtil.ReResolve(program, dbg ? hmifFileName : tmpFileName); program = findHowManyInstances(program); program = BoogieUtil.ReResolve(program, dbg ? splitFileName : tmpFileName); } // Get rid of corral_yield program = og.RemoveCorralYield(program, con.yieldProc); var yieldedProgram = new ProgTransformation.PersistentProgram(program); if (dbg) { Console.WriteLine("Instrumenting: {0}", annotatedFileName); } if (!noTid) { program = og.InstrumentTid(program); } program = og.InstrumentAtomicBlocks(program); if (instrumentPermissions) { program = og.InstrumentPermissions(program); } program = BoogieUtil.ReResolve(program, dbg ? annotatedFileName : tmpFileName); CommandLineOptions.Clo.ContractInfer = true; CommandLineOptions.Clo.AbstractHoudini = absDomain; CommandLineOptions.Clo.UseProverEvaluate = true; CommandLineOptions.Clo.ModelViewFile = "z3model"; Microsoft.Boogie.Houdini.AbstractDomainFactory.Initialize(program); // First, do sequential var answer = DoInference(program, InferenceMode.SEQUENTIAL, annotatedFileName, expandedFileName); program = BoogieUtil.ReadAndOnlyResolve(dbg ? annotatedFileName : tmpFileName); // prune "true" functions var progFuncs = new Dictionary <string, Function>(); program.TopLevelDeclarations.OfType <Function>() .Iter(f => progFuncs.Add(f.Name, f)); var truefuncs = new List <Function>(); foreach (var f in answer) { if (f.Body is LiteralExpr && (f.Body as LiteralExpr).IsTrue) { truefuncs.Add(f); var actualf = progFuncs[f.Name]; actualf.Attributes = BoogieUtil.removeAttr("existential", actualf.Attributes); actualf.Body = Expr.True; } } Console.WriteLine("Sequential check pruned away {0} functions, {1} remain", truefuncs.Count, answer.Count() - truefuncs.Count); // now do concurrent answer = DoInference(program, InferenceMode.CONCURRENT, annotatedFileName, expandedFileName); answer = answer.Concat(truefuncs); var provedAsserts = new Dictionary <string, bool>(); answer.Where(func => QKeyValue.FindBoolAttribute(func.Attributes, "assertGuard")) .Iter(func => { var le = func.Body as LiteralExpr; System.Diagnostics.Debug.Assert(le != null); provedAsserts.Add(func.Name, le.IsFalse); }); // remove injected existential functions answer = answer.Where(func => !QKeyValue.FindBoolAttribute(func.Attributes, "chignore") && !QKeyValue.FindBoolAttribute(func.Attributes, "assertGuard")); if (printAssignment) { using (var tt = new TokenTextWriter(Console.Out)) answer.ToList().Iter(func => func.Emit(tt, 0)); } if (dbg) { Console.WriteLine("Injecting invariants back into the original program: {0}", finalFileName); } program = yieldedProgram.getProgram(); // remove existential functions program.RemoveTopLevelDeclarations(decl => (decl is Function) && QKeyValue.FindBoolAttribute((decl as Function).Attributes, "existential")); program.AddTopLevelDeclarations(answer); program = og.PruneProvedAsserts(program, f => provedAsserts[f]); // Remove ensures and requires program = og.RemoveRequiresAndEnsures(program); // Remove tid func program = og.RemoveThreadIdFunc(program); using (Microsoft.Boogie.TokenTextWriter writer = new Microsoft.Boogie.TokenTextWriter(finalFileName)) program.Emit(writer); }
// Run Alias Analysis on a sequential Boogie program // and returned the pruned program public static PersistentProgram RunAliasAnalysis(PersistentProgram inp, bool pruneEP = true) { var newinp = inp; if (Options.unrollDepth > 0) { Stats.resume("unroll"); var unrp = new cba.LoopUnrollingPass(Options.unrollDepth); newinp = unrp.run(newinp); Stats.stop("unroll"); } var program = newinp.getProgram(); //AliasAnalysis.AliasAnalysis.dbg = true; //AliasAnalysis.AliasConstraintSolver.dbg = true; AliasAnalysis.AliasAnalysisResults res = null; if (Options.UseAliasAnalysisForAssertions) { // Do SSA program = SSA.Compute(program, PhiFunctionEncoding.Verifiable, new HashSet <string> { "int" }); if (Options.inlineDepth > 0) { Stats.resume("inlining"); Stats.resume("read.write"); program = BoogieUtil.ReResolve(program); Stats.stop("read.write"); var op = CommandLineOptions.Clo.InlineDepth; CommandLineOptions.Clo.InlineDepth = Options.inlineDepth; cba.InliningPass.InlineToDepth(program); CommandLineOptions.Clo.InlineDepth = op; RemoveHavocs(program); Stats.stop("inlining"); } Stats.resume("read.write"); program = BoogieUtil.ReResolve(program); Stats.stop("read.write"); // Make sure that aliasing queries are on identifiers only var af = AliasAnalysis.SimplifyAliasingQueries.Simplify(program); Stats.resume("fixpoint"); res = AliasAnalysis.AliasAnalysis.DoAliasAnalysis(program); Stats.stop("fixpoint"); } else { // Make sure that aliasing queries are on identifiers only var af = AliasAnalysis.SimplifyAliasingQueries.Simplify(program); res = new AliasAnalysis.AliasAnalysisResults(); af.Iter(s => res.aliases.Add(s, true)); } var origProgram = inp.getProgram(); AliasAnalysis.PruneAliasingQueries.Prune(origProgram, res); if (pruneEP) { PruneRedundantEntryPoints(origProgram); } return(new PersistentProgram(origProgram, inp.mainProcName, inp.contextBound)); }
static Program GetProgram(string filename) { var init = GetInputProgram(filename); if (Options.addInitialization) { ComputeandInitializeUninitializedLocals(init); } // Do some instrumentation for the input program if (Options.markAssumesAsSlic) { // Mark all assumes as "slic" var AddAnnotation = new Action <AssumeCmd>(ac => { ac.Attributes = new QKeyValue(Token.NoToken, "slic", new List <object>(), ac.Attributes); }); init.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => impl.Blocks .Iter(blk => blk.Cmds.OfType <AssumeCmd>() .Iter(AddAnnotation))); } // Inline procedures supplied with {:inline} annotation cba.Driver.InlineProcedures(init); // Remove {:inline} impls init.RemoveTopLevelDeclarations(decl => (decl is Implementation) && (BoogieUtil.checkAttrExists("inline", decl.Attributes) || BoogieUtil.checkAttrExists("inline", (decl as Implementation).Proc.Attributes))); // Add {:entrypoint} to procs with {:harness} if (Options.useHarnessTag) { foreach (var decl in init.TopLevelDeclarations.OfType <NamedDeclaration>() .Where(d => QKeyValue.FindBoolAttribute(d.Attributes, "harness"))) { decl.AddAttribute("entrypoint"); } } // inlining introduces havoc statements; lets just delete them (TODO: make inlining not introduce redundant havoc statements) foreach (var impl in init.TopLevelDeclarations.OfType <Implementation>()) { impl.Blocks.Iter(blk => blk.Cmds.RemoveAll(cmd => cmd is HavocCmd)); } //Instrument to create the harness harnessInstrumentation = new Instrumentations.HarnessInstrumentation(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.useProvidedEntryPoints); harnessInstrumentation.DoInstrument(); //resolve+typecheck wo bothering about modSets CommandLineOptions.Clo.DoModSetAnalysis = true; init = BoogieUtil.ReResolve(init); CommandLineOptions.Clo.DoModSetAnalysis = false; // Update mod sets BoogieUtil.DoModSetAnalysis(init); if (Options.AddMapSelectNonNullAssumptions) { (new Instrumentations.AssertMapSelectsNonNull()).Visit(init); } BoogieUtil.pruneProcs(init, AvnAnnotations.CORRAL_MAIN_PROC); if (Options.deadCodeDetect) { // Tag branches as reachable var tup = InstrumentBranches.Run(init, AvnAnnotations.CORRAL_MAIN_PROC, Options.UseAliasAnalysisForAngelicAssertions, false); init = tup.Item1; // TODO: inject this information into the program itself DeadCodeBranchesDependencyInfo = tup.Item2; } return(init); }