/// <summary> /// Constructs a reproducable trace. /// </summary> /// <param name="runtime">BugFindingRuntime</param> /// <param name="logger">InMemoryLogger</param> private void ConstructReproducableTrace(BugFindingRuntime runtime, InMemoryLogger logger) { this.ReadableTrace = logger.ToString(); this.ReadableTrace += this.TestReport.GetText(base.Configuration, "<StrategyLog>"); this.BugTrace = runtime.BugTrace; StringBuilder stringBuilder = new StringBuilder(); if (this.Strategy.IsFair()) { stringBuilder.Append("--fair-scheduling").Append(Environment.NewLine); } if (base.Configuration.CacheProgramState) { stringBuilder.Append("--state-caching").Append(Environment.NewLine); stringBuilder.Append("--liveness-temperature-threshold:" + base.Configuration.LivenessTemperatureThreshold). Append(Environment.NewLine); } else { stringBuilder.Append("--liveness-temperature-threshold:" + base.Configuration.LivenessTemperatureThreshold). Append(Environment.NewLine); } if (!base.Configuration.TestMethodName.Equals("")) { stringBuilder.Append("--test-method:" + base.Configuration.TestMethodName). Append(Environment.NewLine); } for (int idx = 0; idx < runtime.ScheduleTrace.Count; idx++) { ScheduleStep step = runtime.ScheduleTrace[idx]; if (step.Type == ScheduleStepType.SchedulingChoice) { stringBuilder.Append($"{step.ScheduledMachineId.Type}" + $"({step.ScheduledMachineId.Value})"); } else if (step.BooleanChoice != null) { stringBuilder.Append(step.BooleanChoice.Value); } else { stringBuilder.Append(step.IntegerChoice.Value); } if (idx < runtime.ScheduleTrace.Count - 1) { stringBuilder.Append(Environment.NewLine); } } this.ReproducableTrace = stringBuilder.ToString(); }
private void MenuItem_Open_Trace_Click(object sender, RoutedEventArgs e) { this.BugTrace = IO.LoadTrace(); if (this.BugTrace != null) { this.ObservableBugTrace = this.GetObservableTrace(); this.BugTraceView.ItemsSource = this.ObservableBugTrace; this.BugTraceView.Items.Refresh(); } }
/// <summary> /// Returns the specified trace. /// </summary> /// <returns>MachineActionTrace</returns> internal static BugTrace LoadTrace() { OpenFileDialog openFileDialog = new OpenFileDialog(); // Sets filter for file extension and default file extension. openFileDialog.DefaultExt = ".pstrace"; openFileDialog.Filter = "P# Trace Files|*.pstrace"; // Displays OpenFileDialog by calling the ShowDialog method. bool?result = openFileDialog.ShowDialog(); BugTrace trace = null; if (result == true) { string fileName = openFileDialog.FileName; if (fileName != null) { using (Stream stream = File.Open(fileName, FileMode.Open)) { DataContractSerializer serializer = new DataContractSerializer(typeof(BugTrace)); try { trace = (BugTrace)serializer.ReadObject(stream); } catch { MessageBox.Show($"Bug trace '{fileName}' is not readable." + "Please make sure you selected a '.pstrace' file."); } } } } return(trace); }
/// <summary> /// Runs the next testing iteration. /// </summary> /// <param name="iteration">Iteration</param> private void RunNextIteration(int iteration) { if (this.ShouldPrintIteration(iteration + 1)) { base.Logger.WriteLine($"..... Iteration #{iteration + 1}"); } // Runtime used to serialize and test the program in this iteration. BugFindingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { // Creates a new instance of the bug-finding runtime. runtime = new BugFindingRuntime(base.Configuration, base.Strategy, base.Reporter); if (base.Configuration.EnableDataRaceDetection) { // Create a reporter to monitor interesting operations for race detection this.Reporter.SetRuntime(runtime); } // If verbosity is turned off, then intercept the program log, and also dispose // the standard output and error streams. if (base.Configuration.Verbose < 2) { runtimeLogger = new InMemoryLogger(); runtime.SetLogger(runtimeLogger); // Sets the scheduling strategy logger to the in-memory logger. base.SchedulingStrategyLogger.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the P# test-harness machine. runtime.RunTestHarness(base.TestMethod, base.TestAction); // Wait for the test to terminate. runtime.Wait(); if (runtime.Scheduler.BugFound) { base.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, null); } // Invoke the per iteration callbacks, if any. foreach (var callback in base.PerIterationCallbacks) { callback(iteration); } if (base.Configuration.RaceFound) { string message = IO.Utilities.Format("Found a race"); runtime.Scheduler.NotifyAssertionFailure(message, false); foreach (var report in this.TestReport.BugReports) { runtime.Logger.WriteLine(report); } } // Checks that no monitor is in a hot state at termination. Only // checked if no safety property violations have been found. if (!runtime.Scheduler.BugFound) { runtime.AssertNoMonitorInHotStateAtTermination(); } this.GatherIterationStatistics(runtime); if (base.TestReport.NumOfFoundBugs > 0) { if (runtimeLogger != null) { this.ReadableTrace = runtimeLogger.ToString(); this.ReadableTrace += this.TestReport.GetText(base.Configuration, "<StrategyLog>"); } this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } } finally { if (base.Configuration.Verbose < 2) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } if (base.Configuration.PerformFullExploration && runtime.Scheduler.BugFound) { base.Logger.WriteLine($"..... Iteration #{iteration + 1} " + $"triggered bug #{base.TestReport.NumOfFoundBugs} " + $"[task-{this.Configuration.TestingProcessId}]"); } // Resets the scheduling strategy logger to the default logger. base.SchedulingStrategyLogger.ResetToDefaultLogger(); // Cleans up the runtime before the next iteration starts. runtimeLogger?.Dispose(); runtime?.Dispose(); } }
/// <summary> /// Runs the next testing iteration. /// </summary> private void RunNextIteration(int iteration) { if (this.ShouldPrintIteration(iteration + 1)) { this.Logger.WriteLine($"..... Iteration #{iteration + 1}"); // Flush when logging to console. if (this.Logger is ConsoleLogger) { Console.Out.Flush(); } } // Runtime used to serialize and test the program in this iteration. SystematicTestingRuntime runtime = null; // Logger used to intercept the program output if no custom logger // is installed and if verbosity is turned off. InMemoryLogger runtimeLogger = null; // Gets a handle to the standard output and error streams. var stdOut = Console.Out; var stdErr = Console.Error; try { // Creates a new instance of the bug-finding runtime. if (this.TestRuntimeFactoryMethod != null) { runtime = (SystematicTestingRuntime)this.TestRuntimeFactoryMethod.Invoke( null, new object[] { this.Configuration, this.Strategy, this.Reporter }); } else { runtime = new SystematicTestingRuntime(this.Configuration, this.Strategy, this.Reporter); } if (this.Configuration.EnableDataRaceDetection) { this.Reporter.RegisterRuntime(runtime); } // If verbosity is turned off, then intercept the program log, and also dispose // the standard output and error streams. if (!this.Configuration.IsVerbose) { runtimeLogger = new InMemoryLogger(true); runtime.SetLogger(runtimeLogger); var writer = new LogWriter(new DisposingLogger()); Console.SetOut(writer); Console.SetError(writer); } // Runs the test inside the test-harness machine. if (this.TestAction != null) { runtime.RunTestHarness(this.TestAction, this.TestName); } else { runtime.RunTestHarness(this.TestFunction, this.TestName); } // Wait for the test to terminate. runtime.WaitAsync().Wait(); // Invokes user-provided cleanup for this iteration. if (this.TestIterationDisposeMethod != null) { // Disposes the test state. this.TestIterationDisposeMethod.Invoke(null, null); } // Invoke the per iteration callbacks, if any. foreach (var callback in this.PerIterationCallbacks) { callback(iteration); } if (this.Configuration.RaceFound) { runtime.Scheduler.NotifyAssertionFailure("Found a race", killTasks: false, cancelExecution: false); foreach (var report in this.TestReport.BugReports) { runtime.Logger.WriteLine(report); } } // Checks that no monitor is in a hot state at termination. Only // checked if no safety property violations have been found. if (!runtime.Scheduler.BugFound) { runtime.CheckNoMonitorInHotStateAtTermination(); } if (runtime.Scheduler.BugFound) { this.ErrorReporter.WriteErrorLine(runtime.Scheduler.BugReport); } this.GatherIterationStatistics(runtime); if (this.TestReport.NumOfFoundBugs > 0) { if (runtimeLogger != null) { this.ReadableTrace = runtimeLogger.ToString(); this.ReadableTrace += this.TestReport.GetText(this.Configuration, "<StrategyLog>"); } this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } } finally { if (!this.Configuration.IsVerbose) { // Restores the standard output and error streams. Console.SetOut(stdOut); Console.SetError(stdErr); } if (this.Configuration.PerformFullExploration && runtime.Scheduler.BugFound) { this.Logger.WriteLine($"..... Iteration #{iteration + 1} " + $"triggered bug #{this.TestReport.NumOfFoundBugs} " + $"[task-{this.Configuration.TestingProcessId}]"); } // Cleans up the runtime before the next iteration starts. runtimeLogger?.Dispose(); runtime?.Dispose(); } }
/// <summary> /// Creates a new bug-finding task. /// </summary> /// <returns>Task</returns> private Task CreateBugFindingTask() { if (base.Configuration.TestingProcessId >= 0) { IO.Error.PrintLine($"... Task {this.Configuration.TestingProcessId} is " + $"using '{base.Configuration.SchedulingStrategy}' strategy."); } else { IO.PrintLine($"... Using '{base.Configuration.SchedulingStrategy}' strategy."); } Task task = new Task(() => { try { if (base.TestInitMethod != null) { // Initializes the test state. base.TestInitMethod.Invoke(null, new object[] { }); } } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } int maxIterations = base.Configuration.SchedulingIterations; for (int i = 0; i < maxIterations; i++) { if (this.CancellationTokenSource.IsCancellationRequested) { break; } if (this.ShouldPrintIteration(i + 1)) { IO.PrintLine($"..... Iteration #{i + 1}"); } var runtime = new PSharpBugFindingRuntime(base.Configuration, base.Strategy, base.TestReport.CoverageInfo); StringWriter sw = null; if (base.Configuration.RedirectTestConsoleOutput && base.Configuration.Verbose < 2) { sw = base.RedirectConsoleOutput(); base.HasRedirectedConsoleOutput = true; } // Starts the test. if (base.TestAction != null) { base.TestAction(runtime); } else { try { base.TestMethod.Invoke(null, new object[] { runtime }); } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } } // Wait for the test to terminate. runtime.Wait(); if (this.Configuration.EnableDataRaceDetection) { this.EmitRaceInstrumentationTraces(runtime, i); } try { // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, null); } } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } // Invoke the per iteration callbacks, if any. foreach (var callback in base.PerIterationCallbacks) { callback(i); } // Cleans up the runtime before the next // iteration starts. this.CleanUpRuntime(); // Checks for any liveness property violations. Requires // that the program has terminated and no safety property // violations have been found. if (!runtime.BugFinder.BugFound) { runtime.LivenessChecker.CheckLivenessAtTermination(); } if (base.HasRedirectedConsoleOutput) { base.ResetOutput(); } this.GatherIterationStatistics(runtime); if (runtime.BugFinder.BugFound) { base.TestReport.NumOfFoundBugs++; base.TestReport.BugReport = runtime.BugFinder.BugReport; if (base.Configuration.PerformFullExploration) { IO.PrintLine($"..... Iteration #{i + 1} triggered " + $"bug #{base.TestReport.NumOfFoundBugs}"); } } else { base.TestReport.BugReport = ""; } if (base.Strategy.HasFinished()) { break; } base.Strategy.ConfigureNextIteration(); if (!base.Configuration.PerformFullExploration && base.TestReport.NumOfFoundBugs > 0) { if (sw != null && !base.Configuration.SuppressTrace) { this.ReadableTrace = sw.ToString(); this.ReadableTrace += this.CreateReport("<StrategyLog>"); this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } break; } else if (sw != null && base.Configuration.PrintTrace) { this.ReadableTrace = sw.ToString(); this.ReadableTrace += this.CreateReport("<StrategyLog>"); this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } // Increases iterations if there is a specified timeout // and the default iteration given. if (base.Configuration.SchedulingIterations == 1 && base.Configuration.Timeout > 0) { maxIterations++; } runtime.Dispose(); } try { if (base.TestDisposeMethod != null) { // Disposes the test state. base.TestDisposeMethod.Invoke(null, new object[] { }); } } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } }, base.CancellationTokenSource.Token); return(task); }
/// <summary> /// Creates a new bug-finding task. /// </summary> /// <returns>Task</returns> private Task CreateBugFindingTask() { if (base.Configuration.TestingProcessId >= 0) { IO.Error.PrintLine($"... Task {this.Configuration.TestingProcessId} is " + $"using '{base.Configuration.SchedulingStrategy}' strategy."); } else { IO.PrintLine($"... Using '{base.Configuration.SchedulingStrategy}' strategy."); } Task task = new Task(() => { try { if (base.TestInitMethod != null) { // Initializes the test state. base.TestInitMethod.Invoke(null, new object[] { }); } } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } int maxIterations = base.Configuration.SchedulingIterations; for (int i = 0; i < maxIterations; i++) { if (this.CancellationTokenSource.IsCancellationRequested) { break; } if (this.ShouldPrintIteration(i + 1)) { IO.PrintLine($"..... Iteration #{i + 1}"); } var runtime = new PSharpBugFindingRuntime(base.Configuration, base.Strategy, base.Visualizer); StringWriter sw = null; if (base.Configuration.RedirectTestConsoleOutput && base.Configuration.Verbose < 2) { sw = base.RedirectConsoleOutput(); base.HasRedirectedConsoleOutput = true; } // Starts the test. if (base.TestAction != null) { base.TestAction(runtime); } else { try { base.TestMethod.Invoke(null, new object[] { runtime }); } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } } // Wait for test to terminate. runtime.Wait(); if (base.Configuration.EnableVisualization) { base.Visualizer.Refresh(); } if (this.Configuration.EnableDataRaceDetection) { this.EmitRaceInstrumentationTraces(runtime, i); } try { // Invokes user-provided cleanup for this iteration. if (base.TestIterationDisposeMethod != null) { // Disposes the test state. base.TestIterationDisposeMethod.Invoke(null, null); } } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } // Invoke the per iteration callbacks, if any. foreach (var callback in base.PerIterationCallbacks) { callback(i); } // Cleans up the runtime before the next // iteration starts. this.CleanUpRuntime(); // Checks for any liveness property violations. Requires // that the program has terminated and no safety property // violations have been found. if (!runtime.BugFinder.BugFound) { runtime.LivenessChecker.CheckLivenessAtTermination(); } if (base.HasRedirectedConsoleOutput) { base.ResetOutput(); } this.ExploredSchedules++; base.ExploredDepth = runtime.BugFinder.ExploredSteps; if (base.Strategy.HasReachedMaxSchedulingSteps()) { this.MaxStepsHit++; } if (runtime.BugFinder.BugFound) { base.NumOfFoundBugs++; base.BugReport = runtime.BugFinder.BugReport; if (base.Configuration.PerformFullExploration) { IO.PrintLine($"..... Iteration #{i + 1} triggered " + $"bug #{base.NumOfFoundBugs}"); } } else { base.BugReport = ""; } if (base.Strategy.HasFinished()) { break; } base.Strategy.ConfigureNextIteration(); if (!base.Configuration.PerformFullExploration && base.NumOfFoundBugs > 0) { if (sw != null && !base.Configuration.SuppressTrace) { this.ReadableTrace = sw.ToString(); this.ReadableTrace += this.CreateReport("<StrategyLog>"); this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } break; } else if (sw != null && base.Configuration.PrintTrace) { this.ReadableTrace = sw.ToString(); this.ReadableTrace += this.CreateReport("<StrategyLog>"); this.BugTrace = runtime.BugTrace; this.ConstructReproducableTrace(runtime); } // Increases iterations if there is a specified timeout // and the default iteration given. if (base.Configuration.SchedulingIterations == 1 && base.Configuration.Timeout > 0) { maxIterations++; } runtime.Dispose(); } try { if (base.TestDisposeMethod != null) { // Disposes the test state. base.TestDisposeMethod.Invoke(null, new object[] { }); } } catch (TargetInvocationException ex) { if (!(ex.InnerException is TaskCanceledException)) { ExceptionDispatchInfo.Capture(ex.InnerException).Throw(); } } }, base.CancellationTokenSource.Token); return task; }