[libFuzzer] implement print_pcs with trace-pc-guard. Change the trace-pc-guard heuris...
authorKostya Serebryany <kcc@google.com>
Thu, 15 Sep 2016 04:36:45 +0000 (04:36 +0000)
committerKostya Serebryany <kcc@google.com>
Thu, 15 Sep 2016 04:36:45 +0000 (04:36 +0000)
llvm-svn: 281577

llvm/lib/Fuzzer/FuzzerInternal.h
llvm/lib/Fuzzer/FuzzerLoop.cpp
llvm/lib/Fuzzer/FuzzerTracePC.cpp
llvm/lib/Fuzzer/FuzzerValueBitMap.h
llvm/lib/Fuzzer/test/fuzzer-printcovpcs.test

index eed3a659eb54b98f267f4340ecdb7f450b4cba3a..9f0641ff46caeb0bfa09400a07c9f40e3338ff40 100644 (file)
@@ -365,13 +365,27 @@ class TracePC {
   size_t UpdateCounterMap(ValueBitMap *Map);
   void FinalizeTrace();
 
+  size_t GetNewPCsAndFlush(uintptr_t **NewPCsPtr = nullptr) {
+    if (NewPCsPtr)
+      *NewPCsPtr = NewPCs;
+    size_t Res = NumNewPCs;
+    NumNewPCs = 0;
+    return Res;
+  }
+
 private:
   bool UseCounters = false;
   size_t TotalCoverage = 0;
   size_t TotalCounterBits = 0;
 
+  static const size_t kMaxNewPCs = 64;
+  uintptr_t NewPCs[kMaxNewPCs];
+  size_t NumNewPCs = 0;
+  void AddNewPC(uintptr_t PC) { NewPCs[(NumNewPCs++) % kMaxNewPCs] = PC; }
+
   uint8_t *Start, *Stop;
   ValueBitMap CounterMap;
+  ValueBitMap TotalCoverageMap;
 };
 
 extern TracePC TPC;
@@ -469,6 +483,7 @@ private:
   void MutateAndTestOne();
   void ReportNewCoverage(const Unit &U);
   void PrintNewPCs();
+  void PrintOneNewPC(uintptr_t PC);
   bool RunOne(const Unit &U) { return RunOne(U.data(), U.size()); }
   void RunOneAndUpdateCorpus(const uint8_t *Data, size_t Size);
   void WriteToOutputCorpus(const Unit &U);
index 54e748fb796fcb02c5fa7e29cfa500ca6b7c3a32..7cb1d4906a513076dadbe5a526ddffd9b5c037f3 100644 (file)
@@ -63,6 +63,7 @@ void Fuzzer::ResetCounters() {
   }
   if (EF->__sanitizer_get_coverage_pc_buffer_pos)
     PcBufferPos = EF->__sanitizer_get_coverage_pc_buffer_pos();
+  TPC.GetNewPCsAndFlush();
 }
 
 void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) {
@@ -556,22 +557,31 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U) {
   }
 }
 
+void Fuzzer::PrintOneNewPC(uintptr_t PC) {
+  if (EF->__sanitizer_symbolize_pc) {
+    char PcDescr[1024];
+    EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
+                                 "%p %F %L", PcDescr, sizeof(PcDescr));
+    PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
+    Printf("\tNEW_PC: %s\n", PcDescr);
+  } else {
+    Printf("\tNEW_PC: %p\n", PC);
+  }
+}
+
 void Fuzzer::PrintNewPCs() {
-  if (Options.PrintNewCovPcs && PrevPcBufferPos != PcBufferPos) {
+  if (!Options.PrintNewCovPcs) return;
+  if (PrevPcBufferPos != PcBufferPos) {
     int NumPrinted = 0;
     for (size_t I = PrevPcBufferPos; I < PcBufferPos; ++I) {
       if (NumPrinted++ > 30) break;  // Don't print too many new PCs.
-      if (EF->__sanitizer_symbolize_pc) {
-        char PcDescr[1024];
-        EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PcBuffer[I]),
-                                     "%p %F %L", PcDescr, sizeof(PcDescr));
-        PcDescr[sizeof(PcDescr) - 1] = 0;  // Just in case.
-        Printf("\tNEW_PC: %s\n", PcDescr);
-      } else {
-        Printf("\tNEW_PC: %p\n", PcBuffer[I]);
-      }
+      PrintOneNewPC(PcBuffer[I]);
     }
   }
