diff options
Diffstat (limited to 'lib/Fuzzer/FuzzerMerge.cpp')
-rw-r--r-- | lib/Fuzzer/FuzzerMerge.cpp | 87 |
1 files changed, 78 insertions, 9 deletions
diff --git a/lib/Fuzzer/FuzzerMerge.cpp b/lib/Fuzzer/FuzzerMerge.cpp index 9e559115680cc..e66460c29e2f8 100644 --- a/lib/Fuzzer/FuzzerMerge.cpp +++ b/lib/Fuzzer/FuzzerMerge.cpp @@ -17,6 +17,7 @@ #include <fstream> #include <iterator> +#include <set> #include <sstream> namespace fuzzer { @@ -73,6 +74,7 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) { size_t ExpectedStartMarker = 0; const size_t kInvalidStartMarker = -1; size_t LastSeenStartMarker = kInvalidStartMarker; + std::vector<uint32_t> TmpFeatures; while (std::getline(IS, Line, '\n')) { std::istringstream ISS1(Line); std::string Marker; @@ -88,17 +90,17 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) { assert(ExpectedStartMarker < Files.size()); ExpectedStartMarker++; } else if (Marker == "DONE") { - // DONE FILE_SIZE COV1 COV2 COV3 ... + // DONE FILE_ID COV1 COV2 COV3 ... size_t CurrentFileIdx = N; if (CurrentFileIdx != LastSeenStartMarker) return false; LastSeenStartMarker = kInvalidStartMarker; if (ParseCoverage) { - auto &V = Files[CurrentFileIdx].Features; - V.clear(); + TmpFeatures.clear(); // use a vector from outer scope to avoid resizes. while (ISS1 >> std::hex >> N) - V.push_back(N); - std::sort(V.begin(), V.end()); + TmpFeatures.push_back(N); + std::sort(TmpFeatures.begin(), TmpFeatures.end()); + Files[CurrentFileIdx].Features = TmpFeatures; } } else { return false; @@ -111,12 +113,20 @@ bool Merger::Parse(std::istream &IS, bool ParseCoverage) { return true; } +size_t Merger::ApproximateMemoryConsumption() const { + size_t Res = 0; + for (const auto &F: Files) + Res += sizeof(F) + F.Features.size() * sizeof(F.Features[0]); + return Res; +} + // Decides which files need to be merged (add thost to NewFiles). // Returns the number of new features added. -size_t Merger::Merge(std::vector<std::string> *NewFiles) { +size_t Merger::Merge(const std::set<uint32_t> &InitialFeatures, + std::vector<std::string> *NewFiles) { NewFiles->clear(); assert(NumFilesInFirstCorpus <= Files.size()); - std::set<uint32_t> AllFeatures; + std::set<uint32_t> AllFeatures(InitialFeatures); // What features are in the initial corpus? for (size_t i = 0; i < NumFilesInFirstCorpus; i++) { @@ -158,6 +168,42 @@ size_t Merger::Merge(std::vector<std::string> *NewFiles) { return AllFeatures.size() - InitialNumFeatures; } +void Merger::PrintSummary(std::ostream &OS) { + for (auto &File : Files) { + OS << std::hex; + OS << File.Name << " size: " << File.Size << " features: "; + for (auto Feature : File.Features) + OS << " " << Feature; + OS << "\n"; + } +} + +std::set<uint32_t> Merger::AllFeatures() const { + std::set<uint32_t> S; + for (auto &File : Files) + S.insert(File.Features.begin(), File.Features.end()); + return S; +} + +std::set<uint32_t> Merger::ParseSummary(std::istream &IS) { + std::string Line, Tmp; + std::set<uint32_t> Res; + while (std::getline(IS, Line, '\n')) { + size_t N; + std::istringstream ISS1(Line); + ISS1 >> Tmp; // Name + ISS1 >> Tmp; // size: + assert(Tmp == "size:" && "Corrupt summary file"); + ISS1 >> std::hex; + ISS1 >> N; // File Size + ISS1 >> Tmp; // features: + assert(Tmp == "features:" && "Corrupt summary file"); + while (ISS1 >> std::hex >> N) + Res.insert(N); + } + return Res; +} + // Inner process. May crash if the target crashes. void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str()); @@ -208,7 +254,9 @@ void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) { // Outer process. Does not call the target code and thus sohuld not fail. void Fuzzer::CrashResistantMerge(const std::vector<std::string> &Args, - const std::vector<std::string> &Corpora) { + const std::vector<std::string> &Corpora, + const char *CoverageSummaryInputPathOrNull, + const char *CoverageSummaryOutputPathOrNull) { if (Corpora.size() <= 1) { Printf("Merge requires two or more corpus dirs\n"); return; @@ -239,15 +287,21 @@ void Fuzzer::CrashResistantMerge(const std::vector<std::string> &Args, // Execute the inner process untill it passes. // Every inner process should execute at least one input. std::string BaseCmd = CloneArgsWithoutX(Args, "keep-all-flags"); + bool Success = false; for (size_t i = 1; i <= AllFiles.size(); i++) { Printf("MERGE-OUTER: attempt %zd\n", i); auto ExitCode = ExecuteCommand(BaseCmd + " -merge_control_file=" + CFPath); if (!ExitCode) { Printf("MERGE-OUTER: succesfull in %zd attempt(s)\n", i); + Success = true; break; } } + if (!Success) { + Printf("MERGE-OUTER: zero succesfull attempts, exiting\n"); + exit(1); + } // Read the control file and do the merge. Merger M; std::ifstream IF(CFPath); @@ -256,8 +310,23 @@ void Fuzzer::CrashResistantMerge(const std::vector<std::string> &Args, IF.seekg(0, IF.beg); M.ParseOrExit(IF, true); IF.close(); + Printf("MERGE-OUTER: consumed %zdMb (%zdMb rss) to parse the control file\n", + M.ApproximateMemoryConsumption() >> 20, GetPeakRSSMb()); + if (CoverageSummaryOutputPathOrNull) { + Printf("MERGE-OUTER: writing coverage summary for %zd files to %s\n", + M.Files.size(), CoverageSummaryOutputPathOrNull); + std::ofstream SummaryOut(CoverageSummaryOutputPathOrNull); + M.PrintSummary(SummaryOut); + } std::vector<std::string> NewFiles; - size_t NumNewFeatures = M.Merge(&NewFiles); + std::set<uint32_t> InitialFeatures; + if (CoverageSummaryInputPathOrNull) { + std::ifstream SummaryIn(CoverageSummaryInputPathOrNull); + InitialFeatures = M.ParseSummary(SummaryIn); + Printf("MERGE-OUTER: coverage summary loaded from %s, %zd features found\n", + CoverageSummaryInputPathOrNull, InitialFeatures.size()); + } + size_t NumNewFeatures = M.Merge(InitialFeatures, &NewFiles); Printf("MERGE-OUTER: %zd new files with %zd new features added\n", NewFiles.size(), NumNewFeatures); for (auto &F: NewFiles) |