Add fuzztest::unstable::ParseReproducerValue function. This function takes a reproducer byte-buffer generated by fuzztest when run with `FUZZTEST_REPRODUCERS_OUT_DIR=` environment variable set and a set of domains and recreates the values which those domains produced when the test failed that generated that reproducer. This can be used to leverage more advanced analysis and minimization tools than can be reasonably used within the fuzztest itself. This function is unstable and not part of the stable public API. It may be changed or removed in the future. PiperOrigin-RevId: 789495655
diff --git a/fuzztest/BUILD b/fuzztest/BUILD index d184dc1..1de585d 100644 --- a/fuzztest/BUILD +++ b/fuzztest/BUILD
@@ -191,6 +191,7 @@ "@abseil-cpp//absl/container:flat_hash_map", "@abseil-cpp//absl/random:bit_gen_ref", "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings:string_view", "@abseil-cpp//absl/types:span", "@com_google_fuzztest//fuzztest/internal:any",
diff --git a/fuzztest/CMakeLists.txt b/fuzztest/CMakeLists.txt index 5a664f2..35ec715 100644 --- a/fuzztest/CMakeLists.txt +++ b/fuzztest/CMakeLists.txt
@@ -38,6 +38,7 @@ absl::flat_hash_map absl::random_bit_gen_ref absl::status + absl::statusor absl::string_view absl::span fuzztest::any
diff --git a/fuzztest/domain_core.h b/fuzztest/domain_core.h index 926aba4..c769223 100644 --- a/fuzztest/domain_core.h +++ b/fuzztest/domain_core.h
@@ -42,6 +42,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/random/bit_gen_ref.h" #include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/types/span.h" #include "./fuzztest/internal/any.h" @@ -1063,6 +1064,39 @@ .WithSerializationDomain(0); } +// UNSTABLE APIs. +// +// IMPORTANT: These functions are internal-facing utility functions and are NOT +// part of the stable public API. They may be changed or removed in a future +// release without notice. +namespace unstable { + +// **UNSABLE API**: Parses raw reproducer data back into the original typed +// input values. +// +// This function can be useful when you need to deserialize the raw byte +// contents of a reproducer file to analyze a failing input with external tools. +// +// Note that the `domains` provided to this function must be identical to those +// used in the `WithDomains(...)` clause of the original FUZZ_TEST. This +// includes the type, order, and configuration of each domain. This function +// cannot verify this condition; any mismatch will lead to garbage output. Any +// change to the version of FuzzTest or the underlying types of the fuzzed +// values may also cause garbage output. +// +// Futhermore 'T' must be a value (not reference) type in passed in +// `Domain<T>`-s and be copyable or movable. This is because unlike with normal +// fuzztest the returned value has a longer lifetime then the fuzztest values +// used to create it. +template <typename... DomainT, + typename ReturnT = std::tuple<typename DomainT::value_type...>> +absl::StatusOr<ReturnT> ParseReproducerValue(std::string_view data, + DomainT... domains) { + return internal::ParseOneReproducerValue( + data, TupleOf(std::forward<DomainT>(domains)...)); +} + +} // namespace unstable } // namespace internal_no_adl // Inject the names from internal_no_adl into fuzztest, without allowing for
diff --git a/fuzztest/internal/domains/BUILD b/fuzztest/internal/domains/BUILD index f5a37a9..66c3467 100644 --- a/fuzztest/internal/domains/BUILD +++ b/fuzztest/internal/domains/BUILD
@@ -65,6 +65,7 @@ "@abseil-cpp//absl/random:bit_gen_ref", "@abseil-cpp//absl/random:distributions", "@abseil-cpp//absl/status", + "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", "@abseil-cpp//absl/time",
diff --git a/fuzztest/internal/domains/CMakeLists.txt b/fuzztest/internal/domains/CMakeLists.txt index f75ee12..6c44277 100644 --- a/fuzztest/internal/domains/CMakeLists.txt +++ b/fuzztest/internal/domains/CMakeLists.txt
@@ -67,6 +67,7 @@ absl::random_bit_gen_ref absl::random_distributions absl::status + absl::statusor absl::strings absl::str_format absl::time
diff --git a/fuzztest/internal/domains/domain.h b/fuzztest/internal/domains/domain.h index 1d38319..801f31e 100644 --- a/fuzztest/internal/domains/domain.h +++ b/fuzztest/internal/domains/domain.h
@@ -26,6 +26,7 @@ #include "absl/functional/function_ref.h" #include "absl/random/bit_gen_ref.h" #include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "./fuzztest/internal/domains/domain_base.h" #include "./fuzztest/internal/domains/domain_type_erasure.h" // IWYU pragma: export @@ -370,6 +371,28 @@ std::unique_ptr<internal::UntypedDomainConcept> inner_; }; +namespace internal { + +template <typename DomainT> +absl::StatusOr<typename DomainT::value_type> ParseOneReproducerValue( + absl::string_view data, DomainT domain) { + const auto ir_object = IRObject::FromString(data); + if (!ir_object) { + return absl::InvalidArgumentError("Unexpected reproducer format"); + } + const auto corpus = domain.ParseCorpus(*ir_object); + if (!corpus) { + return absl::InvalidArgumentError( + "Unexpected FuzzTest serialization IR Value."); + } + absl::Status valid = domain.ValidateCorpusValue(*corpus); + if (!valid.ok()) { + return valid; + } + return domain.GetValue(*corpus); +} +} // namespace internal + } // namespace fuzztest #endif // FUZZTEST_FUZZTEST_INTERNAL_DOMAINS_DOMAIN_H_