summaryrefslogtreecommitdiff
path: root/lib/fuzzer/FuzzerMerge.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/fuzzer/FuzzerMerge.cpp')
-rw-r--r--lib/fuzzer/FuzzerMerge.cpp73
1 files changed, 54 insertions, 19 deletions
diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp
index c05c49225..e3ad8b385 100644
--- a/lib/fuzzer/FuzzerMerge.cpp
+++ b/lib/fuzzer/FuzzerMerge.cpp
@@ -19,6 +19,7 @@
#include <iterator>
#include <set>
#include <sstream>
+#include <unordered_set>
namespace fuzzer {
@@ -221,7 +222,7 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
U.resize(MaxInputLen);
U.shrink_to_fit();
}
- std::ostringstream StartedLine;
+
// Write the pre-run marker.
OF << "STARTED " << i << " " << U.size() << "\n";
OF.flush(); // Flush is important since Command::Execute may crash.
@@ -260,22 +261,39 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
PrintStatsWrapper("DONE ");
}
-static void WriteNewControlFile(const std::string &CFPath,
- const Vector<SizedFile> &OldCorpus,
- const Vector<SizedFile> &NewCorpus) {
- RemoveFile(CFPath);
- std::ofstream ControlFile(CFPath);
- ControlFile << (OldCorpus.size() + NewCorpus.size()) << "\n";
- ControlFile << OldCorpus.size() << "\n";
+static size_t WriteNewControlFile(const std::string &CFPath,
+ const Vector<SizedFile> &OldCorpus,
+ const Vector<SizedFile> &NewCorpus,
+ const Vector<MergeFileInfo> &KnownFiles) {
+ std::unordered_set<std::string> FilesToSkip;
+ for (auto &SF: KnownFiles)
+ FilesToSkip.insert(SF.Name);
+
+ Vector<std::string> FilesToUse;
+ auto MaybeUseFile = [=, &FilesToUse](std::string Name) {
+ if (FilesToSkip.find(Name) == FilesToSkip.end())
+ FilesToUse.push_back(Name);
+ };
for (auto &SF: OldCorpus)
- ControlFile << SF.File << "\n";
+ MaybeUseFile(SF.File);
+ auto FilesToUseFromOldCorpus = FilesToUse.size();
for (auto &SF: NewCorpus)
- ControlFile << SF.File << "\n";
+ MaybeUseFile(SF.File);
+
+ RemoveFile(CFPath);
+ std::ofstream ControlFile(CFPath);
+ ControlFile << FilesToUse.size() << "\n";
+ ControlFile << FilesToUseFromOldCorpus << "\n";
+ for (auto &FN: FilesToUse)
+ ControlFile << FN << "\n";
+
if (!ControlFile) {
Printf("MERGE-OUTER: failed to write to the control file: %s\n",
CFPath.c_str());
exit(1);
}
+
+ return FilesToUse.size();
}
// Outer process. Does not call the target code and thus should not fail.
@@ -291,12 +309,13 @@ void CrashResistantMerge(const Vector<std::string> &Args,
bool V /*Verbose*/) {
if (NewCorpus.empty() && OldCorpus.empty()) return; // Nothing to merge.
size_t NumAttempts = 0;
+ Vector<MergeFileInfo> KnownFiles;
if (FileSize(CFPath)) {
VPrintf(V, "MERGE-OUTER: non-empty control file provided: '%s'\n",
CFPath.c_str());
Merger M;
std::ifstream IF(CFPath);
- if (M.Parse(IF, /*ParseCoverage=*/false)) {
+ if (M.Parse(IF, /*ParseCoverage=*/true)) {
VPrintf(V, "MERGE-OUTER: control file ok, %zd files total,"
" first not processed file %zd\n",
M.Files.size(), M.FirstNotProcessedFile);
@@ -305,12 +324,25 @@ void CrashResistantMerge(const Vector<std::string> &Args,
"(merge has stumbled on it the last time)\n",
M.LastFailure.c_str());
if (M.FirstNotProcessedFile >= M.Files.size()) {
+ // Merge has already been completed with the given merge control file.
+ if (M.Files.size() == OldCorpus.size() + NewCorpus.size()) {
+ VPrintf(
+ V,
+ "MERGE-OUTER: nothing to do, merge has been completed before\n");
+ exit(0);
+ }
+
+ // Number of input files likely changed, start merge from scratch, but
+ // reuse coverage information from the given merge control file.
VPrintf(
- V, "MERGE-OUTER: nothing to do, merge has been completed before\n");
- exit(0);
+ V,
+ "MERGE-OUTER: starting merge from scratch, but reusing coverage "
+ "information from the given control file\n");
+ KnownFiles = M.Files;
+ } else {
+ // There is a merge in progress, continue.
+ NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
}
-
- NumAttempts = M.Files.size() - M.FirstNotProcessedFile;
} else {
VPrintf(V, "MERGE-OUTER: bad control file, will overwrite it\n");
}
@@ -318,10 +350,11 @@ void CrashResistantMerge(const Vector<std::string> &Args,
if (!NumAttempts) {
// The supplied control file is empty or bad, create a fresh one.
- NumAttempts = OldCorpus.size() + NewCorpus.size();
- VPrintf(V, "MERGE-OUTER: %zd files, %zd in the initial corpus\n",
- NumAttempts, OldCorpus.size());
- WriteNewControlFile(CFPath, OldCorpus, NewCorpus);
+ VPrintf(V, "MERGE-OUTER: "
+ "%zd files, %zd in the initial corpus, %zd processed earlier\n",
+ OldCorpus.size() + NewCorpus.size(), OldCorpus.size(),
+ KnownFiles.size());
+ NumAttempts = WriteNewControlFile(CFPath, OldCorpus, NewCorpus, KnownFiles);
}
// Execute the inner process until it passes.
@@ -358,6 +391,8 @@ void CrashResistantMerge(const Vector<std::string> &Args,
VPrintf(V,
"MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n",
M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb());
+
+ M.Files.insert(M.Files.end(), KnownFiles.begin(), KnownFiles.end());
M.Merge(InitialFeatures, NewFeatures, InitialCov, NewCov, NewFiles);
VPrintf(V, "MERGE-OUTER: %zd new files with %zd new features added; "
"%zd new coverage edges\n",