No public description

PiperOrigin-RevId: 568640977
diff --git a/fuzztest/BUILD b/fuzztest/BUILD
index f53398a..55d1730 100644
--- a/fuzztest/BUILD
+++ b/fuzztest/BUILD
@@ -24,6 +24,7 @@
 
 cc_library(
     name = "fuzztest",
+    testonly = True,
     srcs = ["fuzztest.cc"],
     hdrs = ["fuzztest.h"],
     deps = [
@@ -52,6 +53,8 @@
     hdrs = ["init_fuzztest.h"],
     deps = [
         ":googletest_adaptor",
+        ":io",
+        ":logging",
         ":registry",
         ":runtime",
         "@com_google_absl//absl/flags:flag",
@@ -97,6 +100,7 @@
 
 cc_library(
     name = "centipede_adaptor",
+    testonly = True,
     srcs = ["internal/centipede_adaptor.cc"],
     hdrs = ["internal/centipede_adaptor.h"],
     deps = [
@@ -111,6 +115,7 @@
 
 cc_library(
     name = "compatibility_mode",
+    testonly = True,
     srcs = ["internal/compatibility_mode.cc"],
     hdrs = ["internal/compatibility_mode.h"],
     deps = [
@@ -264,6 +269,8 @@
     deps = [
         ":registry",
         ":runtime",
+        "@com_google_absl//absl/functional:function_ref",
+        "@com_google_absl//absl/strings",
         "@com_google_googletest//:gtest",
     ],
 )
@@ -338,12 +345,14 @@
         ":type_support",
         "@com_google_absl//absl/functional:any_invocable",
         "@com_google_absl//absl/strings:str_format",
+        "@com_google_absl//absl/strings:string_view",
         "@com_google_absl//absl/types:span",
     ],
 )
 
 cc_library(
     name = "registry",
+    testonly = True,
     srcs = ["internal/registry.cc"],
     hdrs = ["internal/registry.h"],
     deps = [
diff --git a/fuzztest/init_fuzztest.cc b/fuzztest/init_fuzztest.cc
index 9d05df0..1797780 100644
--- a/fuzztest/init_fuzztest.cc
+++ b/fuzztest/init_fuzztest.cc
@@ -10,10 +10,13 @@
 #include "gtest/gtest.h"
 #include "absl/flags/flag.h"
 #include "absl/strings/match.h"
+#include "absl/strings/str_cat.h"
 #include "absl/strings/str_format.h"
 #include "absl/strings/string_view.h"
 #include "absl/time/time.h"
 #include "./fuzztest/internal/googletest_adaptor.h"
+#include "./fuzztest/internal/io.h"
+#include "./fuzztest/internal/logging.h"
 #include "./fuzztest/internal/registry.h"
 #include "./fuzztest/internal/runtime.h"
 
@@ -124,6 +127,16 @@
     std::exit(0);
   }
 
+  FUZZTEST_INTERNAL_CHECK(
+      internal::Runtime::instance().files_to_replay().empty(),
+      "You cannot manually set corpus files");
+  std::vector<std::string> corpus_files =
+      internal::GetFileOrFilesInDir(absl::StrCat(
+          "security/laser/sundew/blaze/corpora/", *argv[0], "/minimized"));
+  if (!corpus_files.empty()) {
+    internal::Runtime::instance().SetFilesToReplay(corpus_files);
+  }
+
   const auto test_to_fuzz = absl::GetFlag(FUZZTEST_FLAG(fuzz));
   const bool is_test_to_fuzz_specified = test_to_fuzz != kUnspecified;
   if (is_test_to_fuzz_specified) {
@@ -140,7 +153,12 @@
     internal::Runtime::instance().SetFuzzTimeLimit(duration);
   }
 
-  internal::RegisterFuzzTestsAsGoogleTests(argc, argv);
+  std::vector<std::string> crashing_files;
+#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
+  crashing_files = internal::GetFileOrFilesInDir(absl::StrCat(
+      "security/laser/sundew/blaze/corpora/", *argv[0], "/crashing_inputs"));
+#endif
+  internal::RegisterFuzzTestsAsGoogleTests(argc, argv, crashing_files);
 
   const RunMode run_mode = is_test_to_fuzz_specified || is_duration_specified
                                ? RunMode::kFuzz
diff --git a/fuzztest/internal/centipede_adaptor.cc b/fuzztest/internal/centipede_adaptor.cc
index be8fd66..16a5e6f 100644
--- a/fuzztest/internal/centipede_adaptor.cc
+++ b/fuzztest/internal/centipede_adaptor.cc
@@ -19,6 +19,7 @@
 #include <cstring>
 #include <functional>
 #include <memory>
+#include <optional>
 #include <random>
 #include <string>
 #include <thread>
@@ -26,6 +27,7 @@
 #include <vector>
 
 #include "absl/algorithm/container.h"
+#include "absl/strings/string_view.h"
 #include "./centipede/runner_interface.h"
 #include "./fuzztest/internal/domains/domain_base.h"
 #include "./fuzztest/internal/logging.h"
@@ -154,9 +156,10 @@
     const FuzzTest& test, std::unique_ptr<UntypedFixtureDriver> fixture_driver)
     : test_(test), fuzzer_impl_(test_, std::move(fixture_driver)) {}
 
-void CentipedeFuzzerAdaptor::RunInUnitTestMode() {
+void CentipedeFuzzerAdaptor::RunInUnitTestMode(
+    std::optional<absl::string_view> input) {
   // Run the unit test mode directly without using Centipede.
-  fuzzer_impl_.RunInUnitTestMode();
+  fuzzer_impl_.RunInUnitTestMode(input);
 }
 
 int CentipedeFuzzerAdaptor::RunInFuzzingMode(int* argc, char*** argv) {
diff --git a/fuzztest/internal/centipede_adaptor.h b/fuzztest/internal/centipede_adaptor.h
index 4ce3033..e0d256f 100644
--- a/fuzztest/internal/centipede_adaptor.h
+++ b/fuzztest/internal/centipede_adaptor.h
@@ -27,7 +27,7 @@
  public:
   CentipedeFuzzerAdaptor(const FuzzTest& test,
                          std::unique_ptr<UntypedFixtureDriver> fixture_driver);
-  void RunInUnitTestMode() override;
+  void RunInUnitTestMode(std::optional<absl::string_view> input) override;
   int RunInFuzzingMode(int* argc, char*** argv) override;
 
  private:
diff --git a/fuzztest/internal/fixture_driver.h b/fuzztest/internal/fixture_driver.h
index 60fd108..b053268 100644
--- a/fuzztest/internal/fixture_driver.h
+++ b/fuzztest/internal/fixture_driver.h
@@ -99,10 +99,10 @@
  public:
   TypedFixtureDriver(std::unique_ptr<TypedDomainInterface<ValueType>> domain,
                      std::vector<GenericDomainCorpusType> seeds,
-                     SeedProvider seed_provider)
+                     const SeedProvider& seed_provider)
       : domain_(std::move(domain)),
         seeds_(std::move(seeds)),
-        seed_provider_(std::move(seed_provider)) {}
+        seed_provider_(seed_provider) {}
 
   std::vector<GenericDomainCorpusType> GetSeeds() const final {
     std::vector<GenericDomainCorpusType> seeds = GetSeedsFromSeedProvider();
@@ -158,7 +158,7 @@
 
   std::unique_ptr<TypedDomainInterface<ValueType>> domain_;
   std::vector<GenericDomainCorpusType> seeds_;
-  SeedProvider seed_provider_;
+  const SeedProvider& seed_provider_;
 };
 
 // ForceVectorForStringView is a temporary hack for realiably
@@ -220,12 +220,12 @@
 
   explicit FixtureDriver(TargetFunction target_function, const DomainT& domain,
                          std::vector<GenericDomainCorpusType> seeds,
-                         SeedProvider seed_provider)
+                         const SeedProvider& seed_provider)
       : FixtureDriver::TypedFixtureDriver(
             absl::WrapUnique(
                 static_cast<TypedDomainInterface<value_type_t<DomainT>>*>(
                     domain.Clone().release())),
-            std::move(seeds), std::move(seed_provider)),
+            std::move(seeds), seed_provider),
         target_function_(target_function) {}
 
   void Test(MoveOnlyAny&& args_untyped) const override {
@@ -283,12 +283,12 @@
 
   explicit FixtureDriver(TargetFunction target_function, const DomainT& domain,
                          std::vector<GenericDomainCorpusType> seeds,
-                         SeedProvider seed_provider)
+                         const SeedProvider& seed_provider)
       : FixtureDriver::TypedFixtureDriver(
             absl::WrapUnique(
                 static_cast<TypedDomainInterface<value_type_t<DomainT>>*>(
                     domain.Clone().release())),
-            std::move(seeds), std::move(seed_provider)),
+            std::move(seeds), seed_provider),
         target_function_(target_function) {}
 
   void Test(MoveOnlyAny&& args_untyped) const override {
diff --git a/fuzztest/internal/googletest_adaptor.cc b/fuzztest/internal/googletest_adaptor.cc
index e2c2952..eb30ecd 100644
--- a/fuzztest/internal/googletest_adaptor.cc
+++ b/fuzztest/internal/googletest_adaptor.cc
@@ -1,18 +1,36 @@
 #include "./fuzztest/internal/googletest_adaptor.h"
 
+#include <optional>
+#include <string>
+#include <vector>
+
 #include "gtest/gtest.h"
+#include "absl/functional/function_ref.h"
+#include "absl/strings/str_cat.h"
 #include "./fuzztest/internal/registry.h"
 
 namespace fuzztest::internal {
 
-void RegisterFuzzTestsAsGoogleTests(int* argc, char*** argv) {
+void RunExpectExit(absl::FunctionRef<void()> test) {
+#if defined(__APPLE__) || defined(_MSC_VER)
+  test();
+#else
+  EXPECT_EXIT(test(), ::testing::ExitedWithCode(0), "");
+#endif
+}
+
+#define run
+void RegisterFuzzTestsAsGoogleTests(
+    int* argc, char*** argv, const std::vector<std::string>& crashing_inputs) {
   ::fuzztest::internal::ForEachTest([&](auto& test) {
     auto fixture_factory =
         [argc, argv, &test]() -> ::fuzztest::internal::GTest_TestAdaptor* {
-      return new ::fuzztest::internal::GTest_TestAdaptor(test, argc, argv);
+      return new ::fuzztest::internal::GTest_TestAdaptor(test, argc, argv,
+                                                         std::nullopt);
     };
     auto test_factory = [argc, argv, &test]() -> ::testing::Test* {
-      return new ::fuzztest::internal::GTest_TestAdaptor(test, argc, argv);
+      return new ::fuzztest::internal::GTest_TestAdaptor(test, argc, argv,
+                                                         std::nullopt);
     };
     if (test.uses_fixture()) {
       ::testing::RegisterTest(test.suite_name(), test.test_name(), nullptr,
diff --git a/fuzztest/internal/googletest_adaptor.h b/fuzztest/internal/googletest_adaptor.h
index 9b96d22..64b99d9 100644
--- a/fuzztest/internal/googletest_adaptor.h
+++ b/fuzztest/internal/googletest_adaptor.h
@@ -17,9 +17,11 @@
 
 #include <cstdlib>
 #include <memory>
+#include <optional>
 #include <utility>
 
 #include "gtest/gtest.h"
+#include "absl/strings/string_view.h"
 #include "./fuzztest/internal/registry.h"
 #include "./fuzztest/internal/runtime.h"
 
@@ -27,13 +29,18 @@
 
 class GTest_TestAdaptor : public ::testing::Test {
  public:
-  explicit GTest_TestAdaptor(FuzzTest& test, int* argc, char*** argv)
-      : test_(test), argc_(argc), argv_(argv) {}
+  explicit GTest_TestAdaptor(FuzzTest& test, int* argc, char*** argv,
+                             std::optional<absl::string_view> input)
+      : test_(test), argc_(argc), argv_(argv), input_(input) {}
 
   void TestBody() override {
-    auto test = std::move(test_).make();
+    std::cout << "In Test Body..." << std::endl;
+    std::cout << "unit test? "
+              << (Runtime::instance().run_mode() == RunMode::kUnitTest)
+              << std::endl;
+    auto test = test_.make();
     if (Runtime::instance().run_mode() == RunMode::kUnitTest) {
-      test->RunInUnitTestMode();
+      test->RunInUnitTestMode(input_);
     } else {
       ASSERT_EQ(0, test->RunInFuzzingMode(argc_, argv_)) << "Fuzzing failure.";
     }
@@ -55,6 +62,7 @@
   FuzzTest& test_;
   int* argc_;
   char*** argv_;
+  std::optional<absl::string_view> input_;
 };
 
 template <typename Base, typename TestPartResult>
@@ -77,7 +85,8 @@
 };
 
 // Registers FUZZ_TEST as GoogleTest TEST-s.
-void RegisterFuzzTestsAsGoogleTests(int* argc, char*** argv);
+void RegisterFuzzTestsAsGoogleTests(
+    int* argc, char*** argv, const std::vector<std::string>& crashing_inputs);
 
 }  // namespace fuzztest::internal
 
diff --git a/fuzztest/internal/io.cc b/fuzztest/internal/io.cc
index ea817c4..adfed70 100644
--- a/fuzztest/internal/io.cc
+++ b/fuzztest/internal/io.cc
@@ -65,6 +65,10 @@
   FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
 }
 
+std::vector<std::string> GetFileOrFilesInDir(std::string_view file_or_dir) {
+  FUZZTEST_INTERNAL_CHECK(false, "Can't replay in iOS/MacOS");
+}
+
 #else  // defined(__APPLE__)
 
 bool WriteFile(std::string_view filename, std::string_view contents) {
@@ -133,6 +137,36 @@
   return out;
 }
 
+namespace {
+
+void GetAllFilesRecursively(std::string_view dir,
+                            std::vector<std::string>& files) {
+  std::vector<std::string> entries = ListDirectory(dir);
+  for (const auto& entry : entries) {
+    absl::FPrintF(GetStderr(), "entry: %s\n", entry);
+    if (!std::filesystem::is_directory(entry)) {
+      files.push_back(entry);
+    } else {
+      GetAllFilesRecursively(entry, files);
+    }
+  }
+}
+
+}  // namespace
+
+std::vector<std::string> GetFileOrFilesInDir(std::string_view file_or_dir) {
+  // Try as a directory path first.
+  std::vector<std::string> files;
+  GetAllFilesRecursively(file_or_dir, files);
+  // If not, consider it a file path.
+  if (files.empty()) {
+    if (std::filesystem::is_regular_file(file_or_dir)) {
+      files.push_back(std::string(file_or_dir));
+    }
+  }
+  return files;
+}
+
 #endif  // defined(STUB_FILESYSTEM)
 
 }  // namespace fuzztest::internal
diff --git a/fuzztest/internal/io.h b/fuzztest/internal/io.h
index 27a39d9..d253c2c 100644
--- a/fuzztest/internal/io.h
+++ b/fuzztest/internal/io.h
@@ -46,6 +46,8 @@
 // returns an empty list.
 std::vector<std::string> ListDirectory(std::string_view dir);
 
+std::vector<std::string> GetFileOrFilesInDir(std::string_view file_or_dir);
+
 }  // namespace fuzztest::internal
 
 #endif  // FUZZTEST_FUZZTEST_INTERNAL_IO_H_
diff --git a/fuzztest/internal/registration.h b/fuzztest/internal/registration.h
index c9e032c..7b0e940 100644
--- a/fuzztest/internal/registration.h
+++ b/fuzztest/internal/registration.h
@@ -26,6 +26,7 @@
 
 #include "absl/functional/any_invocable.h"
 #include "absl/strings/str_format.h"
+#include "absl/strings/string_view.h"
 #include "absl/types/span.h"
 #include "./fuzztest/domain.h"
 #include "./fuzztest/internal/domains/aggregate_of_impl.h"
@@ -41,6 +42,7 @@
   const char* file = nullptr;
   int line = 0;
   bool uses_fixture = false;
+  std::function<void*(absl::string_view)> factory;
 };
 
 // Use base classes to progressively add members/behavior to the registerer
diff --git a/fuzztest/internal/registry.h b/fuzztest/internal/registry.h
index 6978073..6190489 100644
--- a/fuzztest/internal/registry.h
+++ b/fuzztest/internal/registry.h
@@ -15,6 +15,8 @@
 #ifndef FUZZTEST_FUZZTEST_INTERNAL_REGISTRY_H_
 #define FUZZTEST_FUZZTEST_INTERNAL_REGISTRY_H_
 
+#include <stdbool.h>
+
 #include <memory>
 #include <string_view>
 #include <type_traits>
@@ -82,13 +84,13 @@
 
     return
         [target_function = reg.target_function_, domain = reg.GetDomains(),
-         seeds = reg.seeds(), seed_provider = reg.seed_provider()](
-            const FuzzTest& test) mutable -> std::unique_ptr<FuzzTestFuzzer> {
+         seeds = reg.seeds(), seed_provider = std::move(reg.seed_provider())](
+            const FuzzTest& test) -> std::unique_ptr<FuzzTestFuzzer> {
           return std::make_unique<FuzzerImpl>(
               test,
               std::make_unique<FixtureDriverImpl<decltype(domain), Fixture,
                                                  TargetFunction, SeedProvider>>(
-                  target_function, domain, seeds, std::move(seed_provider)));
+                  target_function, domain, seeds, seed_provider));
         };
   }
 };
diff --git a/fuzztest/internal/runtime.cc b/fuzztest/internal/runtime.cc
index d2089db..041245e 100644
--- a/fuzztest/internal/runtime.cc
+++ b/fuzztest/internal/runtime.cc
@@ -57,6 +57,8 @@
 
 namespace fuzztest::internal {
 
+extern void RunExpectExit(absl::FunctionRef<void()> test);
+
 void (*crash_handler_hook)();
 
 void Runtime::DumpReproducer(std::string_view outdir) const {
@@ -315,9 +317,8 @@
 }
 
 bool FuzzTestFuzzerImpl::ReplayInputsIfAvailable() {
-  runtime_.SetRunMode(RunMode::kFuzz);
-
-  if (const auto file_paths = GetFilesToReplay()) {
+  if (bool early_return;
+      const auto file_paths = GetFilesToReplay(early_return)) {
     for (const std::string& path : *file_paths) {
       const auto content = ReadFile(path);
       if (!content) {
@@ -337,9 +338,10 @@
       absl::FPrintF(GetStderr(), "[.] Replaying %s\n", path);
       RunOneInput({*corpus_value});
     }
-    return true;
+    if (early_return) return true;
   }
 
+  runtime_.SetRunMode(RunMode::kFuzz);
   if (const auto to_minimize = ReadReproducerToMinimize()) {
     absl::FPrintF(GetStderr(),
                   "[!] Looking for smaller mutations indefinitely: please "
@@ -386,16 +388,17 @@
   return false;
 }
 
-std::optional<std::vector<std::string>> FuzzTestFuzzerImpl::GetFilesToReplay() {
+std::optional<std::vector<std::string>> FuzzTestFuzzerImpl::GetFilesToReplay(
+    bool& early_return) {
   auto file_or_dir = absl::NullSafeStringView(getenv("FUZZTEST_REPLAY"));
-  if (file_or_dir.empty()) return std::nullopt;
-  // Try as a directory path first.
-  std::vector<std::string> files = ListDirectory(std::string(file_or_dir));
-  // If not, consider it a file path.
-  if (files.empty()) {
-    files.push_back(std::string(file_or_dir));
+  if (file_or_dir.empty()) {
+    early_return = false;
+    auto result = Runtime::instance().files_to_replay();
+    if (result.empty()) return std::nullopt;
+    return result;
   }
-  return files;
+  early_return = true;
+  return GetFileOrFilesInDir(file_or_dir);
 }
 
 std::optional<corpus_type> FuzzTestFuzzerImpl::ReadReproducerToMinimize() {
@@ -599,12 +602,36 @@
   }
 }
 
-void FuzzTestFuzzerImpl::RunInUnitTestMode() {
+void FuzzTestFuzzerImpl::RunInUnitTestMode(
+    std::optional<absl::string_view> input) {
+  // std::cout << "In UnitTest mode" << std::endl;
   fixture_driver_->SetUpFuzzTest();
   [&] {
     runtime_.EnableReporter(&stats_, [] { return absl::Now(); });
     runtime_.SetCurrentTest(&test_);
 
+    if (input.has_value()) {
+      // std::cout << "has crashing input!" << std::endl;
+      const auto content = ReadFile(*input);
+      if (!content) {
+        absl::FPrintF(GetStderr(),
+                      "[!] Failed to read FUZZTEST_REPLAY file or directory "
+                      "(might be empty): %s\n",
+                      *input);
+      } else {
+        auto corpus_value = TryParse(*content);
+        if (!corpus_value) {
+          absl::FPrintF(GetStderr(),
+                        "[!] Skipping invalid input file %s.\n===\n%s\n===\n",
+                        *input, *content);
+        } else {
+          absl::FPrintF(GetStderr(), "[.] Replaying %s\n", *input);
+          RunOneInput({*corpus_value}, /*expect_pass=*/true);
+        }
+      }
+      return;
+    }
+
     // TODO(sbenzaquen): Currently, some infrastructure code assumes that replay
     // works in unit test mode, so we support it. However, we would like to
     // limit replaying to fuzzing mode only, where we can guarantee that only
@@ -660,7 +687,7 @@
 }
 
 FuzzTestFuzzerImpl::RunResult FuzzTestFuzzerImpl::RunOneInput(
-    const Input& input) {
+    const Input& input, bool expect_pass) {
   ++stats_.runs;
   auto untyped_args = params_domain_->UntypedGetValue(input.args);
   Runtime::Args debug_args{input.args, *params_domain_};
@@ -681,7 +708,11 @@
   }
 
   fixture_driver_->SetUpIteration();
-  fixture_driver_->Test(std::move(untyped_args));
+  if (expect_pass) {
+    RunExpectExit([&]() { fixture_driver_->Test(std::move(untyped_args)); });
+  } else {
+    fixture_driver_->Test(std::move(untyped_args));
+  }
   fixture_driver_->TearDownIteration();
   if (execution_coverage_ != nullptr) {
     execution_coverage_->SetIsTracing(false);
diff --git a/fuzztest/internal/runtime.h b/fuzztest/internal/runtime.h
index cb46d6c..c56f31f 100644
--- a/fuzztest/internal/runtime.h
+++ b/fuzztest/internal/runtime.h
@@ -64,7 +64,7 @@
 class FuzzTestFuzzer {
  public:
   virtual ~FuzzTestFuzzer() = default;
-  virtual void RunInUnitTestMode() = 0;
+  virtual void RunInUnitTestMode(std::optional<absl::string_view> input) = 0;
   // Returns fuzzing mode's exit code. Zero indicates success.
   virtual int RunInFuzzingMode(int* argc, char*** argv) = 0;
 };
@@ -72,7 +72,7 @@
 class FuzzTest;
 
 using FuzzTestFuzzerFactory =
-    absl::AnyInvocable<std::unique_ptr<FuzzTestFuzzer>(const FuzzTest&) &&>;
+    absl::AnyInvocable<std::unique_ptr<FuzzTestFuzzer>(const FuzzTest&) const>;
 
 class FuzzTest {
  public:
@@ -93,7 +93,7 @@
   const char* file() const { return test_info_.file; }
   int line() const { return test_info_.line; }
   bool uses_fixture() const { return test_info_.uses_fixture; }
-  auto make() && { return std::move(make_)(*this); }
+  auto make() const { return make_(*this); }
 
  private:
   BasicTestInfo test_info_;
@@ -154,6 +154,15 @@
   }
   absl::Duration fuzz_time_limit() const { return fuzz_time_limit_; }
 
+  void SetFilesToReplay(absl::Span<const std::string> files_to_replay) {
+    FUZZTEST_INTERNAL_CHECK(files_to_replay_.empty(),
+                            "Replay files are set already!");
+    files_to_replay_ = std::vector<std::string>(files_to_replay.begin(),
+                                                files_to_replay.end());
+  }
+
+  std::vector<std::string>& files_to_replay() { return files_to_replay_; }
+
   void EnableReporter(const RuntimeStats* stats, absl::Time (*clock_fn)()) {
     reporter_enabled_ = true;
     stats_ = stats;
@@ -203,6 +212,7 @@
 
   RunMode run_mode_ = RunMode::kUnitTest;
   absl::Duration fuzz_time_limit_ = absl::InfiniteDuration();
+  std::vector<std::string> files_to_replay_;
 
   bool reporter_enabled_ = false;
   Args* current_args_ = nullptr;
@@ -233,7 +243,7 @@
 
  private:
   // TODO(fniksic): Refactor to reduce code complexity and improve readability.
-  void RunInUnitTestMode() override;
+  void RunInUnitTestMode(std::optional<absl::string_view> input) override;
 
   // TODO(fniksic): Refactor to reduce code complexity and improve readability.
   int RunInFuzzingMode(int* argc, char*** argv) override;
@@ -258,7 +268,7 @@
 
   bool ReplayInputsIfAvailable();
 
-  std::optional<std::vector<std::string>> GetFilesToReplay();
+  std::optional<std::vector<std::string>> GetFilesToReplay(bool& early_return);
 
   std::optional<corpus_type> ReadReproducerToMinimize();
 
@@ -294,7 +304,7 @@
 
   void InitializeCorpus(absl::BitGenRef prng);
 
-  RunResult RunOneInput(const Input& input);
+  RunResult RunOneInput(const Input& input, bool expect_pass = false);
 
   bool ShouldStop();