[fuzzer] add flag prefer_small_during_initial_shuffle, be a bit more verbose
[oota-llvm.git] / lib / Fuzzer / FuzzerLoop.cpp
index 1f2193a45b34462884039c509836eb95cfd8001e..9c65f257d9ca6b0d173efe8313403425e6b055fb 100644 (file)
 //===----------------------------------------------------------------------===//
 
 #include "FuzzerInternal.h"
-#include <sanitizer/asan_interface.h>
+#include <sanitizer/coverage_interface.h>
 #include <algorithm>
-#include <string>
 #include <iostream>
-#include <stdlib.h>
 
 // This function should be defined by the user.
 extern "C" void TestOneInput(const uint8_t *Data, size_t Size);
@@ -50,10 +48,19 @@ void Fuzzer::AlarmCallback() {
 }
 
 void Fuzzer::ShuffleAndMinimize() {
+  bool PreferSmall =
+      (Options.PreferSmallDuringInitialShuffle == 1 ||
+       (Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2));
   if (Options.Verbosity)
-    std::cerr << "Shuffle: " << Corpus.size() << "\n";
+    std::cerr << "Shuffle: Size: " << Corpus.size()
+              << " prefer small: " << PreferSmall
+              << "\n";
   std::vector<Unit> NewCorpus;
-  random_shuffle(Corpus.begin(), Corpus.end());
+  std::random_shuffle(Corpus.begin(), Corpus.end());
+  if (PreferSmall)
+    std::stable_sort(
+        Corpus.begin(), Corpus.end(),
+        [](const Unit &A, const Unit &B) { return A.size() < B.size(); });
   size_t MaxCov = 0;
   Unit &U = CurrentUnit;
   for (const auto &C : Corpus) {
@@ -66,7 +73,9 @@ void Fuzzer::ShuffleAndMinimize() {
         MaxCov = NewCoverage;
         NewCorpus.push_back(U);
         if (Options.Verbosity >= 2)
-          std::cerr << "NEW0: " << NewCoverage << "\n";
+          std::cerr << "NEW0: " << NewCoverage
+                    << " L " << U.size()
+                    << "\n";
       }
     }
   }
@@ -78,12 +87,40 @@ void Fuzzer::ShuffleAndMinimize() {
 size_t Fuzzer::RunOne(const Unit &U) {
   UnitStartTime = system_clock::now();
   TotalNumberOfRuns++;
+  if (Options.UseFullCoverageSet)
+    return RunOneMaximizeFullCoverageSet(U);
+  return RunOneMaximizeTotalCoverage(U);
+}
+
+static uintptr_t HashOfArrayOfPCs(uintptr_t *PCs, uintptr_t NumPCs) {
+  uintptr_t Res = 0;
+  for (uintptr_t i = 0; i < NumPCs; i++) {
+    Res = (Res + PCs[i]) * 7;
+  }
+  return Res;
+}
+
+// Fuly reset the current coverage state, run a single unit,
+// compute a hash function from the full coverage set,
+// return non-zero if the hash value is new.
+// This produces tons of new units and as is it's only suitable for small tests,
+// e.g. test/FullCoverageSetTest.cpp. FIXME: make it scale.
+size_t Fuzzer::RunOneMaximizeFullCoverageSet(const Unit &U) {
+  __sanitizer_reset_coverage();
+  TestOneInput(U.data(), U.size());
+  uintptr_t *PCs;
+  uintptr_t NumPCs =__sanitizer_get_coverage_guards(&PCs);
+  if (FullCoverageSets.insert(HashOfArrayOfPCs(PCs, NumPCs)).second)
+    return FullCoverageSets.size();
+  return 0;
+}
+
+size_t Fuzzer::RunOneMaximizeTotalCoverage(const Unit &U) {
   size_t OldCoverage = __sanitizer_get_total_unique_coverage();
   TestOneInput(U.data(), U.size());
   size_t NewCoverage = __sanitizer_get_total_unique_coverage();
   if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && Options.Verbosity) {
-    size_t Seconds =
-        duration_cast<seconds>(system_clock::now() - ProcessStartTime).count();
+    size_t Seconds = secondsSinceProcessStartUp();
     std::cerr
         << "#" << TotalNumberOfRuns
         << "\tcov: " << NewCoverage
@@ -119,9 +156,10 @@ void Fuzzer::SaveCorpus() {
 
 size_t Fuzzer::MutateAndTestOne(Unit *U) {
   size_t NewUnits = 0;
-  for (size_t i = 0; i < Options.MutateDepth; i++) {
+  for (int i = 0; i < Options.MutateDepth; i++) {
+    if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+      return NewUnits;
     Mutate(U, Options.MaxLen);
-    if (U->empty()) continue;
     size_t NewCoverage = RunOne(*U);
     if (NewCoverage) {
       Corpus.push_back(*U);
@@ -130,6 +168,8 @@ size_t Fuzzer::MutateAndTestOne(Unit *U) {
         std::cerr << "#" << TotalNumberOfRuns
                   << "\tNEW: " << NewCoverage
                   << " L: " << U->size()
+                  << " S: " << Corpus.size()
+                  << " I: " << i
                   << "\t";
         if (U->size() < 30) {
           PrintASCII(*U);
@@ -149,19 +189,20 @@ size_t Fuzzer::MutateAndTestOne(Unit *U) {
 size_t Fuzzer::Loop(size_t NumIterations) {
   size_t NewUnits = 0;
   for (size_t i = 1; i <= NumIterations; i++) {
-    if (Options.DoCrossOver) {
-      for (size_t J1 = 0; J1 < Corpus.size(); J1++) {
+    for (size_t J1 = 0; J1 < Corpus.size(); J1++) {
+      if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
+        return NewUnits;
+      // First, simply mutate the unit w/o doing crosses.
+      CurrentUnit = Corpus[J1];
+      NewUnits += MutateAndTestOne(&CurrentUnit);
+      // Now, cross with others.
+      if (Options.DoCrossOver) {
         for (size_t J2 = 0; J2 < Corpus.size(); J2++) {
           CurrentUnit.clear();
           CrossOver(Corpus[J1], Corpus[J2], &CurrentUnit, Options.MaxLen);
           NewUnits += MutateAndTestOne(&CurrentUnit);
         }
       }
-    } else {  // No CrossOver
-      for (size_t J = 0; J < Corpus.size(); J++) {
-        CurrentUnit = Corpus[J];
-        NewUnits += MutateAndTestOne(&CurrentUnit);
-      }
     }
   }
   return NewUnits;