Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion centipede/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ cc_library(
"@abseil-cpp//absl/strings",
"@abseil-cpp//absl/strings:str_format",
"@abseil-cpp//absl/synchronization",
"@abseil-cpp//absl/time",
"@abseil-cpp//absl/types:span",
"@com_google_fuzztest//common:defs",
"@com_google_fuzztest//common:hash",
Expand Down Expand Up @@ -1138,6 +1139,7 @@ cc_library(
linkstatic = True, # Must be linked statically even when dynamic_mode=on.
deps = [
":centipede_runner_no_main",
":execution_metadata",
":mutation_data",
"@abseil-cpp//absl/base:nullability",
"@abseil-cpp//absl/types:span",
Expand Down Expand Up @@ -1394,6 +1396,7 @@ cc_test(
":thread_pool",
":util",
"@abseil-cpp//absl/container:flat_hash_map",
"@abseil-cpp//absl/time",
"@com_google_fuzztest//common:defs",
"@com_google_fuzztest//common:hash",
"@com_google_fuzztest//common:logging",
Expand Down Expand Up @@ -1955,7 +1958,7 @@ cc_test(
timeout = "long",
srcs = ["centipede_test.cc"],
data = [
"@com_google_fuzztest//centipede",
":centipede",
"@com_google_fuzztest//centipede/testing:abort_fuzz_target",
"@com_google_fuzztest//centipede/testing:async_failing_target",
"@com_google_fuzztest//centipede/testing:expensive_startup_fuzz_target",
Expand Down
21 changes: 15 additions & 6 deletions centipede/centipede_callbacks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@

namespace fuzztest::internal {

constexpr auto kPollMinimalTimeout = absl::Milliseconds(1);

class CentipedeCallbacks::PersistentModeServer {
public:
explicit PersistentModeServer(std::string server_path)
Expand Down Expand Up @@ -194,9 +192,7 @@ class CentipedeCallbacks::PersistentModeServer {
int poll_ret = -1;
do {
poll_fd = {fd, static_cast<short>(event)};
const int poll_timeout_ms = static_cast<int>(absl::ToInt64Milliseconds(
std::max(deadline - absl::Now(), kPollMinimalTimeout)));
poll_ret = poll(&poll_fd, 1, poll_timeout_ms);
poll_ret = poll(&poll_fd, 1, PollTimeoutMs(deadline - absl::Now()));
} while (poll_ret < 0 && errno == EINTR);
if (poll_ret == 1 && (poll_fd.revents & (event | POLLHUP)) == event) {
return true;
Expand Down Expand Up @@ -343,7 +339,6 @@ std::string CentipedeCallbacks::ConstructRunnerFlags(
std::vector<std::string> flags = {
"CENTIPEDE_RUNNER_FLAGS=",
absl::StrCat("timeout_per_input=", env_.timeout_per_input),
absl::StrCat("timeout_per_batch=", env_.timeout_per_batch),
absl::StrCat("address_space_limit_mb=", env_.address_space_limit_mb),
absl::StrCat("rss_limit_mb=", env_.rss_limit_mb),
absl::StrCat("stack_limit_kb=", env_.stack_limit_kb),
Expand Down Expand Up @@ -565,8 +560,12 @@ int CentipedeCallbacks::ExecuteCentipedeSancovBinaryWithShmem(
}

// Run.
const auto batch_start_time = absl::Now();
const int exit_code = RunBatchForBinary(binary);
inputs_blobseq_.ReleaseSharedMemory(); // Inputs are already consumed.
const bool batch_timed_out =
env_.timeout_per_batch > 0 &&
absl::Now() - batch_start_time > absl::Seconds(env_.timeout_per_batch);

// Get results.
batch_result.exit_code() = exit_code;
Expand All @@ -591,6 +590,16 @@ int CentipedeCallbacks::ExecuteCentipedeSancovBinaryWithShmem(

if (env_.print_runner_log) PrintExecutionLog();

if (batch_timed_out) {
FUZZTEST_LOG(INFO)
<< "Batch timeout detected. Replacing the original exit code: "
<< exit_code
<< ", failure description: " << batch_result.failure_description();
batch_result.failure_description() = kExecutionFailurePerBatchTimeout;
batch_result.exit_code() = EXIT_FAILURE;
return EXIT_FAILURE;
}

// TODO: b/467103298 - Handle failures when the exit code is zero, e.g., when
// the target exits via `std::_Exit(0)`.
if (exit_code != EXIT_SUCCESS) {
Expand Down
28 changes: 11 additions & 17 deletions centipede/centipede_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -963,14 +963,8 @@ TEST_F(CentipedeWithTemporaryLocalDir, GetsSeedInputs) {
CentipedeDefaultCallbacks callbacks(env, stop_condition);

std::vector<ByteArray> seeds;
EXPECT_EQ(callbacks.GetSeeds(10, seeds), 10);
EXPECT_THAT(seeds, testing::ContainerEq(std::vector<ByteArray>{
{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}}));
EXPECT_EQ(callbacks.GetSeeds(5, seeds), 10);
EXPECT_THAT(seeds, testing::ContainerEq(
std::vector<ByteArray>{{0}, {1}, {2}, {3}, {4}}));
EXPECT_EQ(callbacks.GetSeeds(100, seeds), 10);
EXPECT_THAT(seeds, testing::ContainerEq(std::vector<ByteArray>{
callbacks.GetSeeds(10, seeds);
EXPECT_THAT(seeds, testing::IsSupersetOf(std::vector<ByteArray>{
{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}}));
}

Expand Down Expand Up @@ -1277,12 +1271,13 @@ TEST_F(CentipedeWithTemporaryLocalDir, UsesProvidedCustomMutator) {
"centipede/testing/fuzz_target_with_custom_mutator");
CentipedeDefaultCallbacks callbacks(env, stop_condition);

const std::vector<ByteArray> inputs = {{1}, {2}, {3}, {4}, {5}, {6}};
const std::vector<Mutant> mutants = callbacks.Mutate(
GetMutationInputRefsFromDataInputs(inputs), inputs.size());
const std::vector<ByteArray> inputs = {{99}};
const std::vector<Mutant> mutants =
callbacks.Mutate(GetMutationInputRefsFromDataInputs(inputs), 5);

// The custom mutator just returns the original inputs as mutants.
EXPECT_EQ(inputs, GetDataFromMutants(mutants));
// The custom mutator just duplicates the original inputs as mutants.
EXPECT_EQ(GetDataFromMutants(mutants),
(std::vector<ByteArray>{{99}, {99}, {99}, {99}, {99}}));
}

TEST_F(CentipedeWithTemporaryLocalDir, FailsOnMisbehavingCustomMutator) {
Expand Down Expand Up @@ -1406,9 +1401,8 @@ TEST_F(CentipedeWithTemporaryLocalDir, EngineWorksInWorkerMode) {
fuzztest::internal::DefaultCallbacksFactory<
fuzztest::internal::CentipedeDefaultCallbacks>
callbacks;
EXPECT_DEATH(
[&] { std::exit(CentipedeMain(env, callbacks)); }(),
ContainsRegex("Failure *: INPUT FAILURE: some_failure_description"));
EXPECT_DEATH([&] { std::exit(CentipedeMain(env, callbacks)); }(),
ContainsRegex("Failure *: some_failure_description"));
}

TEST_F(CentipedeWithTemporaryLocalDir, EngineWorksInStandaloneMode) {
Expand All @@ -1428,7 +1422,7 @@ TEST_F(CentipedeWithTemporaryLocalDir, EngineWorksInStandaloneMode) {
const int status = std::system(test_command.c_str());
std::exit(WEXITSTATUS(status));
}(),
ContainsRegex("Failure *: INPUT FAILURE: some_failure_description"));
ContainsRegex("Failure *: some_failure_description"));
}

} // namespace
Expand Down
8 changes: 3 additions & 5 deletions centipede/command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,7 @@ struct Command::ForkServerProps {
/*fd=*/pipe_[1],
/*events=*/POLLIN,
};
const int poll_timeout_ms = static_cast<int>(absl::ToInt64Milliseconds(
std::max(deadline - absl::Now(), absl::Milliseconds(1))));
poll_ret = poll(&poll_fd, 1, poll_timeout_ms);
poll_ret = poll(&poll_fd, 1, PollTimeoutMs(deadline - absl::Now()));
// The `poll()` syscall can get interrupted: it sets errno==EINTR in that
// case. We should tolerate that.
} while (poll_ret < 0 && errno == EINTR);
Expand Down Expand Up @@ -207,7 +205,7 @@ std::string Command::ToString() const {
ss.reserve(/*env*/ 1 + options_.env_diff.size() + /*path*/ 1 +
/*args*/ options_.args.size() + /*out/err*/ 2);
// env.
ss.push_back("env");
ss.push_back("exec env");
std::vector<std::string> env_to_set;
env_to_set.reserve(options_.env_diff.size());
// Arguments that unset environment variables must appear first.
Expand Down Expand Up @@ -287,7 +285,7 @@ bool Command::StartForkServer(std::string_view temp_dir_path,
{
CENTIPEDE_FORK_SERVER_FIFO0="%s" \
CENTIPEDE_FORK_SERVER_FIFO1="%s" \
exec %s
%s
} &
printf "%%s" $! > "%s"
)sh";
Expand Down
8 changes: 4 additions & 4 deletions centipede/command_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ namespace {
using ::testing::Optional;

TEST(CommandTest, ToString) {
EXPECT_EQ(Command{"x"}.ToString(), "env \\\nx");
EXPECT_EQ(Command{"x"}.ToString(), "exec env \\\nx");
{
Command::Options cmd_options;
cmd_options.args = {"arg1", "arg2"};
EXPECT_EQ((Command{"path", std::move(cmd_options)}.ToString()),
"env \\\npath \\\narg1 \\\narg2");
"exec env \\\npath \\\narg1 \\\narg2");
}
{
Command::Options cmd_options;
cmd_options.env_diff = {"K1=V1", "K2=V2", "-K3"};
EXPECT_EQ((Command{"x", std::move(cmd_options)}.ToString()),
"env \\\n-u K3 \\\nK1=V1 \\\nK2=V2 \\\nx");
"exec env \\\n-u K3 \\\nK1=V1 \\\nK2=V2 \\\nx");
}
}

Expand Down Expand Up @@ -80,7 +80,7 @@ TEST(CommandTest, InputFileWildCard) {
Command::Options cmd_options;
cmd_options.temp_file_path = "TEMP_FILE";
Command cmd{"foo bar @@ baz", std::move(cmd_options)};
EXPECT_EQ(cmd.ToString(), "env \\\nfoo bar TEMP_FILE baz");
EXPECT_EQ(cmd.ToString(), "exec env \\\nfoo bar TEMP_FILE baz");
}

TEST(CommandTest, ForkServer) {
Expand Down
Loading
Loading