Skip to content

Commit f731579

Browse files
xinhaoyuancopybara-github
authored andcommitted
No public description
PiperOrigin-RevId: 944563827
1 parent b8aad15 commit f731579

16 files changed

Lines changed: 889 additions & 590 deletions

centipede/BUILD

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -975,38 +975,6 @@ cc_library(
975975
],
976976
)
977977

978-
cc_library(
979-
name = "engine_worker",
980-
srcs = [
981-
"engine_worker.cc",
982-
"runner_utils.cc",
983-
"runner_utils.h",
984-
],
985-
hdrs = ["engine_worker_abi.h"],
986-
deps = [
987-
":engine_abi",
988-
":execution_metadata",
989-
":feature",
990-
":runner_request",
991-
":runner_result",
992-
":shared_memory_blob_sequence",
993-
"@abseil-cpp//absl/base:nullability",
994-
"@abseil-cpp//absl/random",
995-
"@abseil-cpp//absl/random:bit_gen_ref",
996-
"@com_google_fuzztest//common:defs",
997-
],
998-
)
999-
1000-
cc_library(
1001-
name = "engine_controller_with_subprocess",
1002-
srcs = ["engine_controller_with_subprocess.cc"],
1003-
hdrs = ["engine_controller_abi.h"],
1004-
deps = [
1005-
"@com_google_fuzztest//centipede:engine_abi",
1006-
"@com_google_fuzztest//fuzztest/internal:escaping",
1007-
],
1008-
)
1009-
1010978
# The runner library is special:
1011979
# * It must not be instrumented with asan, sancov, etc.
1012980
# * It must not have heavy dependencies, and ideally not at all.
@@ -1027,8 +995,6 @@ RUNNER_SOURCES_NO_MAIN = [
1027995
"runner_dl_info.cc",
1028996
"runner_dl_info.h",
1029997
"runner_interface.h",
1030-
"runner_utils.cc",
1031-
"runner_utils.h",
1032998
"sancov_callbacks.cc",
1033999
"sancov_interceptors.cc",
10341000
"sancov_object_array.cc",
@@ -1076,11 +1042,13 @@ RUNNER_DEPS = [
10761042
":knobs",
10771043
":mutation_data",
10781044
":rolling_hash",
1079-
":engine_abi",
10801045
":runner_cmp_trace",
10811046
":runner_fork_server",
10821047
":runner_request",
10831048
":runner_result",
1049+
":runner_utils",
1050+
":engine_abi",
1051+
":engine_worker",
10841052
":shared_memory_blob_sequence",
10851053
"@com_google_fuzztest//common:defs",
10861054
"@abseil-cpp//absl/base:core_headers",
@@ -1089,6 +1057,46 @@ RUNNER_DEPS = [
10891057
"@abseil-cpp//absl/types:span",
10901058
]
10911059

1060+
cc_library(
1061+
name = "runner_utils",
1062+
srcs = ["runner_utils.cc"],
1063+
hdrs = ["runner_utils.h"],
1064+
copts = RUNNER_COPTS,
1065+
deps = ["@abseil-cpp//absl/base:nullability"],
1066+
)
1067+
1068+
cc_library(
1069+
name = "engine_worker",
1070+
srcs = [
1071+
"engine_worker.cc",
1072+
],
1073+
hdrs = ["engine_worker_abi.h"],
1074+
copts = RUNNER_COPTS,
1075+
deps = [
1076+
":engine_abi",
1077+
":execution_metadata",
1078+
":feature",
1079+
":runner_request",
1080+
":runner_result",
1081+
":runner_utils",
1082+
":shared_memory_blob_sequence",
1083+
"@abseil-cpp//absl/base:nullability",
1084+
"@abseil-cpp//absl/random",
1085+
"@abseil-cpp//absl/random:bit_gen_ref",
1086+
"@com_google_fuzztest//common:defs",
1087+
],
1088+
)
1089+
1090+
cc_library(
1091+
name = "engine_controller_with_subprocess",
1092+
srcs = ["engine_controller_with_subprocess.cc"],
1093+
hdrs = ["engine_controller_abi.h"],
1094+
deps = [
1095+
"@com_google_fuzztest//centipede:engine_abi",
1096+
"@com_google_fuzztest//fuzztest/internal:escaping",
1097+
],
1098+
)
1099+
10921100
# A fuzz target needs to link with this library in order to run with Centipede.
10931101
# The fuzz target must provide its own main().
10941102
#
@@ -1217,8 +1225,6 @@ cc_library(
12171225
"reverse_pc_table.h",
12181226
"runner_dl_info.cc",
12191227
"runner_dl_info.h",
1220-
"runner_utils.cc",
1221-
"runner_utils.h",
12221228
"sancov_callbacks.cc",
12231229
"sancov_interceptors.cc",
12241230
"sancov_object_array.cc",
@@ -1240,6 +1246,7 @@ cc_library(
12401246
":foreach_nonzero",
12411247
":int_utils",
12421248
":runner_cmp_trace",
1249+
":runner_utils",
12431250
"@abseil-cpp//absl/base:core_headers",
12441251
"@abseil-cpp//absl/base:nullability",
12451252
"@abseil-cpp//absl/numeric:bits",
@@ -1957,7 +1964,7 @@ cc_test(
19571964
timeout = "long",
19581965
srcs = ["centipede_test.cc"],
19591966
data = [
1960-
"@com_google_fuzztest//centipede",
1967+
":centipede",
19611968
"@com_google_fuzztest//centipede/testing:abort_fuzz_target",
19621969
"@com_google_fuzztest//centipede/testing:async_failing_target",
19631970
"@com_google_fuzztest//centipede/testing:expensive_startup_fuzz_target",

centipede/centipede_callbacks.cc

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include <algorithm>
2525
#include <cerrno>
26+
#include <cmath>
2627
#include <cstddef>
2728
#include <cstdlib>
2829
#include <cstring>
@@ -194,8 +195,11 @@ class CentipedeCallbacks::PersistentModeServer {
194195
int poll_ret = -1;
195196
do {
196197
poll_fd = {fd, static_cast<short>(event)};
197-
const int poll_timeout_ms = static_cast<int>(absl::ToInt64Milliseconds(
198-
std::max(deadline - absl::Now(), kPollMinimalTimeout)));
198+
const int poll_timeout_ms =
199+
deadline == absl::InfiniteFuture()
200+
? -1
201+
: static_cast<int>(std::ceil(absl::ToDoubleMilliseconds(
202+
std::max(deadline - absl::Now(), kPollMinimalTimeout))));
199203
poll_ret = poll(&poll_fd, 1, poll_timeout_ms);
200204
} while (poll_ret < 0 && errno == EINTR);
201205
if (poll_ret == 1 && (poll_fd.revents & (event | POLLHUP)) == event) {
@@ -565,8 +569,12 @@ int CentipedeCallbacks::ExecuteCentipedeSancovBinaryWithShmem(
565569
}
566570

567571
// Run.
572+
const auto batch_start_time = absl::Now();
568573
const int exit_code = RunBatchForBinary(binary);
569574
inputs_blobseq_.ReleaseSharedMemory(); // Inputs are already consumed.
575+
const bool batch_timed_out =
576+
env_.timeout_per_batch > 0 &&
577+
absl::Now() - batch_start_time > absl::Seconds(env_.timeout_per_batch);
570578

571579
// Get results.
572580
batch_result.exit_code() = exit_code;
@@ -591,6 +599,12 @@ int CentipedeCallbacks::ExecuteCentipedeSancovBinaryWithShmem(
591599

592600
if (env_.print_runner_log) PrintExecutionLog();
593601

602+
if (batch_timed_out) {
603+
batch_result.failure_description() = "per-batch-timeout-exceeded";
604+
batch_result.exit_code() = EXIT_FAILURE;
605+
return EXIT_FAILURE;
606+
}
607+
594608
// TODO: b/467103298 - Handle failures when the exit code is zero, e.g., when
595609
// the target exits via `std::_Exit(0)`.
596610
if (exit_code != EXIT_SUCCESS) {

centipede/centipede_test.cc

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class CentipedeMock : public CentipedeCallbacks {
8686
// i-th element is the number of bytes with the value 'i' in the input.
8787
// `counters` is converted to FeatureVec and added to
8888
// `batch_result.results()`.
89-
for (auto &input : inputs) {
89+
for (auto& input : inputs) {
9090
ByteArray counters(256);
9191
for (uint8_t byte : input) {
9292
counters[byte]++;
@@ -496,7 +496,7 @@ TEST_F(CentipedeWithTemporaryLocalDir, MutateViaExternalBinary) {
496496
// Must contain normal mutants, but not the ones from crossover.
497497
const auto mutant_data = GetDataFromMutants(result.mutants());
498498
EXPECT_THAT(mutant_data, IsSupersetOf(some_of_expected_mutants));
499-
for (const auto &crossover_mutant : expected_crossover_mutants) {
499+
for (const auto& crossover_mutant : expected_crossover_mutants) {
500500
EXPECT_THAT(mutant_data, Not(Contains(crossover_mutant)));
501501
}
502502
}
@@ -525,7 +525,7 @@ class MergeMock : public CentipedeCallbacks {
525525
std::vector<Mutant> Mutate(absl::Span<const MutationInputRef> inputs,
526526
size_t num_mutants) override {
527527
std::vector<Mutant> mutants(num_mutants);
528-
for (auto &mutant : mutants) {
528+
for (auto& mutant : mutants) {
529529
mutant.data.resize(1);
530530
mutant.data[0] = ++number_of_mutations_;
531531
mutant.origin = Mutant::kOriginNone;
@@ -611,7 +611,7 @@ class FunctionFilterMock : public CentipedeCallbacks {
611611
// Sets the inputs to one of 3 pre-defined values.
612612
std::vector<Mutant> Mutate(absl::Span<const MutationInputRef> inputs,
613613
size_t num_mutants) override {
614-
for (auto &input : inputs) {
614+
for (auto& input : inputs) {
615615
if (!seed_inputs_.contains(input.data)) {
616616
observed_inputs_.insert(input.data);
617617
}
@@ -628,8 +628,8 @@ class FunctionFilterMock : public CentipedeCallbacks {
628628
// Returns one of 3 pre-defined values, that trigger different code paths in
629629
// the test target.
630630
static ByteArray GetMutant(size_t idx) {
631-
const char *mutants[3] = {"func1", "func2-A", "foo"};
632-
const char *mutant = mutants[idx % 3];
631+
const char* mutants[3] = {"func1", "func2-A", "foo"};
632+
const char* mutant = mutants[idx % 3];
633633
return {mutant, mutant + strlen(mutant)};
634634
}
635635

@@ -646,7 +646,7 @@ class FunctionFilterMock : public CentipedeCallbacks {
646646
// Runs a short fuzzing session with the provided `function_filter`.
647647
// Returns a sorted array of observed inputs.
648648
static std::vector<ByteArray> RunWithFunctionFilter(
649-
std::string_view function_filter, const TempDir &tmp_dir) {
649+
std::string_view function_filter, const TempDir& tmp_dir) {
650650
Environment env;
651651
env.workdir = tmp_dir.path();
652652
env.seed = 1; // make the runs predictable.
@@ -717,9 +717,9 @@ class ExtraBinariesMock : public CentipedeCallbacks {
717717
bool Execute(std::string_view binary, absl::Span<const ByteSpan> inputs,
718718
BatchResult& batch_result) override {
719719
bool res = true;
720-
for (const auto &input : inputs) {
720+
for (const auto& input : inputs) {
721721
if (input.size() != 1) continue;
722-
for (const Crash &crash : crashes_) {
722+
for (const Crash& crash : crashes_) {
723723
if (binary == crash.binary && input[0] == crash.input) {
724724
batch_result.exit_code() = EXIT_FAILURE;
725725
batch_result.failure_description() = crash.description;
@@ -736,7 +736,7 @@ class ExtraBinariesMock : public CentipedeCallbacks {
736736
std::vector<Mutant> Mutate(absl::Span<const MutationInputRef> inputs,
737737
size_t num_mutants) override {
738738
std::vector<Mutant> mutants(num_mutants);
739-
for (auto &mutant : mutants) {
739+
for (auto& mutant : mutants) {
740740
mutant.data.resize(1);
741741
mutant.data[0] = ++number_of_mutations_;
742742
mutant.origin = Mutant::kOriginNone;
@@ -754,20 +754,20 @@ struct FileAndContents {
754754
std::string file;
755755
std::string contents;
756756

757-
bool operator==(const FileAndContents &other) const {
757+
bool operator==(const FileAndContents& other) const {
758758
return file == other.file && contents == other.contents;
759759
}
760760

761761
template <typename Sink>
762-
friend void AbslStringify(Sink &sink, const FileAndContents &f) {
762+
friend void AbslStringify(Sink& sink, const FileAndContents& f) {
763763
absl::Format(&sink, "FileAndContents{%s, \"%s\"}", f.file, f.contents);
764764
}
765765
};
766766

767767
MATCHER_P(HasFilesWithContents, expected_files_and_contents, "") {
768-
const std::string &dir_path = arg;
768+
const std::string& dir_path = arg;
769769
std::vector<FileAndContents> files_and_contents;
770-
for (const auto &dir_ent : std::filesystem::directory_iterator(dir_path)) {
770+
for (const auto& dir_ent : std::filesystem::directory_iterator(dir_path)) {
771771
auto file_and_contents = FileAndContents{dir_ent.path().filename()};
772772
ReadFromLocalFile(dir_ent.path().c_str(), file_and_contents.contents);
773773
files_and_contents.push_back(std::move(file_and_contents));
@@ -843,7 +843,7 @@ class UndetectedCrashingInputMock : public CentipedeCallbacks {
843843
if (!first_pass_) {
844844
num_inputs_triaged_ += inputs.size();
845845
}
846-
for (const auto &input : inputs) {
846+
for (const auto& input : inputs) {
847847
FUZZTEST_CHECK_EQ(input.size(), 1); // By construction in `Mutate()`.
848848
// The contents of each mutant is its sequential number.
849849
if (input[0] == crashing_input_idx_) {
@@ -933,7 +933,7 @@ TEST(Centipede, UndetectedCrashingInput) {
933933
absl::StrCat("crashing_batch-", crashing_input_hash);
934934
EXPECT_TRUE(std::filesystem::exists(crashes_dir_path)) << crashes_dir_path;
935935
std::vector<std::string> found_crash_file_names;
936-
for (auto const &dir_ent :
936+
for (auto const& dir_ent :
937937
std::filesystem::directory_iterator(crashes_dir_path)) {
938938
found_crash_file_names.push_back(dir_ent.path().filename());
939939
}
@@ -963,14 +963,8 @@ TEST_F(CentipedeWithTemporaryLocalDir, GetsSeedInputs) {
963963
CentipedeDefaultCallbacks callbacks(env, stop_condition);
964964

965965
std::vector<ByteArray> seeds;
966-
EXPECT_EQ(callbacks.GetSeeds(10, seeds), 10);
967-
EXPECT_THAT(seeds, testing::ContainerEq(std::vector<ByteArray>{
968-
{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}}));
969-
EXPECT_EQ(callbacks.GetSeeds(5, seeds), 10);
970-
EXPECT_THAT(seeds, testing::ContainerEq(
971-
std::vector<ByteArray>{{0}, {1}, {2}, {3}, {4}}));
972-
EXPECT_EQ(callbacks.GetSeeds(100, seeds), 10);
973-
EXPECT_THAT(seeds, testing::ContainerEq(std::vector<ByteArray>{
966+
callbacks.GetSeeds(10, seeds);
967+
EXPECT_THAT(seeds, testing::IsSupersetOf(std::vector<ByteArray>{
974968
{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}}));
975969
}
976970

@@ -1072,8 +1066,8 @@ TEST_F(CentipedeWithTemporaryLocalDir, DetectsStackOverflow) {
10721066

10731067
ASSERT_FALSE(
10741068
callbacks.Execute(env.binary, AsByteSpans(inputs), batch_result));
1075-
EXPECT_THAT(batch_result.log(), HasSubstr("Stack limit exceeded"));
1076-
EXPECT_EQ(batch_result.failure_description(), "stack-limit-exceeded");
1069+
EXPECT_THAT(batch_result.failure_description(),
1070+
HasSubstr("stack-limit-exceeded"));
10771071
}
10781072

10791073
class SetupFailureCallbacks : public CentipedeCallbacks {
@@ -1277,12 +1271,13 @@ TEST_F(CentipedeWithTemporaryLocalDir, UsesProvidedCustomMutator) {
12771271
"centipede/testing/fuzz_target_with_custom_mutator");
12781272
CentipedeDefaultCallbacks callbacks(env, stop_condition);
12791273

1280-
const std::vector<ByteArray> inputs = {{1}, {2}, {3}, {4}, {5}, {6}};
1281-
const std::vector<Mutant> mutants = callbacks.Mutate(
1282-
GetMutationInputRefsFromDataInputs(inputs), inputs.size());
1274+
const std::vector<ByteArray> inputs = {{99}};
1275+
const std::vector<Mutant> mutants =
1276+
callbacks.Mutate(GetMutationInputRefsFromDataInputs(inputs), 5);
12831277

1284-
// The custom mutator just returns the original inputs as mutants.
1285-
EXPECT_EQ(inputs, GetDataFromMutants(mutants));
1278+
// The custom mutator just duplicates the original inputs as mutants.
1279+
EXPECT_EQ(GetDataFromMutants(mutants),
1280+
(std::vector<ByteArray>{{99}, {99}, {99}, {99}, {99}}));
12861281
}
12871282

12881283
TEST_F(CentipedeWithTemporaryLocalDir, FailsOnMisbehavingCustomMutator) {
@@ -1400,14 +1395,14 @@ TEST_F(CentipedeWithTemporaryLocalDir, EngineWorksInWorkerMode) {
14001395
env.test_name = "some_test";
14011396
env.populate_binary_info = false;
14021397
env.fork_server = false;
1403-
env.persistent_mode = false;
1398+
env.persistent_mode = true;
14041399
env.exit_on_crash = true;
1400+
env.stop_at = absl::Now() + absl::Seconds(10);
14051401
fuzztest::internal::DefaultCallbacksFactory<
14061402
fuzztest::internal::CentipedeDefaultCallbacks>
14071403
callbacks;
1408-
EXPECT_DEATH(
1409-
[&] { std::exit(CentipedeMain(env, callbacks)); }(),
1410-
ContainsRegex("Failure *: INPUT FAILURE: some_failure_description"));
1404+
EXPECT_DEATH([&] { std::exit(CentipedeMain(env, callbacks)); }(),
1405+
ContainsRegex("Failure *: some_failure_description"));
14111406
}
14121407

14131408
TEST_F(CentipedeWithTemporaryLocalDir, EngineWorksInStandaloneMode) {
@@ -1427,7 +1422,7 @@ TEST_F(CentipedeWithTemporaryLocalDir, EngineWorksInStandaloneMode) {
14271422
const int status = std::system(test_command.c_str());
14281423
std::exit(WEXITSTATUS(status));
14291424
}(),
1430-
ContainsRegex("Failure *: INPUT FAILURE: some_failure_description"));
1425+
ContainsRegex("Failure *: some_failure_description"));
14311426
}
14321427

14331428
} // namespace

0 commit comments

Comments
 (0)