[fuzzer] add -use_full_coverage_set=1 which solves FullCoverageSetTest. This does...
authorKostya Serebryany <kcc@google.com>
Thu, 29 Jan 2015 23:01:07 +0000 (23:01 +0000)
committerKostya Serebryany <kcc@google.com>
Thu, 29 Jan 2015 23:01:07 +0000 (23:01 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@227507 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Fuzzer/CMakeLists.txt
lib/Fuzzer/FuzzerFlags.def
lib/Fuzzer/FuzzerInternal.h
lib/Fuzzer/FuzzerLoop.cpp
lib/Fuzzer/FuzzerMain.cpp
lib/Fuzzer/test/CMakeLists.txt
lib/Fuzzer/test/ExactTest.cpp [deleted file]
lib/Fuzzer/test/FullCoverageSetTest.cpp [new file with mode: 0644]
lib/Fuzzer/test/fuzzer.test

index 2538375..499cf98 100644 (file)
@@ -1,3 +1,5 @@
+# Disable the coverage instrumentation for the fuzzer itself.
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O2 -fsanitize-coverage=0")
 if( LLVM_USE_SANITIZE_COVERAGE  )
   add_library(LLVMFuzzer STATIC
     EXCLUDE_FROM_ALL  # Do not build if you are not building fuzzers.
index e165ebd..264c105 100644 (file)
@@ -25,3 +25,7 @@ FUZZER_FLAG(int, help, 0, "Print help.")
 FUZZER_FLAG(
     int, save_minimized_corpus, 0,
     "If 1, the minimized corpus is saved into the first input directory")
+FUZZER_FLAG(int, use_full_coverage_set, 0,
+            "Maximize the number of different full"
+            " coverage sets as opposed to maximizing the total coverage."
+            " This is potentially MUCH slower, but may discover more paths.")
index c361ffb..4537971 100644 (file)
@@ -14,6 +14,7 @@
 #include <cstdlib>
 #include <string>
 #include <vector>
+#include <unordered_set>
 
 namespace fuzzer {
 typedef std::vector<uint8_t> Unit;
@@ -43,6 +44,7 @@ class Fuzzer {
     bool DoCrossOver = true;
     bool MutateDepth = 10;
     bool ExitOnFirst = false;
+    bool UseFullCoverageSet  = false;
     std::string OutputCorpus;
   };
   Fuzzer(FuzzingOptions Options) : Options(Options) {
@@ -63,6 +65,8 @@ class Fuzzer {
  private:
   size_t MutateAndTestOne(Unit *U);
   size_t RunOne(const Unit &U);
+  size_t RunOneMaximizeTotalCoverage(const Unit &U);
+  size_t RunOneMaximizeFullCoverageSet(const Unit &U);
   void WriteToOutputCorpus(const Unit &U);
   static void WriteToCrash(const Unit &U, const char *Prefix);
 
@@ -73,6 +77,7 @@ class Fuzzer {
   size_t TotalNumberOfRuns = 0;
 
   std::vector<Unit> Corpus;
+  std::unordered_set<uintptr_t> FullCoverageSets;
   FuzzingOptions Options;
   system_clock::time_point ProcessStartTime = system_clock::now();
   static system_clock::time_point UnitStartTime;
index dcfc965..f3dee7c 100644 (file)
@@ -76,6 +76,35 @@ 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();
index 6031fc8..03e0566 100644 (file)
@@ -117,6 +117,7 @@ int main(int argc, char **argv) {
   Options.DoCrossOver = Flags.cross_over;
   Options.MutateDepth = Flags.mutate_depth;
   Options.ExitOnFirst = Flags.exit_on_first;
+  Options.UseFullCoverageSet = Flags.use_full_coverage_set;
   if (!inputs.empty())
     Options.OutputCorpus = inputs[0];
   Fuzzer F(Options);
index 0c2118f..17afd92 100644 (file)
@@ -1,5 +1,11 @@
+# Build all these tests with -O0, otherwise optimizations may merge some
+# basic blocks and we'll fail to discover the targets.
+# Also enable the coverage instrumentation back (it is disabled
+# for the Fuzzer lib)
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0 -fsanitize-coverage=4")
+
 set(Tests
-  ExactTest
+  FullCoverageSetTest
   InfiniteTest
   NullDerefTest
   SimpleTest
diff --git a/lib/Fuzzer/test/ExactTest.cpp b/lib/Fuzzer/test/ExactTest.cpp
deleted file mode 100644 (file)
index bbfed3c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-// Simple test for a fuzzer. The fuzzer must find the string "FUZZER".
-#include <cstdint>
-#include <cstdlib>
-#include <cstddef>
-#include <iostream>
-
-extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
-  int bits = 0;
-  if (Size > 0 && Data[0] == 'F') bits |= 1;
-  if (Size > 1 && Data[1] == 'U') bits |= 2;
-  if (Size > 2 && Data[2] == 'Z') bits |= 4;
-  if (Size > 3 && Data[3] == 'Z') bits |= 8;
-  if (Size > 4 && Data[4] == 'E') bits |= 16;
-  if (Size > 5 && Data[5] == 'R') bits |= 32;
-  if (bits == 63) {
-    std::cerr <<  "BINGO!\n";
-    abort();
-  }
-}
-
diff --git a/lib/Fuzzer/test/FullCoverageSetTest.cpp b/lib/Fuzzer/test/FullCoverageSetTest.cpp
new file mode 100644 (file)
index 0000000..d4f8c11
--- /dev/null
@@ -0,0 +1,20 @@
+// Simple test for a fuzzer. The fuzzer must find the string "FUZZER".
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+extern "C" void TestOneInput(const uint8_t *Data, size_t Size) {
+  int bits = 0;
+  if (Size > 0 && Data[0] == 'F') bits |= 1;
+  if (Size > 1 && Data[1] == 'U') bits |= 2;
+  if (Size > 2 && Data[2] == 'Z') bits |= 4;
+  if (Size > 3 && Data[3] == 'Z') bits |= 8;
+  if (Size > 4 && Data[4] == 'E') bits |= 16;
+  if (Size > 5 && Data[5] == 'R') bits |= 32;
+  if (bits == 63) {
+    std::cerr <<  "BINGO!\n";
+    exit(1);
+  }
+}
+
index 5f01310..51b42d6 100644 (file)
@@ -11,3 +11,6 @@ TimeoutTest: CRASHED; file written to timeout
 
 RUN: not ./LLVMFuzzer-NullDerefTest 2>&1 | FileCheck %s --check-prefix=NullDerefTest
 NullDerefTest: CRASHED; file written to crash-
+
+RUN: not ./LLVMFuzzer-FullCoverageSetTest -timeout=15 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s --check-prefix=FullCoverageSetTest
+FullCoverageSetTest: BINGO