Use stop time to cap the execution deadline and skip reporting. After this we don't need to set batch timeout to the test time limit - it was a quick workaround for the same purpose. Make some e2e test fuzzing duration to 10s to reduce the flakiness. PiperOrigin-RevId: 818809280
diff --git a/centipede/BUILD b/centipede/BUILD index 59982a3..f22646d 100644 --- a/centipede/BUILD +++ b/centipede/BUILD
@@ -669,6 +669,7 @@ ":runner_request", ":runner_result", ":shared_memory_blob_sequence", + ":stop", ":util", ":workdir", "@abseil-cpp//absl/base:nullability",
diff --git a/centipede/centipede.cc b/centipede/centipede.cc index 97120d3..1b8c53d 100644 --- a/centipede/centipede.cc +++ b/centipede/centipede.cc
@@ -363,8 +363,15 @@ const std::vector<ByteArray> &input_vec, BatchResult &batch_result) { bool success = user_callbacks_.Execute(binary, input_vec, batch_result); - if (!success) ReportCrash(binary, input_vec, batch_result); - return success || batch_result.IsIgnoredFailure(); + if (success) return true; + if (ShouldStop()) { + FUZZTEST_LOG_FIRST_N(WARNING, 1) + << "Crash found but the stop condition is met - not reporting further " + "possibly related crashes."; + return true; + } + ReportCrash(binary, input_vec, batch_result); + return batch_result.IsIgnoredFailure(); } // *** Highly experimental and risky. May not scale well for large targets. ***
diff --git a/centipede/centipede_callbacks.cc b/centipede/centipede_callbacks.cc index 8110dce..d628972 100644 --- a/centipede/centipede_callbacks.cc +++ b/centipede/centipede_callbacks.cc
@@ -50,6 +50,7 @@ #include "./centipede/mutation_input.h" #include "./centipede/runner_request.h" #include "./centipede/runner_result.h" +#include "./centipede/stop.h" #include "./centipede/util.h" #include "./centipede/workdir.h" #include "./common/blob_file.h" @@ -479,7 +480,8 @@ env_.timeout_per_batch == 0 ? absl::InfiniteDuration() : absl::Seconds(env_.timeout_per_batch) + absl::Seconds(5); - const auto deadline = absl::Now() + amortized_timeout; + const auto deadline = + std::min(absl::Now() + amortized_timeout, GetStopTime()); int exit_code = EXIT_SUCCESS; const bool should_clean_up = [&] { if (!cmd.is_executing() && !cmd.ExecuteAsync()) {
diff --git a/centipede/centipede_interface.cc b/centipede/centipede_interface.cc index 321f89a..7b428d2 100644 --- a/centipede/centipede_interface.cc +++ b/centipede/centipede_interface.cc
@@ -692,6 +692,8 @@ << "Skip updating corpus database due to early stop requested."; continue; } + // The test time limit does not apply for the rest of the steps. + ClearEarlyStopRequestAndSetStopTime(/*stop_time=*/absl::InfiniteFuture()); // TODO(xinhaoyuan): Have a separate flag to skip corpus updating instead // of checking whether workdir is specified or not.
diff --git a/centipede/environment.cc b/centipede/environment.cc index 4cd2be6..bed7922 100644 --- a/centipede/environment.cc +++ b/centipede/environment.cc
@@ -285,17 +285,6 @@ timeout_per_input = time_limit_per_input_sec; UpdateTimeoutPerBatchIfEqualTo(autocomputed_timeout_per_batch); - // Adjust `timeout_per_batch` to never exceed the test time limit. - if (const auto test_time_limit = config.GetTimeLimitPerTest(); - test_time_limit < absl::InfiniteDuration()) { - const size_t test_time_limit_seconds = - convert_to_seconds(test_time_limit, "Test time limit"); - timeout_per_batch = - timeout_per_batch == 0 - ? test_time_limit_seconds - : std::min(timeout_per_batch, test_time_limit_seconds); - } - // Convert bytes to MB by rounding up. constexpr auto bytes_to_mb = [](size_t bytes) { return bytes == 0 ? 0 : (bytes - 1) / 1024 / 1024 + 1;
diff --git a/centipede/environment_test.cc b/centipede/environment_test.cc index a906b99..9776192 100644 --- a/centipede/environment_test.cc +++ b/centipede/environment_test.cc
@@ -147,30 +147,6 @@ EXPECT_EQ(env.timeout_per_batch, 0); } -TEST(Environment, UpdatesTimeoutPerBatchFromTargetConfigTimeLimit) { - Environment env; - fuzztest::internal::Configuration config; - config.time_limit = absl::Seconds(123); - config.time_budget_type = fuzztest::internal::TimeBudgetType::kPerTest; - FUZZTEST_CHECK(config.GetTimeLimitPerTest() == absl::Seconds(123)); - env.UpdateWithTargetConfig(config); - EXPECT_EQ(env.timeout_per_batch, 123) - << "`timeout_per_batch` should be set to the test time limit when it was " - "previously unset"; - - env.timeout_per_batch = 456; - env.UpdateWithTargetConfig(config); - EXPECT_EQ(env.timeout_per_batch, 123) - << "`timeout_per_batch` should be set to test time limit when it is " - "shorter than the previous value"; - - env.timeout_per_batch = 56; - env.UpdateWithTargetConfig(config); - EXPECT_EQ(env.timeout_per_batch, 56) - << "`timeout_per_batch` should not be updated with the test time limit " - "when it is longer than the previous value"; -} - TEST(Environment, UpdatesRssLimitMbFromTargetConfigRssLimit) { Environment env; env.rss_limit_mb = Environment::Default().rss_limit_mb;
diff --git a/centipede/stop.cc b/centipede/stop.cc index 20f85bd..6a76c17 100644 --- a/centipede/stop.cc +++ b/centipede/stop.cc
@@ -46,6 +46,8 @@ early_stop.store({exit_code, true}, std::memory_order_release); } +absl::Time GetStopTime() { return stop_time; } + bool ShouldStop() { return EarlyStopRequested() || stop_time < absl::Now(); } int ExitCode() { return early_stop.load(std::memory_order_acquire).exit_code; }
diff --git a/centipede/stop.h b/centipede/stop.h index f4244f8..d3e255d 100644 --- a/centipede/stop.h +++ b/centipede/stop.h
@@ -46,6 +46,13 @@ // ENSURES: Thread-safe. bool ShouldStop(); +// Returns the stop time set from the recent +// `ClearEarlyStopRequestAndSetStopTime()`, or `absl::InfiniteFuture()` it was +// not set. +// +// ENSURES: Thread-safe. +absl::Time GetStopTime(); + // Returns the value most recently passed to `RequestEarlyStop()` or 0 if // `RequestEarlyStop()` was not called since the most recent call to // `ClearEarlyStopRequestAndSetStopTime()` (if any).
diff --git a/e2e_tests/corpus_database_test.cc b/e2e_tests/corpus_database_test.cc index c41f7d4..c369b84 100644 --- a/e2e_tests/corpus_database_test.cc +++ b/e2e_tests/corpus_database_test.cc
@@ -280,11 +280,11 @@ RunBinaryMaybeWithCentipede(GetCorpusDatabaseTestingBinaryPath(), fst_run_options); - // Adjust the fuzzing time so that only 1s remains. + // Adjust the fuzzing time so that only 10s remains. const absl::StatusOr<std::string> fuzzing_time_file = FindFile(corpus_database.path().c_str(), "fuzzing_time"); ASSERT_TRUE(fuzzing_time_file.ok()) << fst_std_err; - ASSERT_TRUE(WriteFile(*fuzzing_time_file, "299s")); + ASSERT_TRUE(WriteFile(*fuzzing_time_file, "290s")); // 2nd run that should resume due to the same execution ID. RunOptions snd_run_options; @@ -301,7 +301,7 @@ snd_std_err, // The resumed fuzz test is the first one defined in the binary. AllOf(HasSubstr("Resuming running the fuzz test FuzzTest.FailsInTwoWays"), - HasSubstr("Fuzzing FuzzTest.FailsInTwoWays for 1s"), + HasSubstr("Fuzzing FuzzTest.FailsInTwoWays for 10s"), // Make sure that FailsInTwoWays finished. HasSubstr("Fuzzing FuzzTest.FailsWithStackOverflow")));
diff --git a/e2e_tests/functional_test.cc b/e2e_tests/functional_test.cc index 4bd3874..ae86a6a 100644 --- a/e2e_tests/functional_test.cc +++ b/e2e_tests/functional_test.cc
@@ -124,6 +124,9 @@ absl::flat_hash_map<std::string, std::string> fuzzer_flags = {}) { fuzzer_flags["print_subprocess_log"] = "true"; fuzzer_flags["unguided"] = "true"; + if (!fuzzer_flags.contains("fuzz_for")) { + fuzzer_flags["fuzz_for"] = "10s"; + } RunOptions run_options; run_options.flags = { {GTEST_FLAG_PREFIX_ "filter", std::string(test_filter)}, @@ -1177,7 +1180,7 @@ // to restrict the filter to only fuzz tests. TEST_F(FuzzingModeCommandLineInterfaceTest, RunsOnlyFuzzTests) { auto [status, std_out, std_err] = - RunWith({{"fuzz_for", "1ns"}}, /*env=*/{}, /*timeout=*/absl::Seconds(10), + RunWith({{"fuzz_for", "1s"}}, /*env=*/{}, /*timeout=*/absl::Seconds(10), "testdata/unit_test_and_fuzz_tests"); EXPECT_THAT_LOG(std_out, @@ -1191,7 +1194,7 @@ TEST_F(FuzzingModeCommandLineInterfaceTest, AllowsSpecifyingFilterWithFuzzForDuration) { auto [status, std_out, std_err] = - RunWith({{"fuzz_for", "1ns"}}, /*env=*/{}, /*timeout=*/absl::Seconds(10), + RunWith({{"fuzz_for", "1s"}}, /*env=*/{}, /*timeout=*/absl::Seconds(10), "testdata/unit_test_and_fuzz_tests", {{GTEST_FLAG_PREFIX_ "filter", "UnitTest.AlwaysPasses:FuzzTest.AlwaysPasses"}});