+  uintptr_t *PCs;
+  if (size_t NumNewPCs = TPC.GetNewPCsAndFlush(&PCs))
+    for (size_t i = 0; i < NumNewPCs; i++)
+      PrintOneNewPC(PCs[i]);
 }
 
 void Fuzzer::ReportNewCoverage(const Unit &U) {
index 2822725f555cb63909032f72a9ec428e45ef961a..b01769203e2699551c9182dd569edfa4222353a0 100644 (file)
@@ -21,14 +21,20 @@ TracePC TPC;
 void TracePC::HandleTrace(uint8_t *Guard, uintptr_t PC) {
   if (UseCounters) {
     uintptr_t GV = *Guard;
-    if (GV == 0)
-      TotalCoverage++;
+    if (GV == 0) {
+      size_t Idx = Guard - Start;
+      if (TotalCoverageMap.AddValue(Idx)) {
+        TotalCoverage++;
+        AddNewPC(PC);
+      }
+    }
     if (GV < 255)
       GV++;
     *Guard = GV;
   } else {
     *Guard = 0xff;
     TotalCoverage++;
+    AddNewPC(PC);
   }
 }
 
@@ -43,12 +49,18 @@ void TracePC::FinalizeTrace() {
     for (uint8_t *X = Start; X < Stop; X++) {
       uint8_t Value = *X;
       size_t Idx = X - Start;
-      if (Value >= 2) {
-        unsigned Bit = 31 - __builtin_clz(Value);
-        assert(Bit < 8);
+      if (Value >= 1) {
+        unsigned Bit = 0;
+        /**/ if (Value >= 128) Bit = 7;
+        else if (Value >= 32) Bit = 6;
+        else if (Value >= 16) Bit = 5;
+        else if (Value >= 8) Bit = 4;
+        else if (Value >= 4) Bit = 3;
+        else if (Value >= 3) Bit = 2;
+        else if (Value >= 2) Bit = 1;
         CounterMap.AddValue(Idx * 8 + Bit);
       }
-      *X = 1;
+      *X = 0;
     }
   }
 }
index 2a917333e21dd4eaf00187af16b56e0642249c9a..6f6ca1164730c912e2b1840729eefe3a5532df31 100644 (file)
@@ -24,12 +24,16 @@ struct ValueBitMap {
   // Clears all bits.
   void Reset() { memset(Map, 0, sizeof(Map)); }
 
-  // Computed a hash function of Value and sets the corresponding bit.
-  inline void AddValue(uintptr_t Value) {
+  // Computes a hash function of Value and sets the corresponding bit.
+  // Returns true if the bit was changed from 0 to 1.
+  inline bool AddValue(uintptr_t Value) {
     uintptr_t Idx = Value < kMapSizeInBits ? Value : Value % kMapSizeInBits;
     uintptr_t WordIdx = Idx / kBitsInWord;
     uintptr_t BitIdx = Idx % kBitsInWord;
-    Map[WordIdx] |= 1UL << BitIdx;
+    uintptr_t Old = Map[WordIdx];
+    uintptr_t New = Old | (1UL << BitIdx);
+    Map[WordIdx] = New;
+    return New != Old;
   }
 
   // Merges 'Other' into 'this', clears 'Other',
index a1ef2b7c84886510fee29d14aee304e6f3699adc..257c9f61597976bf1fcd449756e27cdcf4ee8f25 100644 (file)
@@ -1,7 +1,14 @@
-RUN: LLVMFuzzer-SimpleTest -print_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS
+RUN: LLVMFuzzer-SimpleTest         -print_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS
+RUN: LLVMFuzzer-SimpleTest-TracePC -print_pcs=1 2>&1 | FileCheck %s --check-prefix=PCS
 PCS-NOT: NEW_PC
 PCS:INITED
 PCS:NEW_PC: {{0x[a-f0-9]+}}
+PCS:NEW_PC: {{0x[a-f0-9]+}}
 PCS:NEW
 PCS:BINGO
 
+RUN: LLVMFuzzer-CounterTest-TracePC -use_counters=0 -print_pcs=1 -runs=10000 2>&1 | FileCheck %s --check-prefix=C_PCS
+RUN: LLVMFuzzer-CounterTest-TracePC -use_counters=1 -print_pcs=1 -runs=10000 2>&1 | FileCheck %s --check-prefix=C_PCS
+
+C_PCS: NEW_PC: {{.*}} in LLVMFuzzerTestOneInput {{.*}}CounterTest.cpp:11
+C_PCS: NEW_PC: {{.*}} in LLVMFuzzerTestOneInput {{.*}}CounterTest.cpp:12