[llvm] r284273 - [libFuzzer] add -trace_cmp=1 (guiding mutations based on the observed CMP instructions). This is a reincarnation of the previously deleted -use_traces, but using a different approach for collecting traces. Still a toy, but at least it scales well. Also fix -merge in trace-pc-guard mode

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Fri Oct 14 13:20:33 PDT 2016


Author: kcc
Date: Fri Oct 14 15:20:33 2016
New Revision: 284273

URL: http://llvm.org/viewvc/llvm-project?rev=284273&view=rev
Log:
[libFuzzer] add -trace_cmp=1 (guiding mutations based on the observed CMP instructions). This is a reincarnation of the previously deleted -use_traces, but using a different approach for collecting traces. Still a toy, but at least it scales well. Also fix -merge in trace-pc-guard mode

Modified:
    llvm/trunk/lib/Fuzzer/FuzzerCorpus.h
    llvm/trunk/lib/Fuzzer/FuzzerDefs.h
    llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
    llvm/trunk/lib/Fuzzer/FuzzerFlags.def
    llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
    llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp
    llvm/trunk/lib/Fuzzer/FuzzerMutate.h
    llvm/trunk/lib/Fuzzer/FuzzerOptions.h
    llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
    llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
    llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp
    llvm/trunk/lib/Fuzzer/test/trace-malloc.test

Modified: llvm/trunk/lib/Fuzzer/FuzzerCorpus.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerCorpus.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerCorpus.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerCorpus.h Fri Oct 14 15:20:33 2016
@@ -153,6 +153,12 @@ class InputCorpus {
     return Res;
   }
 
+  void ResetFeatureSet() {
+    assert(Inputs.empty());
+    memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
+    memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
+  }
+
 private:
 
   static const bool FeatureDebug = false;

Modified: llvm/trunk/lib/Fuzzer/FuzzerDefs.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDefs.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDefs.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDefs.h Fri Oct 14 15:20:33 2016
@@ -111,5 +111,11 @@ int NumberOfCpuCores();
 int GetPid();
 void SleepSeconds(int Seconds);
 
+
+struct ScopedDoingMyOwnMemmem {
+  ScopedDoingMyOwnMemmem();
+  ~ScopedDoingMyOwnMemmem();
+};
+
 }  // namespace fuzzer
 #endif  // LLVM_FUZZER_DEFS_H

Modified: llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerDriver.cpp Fri Oct 14 15:20:33 2016
@@ -397,6 +397,7 @@ int FuzzerDriver(int *argc, char ***argv
   Options.UseIndirCalls = Flags.use_indir_calls;
   Options.UseMemcmp = Flags.use_memcmp;
   Options.UseMemmem = Flags.use_memmem;
+  Options.UseCmp = Flags.use_cmp;
   Options.UseValueProfile = Flags.use_value_profile;
   Options.Shrink = Flags.shrink;
   Options.ShuffleAtStartUp = Flags.shuffle;

Modified: llvm/trunk/lib/Fuzzer/FuzzerFlags.def
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerFlags.def?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerFlags.def (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerFlags.def Fri Oct 14 15:20:33 2016
@@ -49,6 +49,7 @@ FUZZER_FLAG_INT(use_memmem, 1,
                 "Use hints from intercepting memmem, strstr, etc")
 FUZZER_FLAG_INT(use_value_profile, 0,
                 "Experimental. Use value profile to guide fuzzing.")
+FUZZER_FLAG_INT(use_cmp, 0, "Experimenta. Use CMP traces to guide mutations")
 FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus elements.")
 FUZZER_FLAG_INT(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
                           " this number of jobs in separate worker processes"
@@ -92,7 +93,7 @@ FUZZER_FLAG_INT(close_fd_mask, 0, "If 1,
 FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
     "try to detect memory leaks during fuzzing (i.e. not only at shut down).")
 FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
-                                 "If >= 2 will also print stack traces.")
+    "If >= 2 will also print stack traces.")
 FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
     "reaching this limit of RSS memory usage.")
 FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"

Modified: llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerLoop.cpp Fri Oct 14 15:20:33 2016
@@ -479,6 +479,9 @@ size_t Fuzzer::RunOne(const uint8_t *Dat
       Res = 1;
   }
 
