[libFuzzer] add one more mutation strategy: byte shuffling
authorKostya Serebryany <kcc@google.com>
Thu, 6 Aug 2015 01:29:13 +0000 (01:29 +0000)
committerKostya Serebryany <kcc@google.com>
Thu, 6 Aug 2015 01:29:13 +0000 (01:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244188 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Fuzzer/FuzzerInterface.h
lib/Fuzzer/FuzzerInternal.h
lib/Fuzzer/FuzzerMutate.cpp
lib/Fuzzer/test/FuzzerUnittest.cpp

index 3be4b05e66c7504b336cc0ddd462e294358093d6..6acae6c67afb86315350323a61dac21cd067dd9a 100644 (file)
@@ -50,7 +50,7 @@ class FuzzerRandomBase {
   // 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; }
+  size_t operator()(size_t n) { return n ? Rand() % n : 0; }
   bool RandBool() { return Rand() % 2; }
 };
 
index 610b4375f24266f6a3d0ec62caca6b8386ff676b..e33ab702178abc913b799d66c68ba3939aa2651d 100644 (file)
@@ -33,6 +33,8 @@ void CopyFileToErr(const std::string &Path);
 std::string DirPlusFile(const std::string &DirPath,
                         const std::string &FileName);
 
+size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize,
+                           FuzzerRandomBase &Rand);
 size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize,
                         FuzzerRandomBase &Rand);
 size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize,
index fc3176299c9144a9146f71e56933b3d79868ae57..c425ae0c1cdd970f6316d0aa46dac7d41b89e062 100644 (file)
@@ -13,6 +13,8 @@
 
 #include "FuzzerInternal.h"
 
+#include <algorithm>
+
 namespace fuzzer {
 
 static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
@@ -33,6 +35,17 @@ static char RandCh(FuzzerRandomBase &Rand) {
   return Special[Rand(sizeof(Special) - 1)];
 }
 
+size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize,
+                           FuzzerRandomBase &Rand) {
+  assert(Size);
+  size_t ShuffleAmount = Rand(std::min(Size, 8UL)) + 1;  // [1,8] and <= Size.
+  size_t ShuffleStart = Rand(Size - ShuffleAmount);
+  assert(ShuffleStart + ShuffleAmount <= Size);
+  std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
+                      Rand);
+  return Size;
+}
+
 size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize,
                         FuzzerRandomBase &Rand) {
   assert(Size);
@@ -78,11 +91,12 @@ size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
     return MaxSize;
   }
   assert(Size > 0);
-  switch (Rand(4)) {
+  switch (Rand(5)) {
   case 0: Size = Mutate_EraseByte(Data, Size, MaxSize, Rand); break;
   case 1: Size = Mutate_InsertByte(Data, Size, MaxSize, Rand); break;
   case 2: Size = Mutate_ChangeByte(Data, Size, MaxSize, Rand); break;
   case 3: Size = Mutate_ChangeBit(Data, Size, MaxSize, Rand); break;
+  case 4: Size = Mutate_ShuffleBytes(Data, Size, MaxSize, Rand); break;
   }
   assert(Size > 0);
   return Size;
index a3e6a136b27d6d1d7ff5b64870b31470110d603b..518cfab5d9381968be3737bf6d31c094b15352a5 100644 (file)
@@ -192,3 +192,26 @@ void TestChangeBit(Mutator M, int NumIter) {
 
 TEST(FuzzerMutate, ChangeBit1) { TestChangeBit(Mutate_ChangeBit, 1 << 16); }
 TEST(FuzzerMutate, ChangeBit2) { TestChangeBit(Mutate, 1 << 18); }
+
+void TestShuffleBytes(Mutator M, int NumIter) {
+  FuzzerRandomLibc Rand(0);
+  int FoundMask = 0;
+  uint8_t CH0[7] = {0x00, 0x22, 0x11, 0x33, 0x44, 0x55, 0x66};
+  uint8_t CH1[7] = {0x11, 0x00, 0x33, 0x22, 0x44, 0x55, 0x66};
+  uint8_t CH2[7] = {0x00, 0x33, 0x11, 0x22, 0x44, 0x55, 0x66};
+  uint8_t CH3[7] = {0x00, 0x11, 0x22, 0x44, 0x55, 0x66, 0x33};
+  uint8_t CH4[7] = {0x00, 0x11, 0x22, 0x33, 0x55, 0x44, 0x66};
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[7] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+    size_t NewSize = M(T, 7, 7, Rand);
+    if (NewSize == 7 && !memcmp(CH0, T, 7)) FoundMask |= 1 << 0;
+    if (NewSize == 7 && !memcmp(CH1, T, 7)) FoundMask |= 1 << 1;
+    if (NewSize == 7 && !memcmp(CH2, T, 7)) FoundMask |= 1 << 2;
+    if (NewSize == 7 && !memcmp(CH3, T, 7)) FoundMask |= 1 << 3;
+    if (NewSize == 7 && !memcmp(CH4, T, 7)) FoundMask |= 1 << 4;
+  }
+  EXPECT_EQ(FoundMask, 31);
+}
+
+TEST(FuzzerMutate, ShuffleBytes1) { TestShuffleBytes(Mutate_ShuffleBytes, 1 << 15); }
+TEST(FuzzerMutate, ShuffleBytes2) { TestShuffleBytes(Mutate, 1 << 16); }