[libFuzzer] make CrossOver just one of the other mutations
authorKostya Serebryany <kcc@google.com>
Sat, 19 Dec 2015 02:49:09 +0000 (02:49 +0000)
committerKostya Serebryany <kcc@google.com>
Sat, 19 Dec 2015 02:49:09 +0000 (02:49 +0000)
llvm-svn: 256081

llvm/lib/Fuzzer/FuzzerInterface.h
llvm/lib/Fuzzer/FuzzerInternal.h
llvm/lib/Fuzzer/FuzzerLoop.cpp
llvm/lib/Fuzzer/FuzzerMutate.cpp
llvm/lib/Fuzzer/test/FuzzerUnittest.cpp
llvm/lib/Fuzzer/test/fuzzer.test

index 329e3a9..65f1707 100644 (file)
@@ -22,6 +22,7 @@
 #include <string>
 
 namespace fuzzer {
+typedef std::vector<uint8_t> Unit;
 
 /// Returns an int 0. Values other than zero are reserved for future.
 typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
@@ -89,8 +90,12 @@ class MutationDispatcher {
   size_t Mutate_AddWordFromDictionary(uint8_t *Data, size_t Size,
                                       size_t MaxSize);
 
+  /// Tries to find an ASCII integer in Data, changes it to another ASCII int.
   size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
 
+  /// CrossOver Data with some other element of the corpus.
+  size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
+
   /// Applies one of the above mutations.
   /// Returns the new size of data which could be up to MaxSize.
   size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
@@ -100,6 +105,7 @@ class MutationDispatcher {
                    size_t Size2, uint8_t *Out, size_t MaxOutSize);
 
   void AddWordToDictionary(const uint8_t *Word, size_t Size);
+  void SetCorpus(const std::vector<Unit> *Corpus);
 
  private:
   FuzzerRandomBase &Rand;
@@ -144,6 +150,9 @@ class UserSuppliedFuzzer {
   virtual int TargetFunction(const uint8_t *Data, size_t Size) = 0;
   virtual void StartMutationSequence() { MD.StartMutationSequence(); }
   virtual void PrintMutationSequence() { MD.PrintMutationSequence(); }
+  virtual void SetCorpus(const std::vector<Unit> *Corpus) {
+    MD.SetCorpus(Corpus);
+  }
   /// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes,
   /// returns the new size of the data, which should be positive.
   virtual size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
index bc6bec7..e96a4bc 100644 (file)
@@ -24,7 +24,6 @@
 #include "FuzzerInterface.h"
 
 namespace fuzzer {
-typedef std::vector<uint8_t> Unit;
 using namespace std::chrono;
 
 std::string FileToString(const std::string &Path);
@@ -132,7 +131,7 @@ class Fuzzer {
 
  private:
   void AlarmCallback();
-  void MutateAndTestOne(Unit *U);
+  void MutateAndTestOne();
   void ReportNewCoverage(const Unit &U);
   bool RunOne(const Unit &U);
   void RunOneAndUpdateCorpus(Unit &U);
index b1ce294..7ea82f4 100644 (file)
@@ -367,29 +367,34 @@ void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
   Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried);
 }
 
-void Fuzzer::MutateAndTestOne(Unit *U) {
+void Fuzzer::MutateAndTestOne() {
+  auto &U = CurrentUnit;
+  USF.StartMutationSequence();
+
+  U = ChooseUnitToMutate();
+
   for (int i = 0; i < Options.MutateDepth; i++) {
     StartTraceRecording();
-    size_t Size = U->size();
-    U->resize(Options.MaxLen);
-    size_t NewSize = USF.Mutate(U->data(), Size, U->size());
+    size_t Size = U.size();
+    U.resize(Options.MaxLen);
+    size_t NewSize = USF.Mutate(U.data(), Size, U.size());
     assert(NewSize > 0 && "Mutator returned empty unit");
     assert(NewSize <= (size_t)Options.MaxLen &&
            "Mutator return overisized unit");
-    U->resize(NewSize);
-    RunOneAndUpdateCorpus(*U);
+    U.resize(NewSize);
+    RunOneAndUpdateCorpus(U);
     size_t NumTraceBasedMutations = StopTraceRecording();
     size_t TBMWidth =
         std::min((size_t)Options.TBMWidth, NumTraceBasedMutations);
     size_t TBMDepth =
         std::min((size_t)Options.TBMDepth, NumTraceBasedMutations);
-    Unit BackUp = *U;
+    Unit BackUp = U;
     for (size_t w = 0; w < TBMWidth; w++) {
-      *U = BackUp;
+      U = BackUp;
       for (size_t d = 0; d < TBMDepth; d++) {
         TotalNumberOfExecutedTraceBasedMutations++;
-        ApplyTraceBasedMutation(USF.GetRand()(NumTraceBasedMutations), U);
-        RunOneAndUpdateCorpus(*U);
+        ApplyTraceBasedMutation(USF.GetRand()(NumTraceBasedMutations), &U);
+        RunOneAndUpdateCorpus(U);
       }
     }
   }
@@ -465,8 +470,9 @@ void Fuzzer::Drill() {
 
 void Fuzzer::Loop() {
   system_clock::time_point LastCorpusReload = system_clock::now();
+  if (Options.DoCrossOver)
+    USF.SetCorpus(&Corpus);
   while (true) {
-    size_t J1 = ChooseUnitIdxToMutate();;
     SyncCorpus();
     auto Now = system_clock::now();
     if (duration_cast<seconds>(Now - LastCorpusReload).count()) {
@@ -479,25 +485,8 @@ void Fuzzer::Loop() {
         secondsSinceProcessStartUp() >
         static_cast<size_t>(Options.MaxTotalTimeSec))
       break;
-    USF.StartMutationSequence();
-    CurrentUnit = Corpus[J1];
-    // Optionally, cross with another unit.
-    if (Options.DoCrossOver && USF.GetRand().RandBool()) {
-      size_t J2 = ChooseUnitIdxToMutate();
-      if (!Corpus[J1].empty() && !Corpus[J2].empty()) {
-        assert(!Corpus[J2].empty());
-        CurrentUnit.resize(Options.MaxLen);
-        size_t NewSize = USF.CrossOver(
-            Corpus[J1].data(), Corpus[J1].size(), Corpus[J2].data(),
-            Corpus[J2].size(), CurrentUnit.data(), CurrentUnit.size());
-        assert(NewSize > 0 && "CrossOver returned empty unit");
-        assert(NewSize <= (size_t)Options.MaxLen &&
-               "CrossOver returned overisized unit");
-        CurrentUnit.resize(NewSize);
-      }
-    }
     // Perform several mutations and runs.
-    MutateAndTestOne(&CurrentUnit);
+    MutateAndTestOne();
   }
 
   PrintStats("DONE  ", "\n");
index 471ae6c..c3fa37a 100644 (file)
@@ -26,6 +26,7 @@ struct MutationDispatcher::Impl {
   std::vector<Unit> Dictionary;
   std::vector<Mutator> Mutators;
   std::vector<Mutator> CurrentMutatorSequence;
+  const std::vector<Unit> *Corpus = nullptr;
 
   void Add(Mutator M) { Mutators.push_back(M); }
   Impl() {
@@ -35,6 +36,7 @@ struct MutationDispatcher::Impl {
     Add({&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"});
     Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"});
     Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"});
+    Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"});
   }
   void AddWordToDictionary(const uint8_t *Word, size_t Size) {
     if (Dictionary.empty()) {
@@ -42,6 +44,7 @@ struct MutationDispatcher::Impl {
     }
     Dictionary.push_back(Unit(Word, Word + Size));
   }
+  void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; }
 };
 
 static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
@@ -154,6 +157,22 @@ size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
   return Size;
 }
 
+size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
+                                            size_t MaxSize) {
+  auto Corpus = MDImpl->Corpus;
+  if (!Corpus || Corpus->size() < 2 || Size == 0) return 0;
+  size_t Idx = Rand(Corpus->size());
+  const Unit &Other = (*Corpus)[Idx];
+  if (Other.empty()) return 0;
+  Unit U(MaxSize);
+  size_t NewSize =
+      CrossOver(Data, Size, Other.data(), Other.size(), U.data(), U.size());
+  assert(NewSize > 0 && "CrossOver returned empty unit");
+  assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
+  memcpy(Data, U.data(), NewSize);
+  return NewSize;
+}
+
 void MutationDispatcher::StartMutationSequence() {
   MDImpl->CurrentMutatorSequence.clear();
 }
@@ -189,6 +208,10 @@ size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
   return Size;
 }
 
+void MutationDispatcher::SetCorpus(const std::vector<Unit> *Corpus) {
+  MDImpl->SetCorpus(Corpus);
+}
+
 void MutationDispatcher::AddWordToDictionary(const uint8_t *Word, size_t Size) {
   MDImpl->AddWordToDictionary(Word, Size);
 }
index b92e618..8c00127 100644 (file)
@@ -239,7 +239,7 @@ TEST(FuzzerMutate, ShuffleBytes1) {
   TestShuffleBytes(&MutationDispatcher::Mutate_ShuffleBytes, 1 << 15);
 }
 TEST(FuzzerMutate, ShuffleBytes2) {
-  TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 16);
+  TestShuffleBytes(&MutationDispatcher::Mutate, 1 << 19);
 }
 
 void TestAddWordFromDictionary(Mutator M, int NumIter) {
index 6515628..206b99e 100644 (file)
@@ -41,10 +41,10 @@ RUN: rm -rf FourIndependentBranchesTestCORPUS
 
 RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
 
-RUN: not LLVMFuzzer-CallerCalleeTest                     -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
-RUN:     LLVMFuzzer-CallerCalleeTest  -use_indir_calls=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s  --check-prefix=Done1000000
+RUN: not LLVMFuzzer-CallerCalleeTest                     -cross_over=0 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
+RUN:     LLVMFuzzer-CallerCalleeTest  -use_indir_calls=0 -cross_over=0 -max_len=6 -seed=1 -runs=1000000 2>&1 | FileCheck %s  --check-prefix=Done1000000
 
-RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=1000001 -timeout=5 2>&1 | FileCheck %s
 
 RUN: not LLVMFuzzer-UserSuppliedFuzzerTest -seed=1 -timeout=15 2>&1 | FileCheck %s
 
@@ -55,13 +55,13 @@ Done1000000: Done 1000000 runs in
 RUN: not LLVMFuzzer-StrncmpTest -use_traces=1 -seed=1 -runs=100000   2>&1 | FileCheck %s
 RUN:     LLVMFuzzer-StrncmpTest               -seed=1 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000
 
-RUN: not LLVMFuzzer-StrcmpTest -use_traces=1 -seed=1 -runs=100000   2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-StrcmpTest -use_traces=1 -seed=1 -runs=200000   2>&1 | FileCheck %s
 RUN:     LLVMFuzzer-StrcmpTest               -seed=1 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000
 
-RUN: not LLVMFuzzer-SwitchTest -use_traces=1 -seed=1 -runs=1000000  2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SwitchTest -use_traces=1 -seed=1 -runs=1000002  2>&1 | FileCheck %s
 RUN:     LLVMFuzzer-SwitchTest               -seed=1 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000
 
-RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000000  2>&1 | FileCheck %s
+RUN: not LLVMFuzzer-SimpleDictionaryTest -dict=%S/dict1.txt -seed=1 -runs=1000003  2>&1 | FileCheck %s
 RUN:     LLVMFuzzer-SimpleDictionaryTest                    -seed=1 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000
 
 RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=1 -runs=100000  2>&1 | FileCheck %s