public static Transform.PassManager GetPassManager(CmdLineOpts options) { // Supply our own PassManager for preparation so we can hook into its events var PM = new Transform.PassManager(); if (options.RemoveTrivialAssumes) { PM.Add(new Transform.TrivialAssumeElimination()); } // Use anonymous methods so we can use closure to read command line options Transform.PassManager.PassRunEvent beforePassHandler = delegate(Object passManager, Transform.PassManager.PassManagerEventArgs eventArgs) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Running pass " + eventArgs.ThePass.GetName()); Console.ResetColor(); if (options.emitProgramBefore) { Console.WriteLine("**** Program before pass:"******"**** END Program before pass"); } }; Transform.PassManager.PassRunEvent afterPassHandler = delegate(Object passManager, Transform.PassManager.PassManagerEventArgs eventArgs) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Finished running pass " + eventArgs.ThePass.GetName()); Console.ResetColor(); if (options.emitProgramAfter) { Console.WriteLine("**** Program after pass:"******"**** END Program after pass:"); } }; PM.BeforePassRun += beforePassHandler; PM.AfterPassRun += afterPassHandler; return(PM); }
public Symbooglix.Transform.IPass GetPass(string name, CmdLineOpts cmdLine) { // Passes without default constructors if (name == StripSymbooglixPrefix(typeof(Transform.AxiomAndEntryRequiresCheckTransformPass).ToString())) { // This pass needs to know the entry points if (cmdLine.EntryPoints == null) { Console.Error.WriteLine("Entry points must be specified to use AxiomAndEntryRequiresCheckTransformPass"); ExitWith(ExitCode.COMMAND_LINE_ERROR); } Predicate <Implementation> isEntryPoint = delegate(Implementation impl) { foreach (var entryPointName in cmdLine.EntryPoints) { if (impl.Name == entryPointName) { return(true); } } return(false); }; return(new Transform.AxiomAndEntryRequiresCheckTransformPass(isEntryPoint)); } // Passes with default constructors try { var passType = Map[name]; return((Symbooglix.Transform.IPass)Activator.CreateInstance(passType)); } catch (KeyNotFoundException) { throw new NonExistantPassException(); } }
public static IStateScheduler GetScheduler(CmdLineOpts options) { IStateScheduler scheduler = null; switch (options.scheduler) { case CmdLineOpts.Scheduler.DFS: scheduler = new DFSStateScheduler(); break; case CmdLineOpts.Scheduler.BFS: scheduler = new BFSStateScheduler(); break; case CmdLineOpts.Scheduler.UntilEndBFS: scheduler = new UntilTerminationBFSStateScheduler(); break; case CmdLineOpts.Scheduler.AltBFS: scheduler = new AlternativeBFSStateScheduler(); break; default: throw new ArgumentException("Unsupported scheduler"); } if (options.PreferLoopEscapingPaths > 0) { scheduler = new LoopEscapingScheduler(scheduler); } if (options.MaxLoopDepth > 0) { scheduler = new LimitLoopBoundScheduler(scheduler, options.MaxLoopDepth); } return(scheduler); }
public static void ApplyFilters(Executor executor, CmdLineOpts options) { if (!options.GPUverifyIgnoreInvariants) { return; } Console.ForegroundColor = ConsoleColor.DarkMagenta; Console.Error.WriteLine("WARNING: GPUVerify invariants will be ignored!"); Console.ResetColor(); executor.AssertFilter = (AssertCmd c) => { if (QKeyValue.FindBoolAttribute(c.Attributes, "originated_from_invariant")) { Console.ForegroundColor = ConsoleColor.DarkMagenta; Console.Error.WriteLine("WARNING: Ignoring invariant {0}", c.ToString()); Console.ResetColor(); return(false); } return(true); }; }
public static int Main(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.Error.WriteLine("Failed to parse args"); ExitWith(ExitCode.COMMAND_LINE_ERROR); } if (options.boogieProgramPath == null) { Console.Error.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); } // Load Boogie program Program program = null; int errors = Microsoft.Boogie.Parser.Parse(options.boogieProgramPath, /*defines=*/ new List <string>(), 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); } // Start building passes var PM = new Symbooglix.Transform.PassManager(); if (options.PassNames == null) { Console.Error.WriteLine("At least one pass must be specified"); ExitWith(ExitCode.COMMAND_LINE_ERROR); } // Add the requested passes to the PassManager foreach (var passName in options.PassNames) { try { var newPass = PBuilder.GetPass(passName, options); PM.Add(newPass); } catch (NonExistantPassException) { Console.Error.WriteLine("Pass {0} does not exist", passName); } } PM.BeforePassRun += delegate(Object passManager, Transform.PassManager.PassManagerEventArgs eventArgs) { Console.ForegroundColor = ConsoleColor.Red; Console.Error.WriteLine("Running pass " + eventArgs.ThePass.GetName()); Console.ResetColor(); if (options.EmitProgramBefore) { Console.Error.WriteLine("**** Program before pass:"******"**** END Program before pass"); } }; PM.AfterPassRun += delegate(Object passManager, Transform.PassManager.PassManagerEventArgs eventArgs) { Console.ForegroundColor = ConsoleColor.Green; Console.Error.WriteLine("Finished running pass " + eventArgs.ThePass.GetName()); Console.ResetColor(); if (options.EmitProgramAfter) { Console.Error.WriteLine("**** Program after pass:"******"**** END Program after pass:"******"Writing output to stdout"); Symbooglix.Util.ProgramPrinter.Print(program, Console.Out, /*pretty=*/ true, Symbooglix.Util.ProgramPrinter.PrintType.UNSTRUCTURED_ONLY); } else { // Write to file Console.Error.WriteLine("Writing output to {0}", options.OutputPath); using (var TW = new StreamWriter(options.OutputPath)) { Symbooglix.Util.ProgramPrinter.Print(program, TW, /*pretty=*/ true, Symbooglix.Util.ProgramPrinter.PrintType.UNSTRUCTURED_ONLY); } } return((int)ExitCode.SUCCESS); }
public static void SetupFileLoggers(CmdLineOpts options, Executor executor, Solver.ISolver solver) { ExecutorFileLoggerHandler executorLogger = null; if (options.outputDir.Length == 0) { executorLogger = new ExecutorFileLoggerHandler(executor, Directory.GetCurrentDirectory(), /*makeDirectoryInPath=*/ true); } else { executorLogger = new ExecutorFileLoggerHandler(executor, options.outputDir, /*makeDirectoryInPath=*/ false); } // Add our loggers executorLogger.AddRootDirLogger(new CallGrindFileLogger()); //executorLogger.AddRootDirLogger(new MemoryUsageLogger()); // FIXME: Disable for experiments it is buggy executorLogger.AddRootDirLogger(new TerminationCounterLogger(TerminationCounter.CountType.ONLY_NON_SPECULATIVE)); executorLogger.AddRootDirLogger(new TerminationCounterLogger(TerminationCounter.CountType.ONLY_SPECULATIVE)); //executorLogger.AddRootDirLogger(new ExecutionTreeLogger(true)); executorLogger.AddRootDirLogger(new ExecutorInfoLogger()); Predicate <ExecutionState> statesToIgnoreFilter = delegate(ExecutionState state) { if (options.SkipLogTerminatedWithSuccess) { if (state.TerminationType is TerminatedWithoutError) { return(true); // Ignore } } if (options.SkipLogTerminatedWithUnsatAssume) { if (state.TerminationType is TerminatedAtUnsatisfiableAssume) { return(true); // Ignore } } return(false); }; bool concurrentLogging = options.ConcurrentLogging > 0; if (options.WriteConstraints > 0) { executorLogger.AddTerminatedStateDirLogger(new ExecutionStateConstraintLogger(ExecutionStateLogger.ExecutorEventType.TERMINATED_STATE, statesToIgnoreFilter, concurrentLogging)); executorLogger.AddTerminatedStateDirLogger(new ExecutionStateUnSatCoreLogger(ExecutionStateLogger.ExecutorEventType.TERMINATED_STATE, statesToIgnoreFilter, concurrentLogging)); executorLogger.AddNonTerminatedStateDirLogger(new ExecutionStateConstraintLogger(ExecutionStateLogger.ExecutorEventType.NON_TERMINATED_STATE_REMOVED, statesToIgnoreFilter, concurrentLogging)); } bool showConstraints = options.ExecutionStateInfoShowConstraints > 0; bool showVariables = options.ExecutionStateInfoShowVariables > 0; if (options.LogTerminatedStateInfo > 0) { executorLogger.AddTerminatedStateDirLogger(new ExecutionStateInfoLogger(ExecutionStateLogger.ExecutorEventType.TERMINATED_STATE, showConstraints, showVariables, statesToIgnoreFilter, concurrentLogging)); } if (options.LogNonTerminatedStateInfo > 0) { executorLogger.AddNonTerminatedStateDirLogger(new ExecutionStateInfoLogger(ExecutionStateLogger.ExecutorEventType.NON_TERMINATED_STATE_REMOVED, showConstraints, showVariables, statesToIgnoreFilter, concurrentLogging)); } executorLogger.Connect(); Console.WriteLine("Logging to directory: " + executorLogger.RootDir.FullName); }
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 Solver.ISolver BuildSolverChain(CmdLineOpts options) { Solver.ISolverImpl solverImpl = null; // Try to guess the location of executable. This is just for convenience if (options.pathToSolver.Length == 0 && options.solver != CmdLineOpts.Solver.DUMMY) { Console.WriteLine("Path to SMT solver not specified. Guessing location"); // Look in the directory of the currently running executable for other solvers var pathToSolver = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), options.solver.ToString().ToLower()); if (File.Exists(pathToSolver)) { Console.WriteLine("Found \"{0}\"", pathToSolver); options.pathToSolver = pathToSolver; } else { // Try with ".exe" appended pathToSolver = pathToSolver + ".exe"; if (File.Exists(pathToSolver)) { Console.WriteLine("Found \"{0}\"", pathToSolver); options.pathToSolver = pathToSolver; } else { Console.Error.WriteLine("Could not find \"{0}\" (also without .exe)", pathToSolver); ExitWith(ExitCode.SOLVER_NOT_FOUND); } } } // HACK: THIS IS GROSS! REMOVE THIS ASAP AND FIND A CLEAN WAY OF DOING THIS!!!!!!!!!!!! var logicToUse = options.ForceQFAUFBV ? SMTLIBQueryPrinter.Logic.QF_AUFBV : SMTLIBQueryPrinter.Logic.DO_NOT_SET; switch (options.solver) { case CmdLineOpts.Solver.CVC4: solverImpl = new Solver.CVC4SMTLIBSolver(options.UseNamedAttributes > 0, options.pathToSolver, options.PersistentSolver > 0, options.emitTriggers > 0, logicToUse); break; case CmdLineOpts.Solver.Z3: solverImpl = new Solver.Z3SMTLIBSolver(options.UseNamedAttributes > 0, options.pathToSolver, options.PersistentSolver > 0, options.emitTriggers > 0, logicToUse); break; case CmdLineOpts.Solver.DUMMY: solverImpl = new Solver.DummySolver(Symbooglix.Solver.Result.UNKNOWN); break; default: throw new NotSupportedException("Unhandled solver type"); } if (options.queryLogPath.Length > 0) { // FIXME: How are we going to ensure this file gets closed properly? StreamWriter QueryLogFile = new StreamWriter(options.queryLogPath, /*append=*/ options.appendLoggedQueries > 0); solverImpl = new Solver.SMTLIBQueryLoggingSolverImpl(solverImpl, QueryLogFile, /*useNamedAttributeBindings=*/ true, options.humanReadable > 0); } if (options.CachingSolver >= 0) { solverImpl = new Solver.SimpleSolverCache(solverImpl, options.CachingSolver); } if (options.ConstraintIndepenceSolver > 0) { solverImpl = new Solver.ConstraintIndependenceSolver(solverImpl); } // Only support this for now. Solver.ISolver solver = new Solver.SimpleSolver(solverImpl); solver.SetTimeout(options.solverTimeout); return(solver); }