[fuzzer] one more experimental search mode: -use_coverage_pairs=1
authorKostya Serebryany <kcc@google.com>
Fri, 20 Feb 2015 03:02:37 +0000 (03:02 +0000)
committerKostya Serebryany <kcc@google.com>
Fri, 20 Feb 2015 03:02:37 +0000 (03:02 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@229957 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Fuzzer/FuzzerDriver.cpp
lib/Fuzzer/FuzzerFlags.def
lib/Fuzzer/FuzzerInternal.h
lib/Fuzzer/FuzzerLoop.cpp
lib/Fuzzer/test/CMakeLists.txt
lib/Fuzzer/test/FourIndependentBranchesTest.cpp [new file with mode: 0644]
lib/Fuzzer/test/fuzzer.test

index 8a8659e5f2be0d7b99a1714ec7ff76998056a9aa..1746afd822d4e6b7383af2d38439c961397f56b3 100644 (file)
@@ -159,6 +159,7 @@ int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
   Options.MutateDepth = Flags.mutate_depth;
   Options.ExitOnFirst = Flags.exit_on_first;
   Options.UseFullCoverageSet = Flags.use_full_coverage_set;
+  Options.UseCoveragePairs = Flags.use_coverage_pairs;
   Options.PreferSmallDuringInitialShuffle =
       Flags.prefer_small_during_initial_shuffle;
   if (Flags.runs >= 0)
index 754d02e0153b3a8c3ac2efeb7957a14d4945b313..068f2451b6b2084f505bcb257e8883ed2c66b121 100644 (file)
@@ -33,9 +33,11 @@ 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"
+            "Experimental: 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.")
+FUZZER_FLAG(int, use_coverage_pairs, 0,
+            "Experimental: Maximize the number of different coverage pairs.")
 FUZZER_FLAG(int, jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
                           " this number of jobs in separate worker processes"
                           " with stdout/stderr redirected to fuzz-JOB.log.")
index bc18c551f59d70152a294c4789151ea5107f0368..980b00ec17bcc8befb1a7671d118748816cd1d61 100644 (file)
@@ -49,6 +49,7 @@ class Fuzzer {
     int  MutateDepth = 5;
     bool ExitOnFirst = false;
     bool UseFullCoverageSet  = false;
+    bool UseCoveragePairs = false;
     int PreferSmallDuringInitialShuffle = -1;
     size_t MaxNumberOfRuns = ULONG_MAX;
     std::string OutputCorpus;
@@ -81,6 +82,7 @@ class Fuzzer {
   size_t RunOne(const Unit &U);
   size_t RunOneMaximizeTotalCoverage(const Unit &U);
   size_t RunOneMaximizeFullCoverageSet(const Unit &U);
+  size_t RunOneMaximizeCoveragePairs(const Unit &U);
   void WriteToOutputCorpus(const Unit &U);
   static void WriteToCrash(const Unit &U, const char *Prefix);
 
@@ -92,6 +94,7 @@ class Fuzzer {
 
   std::vector<Unit> Corpus;
   std::unordered_set<uintptr_t> FullCoverageSets;
+  std::unordered_set<uint64_t>  CoveragePairs;
   UserCallback Callback;
   FuzzingOptions Options;
   system_clock::time_point ProcessStartTime = system_clock::now();
index 1529d06b1cc7de8bc801f547dbcb0f7ac4e13c81..70b63eb618a5d189a1b01070d4984ee240aa3c4a 100644 (file)
@@ -86,6 +86,8 @@ size_t Fuzzer::RunOne(const Unit &U) {
   TotalNumberOfRuns++;
   if (Options.UseFullCoverageSet)
     return RunOneMaximizeFullCoverageSet(U);
+  if (Options.UseCoveragePairs)
+    return RunOneMaximizeCoveragePairs(U);
   return RunOneMaximizeTotalCoverage(U);
 }
 
@@ -97,6 +99,29 @@ static uintptr_t HashOfArrayOfPCs(uintptr_t *PCs, uintptr_t NumPCs) {
   return Res;
 }
 
+// Experimental. Does not yet scale.
+// Fuly reset the current coverage state, run a single unit,
+// collect all coverage pairs and return non-zero if a new pair is observed.
+size_t Fuzzer::RunOneMaximizeCoveragePairs(const Unit &U) {
+  __sanitizer_reset_coverage();
+  Callback(U.data(), U.size());
+  uintptr_t *PCs;
+  uintptr_t NumPCs = __sanitizer_get_coverage_guards(&PCs);
+  bool HasNewPairs = false;
+  for (uintptr_t i = 0; i < NumPCs; i++) {
+    if (!PCs[i]) continue;
+    for (uintptr_t j = 0; j < NumPCs; j++) {
+      if (!PCs[j]) continue;
+      uint64_t Pair = (i << 32) | j;
+      HasNewPairs |= CoveragePairs.insert(Pair).second;
+    }
+  }
+  if (HasNewPairs)
+    return CoveragePairs.size();
+  return 0;
+}
+
+// Experimental.
 // 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.
index eb3c1eee7c181401412df519af0caa6bffb7bd4a..bed9cd89ec95969b598dd1ebc427c1265b683056 100644 (file)
@@ -5,6 +5,7 @@
 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0 -fsanitize-coverage=4")
 
 set(Tests
+  FourIndependentBranchesTest
   FullCoverageSetTest
   InfiniteTest
   NullDerefTest
diff --git a/lib/Fuzzer/test/FourIndependentBranchesTest.cpp b/lib/Fuzzer/test/FourIndependentBranchesTest.cpp
new file mode 100644 (file)
index 0000000..171668b
--- /dev/null
@@ -0,0 +1,18 @@
+// Simple test for a fuzzer. The fuzzer must find the string "FUZZ".
+#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 (bits == 15) {
+    std::cerr <<  "BINGO!\n";
+    exit(1);
+  }
+}
+
index 51b42d67824be40967071ab93731068a423fc757..1e42e7249da102c6e25b76b2129130ddfe3885a8 100644 (file)
@@ -12,5 +12,8 @@ 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
+RUN: not ./LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s --check-prefix=FullCoverageSetTest
 FullCoverageSetTest: BINGO
+
+RUN: not ./LLVMFuzzer-FourIndependentBranchesTest -timeout=15 -seed=1 -use_coverage_pairs=1 2>&1 | FileCheck %s --check-prefix=FourIndependentBranchesTest
+FourIndependentBranchesTest: BINGO