[libFuzzer] add one more mutator: Mutate_ChangeASCIIInteger
authorKostya Serebryany <kcc@google.com>
Tue, 8 Sep 2015 17:19:31 +0000 (17:19 +0000)
committerKostya Serebryany <kcc@google.com>
Tue, 8 Sep 2015 17:19:31 +0000 (17:19 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@247027 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 8798b650383b9a272ba34feb81f7d592353045db..d5af308be76dd18f57592de059eeef85f9b39a85 100644 (file)
@@ -81,6 +81,8 @@ class MutationDispatcher {
   size_t Mutate_AddWordFromDictionary(uint8_t *Data, size_t Size,
                                       size_t MaxSize);
 
+  size_t Mutate_ChangeASCIIInteger(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);
index 9b2015be8691227f2cbc912473f92854a0702bbc..0e8429bcb2720d3698a1ec7e4347e58ee6804eda 100644 (file)
@@ -29,6 +29,7 @@ struct MutationDispatcher::Impl {
     Mutators.push_back(&MutationDispatcher::Mutate_ChangeByte);
     Mutators.push_back(&MutationDispatcher::Mutate_ChangeBit);
     Mutators.push_back(&MutationDispatcher::Mutate_ShuffleBytes);
+    Mutators.push_back(&MutationDispatcher::Mutate_ChangeASCIIInteger);
   }
   void AddWordToDictionary(const uint8_t *Word, size_t Size) {
     if (Dictionary.empty()) {
@@ -116,6 +117,39 @@ size_t MutationDispatcher::Mutate_AddWordFromDictionary(uint8_t *Data,
   return Size + Word.size();
 }
 
+size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
+                                                     size_t MaxSize) {
+  size_t B = Rand(Size);
+  while (B < Size && !isdigit(Data[B])) B++;
+  if (B == Size) return 0;
+  size_t E = B;
+  while (E < Size && isdigit(Data[E])) E++;
+  assert(B < E);
+  // now we have digits in [B, E).
+  // strtol and friends don't accept non-zero-teminated data, parse it manually.
+  uint64_t Val = Data[B] - '0';
+  for (size_t i = B + 1; i < E; i++)
+    Val = Val * 10 + Data[i] - '0';
+
+  // Mutate the integer value.
+  switch(Rand(5)) {
+    case 0: Val++; break;
+    case 1: Val--; break;
+    case 2: Val /= 2; break;
+    case 3: Val *= 2; break;
+    case 4: Val = Rand(Val * Val); break;
+    default: assert(0);
+  }
+  // Just replace the bytes with the new ones, don't bother moving bytes.
+  for (size_t i = B; i < E; i++) {
+    size_t Idx = E + B - i - 1;
+    assert(Idx >= B && Idx < E);
+    Data[Idx] = (Val % 10) + '0';
+    Val /= 10;
+  }
+  return Size;
+}
+
 // Mutates Data in place, returns new size.
 size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
   assert(MaxSize > 0);
index 1a88aef3e1e1e30d08787b296389c82c35a6f6ea..4a96468f8d7a1480bc54ba40be7698707ca14007 100644 (file)
@@ -282,6 +282,37 @@ TEST(FuzzerMutate, AddWordFromDictionary2) {
   TestAddWordFromDictionary(&MutationDispatcher::Mutate, 1 << 15);
 }
 
+void TestChangeASCIIInteger(Mutator M, int NumIter) {
+  FuzzerRandomLibc Rand(0);
+  MutationDispatcher MD(Rand);
+
+  uint8_t CH0[8] = {'1', '2', '3', '4', '5', '6', '7', '7'};
+  uint8_t CH1[8] = {'1', '2', '3', '4', '5', '6', '7', '9'};
+  uint8_t CH2[8] = {'2', '4', '6', '9', '1', '3', '5', '6'};
+  uint8_t CH3[8] = {'0', '6', '1', '7', '2', '8', '3', '9'};
+  int FoundMask = 0;
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {'1', '2', '3', '4', '5', '6', '7', '8'};
+    size_t NewSize = (MD.*M)(T, 8, 8);
+    /**/ if (NewSize == 8 && !memcmp(CH0, T, 8)) FoundMask |= 1 << 0;
+    else if (NewSize == 8 && !memcmp(CH1, T, 8)) FoundMask |= 1 << 1;
+    else if (NewSize == 8 && !memcmp(CH2, T, 8)) FoundMask |= 1 << 2;
+    else if (NewSize == 8 && !memcmp(CH3, T, 8)) FoundMask |= 1 << 3;
+    else if (NewSize == 8)                       FoundMask |= 1 << 4;
+  }
+  EXPECT_EQ(FoundMask, 31);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger1) {
+  TestChangeASCIIInteger(&MutationDispatcher::Mutate_ChangeASCIIInteger,
+                         1 << 15);
+}
+
+TEST(FuzzerMutate, ChangeASCIIInteger2) {
+  TestChangeASCIIInteger(&MutationDispatcher::Mutate, 1 << 15);
+}
+
+
 TEST(FuzzerDictionary, ParseOneDictionaryEntry) {
   Unit U;
   EXPECT_FALSE(ParseOneDictionaryEntry("", &U));