[libFuzzer] start refactoring the Mutator and adding tests to it
[oota-llvm.git] / lib / Fuzzer / FuzzerMutate.cpp
index 60d5623ada608ad6dfc1c54c2ce4ca3839b7cc7a..eec6475f9b8464cee515afa0b4af14a2f51e4dd5 100644 (file)
@@ -9,12 +9,14 @@
 // Mutate a test input.
 //===----------------------------------------------------------------------===//
 
+#include <cstring>
+
 #include "FuzzerInternal.h"
 
 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))
@@ -25,46 +27,50 @@ 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)];
+}
+
+size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize,
+                        FuzzerRandomBase &Rand) {
+  assert(Size);
+  if (Size == 1) return Size;
+  size_t Idx = Rand(Size);
+  // Erase Data[Idx].
+  memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
+  return Size - 1;
 }
 
-// Mutate U in place.
-void Mutate(Unit *U, size_t MaxLen) {
-  assert(MaxLen > 0);
-  assert(U->size() <= MaxLen);
-  if (U->empty()) {
-    for (size_t i = 0; i < MaxLen; i++)
-      U->push_back(RandCh());
-    return;
+// Mutates Data in place, returns new size.
+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(Rand);
+    return MaxSize;
   }
-  assert(!U->empty());
-  switch (rand() % 3) {
-  case 0:
-    if (U->size() > 1) {
-      U->erase(U->begin() + rand() % U->size());
-      break;
-    }
-    // Fallthrough
+  assert(Size > 0);
+  size_t Idx = Rand(Size);
+  switch (Rand(3)) {
+  case 0: Size = Mutate_EraseByte(Data, Size, MaxSize, Rand); break;
   case 1:
-    if (U->size() < MaxLen) {
-      U->insert(U->begin() + rand() % U->size(), RandCh());
-    } else { // At MaxLen.
-      uint8_t Ch = RandCh();
-      size_t Idx = rand() % U->size();
-      (*U)[Idx] = Ch;
+    if (Size < MaxSize) {
+      // Insert new value at Data[Idx].
+      memmove(Data + Idx + 1, Data + Idx, Size - Idx);
+      Data[Idx] = RandCh(Rand);
     }
+    Data[Idx] = RandCh(Rand);
     break;
-  default:
-    {
-      size_t Idx = rand() % U->size();
-      (*U)[Idx] = FlipRandomBit((*U)[Idx]);
-    }
+  case 2:
+    Data[Idx] = FlipRandomBit(Data[Idx], Rand);
     break;
   }
-  assert(!U->empty());
+  assert(Size > 0);
+  return Size;
 }
 
 }  // namespace fuzzer