[llvm] r278687 - [libFuzzer] add InsertRepeatedBytes and EraseBytes.

Kostya Serebryany via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 15 10:48:28 PDT 2016


Author: kcc
Date: Mon Aug 15 12:48:28 2016
New Revision: 278687

URL: http://llvm.org/viewvc/llvm-project?rev=278687&view=rev
Log:
[libFuzzer] add InsertRepeatedBytes and EraseBytes.

New mutation: InsertRepeatedBytes.
Updated mutation: EraseByte => EraseBytes.

This helps https://github.com/google/sanitizers/issues/710
where libFuzzer was not able to find a known bug.
Now it finds it in minutes.

Hopefully, the change is general enough to help other targets.


Added:
    llvm/trunk/lib/Fuzzer/test/RepeatedBytesTest.cpp
    llvm/trunk/lib/Fuzzer/test/repeated-bytes.test
Modified:
    llvm/trunk/lib/Fuzzer/FuzzerInternal.h
    llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp
    llvm/trunk/lib/Fuzzer/test/CMakeLists.txt
    llvm/trunk/lib/Fuzzer/test/FuzzerUnittest.cpp
    llvm/trunk/lib/Fuzzer/test/StrcmpTest.cpp
    llvm/trunk/lib/Fuzzer/test/fuzzer-traces.test

Modified: llvm/trunk/lib/Fuzzer/FuzzerInternal.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerInternal.h?rev=278687&r1=278686&r2=278687&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerInternal.h (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerInternal.h Mon Aug 15 12:48:28 2016
@@ -255,10 +255,12 @@ public:
   size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by shuffling bytes.
   size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
-  /// Mutates data by erasing a byte.
-  size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by erasing bytes.
+  size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by inserting a byte.
   size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize);
+  /// Mutates data by inserting several repeated bytes.
+  size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by chanding one byte.
   size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize);
   /// Mutates data by chanding one bit.