+  if (Res && Options.UseCmp)
+    TPC.ProcessTORC(MD.GetTraceCmpDictionary(), CurrentUnitData, Size);
+
   CheckExitOnSrcPos();
   auto TimeOfUnit =
       duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
@@ -513,6 +516,8 @@ void Fuzzer::ExecuteCallback(const uint8
   UnitStartTime = system_clock::now();
   ResetCounters();  // Reset coverage right before the callback.
   TPC.ResetMaps();
+  if (Options.UseCmp)
+    TPC.ResetTORC();
   if (Options.UseCounters)
     TPC.ResetGuards();
   int Res = CB(DataCopy, Size);
@@ -594,15 +599,22 @@ UnitVector Fuzzer::FindExtraUnits(const
     ShuffleCorpus(&Res);
     TPC.ResetMaps();
     TPC.ResetGuards();
+    Corpus.ResetFeatureSet();
     ResetCoverage();
 
-    for (auto &U : Initial)
+    for (auto &U : Initial) {
+      TPC.ResetMaps();
+      TPC.ResetGuards();
       RunOne(U);
+    }
 
     Tmp.clear();
-    for (auto &U : Res)
+    for (auto &U : Res) {
+      TPC.ResetMaps();
+      TPC.ResetGuards();
       if (RunOne(U))
         Tmp.push_back(U);
+    }
 
     char Stat[7] = "MIN   ";
     Stat[3] = '0' + Iter;

Modified: llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp Fri Oct 14 15:20:33 2016
@@ -43,12 +43,16 @@ MutationDispatcher::MutationDispatcher(R
           {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
           {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
           {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
-           "AddFromManualDict"},
+           "ManualDict"},
           {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
-           "AddFromTempAutoDict"},
+           "TempAutoDict"},
           {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
-           "AddFromPersAutoDict"},
+           "PersAutoDict"},
       });
+  if(Options.UseCmp)
+    DefaultMutators.push_back(
+        {&MutationDispatcher::Mutate_AddWordFromTraceCmpDictionary,
+         "TraceCmpDict"});
 
   if (EF->LLVMFuzzerCustomMutator)
     Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
@@ -171,6 +175,11 @@ size_t MutationDispatcher::Mutate_AddWor
   return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
 }
 
+size_t MutationDispatcher::Mutate_AddWordFromTraceCmpDictionary(
+    uint8_t *Data, size_t Size, size_t MaxSize) {
+  return AddWordFromDictionary(TraceCmpDictionary, Data, Size, MaxSize);
+}
+
 size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
     uint8_t *Data, size_t Size, size_t MaxSize) {
   return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);

Modified: llvm/trunk/lib/Fuzzer/FuzzerMutate.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerMutate.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerMutate.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerMutate.h Fri Oct 14 15:20:33 2016
@@ -55,6 +55,10 @@ public:
   size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size,
                                                    size_t MaxSize);
 
+  /// Mutates data by adding a word from the trace-cmp dictionary.
+  size_t Mutate_AddWordFromTraceCmpDictionary(uint8_t *Data, size_t Size,
+                                              size_t MaxSize);
+
   /// Mutates data by adding a word from the persistent automatic dictionary.
   size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
                                                     size_t MaxSize);
@@ -88,6 +92,8 @@ public:
 
   Random &GetRand() { return Rand; }
 
