[sanitizers] trace buffer API to use user-allocated buffer.
authorMike Aizatsky <aizatsky@chromium.org>
Fri, 5 Aug 2016 20:09:53 +0000 (20:09 +0000)
committerMike Aizatsky <aizatsky@chromium.org>
Fri, 5 Aug 2016 20:09:53 +0000 (20:09 +0000)
Differential Revision: https://reviews.llvm.org/D23185

llvm-svn: 277859

llvm/lib/Fuzzer/FuzzerExtFunctions.def
llvm/lib/Fuzzer/FuzzerInternal.h
llvm/lib/Fuzzer/FuzzerLoop.cpp

index f7dcf9b..cbd0dfb 100644 (file)
@@ -29,7 +29,8 @@ EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
 EXT_FUNC(__lsan_enable, void, (), false);
 EXT_FUNC(__lsan_disable, void, (), false);
 EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
-EXT_FUNC(__sanitizer_get_coverage_pc_buffer, uintptr_t, (uintptr_t**), true);
+EXT_FUNC(__sanitizer_set_coverage_pc_buffer, void, (uintptr_t*, uintptr_t), true);
+EXT_FUNC(__sanitizer_get_coverage_pc_buffer_pos, uintptr_t, (), true);
 EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), false);
 EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
          (void (*malloc_hook)(const volatile void *, size_t),
index 08f8801..5f0574a 100644 (file)
@@ -19,6 +19,7 @@
 #include <climits>
 #include <cstddef>
 #include <cstdlib>
+#include <memory>
 #include <random>
 #include <string.h>
 #include <string>
@@ -334,6 +335,8 @@ private:
   std::vector<Mutator> DefaultMutators;
 };
 
+class CoverageController;
+
 class Fuzzer {
 public:
 
@@ -346,17 +349,16 @@ public:
       CallerCalleeCoverage = 0;
       PcMapBits = 0;
       CounterBitmapBits = 0;
-      PcBufferLen = 0;
       CounterBitmap.clear();
       PCMap.Reset();
+      PcBufferPos = 0;
     }
 
     std::string DebugString() const;
 
     size_t BlockCoverage;
     size_t CallerCalleeCoverage;
-
-    size_t PcBufferLen;
+    size_t PcBufferPos;
     // Precalculated number of bits in CounterBitmap.
     size_t CounterBitmapBits;
     std::vector<uint8_t> CounterBitmap;
@@ -366,6 +368,7 @@ public:
   };
 
   Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options);
