diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:22 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-10-23 17:52:22 +0000 |
commit | 3a1720af1d7f43edc5b214cde0be11bfb94d077e (patch) | |
tree | 029e0ff2d5e3c0eaf2405fd8e669555fdf5e1297 /lib/fuzzer/FuzzerMerge.cpp | |
parent | 8f3cadc28cb2bb9e8f9d69eeaaea1f57f2f7b2ab (diff) |
Notes
Diffstat (limited to 'lib/fuzzer/FuzzerMerge.cpp')
-rw-r--r-- | lib/fuzzer/FuzzerMerge.cpp | 82 |
1 files changed, 61 insertions, 21 deletions
diff --git a/lib/fuzzer/FuzzerMerge.cpp b/lib/fuzzer/FuzzerMerge.cpp index 75b2b5d59b9c..e3ad8b3851e7 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 { @@ -210,6 +211,9 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app); Set<size_t> AllFeatures; + auto PrintStatsWrapper = [this, &AllFeatures](const char* Where) { + this->PrintStats(Where, "\n", 0, AllFeatures.size()); + }; Set<const TracePC::PCTableEntry *> AllPCs; for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) { Fuzzer::MaybeExitGracefully(); @@ -218,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. @@ -238,7 +242,9 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { TPC.UpdateObservedPCs(); // Show stats. if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1))) - PrintStats("pulse "); + PrintStatsWrapper("pulse "); + if (TotalNumberOfRuns == M.NumFilesInFirstCorpus) + PrintStatsWrapper("LOADED"); // Write the post-run marker and the coverage. OF << "FT " << i; for (size_t F : UniqFeatures) @@ -252,25 +258,42 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { OF << "\n"; OF.flush(); } - PrintStats("DONE "); + 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. @@ -286,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); @@ -300,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"); } @@ -313,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. @@ -353,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", |