+  Dictionary *GetTraceCmpDictionary() { return &TraceCmpDictionary; }
+
 private:
 
   struct Mutator {
@@ -116,6 +122,10 @@ private:
   // Persistent dictionary modified by the fuzzer, consists of
   // entries that led to successfull discoveries in the past mutations.
   Dictionary PersistentAutoDictionary;
+
+  // Dictionary from tracing CMP instructions.
+  Dictionary TraceCmpDictionary;
+
   std::vector<Mutator> CurrentMutatorSequence;
   std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
   const InputCorpus *Corpus = nullptr;

Modified: llvm/trunk/lib/Fuzzer/FuzzerOptions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerOptions.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerOptions.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerOptions.h Fri Oct 14 15:20:33 2016
@@ -30,6 +30,7 @@ struct FuzzingOptions {
   bool UseIndirCalls = true;
   bool UseMemcmp = true;
   bool UseMemmem = true;
+  bool UseCmp = false;
   bool UseValueProfile = false;
   bool Shrink = false;
   int ReloadIntervalSec = 1;

Modified: llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.cpp Fri Oct 14 15:20:33 2016
@@ -14,6 +14,7 @@
 
 #include "FuzzerCorpus.h"
 #include "FuzzerDefs.h"
+#include "FuzzerDictionary.h"
 #include "FuzzerTracePC.h"
 #include "FuzzerValueBitMap.h"
 
@@ -170,11 +171,62 @@ __attribute__((always_inline))
 #endif  // __clang__
 void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) {
   uintptr_t PCuint = reinterpret_cast<uintptr_t>(PC);
-  uint64_t ArgDistance = __builtin_popcountl(Arg1 ^ Arg2) + 1; // [1,65]
+  uint64_t ArgXor = Arg1 ^ Arg2;
+  uint64_t ArgDistance = __builtin_popcountl(ArgXor) + 1; // [1,65]
   uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance;
+  TORCInsert(ArgXor, Arg1, Arg2);
   HandleValueProfile(Idx);
 }
 
+void TracePC::ProcessTORC(Dictionary *Dict, const uint8_t *Data, size_t Size) {
+  TORCToDict(TORC8, Dict, Data, Size);
+  TORCToDict(TORC4, Dict, Data, Size);
+}
+
+template <class T>
+void TracePC::TORCToDict(const TableOfRecentCompares<T, kTORCSize> &TORC,
+                         Dictionary *Dict, const uint8_t *Data, size_t Size) {
+  ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
+  for (size_t i = 0; i < TORC.kSize; i++) {
+    T A[2] = {TORC.Table[i][0], TORC.Table[i][1]};
+    if (!A[0] && !A[1]) continue;
+    for (int j = 0; j < 2; j++)
+      TORCToDict(Dict, A[j], A[!j], Data, Size);
+  }
+}
+
+template <class T>
+void TracePC::TORCToDict(Dictionary *Dict, T FindInData, T Substitute,
+                         const uint8_t *Data, size_t Size) {
+  if (FindInData == Substitute) return;
+  if (sizeof(T) == 4) {
+    uint16_t HigherBytes = Substitute >> sizeof(T) * 4;
+    if (HigherBytes == 0 || HigherBytes == 0xffff)
+      TORCToDict(Dict, static_cast<uint16_t>(FindInData),
+                 static_cast<uint16_t>(Substitute), Data, Size);
+  }
+  const size_t DataSize = sizeof(T);
+  const uint8_t *End = Data + Size;
+  int Attempts = 3;
+  // TODO: also swap bytes in FindInData.
+  for (const uint8_t *Cur = Data; Cur < End && Attempts--; Cur++) {
+    Cur = (uint8_t *)memmem(Cur, End - Cur, &FindInData, DataSize);
+    if (!Cur)
+      break;
+    size_t Pos = Cur - Data;
+    for (int Offset = 0; Offset <= 0; Offset++) {
+      T Tmp = Substitute + Offset;
+      Word W(reinterpret_cast<uint8_t *>(&Tmp), sizeof(Tmp));
+      DictionaryEntry DE(W, Pos);
+      // TODO: evict all entries from Dic if it's full.
+      Dict->push_back(DE);
+      // Printf("Dict[%zd] TORC%zd %llx => %llx pos %zd\n", Dict->size(),
+      // sizeof(T),
+      //       (uint64_t)FindInData, (uint64_t)Tmp, Pos);
+    }
+  }
+}
+
 } // namespace fuzzer
 
 extern "C" {

Modified: llvm/trunk/lib/Fuzzer/FuzzerTracePC.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTracePC.h?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTracePC.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTracePC.h Fri Oct 14 15:20:33 2016
@@ -17,6 +17,25 @@
 
 namespace fuzzer {
 
+// TableOfRecentCompares (TORC) remembers the most recently performed
+// comparisons of type T.
+// We record the arguments of CMP instructions in this table unconditionally
+// because it seems cheaper this way than to compute some expensive
+// conditions inside __sanitizer_cov_trace_cmp*.
+// After the unit has been executed we may decide to use the contents of
+// this table to populate a Dictionary.
+template<class T, size_t kSizeT>
+struct TableOfRecentCompares {
+  static const size_t kSize = kSizeT;
+  void Insert(size_t Idx, T Arg1, T Arg2) {
+    Idx = Idx % kSize;
+    Table[Idx][0] = Arg1;
+    Table[Idx][1] = Arg2;
+  }
+  void Clear() { memset(Table, 0, sizeof(Table)); }
+  T Table[kSize][2];
+};
+
 class TracePC {
  public:
   static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems;
@@ -48,6 +67,11 @@ class TracePC {
     memset(Counters, 0, sizeof(Counters));
   }
 
+  void ResetTORC() {
+    TORC4.Clear();
+    TORC8.Clear();
+  }
+
   void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
   void PrintFeatureSet();
 
@@ -64,6 +88,8 @@ class TracePC {
 
   bool UsingTracePcGuard() const {return NumModules; }
 
+  void ProcessTORC(Dictionary *Dict, const uint8_t *Data, size_t Size);
+
 private:
   bool UseCounters = false;
   bool UseValueProfile = false;
@@ -87,6 +113,29 @@ private:
   static const size_t kNumCounters = 1 << 14;
   alignas(8) uint8_t Counters[kNumCounters];
 
+  static const size_t kTORCSize = 1 << 12;
+  TableOfRecentCompares<uint32_t, kTORCSize> TORC4;
+  TableOfRecentCompares<uint64_t, kTORCSize> TORC8;
+  void TORCInsert(size_t Idx, uint8_t Arg1, uint8_t Arg2) {
+    // Do nothing, too small to be interesting.
+  }
+  void TORCInsert(size_t Idx, uint16_t Arg1, uint16_t Arg2) {
+    // Do nothing, these don't usually hapen.
+  }
+  void TORCInsert(size_t Idx, uint32_t Arg1, uint32_t Arg2) {
+    TORC4.Insert(Idx, Arg1, Arg2);
+  }
+  void TORCInsert(size_t Idx, uint64_t Arg1, uint64_t Arg2) {
+    TORC8.Insert(Idx, Arg1, Arg2);
+  }
+
+  template <class T>
+  void TORCToDict(const TableOfRecentCompares<T, kTORCSize> &TORC,
+                  Dictionary *Dict, const uint8_t *Data, size_t Size);
+  template <class T>
+  void TORCToDict(Dictionary *Dict, T FindInData, T Substitute,
+                  const uint8_t *Data, size_t Size);
+
   static const size_t kNumPCs = 1 << 24;
   uintptr_t PCs[kNumPCs];
 

Modified: llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerTraceState.cpp Fri Oct 14 15:20:33 2016
@@ -34,10 +34,8 @@ static bool RecordingMemcmp = false;
 static bool RecordingMemmem = false;
 static bool DoingMyOwnMemmem = false;
 
-struct ScopedDoingMyOwnMemmem {
-  ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
-  ~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
-};
+ScopedDoingMyOwnMemmem::ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
+ScopedDoingMyOwnMemmem::~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
 
 class TraceState {
 public:

Modified: llvm/trunk/lib/Fuzzer/test/trace-malloc.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/trace-malloc.test?rev=284273&r1=284272&r2=284273&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/trace-malloc.test (original)
+++ llvm/trunk/lib/Fuzzer/test/trace-malloc.test Fri Oct 14 15:20:33 2016
@@ -1,4 +1,4 @@
-RUN: LLVMFuzzer-TraceMallocTest -seed=1 -trace_malloc=1 -runs=1000 2>&1 | FileCheck %s
+RUN: LLVMFuzzer-TraceMallocTest -seed=1 -trace_malloc=1 -runs=10000 2>&1 | FileCheck %s
 CHECK-DAG: MallocFreeTracer: STOP 0 0 (same)
 CHECK-DAG: MallocFreeTracer: STOP 0 1 (DIFFERENT)
 CHECK-DAG: MallocFreeTracer: STOP 1 0 (DIFFERENT)




More information about the llvm-commits mailing list