aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Fuzzer/FuzzerLoop.cpp
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2016-03-18 00:23:29 +0000
committerKostya Serebryany <kcc@google.com>2016-03-18 00:23:29 +0000
commit945761b8c29f9cc36372b6485720656371c736bc (patch)
tree1b0089fca7da0892e85fb8a9d06e27bf68b5de50 /llvm/lib/Fuzzer/FuzzerLoop.cpp
parent01864a2d01527adcd67000fdba29a4b5a82e1385 (diff)
downloadllvm-945761b8c29f9cc36372b6485720656371c736bc.zip
llvm-945761b8c29f9cc36372b6485720656371c736bc.tar.gz
llvm-945761b8c29f9cc36372b6485720656371c736bc.tar.bz2
[libFuzzer] improve -merge functionality
llvm-svn: 263769
Diffstat (limited to 'llvm/lib/Fuzzer/FuzzerLoop.cpp')
-rw-r--r--llvm/lib/Fuzzer/FuzzerLoop.cpp126
1 files changed, 75 insertions, 51 deletions
diff --git a/llvm/lib/Fuzzer/FuzzerLoop.cpp b/llvm/lib/Fuzzer/FuzzerLoop.cpp
index 4f3b5a7..3bc5f93 100644
--- a/llvm/lib/Fuzzer/FuzzerLoop.cpp
+++ b/llvm/lib/Fuzzer/FuzzerLoop.cpp
@@ -243,34 +243,25 @@ void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
}
}
+void Fuzzer::ShuffleCorpus(UnitVector *V) {
+ std::random_shuffle(V->begin(), V->end(), MD.GetRand());
+ if (Options.PreferSmall)
+ std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) {
+ return A.size() < B.size();
+ });
+}
+
void Fuzzer::ShuffleAndMinimize() {
- bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 ||
- (Options.PreferSmallDuringInitialShuffle == -1 &&
- MD.GetRand().RandBool()));
- if (Options.Verbosity)
- Printf("INFO: PreferSmall: %d\n", PreferSmall);
PrintStats("READ ");
std::vector<Unit> NewCorpus;
- if (Options.ShuffleAtStartUp) {
- std::random_shuffle(Corpus.begin(), Corpus.end(), MD.GetRand());
- if (PreferSmall)
- std::stable_sort(
- Corpus.begin(), Corpus.end(),
- [](const Unit &A, const Unit &B) { return A.size() < B.size(); });
- }
- Unit U;
- for (const auto &C : Corpus) {
- for (size_t First = 0; First < 1; First++) {
- U.clear();
- size_t Last = std::min(First + Options.MaxLen, C.size());
- U.insert(U.begin(), C.begin() + First, C.begin() + Last);
- if (Options.OnlyASCII)
- ToASCII(U.data(), U.size());
- if (RunOne(U)) {
- NewCorpus.push_back(U);
- if (Options.Verbosity >= 2)
- Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size());
- }
+ if (Options.ShuffleAtStartUp)
+ ShuffleCorpus(&Corpus);
+
+ for (const auto &U : Corpus) {
+ if (RunOne(U)) {
+ NewCorpus.push_back(U);
+ if (Options.Verbosity >= 2)
+ Printf("NEW0: %zd L %zd\n", LastRecordedBlockCoverage, U.size());
}
}
Corpus = NewCorpus;
@@ -438,37 +429,65 @@ void Fuzzer::ReportNewCoverage(const Unit &U) {
NumberOfNewUnitsAdded++;
}
+// Finds minimal number of units in 'Extra' that add coverage to 'Initial'.
+// We do it by actually executing the units, sometimes more than once,
+// because we may be using different coverage-like signals and the only
+// common thing between them is that we can say "this unit found new stuff".
+UnitVector Fuzzer::FindExtraUnits(const UnitVector &Initial,
+ const UnitVector &Extra) {
+ UnitVector Res = Extra;
+ size_t OldSize = Res.size();
+ for (int Iter = 0; Iter < 10; Iter++) {
+ ShuffleCorpus(&Res);
+ ResetCoverage();
+
+ for (auto &U : Initial)
+ RunOne(U);
+
+ Corpus.clear();
+ for (auto &U : Res)
+ if (RunOne(U))
+ Corpus.push_back(U);
+
+ char Stat[7] = "MIN ";
+ Stat[3] = '0' + Iter;
+ PrintStats(Stat);
+
+ size_t NewSize = Corpus.size();
+ Res.swap(Corpus);
+
+ if (NewSize == OldSize)
+ break;
+ OldSize = NewSize;
+ }
+ return Res;
+}
+
void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
if (Corpora.size() <= 1) {
Printf("Merge requires two or more corpus dirs\n");
return;
}
- auto InitialCorpusDir = Corpora[0];
- assert(Options.MaxLen > 0);
- ReadDir(InitialCorpusDir, nullptr, Options.MaxLen);
- Printf("Merge: running the initial corpus '%s' of %d units\n",
- InitialCorpusDir.c_str(), Corpus.size());
- for (auto &U : Corpus)
- RunOne(U);
-
std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end());
- size_t NumTried = 0;
- size_t NumMerged = 0;
- for (auto &C : ExtraCorpora) {
- Corpus.clear();
- ReadDir(C, nullptr, Options.MaxLen);
- Printf("Merge: merging the extra corpus '%s' of %zd units\n", C.c_str(),
- Corpus.size());
- for (auto &U : Corpus) {
- NumTried++;
- if (RunOne(U)) {
- WriteToOutputCorpus(U);
- NumMerged++;
- }
- }
+ assert(Options.MaxLen > 0);
+ UnitVector Initial, Extra;
+ ReadDirToVectorOfUnits(Corpora[0].c_str(), &Initial, nullptr, Options.MaxLen);
+ for (auto &C : ExtraCorpora)
+ ReadDirToVectorOfUnits(C.c_str(), &Extra, nullptr, Options.MaxLen);
+
+ if (!Initial.empty()) {
+ Printf("=== Minimizing the initial corpus of %zd units\n", Initial.size());
+ Initial = FindExtraUnits({}, Initial);
}
- Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried);
+
+ Printf("=== Merging extra %zd units\n", Extra.size());
+ auto Res = FindExtraUnits(Initial, Extra);
+
+ for (auto &U: Res)
+ WriteToOutputCorpus(U);
+
+ Printf("=== Merge: written %zd units\n", Res.size());
}
void Fuzzer::MutateAndTestOne() {
@@ -507,6 +526,12 @@ size_t Fuzzer::ChooseUnitIdxToMutate() {
return Idx;
}
+void Fuzzer::ResetCoverage() {
+ CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage);
+ __sanitizer_reset_coverage();
+ CounterBitmap.clear();
+}
+
// Experimental search heuristic: drilling.
// - Read, shuffle, execute and minimize the corpus.
// - Choose one random unit.
@@ -521,8 +546,7 @@ void Fuzzer::Drill() {
Unit U = ChooseUnitToMutate();
- CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage);
- __sanitizer_reset_coverage();
+ ResetCoverage();
std::vector<Unit> SavedCorpus;
SavedCorpus.swap(Corpus);
@@ -535,7 +559,7 @@ void Fuzzer::Drill() {
SavedOutputCorpusPath.swap(Options.OutputCorpus);
Loop();
- __sanitizer_reset_coverage();
+ ResetCoverage();
PrintStats("REINIT");
SavedOutputCorpusPath.swap(Options.OutputCorpus);