Modified: llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp?rev=278687&r1=278686&r2=278687&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp (original)
+++ llvm/trunk/lib/Fuzzer/FuzzerMutate.cpp Mon Aug 15 12:48:28 2016
@@ -24,8 +24,10 @@ MutationDispatcher::MutationDispatcher(R
   DefaultMutators.insert(
       DefaultMutators.begin(),
       {
-          {&MutationDispatcher::Mutate_EraseByte, "EraseByte"},
+          {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
           {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
+          {&MutationDispatcher::Mutate_InsertRepeatedBytes,
+           "InsertRepeatedBytes"},
           {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
           {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
           {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
@@ -103,14 +105,17 @@ size_t MutationDispatcher::Mutate_Shuffl
   return Size;
 }
 
-size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size,
-                                            size_t MaxSize) {
+size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
+                                             size_t MaxSize) {
   assert(Size);
   if (Size == 1) return 0;
-  size_t Idx = Rand(Size);
-  // Erase Data[Idx].
-  memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
-  return Size - 1;
+  size_t N = Rand(Size / 2) + 1;
+  assert(N < Size);
+  size_t Idx = Rand(Size - N + 1);
+  // Erase Data[Idx:Idx+N].
+  memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
+  // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
+  return Size - N;
 }
 
 size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
@@ -123,6 +128,23 @@ size_t MutationDispatcher::Mutate_Insert
   return Size + 1;
 }
 
+size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
+                                                      size_t Size,
+                                                      size_t MaxSize) {
+  const size_t kMinBytesToInsert = 3;
+  if (Size + kMinBytesToInsert >= MaxSize) return 0;
+  size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
+  size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
+  assert(Size + N <= MaxSize && N);
+  size_t Idx = Rand(Size + 1);
+  // Insert new values at Data[Idx].
+  memmove(Data + Idx + N, Data + Idx, Size - Idx);
+  uint8_t Byte = RandCh(Rand);
+  for (size_t i = 0; i < N; i++)
+    Data[Idx + i] = Byte;
+  return Size + N;
+}
+
 size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
                                              size_t MaxSize) {
   size_t Idx = Rand(Size);

Modified: llvm/trunk/lib/Fuzzer/test/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/CMakeLists.txt?rev=278687&r1=278686&r2=278687&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/CMakeLists.txt (original)
+++ llvm/trunk/lib/Fuzzer/test/CMakeLists.txt Mon Aug 15 12:48:28 2016
@@ -81,6 +81,7 @@ set(Tests
   OneHugeAllocTest
   OutOfMemoryTest
   RepeatedMemcmp
+  RepeatedBytesTest
   SimpleCmpTest
   SimpleDictionaryTest
   SimpleFnAdapterTest

Modified: llvm/trunk/lib/Fuzzer/test/FuzzerUnittest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/FuzzerUnittest.cpp?rev=278687&r1=278686&r2=278687&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/FuzzerUnittest.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/FuzzerUnittest.cpp Mon Aug 15 12:48:28 2016
@@ -88,7 +88,7 @@ TEST(Fuzzer, Hash) {
 typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
                                               size_t MaxSize);
 
-void TestEraseByte(Mutator M, int NumIter) {
+void TestEraseBytes(Mutator M, int NumIter) {
   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
   fuzzer::EF = t.get();
   uint8_t REM0[8] = {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
@@ -99,6 +99,16 @@ void TestEraseByte(Mutator M, int NumIte
   uint8_t REM5[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x66, 0x77};
   uint8_t REM6[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x77};
   uint8_t REM7[8] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66};
+
+  uint8_t REM8[6] = {0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM9[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};
+  uint8_t REM10[6] = {0x00, 0x11, 0x22, 0x55, 0x66, 0x77};
+
+  uint8_t REM11[5] = {0x33, 0x44, 0x55, 0x66, 0x77};
+  uint8_t REM12[5] = {0x00, 0x11, 0x22, 0x33, 0x44};
+  uint8_t REM13[5] = {0x00, 0x44, 0x55, 0x66, 0x77};
+
+
   Random Rand(0);
   MutationDispatcher MD(Rand, {});
   int FoundMask = 0;
@@ -113,15 +123,23 @@ void TestEraseByte(Mutator M, int NumIte
     if (NewSize == 7 && !memcmp(REM5, T, 7)) FoundMask |= 1 << 5;
     if (NewSize == 7 && !memcmp(REM6, T, 7)) FoundMask |= 1 << 6;
     if (NewSize == 7 && !memcmp(REM7, T, 7)) FoundMask |= 1 << 7;
+
+    if (NewSize == 6 && !memcmp(REM8, T, 6)) FoundMask |= 1 << 8;
+    if (NewSize == 6 && !memcmp(REM9, T, 6)) FoundMask |= 1 << 9;
+    if (NewSize == 6 && !memcmp(REM10, T, 6)) FoundMask |= 1 << 10;
+
+    if (NewSize == 5 && !memcmp(REM11, T, 5)) FoundMask |= 1 << 11;
+    if (NewSize == 5 && !memcmp(REM12, T, 5)) FoundMask |= 1 << 12;
+    if (NewSize == 5 && !memcmp(REM13, T, 5)) FoundMask |= 1 << 13;
   }
-  EXPECT_EQ(FoundMask, 255);
+  EXPECT_EQ(FoundMask, (1 << 14) - 1);
 }
 
-TEST(FuzzerMutate, EraseByte1) {
-  TestEraseByte(&MutationDispatcher::Mutate_EraseByte, 100);
+TEST(FuzzerMutate, EraseBytes1) {
+  TestEraseBytes(&MutationDispatcher::Mutate_EraseBytes, 200);
 }
-TEST(FuzzerMutate, EraseByte2) {
-  TestEraseByte(&MutationDispatcher::Mutate, 1000);
+TEST(FuzzerMutate, EraseBytes2) {
+  TestEraseBytes(&MutationDispatcher::Mutate, 2000);
 }
 
 void TestInsertByte(Mutator M, int NumIter) {
@@ -160,6 +178,50 @@ TEST(FuzzerMutate, InsertByte2) {
   TestInsertByte(&MutationDispatcher::Mutate, 1 << 17);
 }
 
+void TestInsertRepeatedBytes(Mutator M, int NumIter) {
+  std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
+  fuzzer::EF = t.get();
+  Random Rand(0);
+  MutationDispatcher MD(Rand, {});
+  int FoundMask = 0;
+  uint8_t INS0[7] = {0x00, 0x11, 0x22, 0x33, 'a', 'a', 'a'};
+  uint8_t INS1[7] = {0x00, 0x11, 0x22, 'a', 'a', 'a', 0x33};
+  uint8_t INS2[7] = {0x00, 0x11, 'a', 'a', 'a', 0x22, 0x33};
+  uint8_t INS3[7] = {0x00, 'a', 'a', 'a', 0x11, 0x22, 0x33};
+  uint8_t INS4[7] = {'a', 'a', 'a', 0x00, 0x11, 0x22, 0x33};
+
+  uint8_t INS5[8] = {0x00, 0x11, 0x22, 0x33, 'b', 'b', 'b', 'b'};
+  uint8_t INS6[8] = {0x00, 0x11, 0x22, 'b', 'b', 'b', 'b', 0x33};
+  uint8_t INS7[8] = {0x00, 0x11, 'b', 'b', 'b', 'b', 0x22, 0x33};
+  uint8_t INS8[8] = {0x00, 'b', 'b', 'b', 'b', 0x11, 0x22, 0x33};
+  uint8_t INS9[8] = {'b', 'b', 'b', 'b', 0x00, 0x11, 0x22, 0x33};
+
+  for (int i = 0; i < NumIter; i++) {
+    uint8_t T[8] = {0x00, 0x11, 0x22, 0x33};
+    size_t NewSize = (MD.*M)(T, 4, 8);
+    if (NewSize == 7 && !memcmp(INS0, T, 7)) FoundMask |= 1 << 0;
+    if (NewSize == 7 && !memcmp(INS1, T, 7)) FoundMask |= 1 << 1;
+    if (NewSize == 7 && !memcmp(INS2, T, 7)) FoundMask |= 1 << 2;
+    if (NewSize == 7 && !memcmp(INS3, T, 7)) FoundMask |= 1 << 3;
+    if (NewSize == 7 && !memcmp(INS4, T, 7)) FoundMask |= 1 << 4;
+
+    if (NewSize == 8 && !memcmp(INS5, T, 8)) FoundMask |= 1 << 5;
+    if (NewSize == 8 && !memcmp(INS6, T, 8)) FoundMask |= 1 << 6;
+    if (NewSize == 8 && !memcmp(INS7, T, 8)) FoundMask |= 1 << 7;
+    if (NewSize == 8 && !memcmp(INS8, T, 8)) FoundMask |= 1 << 8;
+    if (NewSize == 8 && !memcmp(INS9, T, 8)) FoundMask |= 1 << 9;
+
+  }
+  EXPECT_EQ(FoundMask, (1 << 10) - 1);
+}
+
+TEST(FuzzerMutate, InsertRepeatedBytes1) {
+  TestInsertRepeatedBytes(&MutationDispatcher::Mutate_InsertRepeatedBytes, 10000);
+}
+TEST(FuzzerMutate, InsertRepeatedBytes2) {
+  TestInsertRepeatedBytes(&MutationDispatcher::Mutate, 200000);
+}
+
 void TestChangeByte(Mutator M, int NumIter) {
   std::unique_ptr<ExternalFunctions> t(new ExternalFunctions());
   fuzzer::EF = t.get();

Added: llvm/trunk/lib/Fuzzer/test/RepeatedBytesTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/RepeatedBytesTest.cpp?rev=278687&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/RepeatedBytesTest.cpp (added)
+++ llvm/trunk/lib/Fuzzer/test/RepeatedBytesTest.cpp Mon Aug 15 12:48:28 2016
@@ -0,0 +1,29 @@
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+
+// Simple test for a fuzzer. The fuzzer must find repeated bytes.
+#include <assert.h>
+#include <cstdint>
+#include <cstdlib>
+#include <cstddef>
+#include <iostream>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+  assert(Data);
+  // Looking for AAAAAAAAAAAAAAAAAAAAAA or some such.
+  size_t CurA = 0, MaxA = 0;
+  for (size_t i = 0; i < Size; i++) {
+    // Make sure there are no conditionals in the loop so that
+    // coverage can't help the fuzzer.
+    int EQ = Data[i] == 'A';
+    CurA = EQ * (CurA + 1);
+    int GT = CurA > MaxA;
+    MaxA = GT * CurA + (!GT) * MaxA;
+  }
+  if (MaxA >= 20) {
+    std::cout << "BINGO; Found the target (Max: " << MaxA << "), exiting\n";
+    exit(0);
+  }
+  return 0;
+}
+

Modified: llvm/trunk/lib/Fuzzer/test/StrcmpTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/StrcmpTest.cpp?rev=278687&r1=278686&r2=278687&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/StrcmpTest.cpp (original)
+++ llvm/trunk/lib/Fuzzer/test/StrcmpTest.cpp Mon Aug 15 12:48:28 2016
@@ -20,9 +20,9 @@ bool Eq(const uint8_t *Data, size_t Size
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
-  if (Eq(Data, Size, "AAA") &&
-      Size >= 3 && Eq(Data + 3, Size - 3, "BBBB") &&
-      Size >= 7 && Eq(Data + 7, Size - 7, "CCCCCC") &&
+  if (Eq(Data, Size, "ABC") &&
+      Size >= 3 && Eq(Data + 3, Size - 3, "QWER") &&
+      Size >= 7 && Eq(Data + 7, Size - 7, "ZXCVN") &&
       Size >= 14 && Data[13] == 42
     ) {
     fprintf(stderr, "BINGO\n");

Modified: llvm/trunk/lib/Fuzzer/test/fuzzer-traces.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/fuzzer-traces.test?rev=278687&r1=278686&r2=278687&view=diff
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/fuzzer-traces.test (original)
+++ llvm/trunk/lib/Fuzzer/test/fuzzer-traces.test Mon Aug 15 12:48:28 2016
@@ -1,9 +1,10 @@
 CHECK: BINGO
 Done1000000: Done 1000000 runs in
+Done2000000: Done 2000000 runs in
 RUN: not LLVMFuzzer-SimpleCmpTest -use_traces=1 -seed=1 -runs=10000001  2>&1 | FileCheck %s
 
 RUN: not LLVMFuzzer-SwitchTest -use_traces=1 -seed=6 -runs=1000002  2>&1 | FileCheck %s
 RUN:     LLVMFuzzer-SwitchTest               -seed=7 -runs=1000000  2>&1 | FileCheck %s --check-prefix=Done1000000
 
-RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=8 -runs=1000000 -max_len=16  2>&1 | FileCheck %s
-RUN:     LLVMFuzzer-SimpleHashTest               -seed=9 -runs=1000000 -max_len=16 2>&1 | FileCheck %s --check-prefix=Done1000000
+RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=8 -runs=2000000 -max_len=16  2>&1 | FileCheck %s
+RUN:     LLVMFuzzer-SimpleHashTest               -seed=9 -runs=2000000 -max_len=16 2>&1 | FileCheck %s --check-prefix=Done2000000

Added: llvm/trunk/lib/Fuzzer/test/repeated-bytes.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Fuzzer/test/repeated-bytes.test?rev=278687&view=auto
==============================================================================
--- llvm/trunk/lib/Fuzzer/test/repeated-bytes.test (added)
+++ llvm/trunk/lib/Fuzzer/test/repeated-bytes.test Mon Aug 15 12:48:28 2016
@@ -0,0 +1,2 @@
+CHECK: BINGO
+RUN: LLVMFuzzer-RepeatedBytesTest -runs=10000 2>&1 | FileCheck %s




More information about the llvm-commits mailing list