+  ~Fuzzer();
   void AddToCorpus(const Unit &U) {
     Corpus.push_back(U);
     UpdateCorpusDistribution();
@@ -481,6 +484,7 @@ private:
 
   // Maximum recorded coverage.
   Coverage MaxCoverage;
+  std::unique_ptr<CoverageController> CController;
 
   // Need to know our own thread.
   static thread_local bool IsMyThread;
index 89db5e0..9c71562 100644 (file)
@@ -53,20 +53,33 @@ static void MissingExternalApiFunction(const char *FnName) {
 // Only one Fuzzer per process.
 static Fuzzer *F;
 
-struct CoverageController {
-  static void Reset() {
+// Only one CoverageController per process should be created.
+class CoverageController {
+ public:
+  explicit CoverageController(const FuzzingOptions &Options) 
+    : Options(Options) {
+    if (Options.PrintNewCovPcs) {
+      PcBufferLen = 1 << 24;
+      PcBuffer = new uintptr_t[PcBufferLen];
+      EF->__sanitizer_set_coverage_pc_buffer(PcBuffer, PcBufferLen);
+    }
+  }
+
+  uintptr_t* pc_buffer() const { return PcBuffer; }
+
+  void Reset() {
     CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage);
     EF->__sanitizer_reset_coverage();
     PcMapResetCurrent();
   }
 
-  static void ResetCounters(const FuzzingOptions &Options) {
+  void ResetCounters() {
     if (Options.UseCounters) {
       EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
     }
   }
 
-  static void Prepare(const FuzzingOptions &Options, Fuzzer::Coverage *C) {
+  void Prepare(Fuzzer::Coverage *C) {
     if (Options.UseCounters) {
       size_t NumCounters = EF->__sanitizer_get_number_of_counters();
       C->CounterBitmap.resize(NumCounters);
@@ -75,7 +88,7 @@ struct CoverageController {
 
   // Records data to a maximum coverage tracker. Returns true if additional
   // coverage was discovered.
-  static bool RecordMax(const FuzzingOptions &Options, Fuzzer::Coverage *C) {
+  bool RecordMax(Fuzzer::Coverage *C) {
     bool Res = false;
 
     uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
@@ -110,16 +123,23 @@ struct CoverageController {
       C->PcMapBits = NewPcMapBits;
     }
 
-    uintptr_t *CoverageBuf;
-    uint64_t NewPcBufferLen =
-        EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf);
-    if (NewPcBufferLen > C->PcBufferLen) {
+    uint64_t NewPcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos();
+    if (NewPcBufferPos > C->PcBufferPos) {
       Res = true;
-      C->PcBufferLen = NewPcBufferLen;
+      C->PcBufferPos = NewPcBufferPos;
+    }
+
+    if (NewPcBufferPos >= PcBufferLen) {
+      Printf("ERROR: PC buffer overflow.\n");
     }
 
     return Res;
   }
+
+ private:
+  const FuzzingOptions Options;
+  uintptr_t* PcBuffer = nullptr;
+  size_t PcBufferLen = 0;
 };
 
 // Leak detection is expensive, so we first check if there were more mallocs
@@ -145,7 +165,8 @@ void FreeHook(const volatile void *ptr) {
 }
 
 Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options)
-    : CB(CB), MD(MD), Options(Options) {
+    : CB(CB), MD(MD), Options(Options),
+      CController(new CoverageController(Options)) {
   SetDeathCallback();
   InitializeTraceState();
   assert(!F);
@@ -156,6 +177,8 @@ Fuzzer::Fuzzer(UserCallback CB, MutationDispatcher &MD, FuzzingOptions Options)
     EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
 }
 
+Fuzzer::~Fuzzer() { }
+
 void Fuzzer::LazyAllocateCurrentUnitData() {
   if (CurrentUnitData || Options.MaxLen == 0) return;
   CurrentUnitData = new uint8_t[Options.MaxLen];
@@ -421,15 +444,13 @@ void Fuzzer::ShuffleAndMinimize() {
 }
 
 bool Fuzzer::UpdateMaxCoverage() {
-  uintptr_t PrevBufferLen = MaxCoverage.PcBufferLen;
-  bool Res = CoverageController::RecordMax(Options, &MaxCoverage);
-
-  if (Options.PrintNewCovPcs && PrevBufferLen != MaxCoverage.PcBufferLen) {
-    uintptr_t *CoverageBuf;
-    EF->__sanitizer_get_coverage_pc_buffer(&CoverageBuf);
-    assert(CoverageBuf);
-    for (size_t I = PrevBufferLen; I < MaxCoverage.PcBufferLen; ++I) {
-      Printf("%p\n", CoverageBuf[I]);
+  uintptr_t PrevPcBufferPos = MaxCoverage.PcBufferPos;
+  bool Res = CController->RecordMax(&MaxCoverage);
+
+  if (Options.PrintNewCovPcs && PrevPcBufferPos != MaxCoverage.PcBufferPos) {
+    uintptr_t* PcBuffer = CController->pc_buffer();
+    for (size_t I = PrevPcBufferPos; I < MaxCoverage.PcBufferPos; ++I) {
+      Printf("%p\n", PcBuffer[I]);
     }
   }
 
@@ -440,7 +461,7 @@ bool Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
   TotalNumberOfRuns++;
 
   // TODO(aizatsky): this Reset call seems to be not needed.
-  CoverageController::ResetCounters(Options);
+  CController->ResetCounters();
   ExecuteCallback(Data, Size);
   bool Res = UpdateMaxCoverage();
 
@@ -693,9 +714,9 @@ size_t Fuzzer::ChooseUnitIdxToMutate() {
 }
 
 void Fuzzer::ResetCoverage() {
-  CoverageController::Reset();
+  CController->Reset();
   MaxCoverage.Reset();
-  CoverageController::Prepare(Options, &MaxCoverage);
+  CController->Prepare(&MaxCoverage);
 }
 
 // Experimental search heuristic: drilling.