[libFuzzer] allow users to supply their own implementation of rand
authorKostya Serebryany <kcc@google.com>
Fri, 24 Jul 2015 01:06:40 +0000 (01:06 +0000)
committerKostya Serebryany <kcc@google.com>
Fri, 24 Jul 2015 01:06:40 +0000 (01:06 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@243078 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Fuzzer/FuzzerCrossOver.cpp
lib/Fuzzer/FuzzerDriver.cpp
lib/Fuzzer/FuzzerInterface.cpp
lib/Fuzzer/FuzzerInterface.h
lib/Fuzzer/FuzzerInternal.h
lib/Fuzzer/FuzzerLoop.cpp
lib/Fuzzer/FuzzerMutate.cpp
lib/Fuzzer/FuzzerTraceState.cpp
lib/Fuzzer/test/FuzzerUnittest.cpp
lib/Fuzzer/test/UserSuppliedFuzzerTest.cpp

index d93ce5cf4fb8a433e1c33627657d6c7c85551dd3..8b13698b5aef4faeb4464e8a3fa8df13b0ab6e43 100644 (file)
@@ -18,9 +18,9 @@ namespace fuzzer {
 // Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
 size_t CrossOver(const uint8_t *Data1, size_t Size1,
                  const uint8_t *Data2, size_t Size2,
-                 uint8_t *Out, size_t MaxOutSize) {
+                 uint8_t *Out, size_t MaxOutSize, FuzzerRandomBase &Rand) {
   assert(Size1 || Size2);
-  MaxOutSize = rand() % MaxOutSize + 1;
+  MaxOutSize = Rand(MaxOutSize) + 1;
   size_t OutPos = 0;
   size_t Pos1 = 0;
   size_t Pos2 = 0;
@@ -34,7 +34,7 @@ size_t CrossOver(const uint8_t *Data1, size_t Size1,
     if (*InPos < InSize) {
       size_t InSizeLeft = InSize - *InPos;
       size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
-      size_t ExtraSize = rand() % MaxExtraSize + 1;
+      size_t ExtraSize = Rand(MaxExtraSize) + 1;
       memcpy(Out + OutPos, Data + *InPos, ExtraSize);
       OutPos += ExtraSize;
       (*InPos) += ExtraSize;
index 0ee08e1d162424565734a3f37448163bebb35fa9..c0f8220ad655da99676b6a237aaca763ce9b7b0c 100644 (file)
@@ -202,7 +202,8 @@ int ApplyTokens(const Fuzzer &F, const char *InputFilePath) {
 }
 
 int FuzzerDriver(int argc, char **argv, UserCallback Callback) {
-  SimpleUserSuppliedFuzzer SUSF(Callback);
+  FuzzerRandomLibc Rand(0);
+  SimpleUserSuppliedFuzzer SUSF(&Rand, Callback);
   return FuzzerDriver(argc, argv, SUSF);
 }
 
@@ -257,7 +258,7 @@ int FuzzerDriver(int argc, char **argv, UserSuppliedFuzzer &USF) {
     Seed = time(0) * 10000 + getpid();
   if (Flags.verbosity)
     Printf("Seed: %u\n", Seed);
-  srand(Seed);
+  USF.GetRand().ResetSeed(Seed);
 
   // Timer
   if (Flags.timeout > 0)
index dcd4e746013cc7171b4d1bb8c3c409c66ef2a12b..c7553f421fb97f6c8e30e6042ae300aebc53583f 100644 (file)
 #include "FuzzerInternal.h"
 
 namespace fuzzer {
+
+void FuzzerRandomLibc::ResetSeed(int seed) { srand(seed); }
+
+size_t FuzzerRandomLibc::Rand() { return rand(); }
+
+UserSuppliedFuzzer::UserSuppliedFuzzer()
+    : OwnRand(true), Rand(new FuzzerRandomLibc(0)) {}
+
+UserSuppliedFuzzer::UserSuppliedFuzzer(FuzzerRandomBase *Rand) : Rand(Rand) {}
+
+UserSuppliedFuzzer::~UserSuppliedFuzzer() {
+  if (OwnRand)
+    delete Rand;
+}
+
 size_t UserSuppliedFuzzer::BasicMutate(uint8_t *Data, size_t Size,
                                        size_t MaxSize) {
-  return ::fuzzer::Mutate(Data, Size, MaxSize);
+  return ::fuzzer::Mutate(Data, Size, MaxSize, *Rand);
 }
 size_t UserSuppliedFuzzer::BasicCrossOver(const uint8_t *Data1, size_t Size1,
                                           const uint8_t *Data2, size_t Size2,
                                           uint8_t *Out, size_t MaxOutSize) {
-  return ::fuzzer::CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
+  return ::fuzzer::CrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize,
+                             *Rand);
 }
 
 }  // namespace fuzzer.
index 3fd807afcfeb13f4a7db174c66df2fc8ab038ada..3be4b05e66c7504b336cc0ddd462e294358093d6 100644 (file)
@@ -42,6 +42,26 @@ int main(int argc, char **argv) {
 */
 int FuzzerDriver(int argc, char **argv, UserCallback Callback);
 
+class FuzzerRandomBase {
+ public:
+  FuzzerRandomBase(){}
+  virtual ~FuzzerRandomBase(){};
+  virtual void ResetSeed(int seed) = 0;
+  // Return a random number.
+  virtual size_t Rand() = 0;
+  // Return a random number in range [0,n).
+  size_t operator()(size_t n) { return Rand() % n; }
+  bool RandBool() { return Rand() % 2; }
+};
+
+class FuzzerRandomLibc : public FuzzerRandomBase {
+ public:
+  FuzzerRandomLibc(int seed) { ResetSeed(seed); }
+  void ResetSeed(int seed) override;
+  ~FuzzerRandomLibc() override {}
+  size_t Rand() override;
+};
+
 /** An abstract class that allows to use user-supplied mutators with libFuzzer.
 
 Usage:
@@ -50,6 +70,7 @@ Usage:
 #include "FuzzerInterface.h"
 class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
  public:
+  MyFuzzer(fuzzer::FuzzerRandomBase *Rand);
   // Must define the target function.
   void TargetFunction(...) { ... }
   // Optionally define the mutator.
@@ -66,6 +87,8 @@ int main(int argc, char **argv) {
 */
 class UserSuppliedFuzzer {
  public:
+  UserSuppliedFuzzer();  // Deprecated, don't use.
+  UserSuppliedFuzzer(FuzzerRandomBase *Rand);
   /// Executes the target function on 'Size' bytes of 'Data'.
   virtual void TargetFunction(const uint8_t *Data, size_t Size) = 0;
   /// Mutates 'Size' bytes of data in 'Data' inplace into up to 'MaxSize' bytes,
@@ -80,7 +103,9 @@ class UserSuppliedFuzzer {
                            uint8_t *Out, size_t MaxOutSize) {
     return BasicCrossOver(Data1, Size1, Data2, Size2, Out, MaxOutSize);
   }
-  virtual ~UserSuppliedFuzzer() {}
+  virtual ~UserSuppliedFuzzer();
+
+  FuzzerRandomBase &GetRand() { return *Rand; }
 
  protected:
   /// These can be called internally by Mutate and CrossOver.
@@ -88,6 +113,9 @@ class UserSuppliedFuzzer {
   size_t BasicCrossOver(const uint8_t *Data1, size_t Size1,
                         const uint8_t *Data2, size_t Size2,
                         uint8_t *Out, size_t MaxOutSize);
+ private:
+  bool OwnRand = false;
+  FuzzerRandomBase *Rand;
 };
 
 /// Runs the fuzzing with the UserSuppliedFuzzer.
index af3d011f08a4115e7c53f89d12eef70305fcfafd..fe7869871f058482b8ed9aed6b0798070aa53e36 100644 (file)
@@ -33,10 +33,12 @@ void CopyFileToErr(const std::string &Path);
 std::string DirPlusFile(const std::string &DirPath,
                         const std::string &FileName);
 
-size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
+size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
+              FuzzerRandomBase &Rand);
 
 size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
-                 size_t Size2, uint8_t *Out, size_t MaxOutSize);
+                 size_t Size2, uint8_t *Out, size_t MaxOutSize,
+                 FuzzerRandomBase &Rand);
 
 void Printf(const char *Fmt, ...);
 void Print(const Unit &U, const char *PrintAfter = "");
@@ -155,7 +157,8 @@ class Fuzzer {
 
 class SimpleUserSuppliedFuzzer: public UserSuppliedFuzzer {
  public:
-  SimpleUserSuppliedFuzzer(UserCallback Callback) : Callback(Callback) {}
+  SimpleUserSuppliedFuzzer(FuzzerRandomBase *Rand, UserCallback Callback)
+      : UserSuppliedFuzzer(Rand), Callback(Callback) {}
   virtual void TargetFunction(const uint8_t *Data, size_t Size) {
     return Callback(Data, Size);
   }
index d6533910f006235d1b35aa80fc22d9b745803bab..e659223fe1a5bf773a704416f345f0d2d8e8f1cf 100644 (file)
@@ -113,14 +113,14 @@ void Fuzzer::RereadOutputCorpus() {
 
 void Fuzzer::ShuffleAndMinimize() {
   size_t MaxCov = 0;
-  bool PreferSmall =
-      (Options.PreferSmallDuringInitialShuffle == 1 ||
-       (Options.PreferSmallDuringInitialShuffle == -1 && rand() % 2));
+  bool PreferSmall = (Options.PreferSmallDuringInitialShuffle == 1 ||
+                      (Options.PreferSmallDuringInitialShuffle == -1 &&
+                       USF.GetRand().RandBool()));
   if (Options.Verbosity)
     Printf("PreferSmall: %d\n", PreferSmall);
   PrintStats("READ  ", 0);
   std::vector<Unit> NewCorpus;
-  std::random_shuffle(Corpus.begin(), Corpus.end());
+  std::random_shuffle(Corpus.begin(), Corpus.end(), USF.GetRand());
   if (PreferSmall)
     std::stable_sort(
         Corpus.begin(), Corpus.end(),
index f537fa90fd8506f13bdcab44f70fffd3ec78058b..66df98a66f5da71cfec7450097a0d978cea3e4b3 100644 (file)
@@ -15,8 +15,8 @@
 
 namespace fuzzer {
 
-static char FlipRandomBit(char X) {
-  int Bit = rand() % 8;
+static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
+  int Bit = Rand(8);
   char Mask = 1 << Bit;
   char R;
   if (X & (1 << Bit))
@@ -27,24 +27,25 @@ static char FlipRandomBit(char X) {
   return R;
 }
 
-static char RandCh() {
-  if (rand() % 2) return rand();
+static char RandCh(FuzzerRandomBase &Rand) {
+  if (Rand.RandBool()) return Rand(256);
   const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
-  return Special[rand() % (sizeof(Special) - 1)];
+  return Special[Rand(sizeof(Special) - 1)];
 }
 
 // Mutates Data in place, returns new size.
-size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
+size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
+              FuzzerRandomBase &Rand) {
   assert(MaxSize > 0);
   assert(Size <= MaxSize);
   if (Size == 0) {
     for (size_t i = 0; i < MaxSize; i++)
-      Data[i] = RandCh();
+      Data[i] = RandCh(Rand);
     return MaxSize;
   }
   assert(Size > 0);
-  size_t Idx = rand() % Size;
-  switch (rand() % 3) {
+  size_t Idx = Rand(Size);
+  switch (Rand(3)) {
   case 0:
     if (Size > 1) {
       // Erase Data[Idx].
@@ -56,12 +57,12 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
     if (Size < MaxSize) {
       // Insert new value at Data[Idx].
       memmove(Data + Idx + 1, Data + Idx, Size - Idx);
-      Data[Idx] = RandCh();
+      Data[Idx] = RandCh(Rand);
     }
-    Data[Idx] = RandCh();
+    Data[Idx] = RandCh(Rand);
     break;
   case 2:
-    Data[Idx] = FlipRandomBit(Data[Idx]);
+    Data[Idx] = FlipRandomBit(Data[Idx], Rand);
     break;
   }
   assert(Size > 0);
index b2e1e956dfcf0c528099fd62cb285c3ccfbe1261..75b77ca9bf048a44734c69103de167a6bc3e6454 100644 (file)
@@ -191,9 +191,9 @@ class TraceState {
     Mutations.clear();
   }
 
-  size_t StopTraceRecording() {
+  size_t StopTraceRecording(FuzzerRandomBase &Rand) {
     RecordingTraces = false;
-    std::random_shuffle(Mutations.begin(), Mutations.end());
+    std::random_shuffle(Mutations.begin(), Mutations.end(), Rand);
     return Mutations.size();
   }
 
@@ -302,7 +302,7 @@ void Fuzzer::StartTraceRecording() {
 
 size_t Fuzzer::StopTraceRecording() {
   if (!TS) return 0;
-  return TS->StopTraceRecording();
+  return TS->StopTraceRecording(USF.GetRand());
 }
 
 void Fuzzer::ApplyTraceBasedMutation(size_t Idx, Unit *U) {
index 50f2f99760e59333ab68a76fc79b2c92d41494ea..ed52a55a507d6cfb6d0eac70cc32467032531f86 100644 (file)
@@ -10,6 +10,7 @@ extern "C" void LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
 
 TEST(Fuzzer, CrossOver) {
   using namespace fuzzer;
+  FuzzerRandomLibc Rand(0);
   Unit A({0, 1, 2}), B({5, 6, 7});
   Unit C;
   Unit Expected[] = {
@@ -53,7 +54,7 @@ TEST(Fuzzer, CrossOver) {
     for (int Iter = 0; Iter < 3000; Iter++) {
       C.resize(Len);
       size_t NewSize = CrossOver(A.data(), A.size(), B.data(), B.size(),
-                                 C.data(), C.size());
+                                 C.data(), C.size(), Rand);
       C.resize(NewSize);
       FoundUnits.insert(C);
     }
index b46313dbafbf469fd19d61ea465ef4f8bb342b2e..8ebe1575ad039709369a2a01fd299879881df212 100644 (file)
@@ -14,6 +14,8 @@ static const uint64_t kMagic = 8860221463604ULL;
 
 class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
  public:
+  MyFuzzer(fuzzer::FuzzerRandomBase *Rand)
+      : fuzzer::UserSuppliedFuzzer(Rand) {}
   void TargetFunction(const uint8_t *Data, size_t Size) {
     if (Size <= 10) return;
     if (memcmp(Data, &kMagic, sizeof(kMagic))) return;
@@ -42,6 +44,7 @@ class MyFuzzer : public fuzzer::UserSuppliedFuzzer {
 };
 
 int main(int argc, char **argv) {
-  MyFuzzer F;
+  fuzzer::FuzzerRandomLibc Rand(0);
+  MyFuzzer F(&Rand);
   fuzzer::FuzzerDriver(argc, argv, F);
 }