Skip to content

Commit

Permalink
Provide reproduction command when a reproducer is requested.
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 687030163
  • Loading branch information
hadi88 authored and copybara-github committed Oct 17, 2024
1 parent 44f5a57 commit 79d775c
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 38 deletions.
3 changes: 3 additions & 0 deletions e2e_tests/functional_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,9 @@ TEST_F(FuzzingModeCommandLineInterfaceTest, ReproducerIsDumpedWhenEnvVarIsSet) {
ASSERT_TRUE(parsed) << std_err;
auto args = parsed->ToCorpus<std::tuple<std::string>>();
EXPECT_THAT(args, Optional(FieldsAre(StartsWith("Fuzz")))) << std_err;
EXPECT_THAT(std_err,
HasSubstr(absl::StrCat("Reproducer file was dumped at:\n",
replay_files[0].path)));
}

TEST_F(FuzzingModeCommandLineInterfaceTest, SavesCorpusWhenEnvVarIsSet) {
Expand Down
80 changes: 46 additions & 34 deletions fuzztest/internal/runtime.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,20 +96,29 @@ std::string GetFilterForCrashingInput(absl::string_view crashing_input_path) {
// `configuration.crashing_input_to_reproduce` from a command line, using the
// `configuration.reproduction_command_template`.
std::optional<std::string> GetReproductionCommand(
const Configuration& configuration) {
const Configuration& configuration, absl::string_view reproducer_path,
absl::string_view test_name) {
if (!configuration.reproduction_command_template.has_value()) {
return std::nullopt;
}
if (!configuration.crashing_input_to_reproduce.has_value()) {
return std::nullopt;
}
CHECK(absl::StrContains(*configuration.reproduction_command_template,
kTestFilterPlaceholder));
return absl::StrReplaceAll(
*configuration.reproduction_command_template,
{{kTestFilterPlaceholder,
GetFilterForCrashingInput(
*configuration.crashing_input_to_reproduce)}});
if (configuration.crashing_input_to_reproduce.has_value()) {
return absl::StrReplaceAll(
*configuration.reproduction_command_template,
{{kTestFilterPlaceholder,
GetFilterForCrashingInput(
*configuration.crashing_input_to_reproduce)},
{kExtraArgsPlaceholder, ""}});
} else if (!reproducer_path.empty()) {
return absl::StrReplaceAll(
*configuration.reproduction_command_template,
{{kTestFilterPlaceholder, test_name},
{kExtraArgsPlaceholder,
absl::StrCat("--test_env=FUZZTEST_REPLAY=", reproducer_path)}});
} else {
return std::nullopt;
}
}

struct ReproducerDirectory {
Expand Down Expand Up @@ -233,29 +242,6 @@ void Runtime::PrintReport(RawSink out) const {
trim ? kTrimIndicator : "");
});

// Dump the reproducer if requested.
std::optional<ReproducerDirectory> out_dir = GetReproducerDirectory();
if (out_dir.has_value()) {
absl::Format(out, "%s=== Reproduction\n\n", separator);
const std::string reproducer_path = DumpReproducer(out_dir->path);
if (reproducer_path.empty()) {
absl::FPrintF(GetStderr(), "[!] Failed to write reproducer file!\n");
} else {
switch (out_dir->type) {
case ReproducerDirectory::Type::kUserSpecified:
absl::Format(out, "Reproducer file was dumped at:\n%s\n",
reproducer_path);
break;
case ReproducerDirectory::Type::kTestUndeclaredOutputs:
std::string test_name = absl::StrCat(
current_test_->suite_name(), ".", current_test_->test_name());
PrintReproductionInstructionsForUndeclaredOutputs(
out, reproducer_path, test_name);
break;
}
}
}

// There doesn't seem to be a good way to generate a reproducer test when
// the test uses a fixture (see b/241271658).
if (!current_test_->uses_fixture()) {
Expand Down Expand Up @@ -285,9 +271,35 @@ void Runtime::PrintReport(RawSink out) const {
"For reproducing findings please rely on file based "
"reproduction.\n");
}
// Dump the reproducer if requested.
std::string reproducer_path;
const std::string test_name = absl::StrCat(current_test_->suite_name(), ".",
current_test_->test_name());
std::optional<ReproducerDirectory> out_dir = GetReproducerDirectory();
if (out_dir.has_value() &&
(!current_configuration_ ||
!current_configuration_->crashing_input_to_reproduce)) {
absl::Format(out, "%s=== Reproducer\n\n", separator);
reproducer_path = DumpReproducer(out_dir->path);
absl::Format(out, "dumpted at %s\n\n", reproducer_path);
if (reproducer_path.empty()) {
absl::FPrintF(GetStderr(), "[!] Failed to write reproducer file!\n");
} else {
switch (out_dir->type) {
case ReproducerDirectory::Type::kUserSpecified:
absl::Format(out, "Reproducer file was dumped at:\n%s\n",
reproducer_path);
break;
case ReproducerDirectory::Type::kTestUndeclaredOutputs:
PrintReproductionInstructionsForUndeclaredOutputs(
out, reproducer_path, test_name);
break;
}
}
}
if (current_configuration_ != nullptr) {
const auto reproduction_command =
GetReproductionCommand(*current_configuration_);
const auto reproduction_command = GetReproductionCommand(
*current_configuration_, reproducer_path, test_name);
if (reproduction_command.has_value()) {
absl::Format(out, "%s=== Reproduction command\n\n", separator);
absl::Format(out, "%s\n\n", *reproduction_command);
Expand Down
7 changes: 4 additions & 3 deletions fuzztest/internal/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,11 @@ class FuzzTestFuzzerImpl : public FuzzTestFuzzer {

size_t GetStackLimitFromEnvOrConfiguration(const Configuration& configuration);

// A reproduction command template will include this placeholder. This
// placeholder then will be replaced by the proper test filter when creating the
// final reproduction command from the template.
// A reproduction command template will include these placeholders. These
// placeholders then will be replaced by the proper test filter when creating
// the final reproduction command from the template.
static constexpr absl::string_view kTestFilterPlaceholder = "$TEST_FILTER";
static constexpr absl::string_view kExtraArgsPlaceholder = "$EXTRA_ARGS";

} // namespace internal
} // namespace fuzztest
Expand Down
2 changes: 1 addition & 1 deletion fuzztest/internal/runtime_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ argument 0: 17
argument 1: "ABC"
)"));

EXPECT_TRUE(absl::EndsWith(report, R"(
EXPECT_TRUE(absl::StrContains(report, R"(
=================================================================
=== Regression test draft
Expand Down

0 comments on commit 79d775c

Please sign in to comment.