NFC: Rename mutation_input.h to mutation_data.h to include the output types. This is to enable mutator to return extra information with the mutants, as such the origins, which are needed for input reduction and entropy-based corpus scheduling. PiperOrigin-RevId: 877418585
diff --git a/centipede/BUILD b/centipede/BUILD index 4e1de94..15fc743 100644 --- a/centipede/BUILD +++ b/centipede/BUILD
@@ -369,7 +369,7 @@ deps = [ ":centipede_callbacks", ":environment", - ":mutation_input", + ":mutation_data", ":runner_result", ":stop", ":thread_pool", @@ -442,6 +442,7 @@ # used in centipede_runner. ":feature", ":execution_metadata", + ":mutation_data", ":shared_memory_blob_sequence", "@com_google_fuzztest//common:defs", ], @@ -457,14 +458,14 @@ # used in centipede_runner. ":shared_memory_blob_sequence", ":execution_metadata", - ":mutation_input", + ":mutation_data", "@com_google_fuzztest//common:defs", ], ) cc_library( - name = "mutation_input", - hdrs = ["mutation_input.h"], + name = "mutation_data", + hdrs = ["mutation_data.h"], copts = DISABLE_SANCOV_COPTS, deps = [ # This target must have a minimal set of dependencies since it is @@ -483,7 +484,7 @@ deps = [ ":execution_metadata", ":knobs", - ":mutation_input", + ":mutation_data", "@abseil-cpp//absl/base:nullability", "@com_google_fuzztest//common:defs", ], @@ -627,7 +628,7 @@ ":control_flow", ":environment", ":fuzztest_mutator", - ":mutation_input", + ":mutation_data", ":runner_request", ":runner_result", ":shared_memory_blob_sequence", @@ -719,7 +720,7 @@ ":environment", ":feature", ":feature_set", - ":mutation_input", + ":mutation_data", ":pc_info", ":runner_result", ":rusage_profiler", @@ -855,7 +856,7 @@ deps = [ ":centipede_callbacks", ":environment", - ":mutation_input", + ":mutation_data", ":runner_result", ":stop", "@abseil-cpp//absl/status", @@ -873,7 +874,7 @@ ":byte_array_mutator", ":execution_metadata", ":knobs", - ":mutation_input", + ":mutation_data", "@abseil-cpp//absl/random", "@abseil-cpp//absl/types:span", "@com_google_fuzztest//common:defs", @@ -958,6 +959,7 @@ hdrs = ["dispatcher.h"], deps = [ ":execution_metadata", + ":mutation_data", ":runner_request", ":runner_result", ":shared_memory_blob_sequence", @@ -1033,7 +1035,7 @@ ":foreach_nonzero", ":int_utils", ":knobs", - ":mutation_input", + ":mutation_data", ":rolling_hash", ":runner_cmp_trace", ":runner_fork_server", @@ -1098,7 +1100,7 @@ linkstatic = True, # Must be linked statically even when dynamic_mode=on. deps = [ ":centipede_runner_no_main", - ":mutation_input", + ":mutation_data", "@abseil-cpp//absl/base:nullability", "@com_google_fuzztest//common:defs", ], @@ -1237,7 +1239,7 @@ ":corpus", ":environment", ":feature", - ":mutation_input", + ":mutation_data", ":runner_result", ":util", "@com_google_fuzztest//common:defs", @@ -1509,6 +1511,7 @@ deps = [ ":execution_metadata", ":feature", + ":mutation_data", ":runner_result", ":shared_memory_blob_sequence", "@com_google_fuzztest//common:defs", @@ -1518,10 +1521,10 @@ ) cc_test( - name = "mutation_input_test", - srcs = ["mutation_input_test.cc"], + name = "mutation_data_test", + srcs = ["mutation_data_test.cc"], deps = [ - ":mutation_input", + ":mutation_data", "@com_google_fuzztest//common:defs", "@googletest//:gtest_main", ], @@ -1534,7 +1537,7 @@ ":byte_array_mutator", ":execution_metadata", ":knobs", - ":mutation_input", + ":mutation_data", ":runner_cmp_trace", "@abseil-cpp//absl/container:flat_hash_set", "@com_google_fuzztest//common:defs", @@ -1567,7 +1570,7 @@ ":execution_metadata", ":fuzztest_mutator", ":knobs", - ":mutation_input", + ":mutation_data", "@abseil-cpp//absl/container:flat_hash_set", "@abseil-cpp//absl/strings", "@com_google_fuzztest//common:defs", @@ -1914,7 +1917,7 @@ ":centipede_interface", ":environment", ":feature", - ":mutation_input", + ":mutation_data", ":runner_result", ":stop", ":util",
diff --git a/centipede/byte_array_mutator.cc b/centipede/byte_array_mutator.cc index 9a29a43..60834c7 100644 --- a/centipede/byte_array_mutator.cc +++ b/centipede/byte_array_mutator.cc
@@ -24,7 +24,7 @@ #include "./centipede/execution_metadata.h" #include "./centipede/knobs.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./common/defs.h" namespace fuzztest::internal { @@ -321,27 +321,28 @@ // TODO(kcc): add tests with different values of knobs. const KnobId knob_mutate_or_crossover = Knobs::NewId("mutate_or_crossover"); -std::vector<ByteArray> ByteArrayMutator::MutateMany( - const std::vector<MutationInputRef> &inputs, size_t num_mutants) { +std::vector<Mutant> ByteArrayMutator::MutateMany( + const std::vector<MutationInputRef>& inputs, size_t num_mutants) { if (inputs.empty()) abort(); // TODO(xinhaoyuan): Consider metadata in other inputs instead of always the // first one. SetMetadata(inputs[0].metadata != nullptr ? *inputs[0].metadata : ExecutionMetadata()); size_t num_inputs = inputs.size(); - std::vector<ByteArray> mutants; + std::vector<Mutant> mutants; mutants.reserve(num_mutants); for (size_t i = 0; i < num_mutants; ++i) { - auto mutant = inputs[rng_() % num_inputs].data; - if (mutant.size() <= max_len_ && + Mutant mutant; + mutant.data = inputs[rng_() % num_inputs].data; + if (mutant.data.size() <= max_len_ && knobs_.GenerateBool(knob_mutate_or_crossover, rng_())) { // Do crossover only if the mutant is not over the max_len_. // Perform crossover with some other input. It may be the same input. const auto &other_input = inputs[rng_() % num_inputs].data; - CrossOver(mutant, other_input); + CrossOver(mutant.data, other_input); } else { // Perform mutation. - Mutate(mutant); + Mutate(mutant.data); } mutants.push_back(std::move(mutant)); }
diff --git a/centipede/byte_array_mutator.h b/centipede/byte_array_mutator.h index 3c6978c..cec8208 100644 --- a/centipede/byte_array_mutator.h +++ b/centipede/byte_array_mutator.h
@@ -25,7 +25,7 @@ #include "absl/base/nullability.h" #include "./centipede/execution_metadata.h" #include "./centipede/knobs.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./common/defs.h" namespace fuzztest::internal { @@ -108,8 +108,8 @@ } // Takes non-empty `inputs` and produces `num_mutants` mutants. - std::vector<ByteArray> MutateMany(const std::vector<MutationInputRef> &inputs, - size_t num_mutants); + std::vector<Mutant> MutateMany(const std::vector<MutationInputRef>& inputs, + size_t num_mutants); using CrossOverFn = void (ByteArrayMutator::*)(ByteArray &, const ByteArray &);
diff --git a/centipede/byte_array_mutator_test.cc b/centipede/byte_array_mutator_test.cc index ae35641..7c20d48 100644 --- a/centipede/byte_array_mutator_test.cc +++ b/centipede/byte_array_mutator_test.cc
@@ -25,7 +25,7 @@ #include "absl/container/flat_hash_set.h" #include "./centipede/execution_metadata.h" #include "./centipede/knobs.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_cmp_trace.h" #include "./common/defs.h" @@ -928,12 +928,12 @@ {0, 1, 2, 3, 4, 5, 6, 7}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, }; - const std::vector<ByteArray> mutants = + const std::vector<Mutant> mutants = mutator.MutateMany(GetMutationInputRefsFromDataInputs(aligned_inputs), kNumMutantsToGenerate); EXPECT_EQ(mutants.size(), kNumMutantsToGenerate); - for (const ByteArray &mutant : mutants) { - EXPECT_EQ(mutant.size() % kSizeAlignment, 0); + for (const Mutant& mutant : mutants) { + EXPECT_EQ(mutant.data.size() % kSizeAlignment, 0); } } @@ -958,13 +958,13 @@ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, }; - const std::vector<ByteArray> mutants = + const std::vector<Mutant> mutants = mutator.MutateMany(GetMutationInputRefsFromDataInputs(unaligned_inputs), kNumMutantsToGenerate); EXPECT_EQ(mutants.size(), kNumMutantsToGenerate); - for (const ByteArray &mutant : mutants) { - if (mutant.size() % kSizeAlignment != 0) { - EXPECT_LE(mutant.size(), 11); + for (const Mutant& mutant : mutants) { + if (mutant.data.size() % kSizeAlignment != 0) { + EXPECT_LE(mutant.data.size(), 11); } } } @@ -982,12 +982,12 @@ {0, 1, 2}, {0, 1, 2, 3}, }; - const std::vector<ByteArray> mutants = mutator.MutateMany( + const std::vector<Mutant> mutants = mutator.MutateMany( GetMutationInputRefsFromDataInputs(inputs), kNumMutantsToGenerate); EXPECT_EQ(mutants.size(), kNumMutantsToGenerate); - for (const ByteArray &mutant : mutants) { - EXPECT_LE(mutant.size(), kMaxLen); + for (const Mutant& mutant : mutants) { + EXPECT_LE(mutant.data.size(), kMaxLen); } } @@ -1001,16 +1001,16 @@ const std::vector<ByteArray> large_input = { {0, 1, 2, 3, 4, 5, 6, 7}, {0}, {0, 1}, {0, 1, 2}, {0, 1, 2, 3}, }; - const std::vector<ByteArray> mutants = mutator.MutateMany( + const std::vector<Mutant> mutants = mutator.MutateMany( GetMutationInputRefsFromDataInputs(large_input), kNumMutantsToGenerate); EXPECT_EQ(mutants.size(), kNumMutantsToGenerate); - for (const ByteArray &mutant : mutants) { - if (mutant.size() > kMaxLen) { + for (const Mutant& mutant : mutants) { + if (mutant.data.size() > kMaxLen) { // The only mutant larger than max length should be the same large input // that mutation originally started with. All other mutants should be // within the maximum length specified. - EXPECT_EQ(mutant, large_input[0]); + EXPECT_EQ(mutant.data, large_input[0]); } } }
diff --git a/centipede/centipede.cc b/centipede/centipede.cc index b18f995..2dab183 100644 --- a/centipede/centipede.cc +++ b/centipede/centipede.cc
@@ -82,7 +82,7 @@ #include "./centipede/environment.h" #include "./centipede/feature.h" #include "./centipede/feature_set.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_result.h" #include "./centipede/rusage_profiler.h" #include "./centipede/rusage_stats.h" @@ -427,10 +427,10 @@ } bool Centipede::RunBatch( - const std::vector<ByteArray> &input_vec, - BlobFileWriter *absl_nullable corpus_file, - BlobFileWriter *absl_nullable features_file, - BlobFileWriter *absl_nullable unconditional_features_file) { + const std::vector<ByteArray>& input_vec, + BlobFileWriter* absl_nullable corpus_file, + BlobFileWriter* absl_nullable features_file, + BlobFileWriter* absl_nullable unconditional_features_file) { BatchResult batch_result; bool success = ExecuteAndReportCrash(env_.binary, input_vec, batch_result); FUZZTEST_CHECK_EQ(input_vec.size(), batch_result.results().size()); @@ -868,14 +868,19 @@ MutationInputRef{corpus_record.data, &corpus_record.metadata}); } - const std::vector<ByteArray> mutants = + std::vector<Mutant> mutants = user_callbacks_.Mutate(mutation_inputs, batch_size); if (ShouldStop()) break; - - bool gained_new_coverage = - RunBatch(mutants, corpus_file.get(), features_file.get(), nullptr); new_runs += mutants.size(); + std::vector<ByteArray> inputs; + inputs.reserve(mutants.size()); + for (auto& mutant : mutants) { + inputs.push_back(std::move(mutant.data)); + } + bool gained_new_coverage = + RunBatch(inputs, corpus_file.get(), features_file.get(), nullptr); + if (gained_new_coverage) { UpdateAndMaybeLogStats("new-feature", 1); } else if (((batch_index - 1) & batch_index) == 0) {
diff --git a/centipede/centipede.h b/centipede/centipede.h index 625938f..aa25a42 100644 --- a/centipede/centipede.h +++ b/centipede/centipede.h
@@ -84,10 +84,10 @@ // * its features are written to `features_file` (if that's non-null). // Returns true if new features were observed. // Post-condition: `batch_result.results.size()` == `input_vec.size()`. - bool RunBatch(const std::vector<ByteArray> &input_vec, - BlobFileWriter *absl_nullable corpus_file, - BlobFileWriter *absl_nullable features_file, - BlobFileWriter *absl_nullable unconditional_features_file); + bool RunBatch(const std::vector<ByteArray>& input_vec, + BlobFileWriter* absl_nullable corpus_file, + BlobFileWriter* absl_nullable features_file, + BlobFileWriter* absl_nullable unconditional_features_file); // Loads seed inputs from the user callbacks, execute them, and store them // with the corresponding features into `corpus_file` and `features_file`. void LoadSeedInputs(BlobFileWriter *absl_nonnull corpus_file,
diff --git a/centipede/centipede_callbacks.cc b/centipede/centipede_callbacks.cc index 14e11e8..66c6c6c 100644 --- a/centipede/centipede_callbacks.cc +++ b/centipede/centipede_callbacks.cc
@@ -48,7 +48,7 @@ #include "./centipede/binary_info.h" #include "./centipede/command.h" #include "./centipede/control_flow.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_request.h" #include "./centipede/runner_result.h" #include "./centipede/stop.h"
diff --git a/centipede/centipede_callbacks.h b/centipede/centipede_callbacks.h index 0a946f1..181fd2a 100644 --- a/centipede/centipede_callbacks.h +++ b/centipede/centipede_callbacks.h
@@ -30,7 +30,7 @@ #include "./centipede/command.h" #include "./centipede/environment.h" #include "./centipede/fuzztest_mutator.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_result.h" #include "./centipede/shared_memory_blob_sequence.h" #include "./centipede/util.h" @@ -72,8 +72,8 @@ BatchResult &batch_result) = 0; // Takes non-empty `inputs` and returns at most `num_mutants` mutated inputs. - virtual std::vector<ByteArray> Mutate( - const std::vector<MutationInputRef> &inputs, size_t num_mutants) { + virtual std::vector<Mutant> Mutate( + const std::vector<MutationInputRef>& inputs, size_t num_mutants) { return env_.use_legacy_default_mutator ? byte_array_mutator_.MutateMany(inputs, num_mutants) : fuzztest_mutator_.MutateMany(inputs, num_mutants);
diff --git a/centipede/centipede_default_callbacks.cc b/centipede/centipede_default_callbacks.cc index 73b8b8e..67fe09f 100644 --- a/centipede/centipede_default_callbacks.cc +++ b/centipede/centipede_default_callbacks.cc
@@ -25,7 +25,7 @@ #include "absl/status/statusor.h" #include "./centipede/centipede_callbacks.h" #include "./centipede/environment.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_result.h" #include "./centipede/stop.h" #include "./common/defs.h" @@ -72,8 +72,8 @@ "Failed to get serialized configuration from the target binary."); } -std::vector<ByteArray> CentipedeDefaultCallbacks::Mutate( - const std::vector<MutationInputRef> &inputs, size_t num_mutants) { +std::vector<Mutant> CentipedeDefaultCallbacks::Mutate( + const std::vector<MutationInputRef>& inputs, size_t num_mutants) { if (num_mutants == 0) return {}; // In persistent mode, mutation could fail due to previous asynchronous // failure, thus give it one more chance to mutate in a clean state.
diff --git a/centipede/centipede_default_callbacks.h b/centipede/centipede_default_callbacks.h index 0b78562..9fb157f 100644 --- a/centipede/centipede_default_callbacks.h +++ b/centipede/centipede_default_callbacks.h
@@ -28,7 +28,7 @@ #include "absl/status/statusor.h" #include "./centipede/centipede_callbacks.h" #include "./centipede/environment.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_result.h" #include "./common/defs.h" @@ -42,8 +42,8 @@ absl::StatusOr<std::string> GetSerializedTargetConfig() override; bool Execute(std::string_view binary, const std::vector<ByteArray> &inputs, BatchResult &batch_result) override; - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override; private: std::optional<bool> custom_mutator_is_usable_ = std::nullopt;
diff --git a/centipede/centipede_test.cc b/centipede/centipede_test.cc index 16e928f..9454d34 100644 --- a/centipede/centipede_test.cc +++ b/centipede/centipede_test.cc
@@ -38,7 +38,7 @@ #include "./centipede/centipede_interface.h" #include "./centipede/environment.h" #include "./centipede/feature.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_result.h" #include "./centipede/stop.h" #include "./centipede/util.h" @@ -106,19 +106,19 @@ // (the value {0} is produced by the default GetSeeds()). // Next 65536 mutations are 2-byte sequences {0,0} ... {255, 255}. // Then repeat 2-byte sequences. - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - std::vector<ByteArray> mutants; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + std::vector<Mutant> mutants; mutants.reserve(num_mutants); for (size_t i = 0; i < num_mutants; ++i) { num_mutations_++; if (num_mutations_ < 256) { - mutants.push_back({static_cast<uint8_t>(num_mutations_)}); + mutants.push_back({/*data=*/{static_cast<uint8_t>(num_mutations_)}}); continue; } uint8_t byte0 = (num_mutations_ - 256) / 256; uint8_t byte1 = (num_mutations_ - 256) % 256; - mutants.push_back({byte0, byte1}); + mutants.push_back({/*data=*/{byte0, byte1}}); } return mutants; } @@ -350,8 +350,8 @@ } // Will not be called. - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { FUZZTEST_LOG(FATAL); } @@ -436,8 +436,9 @@ GetMutationInputRefsFromDataInputs(inputs), 10000); EXPECT_EQ(result.exit_code(), EXIT_SUCCESS); EXPECT_TRUE(result.has_custom_mutator()); - EXPECT_THAT(result.mutants(), AllOf(IsSupersetOf(all_expected_mutants), - Each(Not(IsEmpty())))); + EXPECT_THAT( + GetDataFromMutants(result.mutants()), + AllOf(IsSupersetOf(all_expected_mutants), Each(Not(IsEmpty())))); } } @@ -451,9 +452,10 @@ 10000); EXPECT_EQ(result.exit_code(), EXIT_SUCCESS); EXPECT_TRUE(result.has_custom_mutator()); - EXPECT_THAT(result.mutants(), AllOf(IsSupersetOf(all_expected_mutants), - Each(Not(IsEmpty())))); - EXPECT_THAT(result.mutants(), + const auto mutant_data = GetDataFromMutants(result.mutants()); + EXPECT_THAT(mutant_data, AllOf(IsSupersetOf(all_expected_mutants), + Each(Not(IsEmpty())))); + EXPECT_THAT(mutant_data, AllOf(IsSupersetOf(all_expected_mutants), Each(Not(IsEmpty())), // The byte_array_mutator may insert up to 20 bytes to an // input, which may push the size over the max_len. @@ -471,9 +473,10 @@ binary_with_custom_mutator, GetMutationInputRefsFromDataInputs(inputs), 10000); // Must contain normal mutants, but not the ones from crossover. - EXPECT_THAT(result.mutants(), IsSupersetOf(some_of_expected_mutants)); + const auto mutant_data = GetDataFromMutants(result.mutants()); + EXPECT_THAT(mutant_data, IsSupersetOf(some_of_expected_mutants)); for (const auto &crossover_mutant : expected_crossover_mutants) { - EXPECT_THAT(result.mutants(), Not(Contains(crossover_mutant))); + EXPECT_THAT(mutant_data, Not(Contains(crossover_mutant))); } } } @@ -497,12 +500,12 @@ } // Every consecutive mutation is {number_of_mutations_} (starting from 1). - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - std::vector<ByteArray> mutants{num_mutants}; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + std::vector<Mutant> mutants(num_mutants); for (auto &mutant : mutants) { - mutant.resize(1); - mutant[0] = ++number_of_mutations_; + mutant.data.resize(1); + mutant.data[0] = ++number_of_mutations_; } return mutants; } @@ -582,17 +585,17 @@ } // Sets the inputs to one of 3 pre-defined values. - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { for (auto &input : inputs) { if (!seed_inputs_.contains(input.data)) { observed_inputs_.insert(input.data); } } - std::vector<ByteArray> mutants; + std::vector<Mutant> mutants; mutants.reserve(num_mutants); for (size_t i = 0; i < num_mutants; ++i) { - mutants.push_back(GetMutant(++number_of_mutations_)); + mutants.push_back({/*data=*/GetMutant(++number_of_mutations_)}); } return mutants; } @@ -703,12 +706,12 @@ } // Sets the mutants to different 1-byte values. - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - std::vector<ByteArray> mutants{num_mutants}; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + std::vector<Mutant> mutants(num_mutants); for (auto &mutant : mutants) { - mutant.resize(1); - mutant[0] = ++number_of_mutations_; + mutant.data.resize(1); + mutant.data[0] = ++number_of_mutations_; } return mutants; } @@ -836,13 +839,13 @@ } // Sets the mutants to different 1-byte values. - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - std::vector<ByteArray> mutants; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + std::vector<Mutant> mutants; mutants.reserve(num_mutants); for (size_t i = 0; i < num_mutants; ++i) { // The contents of each mutant is simply its sequential number. - mutants.push_back({static_cast<uint8_t>(curr_input_idx_++)}); + mutants.push_back({/*data=*/{static_cast<uint8_t>(curr_input_idx_++)}}); } return mutants; } @@ -996,9 +999,9 @@ return true; } - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - return {num_mutants, {0}}; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + return {num_mutants, {/*data=*/{0}}}; } bool thread_check_passed() { return thread_check_passed_; } @@ -1051,9 +1054,9 @@ return false; } - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - return {num_mutants, {0}}; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + return {num_mutants, {/*data=*/{0}}}; } int execute_count() const { return execute_count_; } @@ -1089,9 +1092,9 @@ return false; } - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - return {num_mutants, {0}}; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + return {num_mutants, {/*data=*/{0}}}; } int execute_count() const { return execute_count_; } @@ -1127,9 +1130,9 @@ return false; } - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { - return {num_mutants, {0}}; + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { + return {num_mutants, {/*data=*/{0}}}; } int execute_count() const { return execute_count_; } @@ -1160,11 +1163,11 @@ CentipedeDefaultCallbacks callbacks(env); const std::vector<ByteArray> inputs = {{1}, {2}, {3}, {4}, {5}, {6}}; - const std::vector<ByteArray> mutants = callbacks.Mutate( + const std::vector<Mutant> mutants = callbacks.Mutate( GetMutationInputRefsFromDataInputs(inputs), inputs.size()); // The custom mutator just returns the original inputs as mutants. - EXPECT_EQ(inputs, mutants); + EXPECT_EQ(inputs, GetDataFromMutants(mutants)); } TEST_F(CentipedeWithTemporaryLocalDir, FailsOnMisbehavingCustomMutator) { @@ -1193,12 +1196,12 @@ CentipedeDefaultCallbacks callbacks(env); const std::vector<ByteArray> inputs = {{1}, {2}, {3}, {4}, {5}, {6}}; - const std::vector<ByteArray> mutants = callbacks.Mutate( + const std::vector<Mutant> mutants = callbacks.Mutate( GetMutationInputRefsFromDataInputs(inputs), inputs.size()); // The built-in mutator performs non-trivial mutations. EXPECT_EQ(inputs.size(), mutants.size()); - EXPECT_NE(inputs, mutants); + EXPECT_NE(inputs, GetDataFromMutants(mutants)); } TEST_F(CentipedeWithTemporaryLocalDir,
diff --git a/centipede/dispatcher.cc b/centipede/dispatcher.cc index d82cd28..6980b35 100644 --- a/centipede/dispatcher.cc +++ b/centipede/dispatcher.cc
@@ -31,6 +31,7 @@ #include "absl/base/nullability.h" #include "./centipede/execution_metadata.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_request.h" #include "./centipede/runner_result.h" #include "./centipede/shared_memory_blob_sequence.h" @@ -433,6 +434,7 @@ using fuzztest::internal::kDispatcherTestGetSeedsOutputDirFlagHeader; using fuzztest::internal::kDispatcherTestListingPrefixFlagHeader; using fuzztest::internal::kDispatcherTestNameFlagHeader; +using fuzztest::internal::MutantRef; using fuzztest::internal::MutationResult; int FuzzTestDispatcherIsEnabled() { @@ -535,9 +537,10 @@ "mutant must be non-empty with a valid pointer"); auto* output = GetOutputsBlobSequence(); DispatcherCheck(output != nullptr, "outputs blob sequence must exist"); - DispatcherCheck(MutationResult::WriteMutant( - {static_cast<const uint8_t*>(data), size}, *output), - "failed to write mutant"); + DispatcherCheck( + MutationResult::WriteMutant( + MutantRef{{static_cast<const uint8_t*>(data), size}}, *output), + "failed to write mutant"); } void FuzzTestDispatcherEmitFeedbackAs32BitFeatures(const uint32_t* features,
diff --git a/centipede/fuzztest_mutator.cc b/centipede/fuzztest_mutator.cc index 0690f28..6985fdf 100644 --- a/centipede/fuzztest_mutator.cc +++ b/centipede/fuzztest_mutator.cc
@@ -29,7 +29,7 @@ #include "./centipede/byte_array_mutator.h" #include "./centipede/execution_metadata.h" #include "./centipede/knobs.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./common/defs.h" #include "./common/logging.h" #include "./fuzztest/domain_core.h" @@ -139,12 +139,12 @@ } } -std::vector<ByteArray> FuzzTestMutator::MutateMany( - const std::vector<MutationInputRef> &inputs, size_t num_mutants) { +std::vector<Mutant> FuzzTestMutator::MutateMany( + const std::vector<MutationInputRef>& inputs, size_t num_mutants) { if (inputs.empty()) abort(); auto& cmp_tables = mutation_metadata_->cmp_tables; cmp_tables.resize(inputs.size()); - std::vector<ByteArray> mutants; + std::vector<Mutant> mutants; mutants.reserve(num_mutants); for (int i = 0; i < num_mutants; ++i) { auto index = absl::Uniform<size_t>(prng_, 0, inputs.size()); @@ -152,16 +152,16 @@ cmp_tables[index].emplace(/*compact=*/true); PopulateCmpEntries(*inputs[index].metadata, *cmp_tables[index]); } - auto mutant = inputs[index].data; - if (mutant.size() > max_len_) mutant.resize(max_len_); + Mutant mutant = {/*data=*/inputs[index].data}; + if (mutant.data.size() > max_len_) mutant.data.resize(max_len_); if (knobs_.GenerateBool(knob_mutate_or_crossover, prng_())) { // Perform crossover with some other input. It may be the same input. const auto &other_input = inputs[absl::Uniform<size_t>(prng_, 0, inputs.size())].data; - CrossOver(mutant, other_input); + CrossOver(mutant.data, other_input); } else { domain_->Mutate( - mutant, prng_, + mutant.data, prng_, {/*cmp_tables=*/cmp_tables[index].has_value() ? &*cmp_tables[index] : nullptr}, /*only_shrink=*/false);
diff --git a/centipede/fuzztest_mutator.h b/centipede/fuzztest_mutator.h index 8b68460..ff204f2 100644 --- a/centipede/fuzztest_mutator.h +++ b/centipede/fuzztest_mutator.h
@@ -22,7 +22,7 @@ #include "./centipede/execution_metadata.h" #include "./centipede/knobs.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./common/defs.h" #include "./fuzztest/internal/table_of_recent_compares.h" @@ -44,8 +44,8 @@ ~FuzzTestMutator(); // Takes non-empty `inputs` and produces `num_mutants` mutants. - std::vector<ByteArray> MutateMany(const std::vector<MutationInputRef> &inputs, - size_t num_mutants); + std::vector<Mutant> MutateMany(const std::vector<MutationInputRef>& inputs, + size_t num_mutants); // Adds `dict_entries` to the internal mutation dictionary. void AddToDictionary(const std::vector<ByteArray>& dict_entries);
diff --git a/centipede/fuzztest_mutator_test.cc b/centipede/fuzztest_mutator_test.cc index 327bc83..6c4d747 100644 --- a/centipede/fuzztest_mutator_test.cc +++ b/centipede/fuzztest_mutator_test.cc
@@ -24,7 +24,7 @@ #include "absl/strings/str_join.h" #include "./centipede/execution_metadata.h" #include "./centipede/knobs.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./common/defs.h" namespace fuzztest::internal { @@ -33,6 +33,7 @@ using ::testing::AllOf; using ::testing::Each; +using ::testing::Field; using ::testing::IsSupersetOf; using ::testing::Le; using ::testing::SizeIs; @@ -49,10 +50,10 @@ std::vector<MutationInputRef> mutation_inputs = {{data}}; constexpr size_t kMutantSequenceLength = 100; for (size_t iter = 0; iter < kMutantSequenceLength; iter++) { - const std::vector<ByteArray> mutants = + const std::vector<Mutant> mutants = mutator[i].MutateMany(mutation_inputs, 1); ASSERT_EQ(mutants.size(), 1); - res[i].push_back(mutants[0]); + res[i].push_back(mutants[0].data); } } EXPECT_NE(res[0], res[1]); @@ -64,7 +65,7 @@ FuzzTestMutator mutator(knobs, /*seed=*/1); EXPECT_TRUE(mutator.set_max_len(kMaxLen)); constexpr size_t kNumMutantsToGenerate = 10000; - const std::vector<ByteArray> mutants = mutator.MutateMany( + const std::vector<Mutant> mutants = mutator.MutateMany( { {/*data=*/{0, 1, 2, 3, 4, 5, 6, 7}}, {/*data=*/{0}}, @@ -74,70 +75,70 @@ }, kNumMutantsToGenerate); - EXPECT_THAT(mutants, - AllOf(SizeIs(kNumMutantsToGenerate), Each(SizeIs(Le(kMaxLen))))); + EXPECT_THAT(mutants, AllOf(SizeIs(kNumMutantsToGenerate), + Each(Field(&Mutant::data, SizeIs(Le(kMaxLen)))))); } TEST(FuzzTestMutator, CrossOverInsertsDataFromOtherInputs) { const Knobs knobs; FuzzTestMutator mutator(knobs, /*seed=*/1); constexpr size_t kNumMutantsToGenerate = 100000; - const std::vector<ByteArray> mutants = mutator.MutateMany( + const std::vector<Mutant> mutants = mutator.MutateMany( { {/*data=*/{0, 1, 2, 3}}, {/*data=*/{4, 5, 6, 7}}, }, kNumMutantsToGenerate); - EXPECT_THAT(mutants, IsSupersetOf(std::vector<ByteArray>{ - // The entire other input - {4, 5, 6, 7, 0, 1, 2, 3}, - {0, 1, 4, 5, 6, 7, 2, 3}, - {0, 1, 2, 3, 4, 5, 6, 7}, - // The prefix of other input - {4, 5, 6, 0, 1, 2, 3}, - {0, 1, 4, 5, 6, 2, 3}, - {0, 1, 2, 3, 4, 5, 6}, - // The suffix of other input - {5, 6, 7, 0, 1, 2, 3}, - {0, 1, 5, 6, 7, 2, 3}, - {0, 1, 2, 3, 5, 6, 7}, - // The middle of other input - {5, 6, 0, 1, 2, 3}, - {0, 1, 5, 6, 2, 3}, - {0, 1, 2, 3, 5, 6}, - })); + EXPECT_THAT(GetDataFromMutants(mutants), IsSupersetOf(std::vector<ByteArray>{ + // The entire other input + {4, 5, 6, 7, 0, 1, 2, 3}, + {0, 1, 4, 5, 6, 7, 2, 3}, + {0, 1, 2, 3, 4, 5, 6, 7}, + // The prefix of other input + {4, 5, 6, 0, 1, 2, 3}, + {0, 1, 4, 5, 6, 2, 3}, + {0, 1, 2, 3, 4, 5, 6}, + // The suffix of other input + {5, 6, 7, 0, 1, 2, 3}, + {0, 1, 5, 6, 7, 2, 3}, + {0, 1, 2, 3, 5, 6, 7}, + // The middle of other input + {5, 6, 0, 1, 2, 3}, + {0, 1, 5, 6, 2, 3}, + {0, 1, 2, 3, 5, 6}, + })); } TEST(FuzzTestMutator, CrossOverOverwritesDataFromOtherInputs) { const Knobs knobs; FuzzTestMutator mutator(knobs, /*seed=*/1); constexpr size_t kNumMutantsToGenerate = 100000; - const std::vector<ByteArray> mutants = mutator.MutateMany( + const std::vector<Mutant> mutants = mutator.MutateMany( { {/*data=*/{0, 1, 2, 3, 4, 5, 6, 7}}, {/*data=*/{100, 101, 102, 103}}, }, kNumMutantsToGenerate); - EXPECT_THAT(mutants, IsSupersetOf(std::vector<ByteArray>{ - // The entire other input - {100, 101, 102, 103, 4, 5, 6, 7}, - {0, 1, 100, 101, 102, 103, 6, 7}, - {0, 1, 2, 3, 100, 101, 102, 103}, - // The prefix of other input - {100, 101, 102, 3, 4, 5, 6, 7}, - {0, 1, 2, 100, 101, 102, 6, 7}, - {0, 1, 2, 3, 4, 100, 101, 102}, - // The suffix of other input - {101, 102, 103, 3, 4, 5, 6, 7}, - {0, 1, 2, 101, 102, 103, 6, 7}, - {0, 1, 2, 3, 4, 101, 102, 103}, - // The middle of other input - {101, 102, 2, 3, 4, 5, 6, 7}, - {0, 1, 2, 101, 102, 5, 6, 7}, - {0, 1, 2, 3, 4, 5, 101, 102}, - })); + EXPECT_THAT(GetDataFromMutants(mutants), IsSupersetOf(std::vector<ByteArray>{ + // The entire other input + {100, 101, 102, 103, 4, 5, 6, 7}, + {0, 1, 100, 101, 102, 103, 6, 7}, + {0, 1, 2, 3, 100, 101, 102, 103}, + // The prefix of other input + {100, 101, 102, 3, 4, 5, 6, 7}, + {0, 1, 2, 100, 101, 102, 6, 7}, + {0, 1, 2, 3, 4, 100, 101, 102}, + // The suffix of other input + {101, 102, 103, 3, 4, 5, 6, 7}, + {0, 1, 2, 101, 102, 103, 6, 7}, + {0, 1, 2, 3, 4, 101, 102, 103}, + // The middle of other input + {101, 102, 2, 3, 4, 5, 6, 7}, + {0, 1, 2, 101, 102, 5, 6, 7}, + {0, 1, 2, 3, 4, 5, 101, 102}, + })); } // Test parameter containing the mutation settings and the expectations of a @@ -181,12 +182,12 @@ const std::vector<MutationInputRef> inputs = { {/*data=*/GetParam().seed_input, /*metadata=*/&metadata}}; for (size_t i = 0; i < GetParam().max_num_iterations; i++) { - const std::vector<ByteArray> mutants = mutator.MutateMany(inputs, 1); + const std::vector<Mutant> mutants = mutator.MutateMany(inputs, 1); ASSERT_EQ(mutants.size(), 1); const auto& mutant = mutants[0]; - EXPECT_FALSE(unexpected_mutants.contains(mutant)) - << "Unexpected mutant: {" << absl::StrJoin(mutant, ",") << "}"; - unmatched_expected_mutants.erase(mutant); + EXPECT_FALSE(unexpected_mutants.contains(mutant.data)) + << "Unexpected mutant: {" << absl::StrJoin(mutant.data, ",") << "}"; + unmatched_expected_mutants.erase(mutant.data); if (unmatched_expected_mutants.empty() && i >= GetParam().min_num_iterations) break;
diff --git a/centipede/minimize_crash.cc b/centipede/minimize_crash.cc index d9fa681..2f41046 100644 --- a/centipede/minimize_crash.cc +++ b/centipede/minimize_crash.cc
@@ -26,7 +26,7 @@ #include "absl/synchronization/mutex.h" #include "./centipede/centipede_callbacks.h" #include "./centipede/environment.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_result.h" #include "./centipede/stop.h" #include "./centipede/thread_pool.h" @@ -114,11 +114,11 @@ // discarding all inputs that are too large. // TODO(kcc): modify the Mutate() interface such that max_len can be passed. // - const std::vector<ByteArray> mutants = callbacks->Mutate( + const std::vector<Mutant> mutants = callbacks->Mutate( GetMutationInputRefsFromDataInputs(recent_crashers), env.batch_size); std::vector<ByteArray> smaller_mutants; for (const auto &m : mutants) { - if (m.size() < min_known_size) smaller_mutants.push_back(m); + if (m.data.size() < min_known_size) smaller_mutants.push_back(m.data); } // Execute all mutants. If a new crasher is found, add it to `queue`.
diff --git a/centipede/mutation_input.h b/centipede/mutation_data.h similarity index 60% rename from centipede/mutation_input.h rename to centipede/mutation_data.h index 504c753..a4ef7f1 100644 --- a/centipede/mutation_input.h +++ b/centipede/mutation_data.h
@@ -12,12 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Data types used for mutation inputs. +// Data types used for mutation. // // This library is for both engine and runner. -#ifndef THIRD_PARTY_CENTIPEDE_MUTATION_INPUT_H_ -#define THIRD_PARTY_CENTIPEDE_MUTATION_INPUT_H_ +#ifndef THIRD_PARTY_CENTIPEDE_MUTATION_DATA_H_ +#define THIRD_PARTY_CENTIPEDE_MUTATION_DATA_H_ #include <vector> @@ -48,6 +48,39 @@ return results; } +// Represents a mutation result. +struct Mutant { + // The mutant `data`. + ByteArray data; +}; + +inline bool operator==(const Mutant& mutant, const Mutant& other) { + return mutant.data == other.data; +} + +// A reference counterpart of `Mutant`. Needed because it can be constructed +// from std::string and/or by the C-only dispatcher without copying the +// underlying data. +struct MutantRef { + MutantRef() = default; + + explicit MutantRef(const Mutant& mutant) : data(mutant.data) {} + + explicit MutantRef(ByteSpan data) : data(data) {} + + ByteSpan data; +}; + +inline std::vector<ByteArray> GetDataFromMutants( + const std::vector<Mutant>& mutants) { + std::vector<ByteArray> results; + results.reserve(mutants.size()); + for (const auto& mutant : mutants) { + results.push_back(mutant.data); + } + return results; +} + } // namespace fuzztest::internal -#endif // THIRD_PARTY_CENTIPEDE_MUTATION_INPUT_H_ +#endif // THIRD_PARTY_CENTIPEDE_MUTATION_DATA_H_
diff --git a/centipede/mutation_input_test.cc b/centipede/mutation_data_test.cc similarity index 96% rename from centipede/mutation_input_test.cc rename to centipede/mutation_data_test.cc index f1bc741..4ccf7ca 100644 --- a/centipede/mutation_input_test.cc +++ b/centipede/mutation_data_test.cc
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include <vector>
diff --git a/centipede/runner.cc b/centipede/runner.cc index fbf5a2b..4324529 100644 --- a/centipede/runner.cc +++ b/centipede/runner.cc
@@ -53,7 +53,7 @@ #include "./centipede/dispatcher_flag_helper.h" #include "./centipede/execution_metadata.h" #include "./centipede/feature.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_interface.h" #include "./centipede/runner_request.h" #include "./centipede/runner_result.h" @@ -327,8 +327,8 @@ std::string RunnerCallbacks::GetSerializedTargetConfig() { return ""; } bool RunnerCallbacks::Mutate( - const std::vector<MutationInputRef> & /*inputs*/, size_t /*num_mutants*/, - std::function<void(ByteSpan)> /*new_mutant_callback*/) { + const std::vector<MutationInputRef>& /*inputs*/, size_t /*num_mutants*/, + std::function<void(MutantRef)> /*new_mutant_callback*/) { RunnerCheck(!HasCustomMutator(), "Class deriving from RunnerCallbacks must implement Mutate() if " "HasCustomMutator() returns true."); @@ -358,8 +358,8 @@ return custom_mutator_cb_ != nullptr; } - bool Mutate(const std::vector<MutationInputRef> &inputs, size_t num_mutants, - std::function<void(ByteSpan)> new_mutant_callback) override; + bool Mutate(const std::vector<MutationInputRef>& inputs, size_t num_mutants, + std::function<void(MutantRef)> new_mutant_callback) override; private: FuzzerTestOneInputCallback test_one_input_cb_; @@ -623,7 +623,7 @@ } if (!callbacks.HasCustomMutator()) return EXIT_SUCCESS; - if (!callbacks.Mutate(input_refs, num_mutants, [&](ByteSpan mutant) { + if (!callbacks.Mutate(input_refs, num_mutants, [&](MutantRef mutant) { MutationResult::WriteMutant(mutant, outputs_blobseq); })) { return EXIT_FAILURE; @@ -632,36 +632,41 @@ } bool LegacyRunnerCallbacks::Mutate( - const std::vector<MutationInputRef> &inputs, size_t num_mutants, - std::function<void(ByteSpan)> new_mutant_callback) { + const std::vector<MutationInputRef>& inputs, size_t num_mutants, + std::function<void(MutantRef)> new_mutant_callback) { if (custom_mutator_cb_ == nullptr) return false; unsigned int seed = GetRandomSeed(); const size_t num_inputs = inputs.size(); const size_t max_mutant_size = state->run_time_flags.max_len; constexpr size_t kAverageMutationAttempts = 2; - ByteArray mutant(max_mutant_size); + // Reused across iterations to save memory allocations. + Mutant mutant; for (size_t attempt = 0, num_outputs = 0; attempt < num_mutants * kAverageMutationAttempts && num_outputs < num_mutants; ++attempt) { - const auto &input_data = inputs[rand_r(&seed) % num_inputs].data; - + const auto& input_data = inputs[rand_r(&seed) % num_inputs].data; size_t size = std::min(input_data.size(), max_mutant_size); - std::copy(input_data.cbegin(), input_data.cbegin() + size, mutant.begin()); + mutant.data.resize(max_mutant_size); + std::copy(input_data.cbegin(), input_data.cbegin() + size, + mutant.data.begin()); size_t new_size = 0; if ((custom_crossover_cb_ != nullptr) && rand_r(&seed) % 100 < state->run_time_flags.crossover_level) { // Perform crossover `crossover_level`% of the time. const auto &other_data = inputs[rand_r(&seed) % num_inputs].data; - new_size = custom_crossover_cb_( - input_data.data(), input_data.size(), other_data.data(), - other_data.size(), mutant.data(), max_mutant_size, rand_r(&seed)); + new_size = custom_crossover_cb_(input_data.data(), input_data.size(), + other_data.data(), other_data.size(), + mutant.data.data(), max_mutant_size, + rand_r(&seed)); } else { - new_size = custom_mutator_cb_(mutant.data(), size, max_mutant_size, + new_size = custom_mutator_cb_(mutant.data.data(), size, max_mutant_size, rand_r(&seed)); } if (new_size == 0) continue; - new_mutant_callback({mutant.data(), new_size}); + if (new_size > max_mutant_size) new_size = max_mutant_size; + mutant.data.resize(new_size); + new_mutant_callback(MutantRef{mutant}); ++num_outputs; } return true;
diff --git a/centipede/runner_interface.h b/centipede/runner_interface.h index 09e2bbd..cfbf849 100644 --- a/centipede/runner_interface.h +++ b/centipede/runner_interface.h
@@ -25,7 +25,7 @@ #include <vector> #include "absl/base/nullability.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./common/defs.h" // Typedefs for the libFuzzer API, https://llvm.org/docs/LibFuzzer.html @@ -153,9 +153,9 @@ // // TODO(xinhaoyuan): Consider supporting only_shrink to speed up // input shrinking. - virtual bool Mutate(const std::vector<MutationInputRef> &inputs, + virtual bool Mutate(const std::vector<MutationInputRef>& inputs, size_t num_mutants, - std::function<void(ByteSpan)> new_mutant_callback); + std::function<void(MutantRef)> new_mutant_callback); virtual ~RunnerCallbacks() = default; };
diff --git a/centipede/runner_request.cc b/centipede/runner_request.cc index 7d286d3..6a33cb7 100644 --- a/centipede/runner_request.cc +++ b/centipede/runner_request.cc
@@ -18,7 +18,7 @@ #include <vector> #include "./centipede/execution_metadata.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/shared_memory_blob_sequence.h" #include "./common/defs.h"
diff --git a/centipede/runner_request.h b/centipede/runner_request.h index 63b90a2..f95189f 100644 --- a/centipede/runner_request.h +++ b/centipede/runner_request.h
@@ -21,7 +21,7 @@ #include <vector> #include "./centipede/execution_metadata.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/shared_memory_blob_sequence.h" #include "./common/defs.h"
diff --git a/centipede/runner_result.cc b/centipede/runner_result.cc index 3b726e7..7760fa5 100644 --- a/centipede/runner_result.cc +++ b/centipede/runner_result.cc
@@ -22,6 +22,7 @@ #include "./centipede/execution_metadata.h" #include "./centipede/feature.h" +#include "./centipede/mutation_data.h" #include "./centipede/shared_memory_blob_sequence.h" #include "./common/defs.h" @@ -185,8 +186,8 @@ reinterpret_cast<const uint8_t *>(&has_custom_mutator)}); } -bool MutationResult::WriteMutant(ByteSpan mutant, BlobSequence &blobseq) { - return blobseq.Write({kTagMutant, mutant.size(), mutant.data()}); +bool MutationResult::WriteMutant(MutantRef mutant, BlobSequence& blobseq) { + return blobseq.Write({kTagMutant, mutant.data.size(), mutant.data.data()}); } bool MutationResult::Read(size_t num_mutants, BlobSequence &blobseq) { @@ -202,7 +203,7 @@ const Blob blob = blobseq.Read(); if (blob.tag != kTagMutant) return false; if (blob.size == 0) break; - mutants_.emplace_back(blob.data, blob.data + blob.size); + mutants_.push_back({ByteArray{blob.data, blob.data + blob.size}}); } return true; }
diff --git a/centipede/runner_result.h b/centipede/runner_result.h index 1b94f31..8266103 100644 --- a/centipede/runner_result.h +++ b/centipede/runner_result.h
@@ -25,6 +25,7 @@ #include "./centipede/execution_metadata.h" #include "./centipede/feature.h" +#include "./centipede/mutation_data.h" #include "./centipede/shared_memory_blob_sequence.h" #include "./common/defs.h" @@ -217,7 +218,7 @@ BlobSequence& blobseq); // Writes one mutant to `blobseq`. Returns true iff successful. - static bool WriteMutant(ByteSpan mutant, BlobSequence& blobseq); + static bool WriteMutant(MutantRef mutant, BlobSequence& blobseq); // Reads whether the target has a custom mutator, and if so, reads at most // `num_mutants` mutants from `blobseq`. Returns true iff successful. @@ -227,13 +228,13 @@ int exit_code() const { return exit_code_; } int& exit_code() { return exit_code_; } bool has_custom_mutator() const { return has_custom_mutator_; } - const std::vector<ByteArray>& mutants() const& { return mutants_; } - std::vector<ByteArray>&& mutants() && { return std::move(mutants_); } + const std::vector<Mutant>& mutants() const& { return mutants_; } + std::vector<Mutant>&& mutants() && { return std::move(mutants_); } private: int exit_code_ = EXIT_SUCCESS; bool has_custom_mutator_ = false; - std::vector<ByteArray> mutants_; + std::vector<Mutant> mutants_; }; } // namespace fuzztest::internal
diff --git a/centipede/runner_result_test.cc b/centipede/runner_result_test.cc index 864401a..5ac46f3 100644 --- a/centipede/runner_result_test.cc +++ b/centipede/runner_result_test.cc
@@ -29,6 +29,7 @@ #include "gtest/gtest.h" #include "./centipede/execution_metadata.h" #include "./centipede/feature.h" +#include "./centipede/mutation_data.h" #include "./centipede/shared_memory_blob_sequence.h" #include "./common/defs.h" #include "./common/test_util.h" @@ -213,9 +214,9 @@ // Write a mutation result. ASSERT_TRUE(MutationResult::WriteHasCustomMutator(true, blobseq)); - ASSERT_TRUE(MutationResult::WriteMutant({1, 2, 3}, blobseq)); - ASSERT_TRUE(MutationResult::WriteMutant({4, 5, 6}, blobseq)); - ASSERT_TRUE(MutationResult::WriteMutant({7, 8, 9}, blobseq)); + ASSERT_TRUE(MutationResult::WriteMutant(MutantRef{{1, 2, 3}}, blobseq)); + ASSERT_TRUE(MutationResult::WriteMutant(MutantRef{{4, 5, 6}}, blobseq)); + ASSERT_TRUE(MutationResult::WriteMutant(MutantRef{{7, 8, 9}}, blobseq)); blobseq.Reset(); MutationResult mutation_result; @@ -224,7 +225,7 @@ EXPECT_TRUE(mutation_result.has_custom_mutator()); EXPECT_THAT( mutation_result.mutants(), - ElementsAre(ByteArray{1, 2, 3}, ByteArray{4, 5, 6}, ByteArray{7, 8, 9})); + ElementsAre(Mutant{{1, 2, 3}}, Mutant{{4, 5, 6}}, Mutant{{7, 8, 9}})); } TEST(ExecutionResult, ReadResultSucceedsOnlyWithInputBegin) {
diff --git a/centipede/test_coverage_util.h b/centipede/test_coverage_util.h index c06a9bf..4a61ab3 100644 --- a/centipede/test_coverage_util.h +++ b/centipede/test_coverage_util.h
@@ -25,7 +25,7 @@ #include "./centipede/corpus.h" #include "./centipede/environment.h" #include "./centipede/feature.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_result.h" #include "./common/defs.h" namespace fuzztest::internal { @@ -50,8 +50,8 @@ FUZZTEST_CHECK_EQ(EXIT_SUCCESS, result); return true; } - std::vector<ByteArray> Mutate(const std::vector<MutationInputRef> &inputs, - size_t num_mutants) override { + std::vector<Mutant> Mutate(const std::vector<MutationInputRef>& inputs, + size_t num_mutants) override { return {}; } };
diff --git a/centipede/testing/BUILD b/centipede/testing/BUILD index e127773..216d83e 100644 --- a/centipede/testing/BUILD +++ b/centipede/testing/BUILD
@@ -85,7 +85,7 @@ "@abseil-cpp//absl/flags:flag", "@abseil-cpp//absl/flags:parse", "@com_google_fuzztest//centipede:centipede_runner_no_main", - "@com_google_fuzztest//centipede:mutation_input", + "@com_google_fuzztest//centipede:mutation_data", "@com_google_fuzztest//common:defs", ], )
diff --git a/centipede/testing/async_failing_target.cc b/centipede/testing/async_failing_target.cc index e66ac8b..3d81ebc 100644 --- a/centipede/testing/async_failing_target.cc +++ b/centipede/testing/async_failing_target.cc
@@ -33,7 +33,7 @@ bool Mutate(const std::vector<fuzztest::internal::MutationInputRef>& inputs, size_t num_mutants, - std::function<void(fuzztest::internal::ByteSpan)> + std::function<void(fuzztest::internal::MutantRef)> new_mutant_callback) override { if (to_fail_in_mutation) { fprintf(stderr, "Fail in mutation\n");
diff --git a/centipede/testing/fuzz_target_with_custom_mutator.cc b/centipede/testing/fuzz_target_with_custom_mutator.cc index a95dbf8..980ab99 100644 --- a/centipede/testing/fuzz_target_with_custom_mutator.cc +++ b/centipede/testing/fuzz_target_with_custom_mutator.cc
@@ -19,7 +19,7 @@ #include "absl/base/nullability.h" #include "absl/flags/flag.h" #include "absl/flags/parse.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_interface.h" #include "./common/defs.h" @@ -28,6 +28,7 @@ "failure."); using fuzztest::internal::ByteSpan; +using fuzztest::internal::MutantRef; class CustomMutatorRunnerCallbacks : public fuzztest::internal::RunnerCallbacks { @@ -38,12 +39,10 @@ bool Mutate(const std::vector<fuzztest::internal::MutationInputRef>& inputs, size_t num_mutants, - std::function<void(ByteSpan)> new_mutant_callback) override { - size_t i = 0; - for (fuzztest::internal::MutationInputRef input : inputs) { - if (i++ >= num_mutants) break; + std::function<void(MutantRef)> new_mutant_callback) override { + for (size_t i = 0; i < inputs.size() && i < num_mutants; ++i) { // Just return the original input as a mutant. - new_mutant_callback(input.data); + new_mutant_callback(MutantRef{inputs[i].data}); } return true; }
diff --git a/fuzztest/internal/BUILD b/fuzztest/internal/BUILD index 0ea46b8..c5d988a 100644 --- a/fuzztest/internal/BUILD +++ b/fuzztest/internal/BUILD
@@ -79,7 +79,7 @@ "@com_google_fuzztest//centipede:environment", "@com_google_fuzztest//centipede:execution_metadata", "@com_google_fuzztest//centipede:fuzztest_mutator", - "@com_google_fuzztest//centipede:mutation_input", + "@com_google_fuzztest//centipede:mutation_data", "@com_google_fuzztest//centipede:runner_result", "@com_google_fuzztest//centipede:stop", "@com_google_fuzztest//centipede:workdir",
diff --git a/fuzztest/internal/centipede_adaptor.cc b/fuzztest/internal/centipede_adaptor.cc index 9bb0256..b323e2f 100644 --- a/fuzztest/internal/centipede_adaptor.cc +++ b/fuzztest/internal/centipede_adaptor.cc
@@ -70,7 +70,7 @@ #include "./centipede/environment.h" #include "./centipede/execution_metadata.h" #include "./centipede/fuzztest_mutator.h" -#include "./centipede/mutation_input.h" +#include "./centipede/mutation_data.h" #include "./centipede/runner_interface.h" #include "./centipede/runner_result.h" #include "./centipede/stop.h" @@ -516,10 +516,8 @@ bool HasCustomMutator() const override { return true; } - bool Mutate(const std::vector<fuzztest::internal::MutationInputRef>& inputs, - size_t num_mutants, - std::function<void(fuzztest::internal::ByteSpan)> - new_mutant_callback) override { + bool Mutate(const std::vector<MutationInputRef>& inputs, size_t num_mutants, + std::function<void(MutantRef)> new_mutant_callback) override { if (inputs.empty()) return false; cmp_tables.resize(inputs.size()); absl::Cleanup cmp_tables_cleaner = [this]() { cmp_tables.clear(); }; @@ -556,7 +554,7 @@ fuzzer_impl_.params_domain_.SerializeCorpus(mutant.args)); } new_mutant_callback( - {(unsigned char*)mutant_data.data(), mutant_data.size()}); + MutantRef{{(unsigned char*)mutant_data.data(), mutant_data.size()}}); } return true; }