summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Metzman <metzman@chromium.org>2019-04-30 20:56:18 +0000
committerJonathan Metzman <metzman@chromium.org>2019-04-30 20:56:18 +0000
commit0128c9bfa882ac8ca16929201352e3d8bea9aff8 (patch)
tree489fe1452580d40cf3d4f5e799f15c7e906281b9
parent8a8060f4fdb751a3ccf9a63d7c8ab5928f801abe (diff)
downloadcompiler-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.cpp23
-rw-r--r--lib/fuzzer/FuzzerFlags.def3
-rw-r--r--lib/fuzzer/FuzzerFork.cpp9
-rw-r--r--lib/fuzzer/FuzzerIO.cpp5
-rw-r--r--lib/fuzzer/FuzzerIO.h2
-rw-r--r--test/fuzzer/seed_inputs.test24
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