From 1e45588f5c895e2f5b30a3b9d4b96b949f12b815 Mon Sep 17 00:00:00 2001 From: Hadi Ravanbakhsh Date: Fri, 21 Nov 2025 08:46:22 -0800 Subject: [PATCH] Support using environment variables for the corpus_database flag PiperOrigin-RevId: 835240175 --- fuzztest/BUILD | 1 + fuzztest/init_fuzztest.cc | 34 +++++++++++++++++++++++++++++----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/fuzztest/BUILD b/fuzztest/BUILD index ad8e66de1..2501598a3 100644 --- a/fuzztest/BUILD +++ b/fuzztest/BUILD @@ -121,6 +121,7 @@ cc_library( deps = [ "@abseil-cpp//absl/algorithm:container", "@abseil-cpp//absl/base:no_destructor", + "@abseil-cpp//absl/container:flat_hash_map", "@abseil-cpp//absl/container:flat_hash_set", "@abseil-cpp//absl/flags:flag", "@abseil-cpp//absl/flags:parse", diff --git a/fuzztest/init_fuzztest.cc b/fuzztest/init_fuzztest.cc index bd137b529..fca4c6f0e 100644 --- a/fuzztest/init_fuzztest.cc +++ b/fuzztest/init_fuzztest.cc @@ -1,5 +1,8 @@ #include "./fuzztest/init_fuzztest.h" +#include "absl/container/flat_hash_map.h" +#include "absl/strings/str_replace.h" + #if defined(__linux__) #include #endif @@ -322,6 +325,23 @@ std::optional GetReplayCorpusTime() { return replay_corpus_time_limit; } +std::string ReplaceEnvVars(absl::string_view flag) { + absl::flat_hash_map envs; + for (auto it_begin = flag.find('{'); it_begin != std::string::npos; + ++it_begin) { + auto it_end = flag.find('}', it_begin + 1); + if (it_end == std::string::npos) break; + absl::string_view env_name = + flag.substr(it_begin + 1, it_end - it_begin - 1); + // Nested environment variables are not supported. + if (absl::StrContains(env_name, '{')) continue; + auto env_value = absl::NullSafeStringView(getenv(env_name.data())); + if (env_value.empty()) continue; + envs.insert({std::string(env_name), std::string(env_value)}); + } + return absl::StrReplaceAll(flag, envs); +} + internal::Configuration CreateConfigurationsFromFlags( absl::string_view binary_identifier) { const bool reproduce_findings_as_separate_tests = @@ -347,11 +367,15 @@ internal::Configuration CreateConfigurationsFromFlags( FUZZTEST_CHECK(!jobs.has_value() || *jobs > 0) << "If specified, --" << FUZZTEST_FLAG(jobs).Name() << " must be positive."; - std::string corpus_database = absl::GetFlag(FUZZTEST_FLAG(corpus_database)); - if (!corpus_database.empty() && corpus_database[0] != '/' && - std::getenv("TEST_SRCDIR")) { - corpus_database = - absl::StrCat(std::getenv("TEST_SRCDIR"), "/", corpus_database); + std::string corpus_database = + ReplaceEnvVars(absl::GetFlag(FUZZTEST_FLAG(corpus_database))); + if (!corpus_database.empty() && corpus_database[0] != '/') { + // TODO(hadi88): Use the undeclared outputs directory instead of + // TEST_SRCDIR once Chlor uses the env_var for corpus_database. + if (std::getenv("TEST_SRCDIR")) { + corpus_database = + absl::StrCat(std::getenv("TEST_SRCDIR"), "/", corpus_database); + } } return internal::Configuration{ corpus_database,