internal static string GetTagFromNonCandidateAttributes(QKeyValue Attributes) { string tag = QKeyValue.FindStringAttribute(Attributes, "staged_houdini_tag"); return tag; }
private Block Abstract(Block b) { var newCmds = new List <Cmd>(); foreach (Cmd c in b.Cmds) { if (c is CallCmd) { var call = c as CallCmd; if (QKeyValue.FindBoolAttribute(call.Attributes, "atomic")) { // Discard the call Debug.Assert(call.Ins.Count >= 1); var ie = call.Ins[0] as IdentifierExpr; Debug.Assert(ie != null); Debug.Assert(verifier.ArrayModelledAdversarially(ie.Decl)); continue; } for (int i = 0; i < call.Ins.Count; i++) { ReadCollector rc = new ReadCollector(verifier.KernelArrayInfo); rc.Visit(call.Ins[i]); bool foundAdversarial = false; foreach (AccessRecord ar in rc.NonPrivateAccesses) { if (verifier.ArrayModelledAdversarially(ar.V)) { foundAdversarial = true; break; } } if (foundAdversarial) { LocalVariable lv = new LocalVariable( Token.NoToken, new TypedIdent(Token.NoToken, "_abstracted_call_arg_" + abstractedCallArgCounter, call.Ins[i].Type)); abstractedCallArgCounter++; newLocalVars.Add(lv); newCmds.Add(new HavocCmd( Token.NoToken, new List <IdentifierExpr>(new IdentifierExpr[] { new IdentifierExpr(Token.NoToken, lv) }))); call.Ins[i] = new IdentifierExpr(Token.NoToken, lv); } } } if (c is AssignCmd) { AssignCmd assign = c as AssignCmd; var lhss = new List <AssignLhs>(); var rhss = new List <Expr>(); foreach (var lhsRhs in assign.Lhss.Zip(assign.Rhss)) { AssignLhs lhs = lhsRhs.Item1; Expr rhs = lhsRhs.Item2; ReadCollector rc = new ReadCollector(verifier.KernelArrayInfo); rc.Visit(rhs); bool foundAdversarial = false; foreach (AccessRecord ar in rc.NonPrivateAccesses) { if (verifier.ArrayModelledAdversarially(ar.V)) { foundAdversarial = true; break; } } if (foundAdversarial) { Debug.Assert(lhs is SimpleAssignLhs); newCmds.Add(new HavocCmd(c.tok, new List <IdentifierExpr>(new IdentifierExpr[] { (lhs as SimpleAssignLhs).AssignedVariable }))); continue; } WriteCollector wc = new WriteCollector(verifier.KernelArrayInfo); wc.Visit(lhs); if (wc.FoundNonPrivateWrite()) { if (verifier.ArrayModelledAdversarially(wc.GetAccess().V)) { continue; // Just remove the write } } lhss.Add(lhs); rhss.Add(rhs); } if (lhss.Count != 0) { newCmds.Add(new AssignCmd(assign.tok, lhss, rhss)); } continue; } newCmds.Add(c); } b.Cmds = newCmds; return(b); }
public static bool MatchSig(Implementation toMatch, DeclWithFormals dwf, Program boogieProgram, out QKeyValue toMatchAnyParamsAttributes, out int anyParamsPosition, out QKeyValue toMatchAnyParamsAttributesOut, out int anyParamsPositionOut, out Dictionary <Declaration, Expr> paramSubstitution, bool matchPtrs) { toMatchAnyParamsAttributes = null; anyParamsPosition = int.MaxValue; toMatchAnyParamsAttributesOut = null; anyParamsPositionOut = int.MaxValue; paramSubstitution = new Dictionary <Declaration, Expr>(); if (!ExprMatchVisitor.AreAttributesASubset(toMatch.Attributes, dwf.Attributes)) { return(false); } // match procedure name // Positive filters: AnyProcedure, NameMatches, ByName if (BoogieUtil.checkAttrExists(ExprMatchVisitor.BoogieKeyWords.AnyProcedure, toMatch.Attributes)) { //do nothing } else if (BoogieUtil.checkAttrExists(ExprMatchVisitor.BoogieKeyWords.NameMatches, toMatch.Attributes)) { var nmAttrParams = BoogieUtil.getAttr(ExprMatchVisitor.BoogieKeyWords.NameMatches, toMatch.Attributes); Debug.Assert(nmAttrParams.Count() == 1, "Expecting exactly one #NameMatches attribute, found " + nmAttrParams.Count()); var regex = nmAttrParams.First().ToString(); var m = Regex.Match(dwf.Name, regex); if (m.Success) { //do nothing } else { return(false); } } else if (toMatch.Name != dwf.Name) { return(false); } //Negative filter: NameNotMatches (can be multiple of them) if (BoogieUtil.checkAttrExists(ExprMatchVisitor.BoogieKeyWords.NameNotMatches, toMatch.Attributes)) { //get the params from multiple matching key var getAttrRepeated = new Func <QKeyValue, string, IList <IList <object> > >((attr, name) => { var ret = new List <IList <object> >(); for (; attr != null; attr = attr.Next) { if (attr.Key == name) { ret.Add(attr.Params); } } return(ret); }); var nmAttrParams = getAttrRepeated(toMatch.Attributes, ExprMatchVisitor.BoogieKeyWords.NameNotMatches); foreach (var nm in nmAttrParams) { if (Regex.Match(dwf.Name, nm.First().ToString()).Success) { return(false); } } } // if the procedure name is matched, it may still be that we are looking only for stubs if (BoogieUtil.checkAttrExists(ExprMatchVisitor.BoogieKeyWords.NoImplementation, toMatch.Attributes)) { foreach (var i in boogieProgram.Implementations) { if (i.Name == dwf.Name) { return(false); } } } Procedure dwfProc = null; if (dwf is Implementation) { dwfProc = ((Implementation)dwf).Proc; } else if (dwf is Procedure) { dwfProc = (Procedure)dwf; } if (!MatchParams(ref toMatchAnyParamsAttributes, ref anyParamsPosition, paramSubstitution, toMatch.InParams, toMatch.Proc.InParams, dwf.InParams, dwfProc.InParams, matchPtrs)) { return(false); } if (!MatchParams(ref toMatchAnyParamsAttributesOut, ref anyParamsPositionOut, paramSubstitution, toMatch.OutParams, toMatch.Proc.OutParams, dwf.OutParams, dwfProc.OutParams, matchPtrs)) { return(false); } return(true); }
public static Program InjectDualityProof(Program program, string DualityProofFile) { Program DualityProof; using (var st = new System.IO.StreamReader(DualityProofFile)) { var s = ParserHelper.Fill(st, new List <string>()); // replace %i by bound_var_i for (int i = 0; i <= 9; i++) { s = s.Replace(string.Format("%{0}", i), string.Format("pm_bv_{0}", i)); } var v = Parser.Parse(s, DualityProofFile, out DualityProof); if (v != 0) { throw new Exception("Failed to parse " + DualityProofFile); } } var implToContracts = new Dictionary <string, List <Expr> >(); foreach (var proc in DualityProof.TopLevelDeclarations.OfType <Procedure>()) { implToContracts.Add(proc.Name, new List <Expr>()); foreach (var ens in proc.Ensures) { implToContracts[proc.Name].AddRange(GetExprConjunctions(ens.Condition)); } } var counter = 0; var GetExistentialConstant = new Func <Constant>(() => { var c = new Constant(Token.NoToken, new TypedIdent(Token.NoToken, "DualityProofConst" + (counter++), Microsoft.Boogie.Type.Bool), false); c.AddAttribute("existential"); return(c); }); var constsToAdd = new List <Declaration>(); foreach (var proc in program.TopLevelDeclarations.OfType <Procedure>()) { if (!implToContracts.ContainsKey(proc.Name)) { continue; } if (QKeyValue.FindBoolAttribute(proc.Attributes, "nohoudini")) { continue; } foreach (var expr in implToContracts[proc.Name]) { var c = GetExistentialConstant(); constsToAdd.Add(c); proc.Ensures.Add(new Ensures(false, Expr.Imp(Expr.Ident(c), expr))); } } program.TopLevelDeclarations.AddRange(constsToAdd); return(program); }
public static int RealMain(String[] args) { // Debug log output goes to standard error. Debug.Listeners.Add(new ExceptionThrowingTextWritierTraceListener(Console.Error)); // FIXME: Urgh... we are forced to use Boogie's command line // parser becaue the Boogie program resolver/type checker // is dependent on the parser being used...EURGH! CommandLineOptions.Install(new Microsoft.Boogie.CommandLineOptions()); var options = new CmdLineOpts(); if (!CommandLine.Parser.Default.ParseArguments(args, options)) { Console.WriteLine("Failed to parse args"); ExitWith(ExitCode.COMMAND_LINE_ERROR); } if (options.boogieProgramPath == null) { Console.WriteLine("A boogie program must be specified. See --help"); ExitWith(ExitCode.COMMAND_LINE_ERROR); } if (!File.Exists(options.boogieProgramPath)) { Console.WriteLine("Boogie program \"" + options.boogieProgramPath + "\" does not exist"); ExitWith(ExitCode.COMMAND_LINE_ERROR); } Program program = null; if (options.Defines != null) { foreach (var define in options.Defines) { Console.WriteLine("Adding define \"" + define + "\" to Boogie parser"); } } int errors = Microsoft.Boogie.Parser.Parse(options.boogieProgramPath, options.Defines, out program); if (errors != 0) { Console.WriteLine("Failed to parse"); ExitWith(ExitCode.PARSE_ERROR); } errors = program.Resolve(); if (errors != 0) { Console.WriteLine("Failed to resolve."); ExitWith(ExitCode.RESOLVE_ERROR); } if (options.useModSetTransform > 0) { // This is useful for Boogie Programs produced by the GPUVerify tool that // have had instrumentation added that invalidates the modset attached to // procedures. By running the analysis we may modify the modsets attached to // procedures in the program to be correct so that Boogie's Type checker doesn't // produce an error. var modsetAnalyser = new ModSetCollector(); modsetAnalyser.DoModSetAnalysis(program); } errors = program.Typecheck(); if (errors != 0) { Console.WriteLine("Failed to Typecheck."); ExitWith(ExitCode.TYPECHECK_ERROR); } IStateScheduler scheduler = GetScheduler(options); // Limit Depth if necessary if (options.MaxDepth >= 0) { scheduler = new LimitExplicitDepthScheduler(scheduler, options.MaxDepth); Console.WriteLine("Using Depth limit:{0}", options.MaxDepth); } if (options.FailureLimit < 0) { Console.Error.WriteLine("FailureLimit must be >= 0"); ExitWith(ExitCode.COMMAND_LINE_ERROR); } Console.WriteLine("Using Scheduler: {0}", scheduler.ToString()); var nonSpeculativeterminationCounter = new TerminationCounter(TerminationCounter.CountType.ONLY_NON_SPECULATIVE); var speculativeTerminationCounter = new TerminationCounter(TerminationCounter.CountType.ONLY_SPECULATIVE); IExprBuilder builder = new SimpleExprBuilder(/*immutable=*/ true); ISymbolicPool symbolicPool = null; if (options.useSymbolicPoolCache > 0) { throw new Exception("DON'T USE THIS. IT'S BROKEN"); symbolicPool = new CachingSymbolicPool(); } else { symbolicPool = new SimpleSymbolicPool(); } Console.WriteLine("Using Symbolic Pool: {0}", symbolicPool.ToString()); if (options.useConstantFolding > 0) { if (options.ConstantCaching > 0) { Console.WriteLine("Using ConstantCachingExprBuilder"); builder = new ConstantCachingExprBuilder(builder); } builder = new ConstantFoldingExprBuilder(builder); } // Destroy the solver when we stop using it using (var solver = BuildSolverChain(options)) { Executor executor = new Executor(program, scheduler, solver, builder, symbolicPool); executor.ExecutorTimeoutReached += delegate(object sender, Executor.ExecutorTimeoutReachedArgs eventArgs) { TimeoutHit = true; // Record so we can set the exitcode appropriately later Console.Error.WriteLine("Timeout hit. Trying to kill Executor (may wait for solver)"); }; // Check all implementations exist and build list of entry points to execute var entryPoints = new List <Implementation>(); // This is specific to GPUVerify if (options.gpuverifyEntryPoints) { var kernels = program.TopLevelDeclarations.OfType <Implementation>().Where(impl => QKeyValue.FindBoolAttribute(impl.Attributes, "kernel")); foreach (var kernel in kernels) { entryPoints.Add(kernel); } if (entryPoints.Count() == 0) { Console.WriteLine("Could not find any kernel entry points"); ExitWith(ExitCode.ENTRY_POINT_NOT_FOUND_ERROR); } } else { // Set main as default. if (options.entryPoints == null) { options.entryPoints = new List <string>() { "main" } } ; foreach (var implString in options.entryPoints) { Implementation entry = program.TopLevelDeclarations.OfType <Implementation>().Where(i => i.Name == implString).FirstOrDefault(); if (entry == null) { Console.WriteLine("Could not find implementation \"" + implString + "\" to use as entry point"); ExitWith(ExitCode.ENTRY_POINT_NOT_FOUND_ERROR); } entryPoints.Add(entry); } } if (options.useInstructionPrinter) { Console.WriteLine("Installing instruction printer"); var instrPrinter = new InstructionPrinter(Console.Out); instrPrinter.Connect(executor); } if (options.useCallSequencePrinter) { Console.WriteLine("Installing call sequence printer"); var callPrinter = new CallPrinter(Console.Out); callPrinter.Connect(executor); } if (options.gotoAssumeLookAhead > 0) { executor.UseGotoLookAhead = true; } else { executor.UseGotoLookAhead = false; } if (options.ForkAtPredicatedAssign) { executor.UseForkAtPredicatedAssign = true; } if (options.CheckEntryRequires > 0) { executor.CheckEntryRequires = true; } else { Console.WriteLine("Warning: Requires at the entry point are not being checked"); executor.CheckEntryRequires = false; } if (options.CheckEntryAxioms > 0) { executor.CheckEntryAxioms = true; } else { Console.WriteLine("Warning: Axioms are not being checked"); executor.CheckEntryAxioms = false; } if (options.CheckUniqueVariableDecls > 0) { executor.CheckUniqueVariableDecls = true; } else { Console.WriteLine("Warning: Unique variables are not being checked"); executor.CheckUniqueVariableDecls = false; } if (options.GlobalDDE > 0) { executor.UseGlobalDDE = true; Console.WriteLine("WARNING: Using GlobalDDE. This may remove unsatisfiable axioms"); } else { executor.UseGlobalDDE = false; } // Just print a message about break points for now. executor.BreakPointReached += BreakPointPrinter.handleBreakPoint; // Write to the console about context changes var contextChangeReporter = new ContextChangedReporter(); contextChangeReporter.Connect(executor); var stateHandler = new TerminationConsoleReporter(); stateHandler.Connect(executor); nonSpeculativeterminationCounter.Connect(executor); speculativeTerminationCounter.Connect(executor); if (options.FileLogging > 0) { SetupFileLoggers(options, executor, solver); } SetupTerminationCatchers(executor); ApplyFilters(executor, options); if (options.FailureLimit > 0) { var failureLimiter = new FailureLimiter(options.FailureLimit); failureLimiter.Connect(executor); Console.WriteLine("Using failure limit of {0}", options.FailureLimit); } try { // Supply our own PassManager for preparation so we can hook into its events executor.PreparationPassManager = GetPassManager(options); foreach (var entryPoint in entryPoints) { Console.ForegroundColor = ConsoleColor.Cyan; Console.WriteLine("Entering Implementation " + entryPoint.Name + " as entry point"); Console.ResetColor(); executor.Run(entryPoint, options.timeout); } } catch (InitialStateTerminated) { if (options.CatchExceptions == 0) { throw; } Console.ForegroundColor = ConsoleColor.Red; Console.Error.WriteLine("The initial state terminated. Execution cannot continue"); Console.ResetColor(); ExitWith(ExitCode.INITIAL_STATE_TERMINATED); } catch (RecursiveFunctionDetectedException rfdException) { if (options.CatchExceptions == 0) { throw; } Console.ForegroundColor = ConsoleColor.Red; Console.Error.WriteLine("Detected the following recursive functions"); foreach (var function in rfdException.Functions) { Console.Error.Write(function.Name + ": "); if (function.Body != null) { Console.Error.WriteLine(function.Body.ToString()); } if (function.DefinitionAxiom != null) { Console.Error.WriteLine(function.DefinitionAxiom.Expr.ToString()); } } Console.ResetColor(); ExitWith(ExitCode.RECURSIVE_FUNCTIONS_FOUND_ERROR); } catch (OutOfMemoryException e) { if (options.CatchExceptions == 0) { throw; } Console.Error.WriteLine("Ran out of memory!"); Console.Error.WriteLine(e.ToString()); ExitWith(ExitCode.OUT_OF_MEMORY); } catch (NotImplementedException e) { if (options.CatchExceptions == 0) { throw; } Console.Error.WriteLine("Feature not implemented!"); Console.Error.WriteLine(e.ToString()); ExitWith(ExitCode.NOT_IMPLEMENTED_EXCEPTION); } catch (NotSupportedException e) { if (options.CatchExceptions == 0) { throw; } Console.Error.WriteLine("Feature not supported!"); Console.Error.WriteLine(e.ToString()); ExitWith(ExitCode.NOT_SUPPORTED_EXCEPTION); } Console.WriteLine("Finished executing"); DumpStats(executor, solver, nonSpeculativeterminationCounter, speculativeTerminationCounter); } if (TimeoutHit) { ExitWith(nonSpeculativeterminationCounter.NumberOfFailures > 0 ? ExitCode.ERRORS_TIMEOUT : ExitCode.NO_ERRORS_TIMEOUT); throw new InvalidOperationException("Unreachable"); } var exitCode = nonSpeculativeterminationCounter.NumberOfFailures > 0 ? ExitCode.ERRORS_NO_TIMEOUT : ExitCode.NO_ERRORS_NO_TIMEOUT; if (exitCode == ExitCode.NO_ERRORS_NO_TIMEOUT) { // If no errors were found we may need to pick a different exit code // because path exploration may not have been exhaustive due to speculative paths // or hitting a bound. This isn't perfect because we may hit a bound and have speculative // paths so we could use either exit code in this case. if (nonSpeculativeterminationCounter.DisallowedSpeculativePaths > 0 || speculativeTerminationCounter.NumberOfTerminatedStates > 0) { exitCode = ExitCode.NO_ERRORS_NO_TIMEOUT_BUT_FOUND_SPECULATIVE_PATHS; Console.WriteLine("NOTE: Bugs may have been missed!"); } else if (nonSpeculativeterminationCounter.DisallowedPathDepths > 0) { exitCode = ExitCode.NO_ERRORS_NO_TIMEOUT_BUT_HIT_BOUND; Console.WriteLine("NOTE: Bugs may have been missed!"); } } ExitWith(exitCode); return((int)exitCode); // This is required to keep the compiler happy. }
public static HashSet <string> RunHoudini(Program program, bool RobustAgainstEvaluate = false) { HoudiniStats.Reset(); HoudiniInlining.RobustAgainstEvaluate = DualHoudini? false : RobustAgainstEvaluate; if (DualHoudini && CommandLineOptions.Clo.InlineDepth > 0) { throw new DualHoudiniFail("InlineDepth not supported"); } // Gather existential constants var CandidateConstants = new Dictionary <string, Constant>(); program.TopLevelDeclarations.OfType <Constant>() .Where(c => QKeyValue.FindBoolAttribute(c.Attributes, "existential")) .Iter(c => CandidateConstants.Add(c.Name, c)); // Create a function, one for each impl, for book-keeping var CandidateFuncsAssumed = new Dictionary <string, Function>(); var CandidateFuncsAsserted = new Dictionary <string, Function>(); var AssumeToAssert = new Dictionary <Function, Function>(); program.TopLevelDeclarations.OfType <Implementation>() .Iter(impl => { var fassumed = GetCandidateFunc(CandidateFuncPrefix, impl.Name); var fasserted = GetCandidateFunc(CandidateFuncAssertedPrefix, impl.Name); CandidateFuncsAssumed.Add(impl.Name, fassumed); CandidateFuncsAsserted.Add(impl.Name, fasserted); AssumeToAssert.Add(fassumed, fasserted); }); // Tag the ensures so we can keep track of them var iterimpls = program.TopLevelDeclarations.OfType <Implementation>().ToList(); iterimpls.Iter(impl => InstrumentEnsures(program, impl, CandidateFuncsAssumed[impl.Name], CandidateConstants)); //BoogieUtil.PrintProgram(program, "h2.bpl"); var RewriteAssumedToAssertedAction = new Action <Implementation>(impl => { // Rewrite functions that are asserted var rewrite = new RewriteFuncs(AssumeToAssert); foreach (var blk in impl.Blocks) { foreach (var acmd in blk.Cmds.OfType <AssertCmd>()) { acmd.Expr = rewrite.VisitExpr(acmd.Expr); } } var funcs = new HashSet <Function>(CandidateFuncsAssumed.Values); // Move call-site constant to the first argument of CandidateFuncs foreach (var blk in impl.Blocks) { Expr cv = null; // walk backwards for (int i = blk.Cmds.Count - 1; i >= 0; i--) { var acmd = blk.Cmds[i] as AssumeCmd; if (acmd == null) { continue; } if (QKeyValue.FindBoolAttribute(acmd.Attributes, StratifiedVCGenBase.callSiteVarAttr)) { cv = acmd.Expr; continue; } InsertControlVar.Apply(acmd.Expr, funcs, cv); } } //impl.Emit(new TokenTextWriter(Console.Out), 0); }); program.AddTopLevelDeclarations(CandidateFuncsAssumed.Values); program.AddTopLevelDeclarations(CandidateFuncsAsserted.Values); var callgraph = BoogieUtil.GetCallGraph(program); var impl2Priority = DeterminePriorityOrder(program, callgraph); var impls = new HashSet <string>(impl2Priority.Keys); HoudiniStats.Start("VCGen"); // VC Gen var hi = new HoudiniInlining(program, CommandLineOptions.Clo.SimplifyLogFilePath, CommandLineOptions.Clo.SimplifyLogFileAppend, RewriteAssumedToAssertedAction); HoudiniStats.Stop("VCGen"); var worklist = new SortedSet <Tuple <int, string> >(); impl2Priority.Iter(tup => worklist.Add(Tuple.Create(tup.Value, tup.Key))); // Current assignment: set of true constants // Initially: everything is true var assignment = new HashSet <string>(CandidateConstants.Keys); var prover = hi.prover; var reporter = new EmptyErrorReporter(); // assert true to flush all one-time axioms, decls, etc prover.Assert(VCExpressionGenerator.True, true); HoudiniStats.Start("MainLoop"); // worklist algorithm while (worklist.Any()) { var implName = worklist.First().Item2; worklist.Remove(worklist.First()); if (dbg) { Console.WriteLine("Processing " + implName); } prover.LogComment("Processing " + implName); prover.Push(); var hvc = new HoudiniVC(hi.implName2StratifiedInliningInfo[implName], impls, assignment); var openCallSites = new HashSet <StratifiedCallSite>(hvc.CallSites); prover.Assert(hvc.vcexpr, true); var candidates = !DualHoudini ? new HashSet <string>(hvc.constantToAssertedExpr.Keys.Where(k => assignment.Contains(k))) : new HashSet <string>(hvc.constantToAssumedExpr.Select(t => t.Item1).Where(k => assignment.Contains(k))); var provedTrue = new HashSet <string>(); var provedFalse = new HashSet <string>(); var idepth = Math.Max(0, CommandLineOptions.Clo.InlineDepth); // iterate over idepth while (true) { // Part 1: over-approximate var proved = ProveCandidates(prover, hvc.constantToAssertedExpr, hvc.constantToAssumedExpr, candidates.Difference(provedTrue.Union(provedFalse))); provedTrue.UnionWith(proved); if (dbg) { Console.WriteLine("Proved {0} candiates at depth {1}", proved.Count, CommandLineOptions.Clo.InlineDepth - idepth); } if (idepth == 0 || openCallSites.Count == 0) { break; } // Part 2: under-approximate prover.Push(); foreach (var cs in openCallSites) { prover.Assert(cs.callSiteExpr, false); } var remaining = candidates.Difference(provedTrue.Union(provedFalse)); proved = ProveCandidates(prover, hvc.constantToAssertedExpr, hvc.constantToAssumedExpr, remaining); provedFalse.UnionWith(remaining.Difference(proved)); if (dbg) { Console.WriteLine("Disproved {0} candiates at depth {1}", remaining.Difference(proved).Count, CommandLineOptions.Clo.InlineDepth - idepth); } prover.Pop(); // resolved all? if (candidates.Difference(provedTrue.Union(provedFalse)).Count == 0) { break; } // Inline one level idepth--; var nextOpenCallSites = new HashSet <StratifiedCallSite>(); foreach (var cs in openCallSites) { var callee = new HoudiniVC(hi.implName2StratifiedInliningInfo[cs.callSite.calleeName], impls, assignment); var calleevc = cs.Attach(callee); prover.Assert(prover.VCExprGen.Implies(cs.callSiteExpr, calleevc), true); nextOpenCallSites.UnionWith(callee.CallSites); } openCallSites = nextOpenCallSites; } prover.Pop(); var failed = candidates.Difference(provedTrue); assignment.ExceptWith(failed); if (failed.Count != 0) { // add dependencies back into the worklist if (!DualHoudini) { foreach (var caller in callgraph.Predecessors(implName)) { worklist.Add(Tuple.Create(impl2Priority[caller], caller)); } } else { foreach (var caller in callgraph.Successors(implName)) { worklist.Add(Tuple.Create(impl2Priority[caller], caller)); } } } } HoudiniStats.Stop("MainLoop"); hi.Close(); return(assignment); }
static void removeTemplates(string file, string outfile) { var program = ParseProgram(file); foreach (var proc in program.TopLevelDeclarations.OfType <Procedure>().Where(p => QKeyValue.FindBoolAttribute(p.Attributes, "template"))) { proc.Ensures.RemoveAll(ens => !ens.Free); } var sw = new StreamWriter(outfile, false); var tw = new TokenTextWriter(sw); program.Emit(tw); sw.Close(); tw.Close(); }
public void DualiseKernel() { List <Declaration> newTopLevelDeclarations = new List <Declaration>(); // This loop really does have to be a "for(i ...)" loop. The reason is // that dualisation may add additional functions to the program, which // get put into the program's top level declarations and also need to // be dualised. var decls = Verifier.Program.TopLevelDeclarations.ToList(); for (int i = 0; i < UpdateDeclarationsAndCountTotal(decls); i++) { Declaration d = decls[i]; if (d is Axiom) { VariableDualiser vd1 = new VariableDualiser(1, Verifier, null); VariableDualiser vd2 = new VariableDualiser(2, Verifier, null); Axiom newAxiom1 = vd1.VisitAxiom(d.Clone() as Axiom); Axiom newAxiom2 = vd2.VisitAxiom(d.Clone() as Axiom); newTopLevelDeclarations.Add(newAxiom1); // Test whether dualisation had any effect by seeing whether the new // axioms are syntactically indistinguishable. If they are, then there // is no point adding the second axiom. if (!newAxiom1.ToString().Equals(newAxiom2.ToString())) { newTopLevelDeclarations.Add(newAxiom2); } continue; } if (d is Procedure) { DualiseProcedure(d as Procedure); newTopLevelDeclarations.Add(d); continue; } if (d is Implementation) { DualiseImplementation(d as Implementation); newTopLevelDeclarations.Add(d); continue; } if (d is Variable && ((d as Variable).IsMutable || Verifier.IsThreadLocalIdConstant(d as Variable) || (Verifier.IsGroupIdConstant(d as Variable) && !GPUVerifyVCGenCommandLineOptions.OnlyIntraGroupRaceChecking))) { var v = d as Variable; if (v.Name.Contains("_NOT_ACCESSED_") || v.Name.Contains("_ARRAY_OFFSET")) { newTopLevelDeclarations.Add(v); continue; } if (QKeyValue.FindBoolAttribute(v.Attributes, "atomic_usedmap")) { if (QKeyValue.FindBoolAttribute(v.Attributes, "atomic_group_shared") && !GPUVerifyVCGenCommandLineOptions.OnlyIntraGroupRaceChecking) { var type = new MapType( Token.NoToken, new List <TypeVariable>(), new List <Microsoft.Boogie.Type> { Microsoft.Boogie.Type.GetBvType(1) }, v.TypedIdent.Type); var newV = new GlobalVariable( Token.NoToken, new TypedIdent(Token.NoToken, v.Name, type)); newV.Attributes = v.Attributes; newTopLevelDeclarations.Add(newV); } else { newTopLevelDeclarations.Add(v); } continue; } if (Verifier.KernelArrayInfo.GetGlobalArrays(true).Contains(v)) { newTopLevelDeclarations.Add(v); continue; } if (Verifier.KernelArrayInfo.GetGroupSharedArrays(true).Contains(v)) { if (!GPUVerifyVCGenCommandLineOptions.OnlyIntraGroupRaceChecking) { var type = new MapType( Token.NoToken, new List <TypeVariable>(), new List <Microsoft.Boogie.Type> { Microsoft.Boogie.Type.GetBvType(1) }, v.TypedIdent.Type); var newV = new GlobalVariable( Token.NoToken, new TypedIdent(Token.NoToken, v.Name, type)); newV.Attributes = v.Attributes; newTopLevelDeclarations.Add(newV); } else { newTopLevelDeclarations.Add(v); } continue; } newTopLevelDeclarations.Add(new VariableDualiser(1, Verifier, null).VisitVariable((Variable)v.Clone())); if (!QKeyValue.FindBoolAttribute(v.Attributes, "race_checking")) { newTopLevelDeclarations.Add(new VariableDualiser(2, Verifier, null).VisitVariable((Variable)v.Clone())); } continue; } newTopLevelDeclarations.Add(d); } Verifier.Program.TopLevelDeclarations = newTopLevelDeclarations; }
private void MakeDual(List <Cmd> cs, Cmd c) { if (c is CallCmd) { CallCmd call = c as CallCmd; if (QKeyValue.FindBoolAttribute(call.Proc.Attributes, "barrier_invariant")) { // There may be a predicate, and there must be an invariant expression and at least one instantiation Debug.Assert(call.Ins.Count >= (2 + (Verifier.UniformityAnalyser.IsUniform(call.callee) ? 0 : 1))); var biDescriptor = new UnaryBarrierInvariantDescriptor( Verifier.UniformityAnalyser.IsUniform(call.callee) ? Expr.True : call.Ins[0], Expr.Neq(call.Ins[Verifier.UniformityAnalyser.IsUniform(call.callee) ? 0 : 1], Verifier.IntRep.GetZero(Verifier.IntRep.GetIntType(1))), call.Attributes, this, procName, Verifier); for (var i = 1 + (Verifier.UniformityAnalyser.IsUniform(call.callee) ? 0 : 1); i < call.Ins.Count; i++) { biDescriptor.AddInstantiationExpr(call.Ins[i]); } barrierInvariantDescriptors.Add(biDescriptor); return; } if (QKeyValue.FindBoolAttribute(call.Proc.Attributes, "binary_barrier_invariant")) { // There may be a predicate, and there must be an invariant expression and at least one pair of // instantiation expressions Debug.Assert(call.Ins.Count >= (3 + (Verifier.UniformityAnalyser.IsUniform(call.callee) ? 0 : 1))); var biDescriptor = new BinaryBarrierInvariantDescriptor( Verifier.UniformityAnalyser.IsUniform(call.callee) ? Expr.True : call.Ins[0], Expr.Neq(call.Ins[Verifier.UniformityAnalyser.IsUniform(call.callee) ? 0 : 1], Verifier.IntRep.GetZero(Verifier.IntRep.GetIntType(1))), call.Attributes, this, procName, Verifier); for (var i = 1 + (Verifier.UniformityAnalyser.IsUniform(call.callee) ? 0 : 1); i < call.Ins.Count; i += 2) { biDescriptor.AddInstantiationExprPair(call.Ins[i], call.Ins[i + 1]); } barrierInvariantDescriptors.Add(biDescriptor); return; } if (GPUVerifier.IsBarrier(call.Proc)) { // Assert barrier invariants foreach (var biIDescriptor in barrierInvariantDescriptors) { QKeyValue sourceLocationInfo = biIDescriptor.GetSourceLocationInfo(); cs.Add(biIDescriptor.GetAssertCmd()); var vd = new VariableDualiser(1, Verifier, procName); if (GPUVerifyVCGenCommandLineOptions.BarrierAccessChecks) { foreach (Expr accessExpr in biIDescriptor.GetAccessedExprs()) { var assert = new AssertCmd(Token.NoToken, accessExpr, MakeThreadSpecificAttributes(sourceLocationInfo, 1)); assert.Attributes = new QKeyValue( Token.NoToken, "barrier_invariant_access_check", new List <object> { Expr.True }, assert.Attributes); cs.Add(vd.VisitAssertCmd(assert)); } } } } List <Expr> uniformNewIns = new List <Expr>(); List <Expr> nonUniformNewIns = new List <Expr>(); for (int i = 0; i < call.Ins.Count; i++) { if (Verifier.UniformityAnalyser.knowsOf(call.callee) && Verifier.UniformityAnalyser.IsUniform(call.callee, Verifier.UniformityAnalyser.GetInParameter(call.callee, i))) { uniformNewIns.Add(call.Ins[i]); } else if (!Verifier.OnlyThread2.Contains(call.callee)) { nonUniformNewIns.Add(new VariableDualiser(1, Verifier, procName).VisitExpr(call.Ins[i])); } } for (int i = 0; i < call.Ins.Count; i++) { if (!(Verifier.UniformityAnalyser.knowsOf(call.callee) && Verifier.UniformityAnalyser.IsUniform(call.callee, Verifier.UniformityAnalyser.GetInParameter(call.callee, i))) && !Verifier.OnlyThread1.Contains(call.callee)) { nonUniformNewIns.Add(new VariableDualiser(2, Verifier, procName).VisitExpr(call.Ins[i])); } } List <Expr> newIns = uniformNewIns; newIns.AddRange(nonUniformNewIns); List <IdentifierExpr> uniformNewOuts = new List <IdentifierExpr>(); List <IdentifierExpr> nonUniformNewOuts = new List <IdentifierExpr>(); for (int i = 0; i < call.Outs.Count; i++) { if (Verifier.UniformityAnalyser.knowsOf(call.callee) && Verifier.UniformityAnalyser.IsUniform(call.callee, Verifier.UniformityAnalyser.GetOutParameter(call.callee, i))) { uniformNewOuts.Add(call.Outs[i]); } else { nonUniformNewOuts.Add(new VariableDualiser(1, Verifier, procName).VisitIdentifierExpr(call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr); } } for (int i = 0; i < call.Outs.Count; i++) { if (!(Verifier.UniformityAnalyser.knowsOf(call.callee) && Verifier.UniformityAnalyser.IsUniform(call.callee, Verifier.UniformityAnalyser.GetOutParameter(call.callee, i)))) { nonUniformNewOuts.Add(new VariableDualiser(2, Verifier, procName).VisitIdentifierExpr(call.Outs[i].Clone() as IdentifierExpr) as IdentifierExpr); } } List <IdentifierExpr> newOuts = uniformNewOuts; newOuts.AddRange(nonUniformNewOuts); CallCmd newCallCmd = new CallCmd(call.tok, call.callee, newIns, newOuts); newCallCmd.Proc = call.Proc; newCallCmd.Attributes = call.Attributes; if (newCallCmd.callee.StartsWith("_LOG_ATOMIC")) { QKeyValue curr = newCallCmd.Attributes; if (curr.Key.StartsWith("arg")) { newCallCmd.Attributes = new QKeyValue(Token.NoToken, curr.Key, new List <object>(new object[] { Dualise(curr.Params[0] as Expr, 1) }), curr.Next); } for (curr = newCallCmd.Attributes; curr.Next != null; curr = curr.Next) { if (curr.Next.Key.StartsWith("arg")) { curr.Next = new QKeyValue(Token.NoToken, curr.Next.Key, new List <object>(new object[] { Dualise(curr.Next.Params[0] as Expr, 1) }), curr.Next.Next); } } } else if (newCallCmd.callee.StartsWith("_CHECK_ATOMIC")) { QKeyValue curr = newCallCmd.Attributes; if (curr.Key.StartsWith("arg")) { newCallCmd.Attributes = new QKeyValue(Token.NoToken, curr.Key, new List <object>(new object[] { Dualise(curr.Params[0] as Expr, 2) }), curr.Next); } for (curr = newCallCmd.Attributes; curr.Next != null; curr = curr.Next) { if (curr.Next.Key.StartsWith("arg")) { curr.Next = new QKeyValue(Token.NoToken, curr.Next.Key, new List <object>(new object[] { Dualise(curr.Next.Params[0] as Expr, 2) }), curr.Next.Next); } } } cs.Add(newCallCmd); if (GPUVerifier.IsBarrier(call.Proc)) { foreach (var biDescriptor in barrierInvariantDescriptors) { foreach (var instantiation in biDescriptor.GetInstantiationCmds()) { cs.Add(instantiation); } } barrierInvariantDescriptors.Clear(); } } else if (c is AssignCmd) { AssignCmd assign = c as AssignCmd; var vd1 = new VariableDualiser(1, Verifier, procName); var vd2 = new VariableDualiser(2, Verifier, procName); List <AssignLhs> lhss1 = new List <AssignLhs>(); List <AssignLhs> lhss2 = new List <AssignLhs>(); List <Expr> rhss1 = new List <Expr>(); List <Expr> rhss2 = new List <Expr>(); foreach (var pair in assign.Lhss.Zip(assign.Rhss)) { if (pair.Item1 is SimpleAssignLhs && Verifier.UniformityAnalyser.IsUniform( procName, (pair.Item1 as SimpleAssignLhs).AssignedVariable.Name)) { lhss1.Add(pair.Item1); rhss1.Add(pair.Item2); } else { lhss1.Add(vd1.Visit(pair.Item1.Clone() as AssignLhs) as AssignLhs); lhss2.Add(vd2.Visit(pair.Item1.Clone() as AssignLhs) as AssignLhs); rhss1.Add(vd1.VisitExpr(pair.Item2.Clone() as Expr)); rhss2.Add(vd2.VisitExpr(pair.Item2.Clone() as Expr)); } } Debug.Assert(lhss1.Count > 0); cs.Add(new AssignCmd(Token.NoToken, lhss1, rhss1)); if (lhss2.Count > 0) { cs.Add(new AssignCmd(Token.NoToken, lhss2, rhss2)); } } else if (c is HavocCmd) { HavocCmd havoc = c as HavocCmd; Debug.Assert(havoc.Vars.Count() == 1); HavocCmd newHavoc; var idents = new List <IdentifierExpr> { (IdentifierExpr) new VariableDualiser(1, Verifier, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr), (IdentifierExpr) new VariableDualiser(2, Verifier, procName).VisitIdentifierExpr(havoc.Vars[0].Clone() as IdentifierExpr) }; newHavoc = new HavocCmd(havoc.tok, idents); cs.Add(newHavoc); } else if (c is AssertCmd) { AssertCmd a = c as AssertCmd; if (QKeyValue.FindBoolAttribute(a.Attributes, "sourceloc") || QKeyValue.FindBoolAttribute(a.Attributes, "block_sourceloc") || QKeyValue.FindBoolAttribute(a.Attributes, "array_bounds")) { // This is just a location marker, so we do not dualise it cs.Add(new AssertCmd( Token.NoToken, new VariableDualiser(1, Verifier, procName).VisitExpr(a.Expr.Clone() as Expr), (QKeyValue)a.Attributes.Clone())); } else { var isUniform = Verifier.UniformityAnalyser.IsUniform(procName, a.Expr); cs.Add(MakeThreadSpecificAssert(a, 1)); if (!GPUVerifyVCGenCommandLineOptions.AsymmetricAsserts && !ContainsAsymmetricExpression(a.Expr) && !isUniform) { cs.Add(MakeThreadSpecificAssert(a, 2)); } } } else if (c is AssumeCmd) { AssumeCmd ass = c as AssumeCmd; if (QKeyValue.FindStringAttribute(ass.Attributes, "captureState") != null) { cs.Add(c); } else if (QKeyValue.FindBoolAttribute(ass.Attributes, "backedge")) { AssumeCmd newAss = new AssumeCmd( c.tok, Expr.Or( new VariableDualiser(1, Verifier, procName).VisitExpr(ass.Expr.Clone() as Expr), new VariableDualiser(2, Verifier, procName).VisitExpr(ass.Expr.Clone() as Expr))); newAss.Attributes = ass.Attributes; cs.Add(newAss); } else if (QKeyValue.FindBoolAttribute(ass.Attributes, "atomic_refinement")) { // Generate the following: // havoc v$1, v$2; // assume !_USED[offset$1][v$1]; // _USED[offset$1][v$1] := true; // assume !_USED[offset$2][v$2]; // _USED[offset$2][v$2] := true; Expr variable = QKeyValue.FindExprAttribute(ass.Attributes, "variable"); Expr offset = QKeyValue.FindExprAttribute(ass.Attributes, "offset"); List <Expr> offsets = Enumerable.Range(1, 2).Select(x => new VariableDualiser(x, Verifier, procName).VisitExpr(offset.Clone() as Expr)).ToList(); List <Expr> vars = Enumerable.Range(1, 2).Select(x => new VariableDualiser(x, Verifier, procName).VisitExpr(variable.Clone() as Expr)).ToList(); IdentifierExpr arrayRef = new IdentifierExpr(Token.NoToken, Verifier.FindOrCreateUsedMap(QKeyValue.FindStringAttribute(ass.Attributes, "arrayref"), vars[0].Type)); bool isShared = QKeyValue.FindBoolAttribute(arrayRef.Decl.Attributes, "atomic_group_shared"); foreach (int i in Enumerable.Range(0, 2)) { Expr assumeSelect = arrayRef; if (isShared && !GPUVerifyVCGenCommandLineOptions.OnlyIntraGroupRaceChecking) { assumeSelect = new NAryExpr( Token.NoToken, new MapSelect(Token.NoToken, 1), new List <Expr> { assumeSelect, Verifier.GroupSharedIndexingExpr(i + 1) }); } assumeSelect = new NAryExpr( Token.NoToken, new MapSelect(Token.NoToken, 1), new List <Expr> { assumeSelect, offsets[i] }); assumeSelect = new NAryExpr( Token.NoToken, new MapSelect(Token.NoToken, 1), new List <Expr> { assumeSelect, vars[i] }); AssumeCmd newAssume = new AssumeCmd(c.tok, Expr.Not(assumeSelect)); cs.Add(newAssume); AssignLhs lhs = new SimpleAssignLhs(Token.NoToken, arrayRef); if (isShared && !GPUVerifyVCGenCommandLineOptions.OnlyIntraGroupRaceChecking) { lhs = new MapAssignLhs( Token.NoToken, lhs, new List <Expr> { Verifier.GroupSharedIndexingExpr(i + 1) }); } lhs = new MapAssignLhs( Token.NoToken, lhs, new List <Expr> { offsets[i] }); lhs = new MapAssignLhs( Token.NoToken, lhs, new List <Expr> { vars[i] }); AssignCmd assign = new AssignCmd( c.tok, new List <AssignLhs> { lhs }, new List <Expr> { Expr.True }); cs.Add(assign); } } else { var isUniform = Verifier.UniformityAnalyser.IsUniform(procName, ass.Expr); AssumeCmd newAss = new AssumeCmd(c.tok, new VariableDualiser(1, Verifier, procName).VisitExpr(ass.Expr.Clone() as Expr)); if (!ContainsAsymmetricExpression(ass.Expr) && !isUniform) { newAss.Expr = Expr.And(newAss.Expr, new VariableDualiser(2, Verifier, procName).VisitExpr(ass.Expr.Clone() as Expr)); } newAss.Attributes = ass.Attributes; cs.Add(newAss); } } else { Debug.Assert(false); } }
///////////////////////////////////////////////////////////////////////////////////// public bool Visit(VCExprQuantifier node, LineariserOptions options) { Contract.Assert(node.TypeParameters.Count == 0); UnderQuantifier++; Namer.PushScope(); try { string kind = node.Quan == Quantifier.ALL ? "forall" : "exists"; wr.Write("({0} (", kind); for (int i = 0; i < node.BoundVars.Count; i++) { VCExprVar var = node.BoundVars[i]; Contract.Assert(var != null); string printedName = Namer.GetQuotedLocalName(var, var.Name); Contract.Assert(printedName != null); wr.Write("({0} {1}) ", printedName, TypeToString(var.Type)); } wr.Write(") "); VCQuantifierInfos infos = node.Infos; var weight = QKeyValue.FindIntAttribute(infos.attributes, "weight", 1); if (!ProverOptions.UseWeights) { weight = 1; } var hasAttrs = node.Triggers.Count > 0 || infos.qid != null || weight != 1 || infos.uniqueId != -1; if (hasAttrs) { wr.Write("(! "); } Linearise(node.Body, options); if (hasAttrs) { wr.Write("\n"); if (infos.qid != null) { wr.Write(" :qid {0}\n", SMTLibNamer.QuoteId(infos.qid)); } if (weight != 1) { wr.Write(" :weight {0}\n", weight); } if (infos.uniqueId != -1) { wr.Write(" :skolemid |{0}|\n", infos.uniqueId); } WriteTriggers(node.Triggers, options); wr.Write(")"); } wr.Write(")"); return(true); } finally { UnderQuantifier--; Namer.PopScope(); } }
///////////////////////////////////////////////////////////////////////////////////// public bool Visit(VCExprQuantifier node, LineariserOptions options) { //Contract.Requires(options != null); //Contract.Requires(node != null); AssertAsFormula(node.Quan.ToString(), options); Contract.Assert(node.TypeParameters.Count == 0); Namer.PushScope(); try { string kind = node.Quan == Quantifier.ALL ? "FORALL" : "EXISTS"; wr.Write("({0} (", kind); for (int i = 0; i < node.BoundVars.Count; i++) { VCExprVar var = node.BoundVars[i]; Contract.Assert(var != null); string printedName = Namer.GetLocalName(var, var.Name); Contract.Assert(printedName != null); if (i != 0) { wr.Write(" "); } WriteId(printedName); if (options.UseTypes) { wr.Write(" :TYPE {0}", TypeToString(var.Type)); } } wr.Write(") "); WriteTriggers(node.Triggers, options); if (options.QuantifierIds) { // only needed for Z3 VCQuantifierInfos infos = node.Infos; Contract.Assert(infos != null); if (infos.qid != null) { wr.Write("(QID "); wr.Write(infos.qid); wr.Write(") "); } if (0 <= infos.uniqueId) { wr.Write("(SKOLEMID "); wr.Write(infos.uniqueId); wr.Write(") "); } } if (options.UseWeights) { int weight = QKeyValue.FindIntAttribute(node.Infos.attributes, "weight", 1); if (weight != 1) { wr.Write("(WEIGHT "); wr.Write(weight); wr.Write(") "); } } Linearise(node.Body, options); wr.Write(")"); return(true); } finally { Namer.PopScope(); } }
static void Main(string[] args) { if (args.Length != 1) { Console.WriteLine("Usage: SplitRMT.exe file.bpl"); return; } // Initialize CommandLineOptions.Install(new CommandLineOptions()); CommandLineOptions.Clo.PrintInstrumented = true; var program = BoogieUtil.ReadAndResolve(args[0]); // check input foreach (var proc in program.TopLevelDeclarations.OfType <Procedure>()) { if (proc.Requires.Any(req => !req.Free)) { Console.WriteLine("Error: non-free requires not yet supported"); return; } } var eplist = program.TopLevelDeclarations.OfType <Implementation>() .Where(impl => QKeyValue.FindBoolAttribute(impl.Attributes, "entrypoint") || QKeyValue.FindBoolAttribute(impl.Proc.Attributes, "entrypoint")); if (eplist.Count() != 1) { Console.WriteLine("Error: Unique entrypoint not found"); return; } var main = eplist.First(); Console.WriteLine("Entrypoint: {0}", main.Name); // entrypoint + all assumes MarkAllAssumes(program, args[0]); // split on asserted postconditions var cnt = Split(program, args[0]); Console.WriteLine("Produced {0} file(s) after splitting", cnt); }