diff options
author | Jonathan Metzman <metzman@chromium.org> | 2019-04-30 20:56:18 +0000 |
---|---|---|
committer | Jonathan Metzman <metzman@chromium.org> | 2019-04-30 20:56:18 +0000 |
commit | 0128c9bfa882ac8ca16929201352e3d8bea9aff8 (patch) | |
tree | 489fe1452580d40cf3d4f5e799f15c7e906281b9 | |
parent | 8a8060f4fdb751a3ccf9a63d7c8ab5928f801abe (diff) | |
download | compiler-rt-0128c9bfa882ac8ca16929201352e3d8bea9aff8.tar.gz |
[libFuzzer] Replace -seed_corpus to better support fork mode on Win
Summary:
Pass seed corpus list in a file to get around argument length limits on Windows.
This limit was preventing many uses of fork mode on Windows.
Reviewers: kcc, morehouse
Reviewed By: kcc
Subscribers: #sanitizers, llvm-commits
Tags: #sanitizers, #llvm
Differential Revision: https://reviews.llvm.org/D60980
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@359610 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/fuzzer/FuzzerDriver.cpp | 23 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerFlags.def | 3 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerFork.cpp | 9 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerIO.cpp | 5 | ||||
-rw-r--r-- | lib/fuzzer/FuzzerIO.h | 2 | ||||
-rw-r--r-- | test/fuzzer/seed_inputs.test | 24 |
6 files changed, 56 insertions, 10 deletions
diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp index a51ac9310..b9c892747 100644 --- a/lib/fuzzer/FuzzerDriver.cpp +++ b/lib/fuzzer/FuzzerDriver.cpp @@ -763,16 +763,25 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { exit(0); } - // Parse -seed_inputs=file1,file2,... + // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file Vector<std::string> ExtraSeedFiles; if (Flags.seed_inputs) { - std::string s = Flags.seed_inputs; - size_t comma_pos; - while ((comma_pos = s.find_last_of(',')) != std::string::npos) { - ExtraSeedFiles.push_back(s.substr(comma_pos + 1)); - s = s.substr(0, comma_pos); + std::string SeedInputs; + if (Flags.seed_inputs[0] == '@') + SeedInputs = FileToString(Flags.seed_inputs + 1); // File contains list. + else + SeedInputs = Flags.seed_inputs; // seed_inputs contains the list. + if (SeedInputs.empty()) { + Printf("seed_inputs is empty or @file does not exist.\n"); + exit(1); + } + // Parse SeedInputs. + size_t comma_pos = 0; + while ((comma_pos = SeedInputs.find_last_of(',')) != std::string::npos) { + ExtraSeedFiles.push_back(SeedInputs.substr(comma_pos + 1)); + SeedInputs = SeedInputs.substr(0, comma_pos); } - ExtraSeedFiles.push_back(s); + ExtraSeedFiles.push_back(SeedInputs); } F->Loop(*Inputs, ExtraSeedFiles); diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def index d3da3e5cb..b4ec5f298 100644 --- a/lib/fuzzer/FuzzerFlags.def +++ b/lib/fuzzer/FuzzerFlags.def @@ -21,7 +21,8 @@ FUZZER_FLAG_INT(len_control, 100, "Try generating small inputs first, " "limit is increased (smaller == faster). If 0, immediately try inputs with " "size up to max_len.") FUZZER_FLAG_STRING(seed_inputs, "A comma-separated list of input files " - "to use as an additional seed corpus") + "to use as an additional seed corpus. Alternatively, an \"@\" followed by " + "the name of a file containing the comma-seperated list.") FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.") FUZZER_FLAG_INT(mutate_depth, 5, "Apply this number of consecutive mutations to each input.") diff --git a/lib/fuzzer/FuzzerFork.cpp b/lib/fuzzer/FuzzerFork.cpp index 9d338aa47..dd16ec1e2 100644 --- a/lib/fuzzer/FuzzerFork.cpp +++ b/lib/fuzzer/FuzzerFork.cpp @@ -66,6 +66,7 @@ struct FuzzJob { std::string CorpusDir; std::string FeaturesDir; std::string LogPath; + std::string SeedListPath; std::string CFPath; // Fuzzing Outputs. @@ -74,6 +75,7 @@ struct FuzzJob { ~FuzzJob() { RemoveFile(CFPath); RemoveFile(LogPath); + RemoveFile(SeedListPath); RmDirRecursive(CorpusDir); RmDirRecursive(FeaturesDir); } @@ -121,8 +123,11 @@ struct GlobalEnv { for (size_t i = 0; i < CorpusSubsetSize; i++) Seeds += (Seeds.empty() ? "" : ",") + Files[Rand->SkewTowardsLast(Files.size())]; - if (!Seeds.empty()) - Cmd.addFlag("seed_inputs", Seeds); + if (!Seeds.empty()) { + Job->SeedListPath = std::to_string(JobId) + ".seeds"; + WriteToFile(Seeds, Job->SeedListPath); + Cmd.addFlag("seed_inputs", "@" + Job->SeedListPath); + } Job->LogPath = DirPlusFile(TempDir, std::to_string(JobId) + ".log"); Job->CorpusDir = DirPlusFile(TempDir, "C" + std::to_string(JobId)); Job->FeaturesDir = DirPlusFile(TempDir, "F" + std::to_string(JobId)); diff --git a/lib/fuzzer/FuzzerIO.cpp b/lib/fuzzer/FuzzerIO.cpp index a8140b601..7e5ba30a2 100644 --- a/lib/fuzzer/FuzzerIO.cpp +++ b/lib/fuzzer/FuzzerIO.cpp @@ -64,6 +64,11 @@ void WriteToFile(const Unit &U, const std::string &Path) { WriteToFile(U.data(), U.size(), Path); } +void WriteToFile(const std::string &Data, const std::string &Path) { + WriteToFile(reinterpret_cast<const uint8_t *>(Data.c_str()), Data.size(), + Path); +} + void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path) { // Use raw C interface because this function may be called from a sig handler. FILE *Out = fopen(Path.c_str(), "wb"); diff --git a/lib/fuzzer/FuzzerIO.h b/lib/fuzzer/FuzzerIO.h index cbfafa5c3..fe0d7b451 100644 --- a/lib/fuzzer/FuzzerIO.h +++ b/lib/fuzzer/FuzzerIO.h @@ -25,6 +25,8 @@ std::string FileToString(const std::string &Path); void CopyFileToErr(const std::string &Path); void WriteToFile(const uint8_t *Data, size_t Size, const std::string &Path); +// Write Data.c_str() to the file without terminating null character. +void WriteToFile(const std::string &Data, const std::string &Path); void WriteToFile(const Unit &U, const std::string &Path); void ReadDirToVectorOfUnits(const char *Path, Vector<Unit> *V, diff --git a/test/fuzzer/seed_inputs.test b/test/fuzzer/seed_inputs.test new file mode 100644 index 000000000..d61e6cf7a --- /dev/null +++ b/test/fuzzer/seed_inputs.test @@ -0,0 +1,24 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-SimpleTest + +USE-1: INFO: seed corpus: files: 1 +RUN: echo -n "%t-SimpleTest" > %t.seed-inputs +# Test both formats of -seed_inputs argument. +RUN: %run %t-SimpleTest -runs=1 -seed_inputs=@%t.seed-inputs 2>&1 | FileCheck %s --check-prefix=USE-1 +RUN: %run %t-SimpleTest -runs=1 -seed_inputs=%t-SimpleTest 2>&1 | FileCheck %s --check-prefix=USE-1 + +USE-2: INFO: seed corpus: files: 2 +RUN: echo -n "%t-SimpleTest,%t-SimpleTest" > %t.seed-inputs +RUN: %run %t-SimpleTest -runs=1 -seed_inputs=@%t.seed-inputs 2>&1 | FileCheck %s --check-prefix=USE-2 +RUN: %run %t-SimpleTest -runs=1 -seed_inputs=%t-SimpleTest,%t-SimpleTest 2>&1 | FileCheck %s --check-prefix=USE-2 + +# Test that missing files and trailing commas are tolerated. +RUN: echo -n "%t-SimpleTest,%t-SimpleTest,nonexistent-file," > %t.seed-inputs +RUN: %run %t-SimpleTest -runs=1 -seed_inputs=@%t.seed-inputs 2>&1 | FileCheck %s --check-prefix=USE-2 +RUN: %run %t-SimpleTest -runs=1 -seed_inputs=%t-SimpleTest,%t-SimpleTest,nonexistent-file, 2>&1 | FileCheck %s --check-prefix=USE-2 + +# Test that using a non existent file or an empty seed list fails. +EMPTY: seed_inputs is empty or @file does not exist. +RUN: not %run %t-SimpleTest -runs=1 -seed_inputs=@nonexistent-file 2>&1 | FileCheck %s --check-prefix=EMPTY +RUN: echo -n "" > %t.seed-inputs +RUN: not %run %t-SimpleTest -runs=1 -seed_inputs=@%t.seed-inputs 2>&1 | FileCheck %s --check-prefix=EMPTY +RUN: not %run %t-SimpleTest -runs=1 -seed_inputs= 2>&1 | FileCheck %s --check-prefix=EMPTY |