[libFuzzer] add one more mutation strategy: byte shuffling
[oota-llvm.git] / lib / Fuzzer / FuzzerMutate.cpp
1 //===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // Mutate a test input.
10 //===----------------------------------------------------------------------===//
11
12 #include <cstring>
13
14 #include "FuzzerInternal.h"
15
16 #include <algorithm>
17
18 namespace fuzzer {
19
20 static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
21   int Bit = Rand(8);
22   char Mask = 1 << Bit;
23   char R;
24   if (X & (1 << Bit))
25     R = X & ~Mask;
26   else
27     R = X | Mask;
28   assert(R != X);
29   return R;
30 }
31
32 static char RandCh(FuzzerRandomBase &Rand) {
33   if (Rand.RandBool()) return Rand(256);
34   const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
35   return Special[Rand(sizeof(Special) - 1)];
36 }
37
38 size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize,
39                            FuzzerRandomBase &Rand) {
40   assert(Size);
41   size_t ShuffleAmount = Rand(std::min(Size, 8UL)) + 1;  // [1,8] and <= Size.
42   size_t ShuffleStart = Rand(Size - ShuffleAmount);
43   assert(ShuffleStart + ShuffleAmount <= Size);
44   std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
45                       Rand);
46   return Size;
47 }
48
49 size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize,
50                         FuzzerRandomBase &Rand) {
51   assert(Size);
52   if (Size == 1) return Size;
53   size_t Idx = Rand(Size);
54   // Erase Data[Idx].
55   memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
56   return Size - 1;
57 }
58
59 size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize,
60                          FuzzerRandomBase &Rand) {
61   if (Size == MaxSize) return Size;
62   size_t Idx = Rand(Size + 1);
63   // Insert new value at Data[Idx].
64   memmove(Data + Idx + 1, Data + Idx, Size - Idx);
65   Data[Idx] = RandCh(Rand);
66   return Size + 1;
67 }
68
69 size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize,
70                          FuzzerRandomBase &Rand) {
71   size_t Idx = Rand(Size);
72   Data[Idx] = RandCh(Rand);
73   return Size;
74 }
75
76 size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize,
77                         FuzzerRandomBase &Rand) {
78   size_t Idx = Rand(Size);
79   Data[Idx] = FlipRandomBit(Data[Idx], Rand);
80   return Size;
81 }
82
83 // Mutates Data in place, returns new size.
84 size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
85               FuzzerRandomBase &Rand) {
86   assert(MaxSize > 0);
87   assert(Size <= MaxSize);
88   if (Size == 0) {
89     for (size_t i = 0; i < MaxSize; i++)
90       Data[i] = RandCh(Rand);
91     return MaxSize;
92   }
93   assert(Size > 0);
94   switch (Rand(5)) {
95   case 0: Size = Mutate_EraseByte(Data, Size, MaxSize, Rand); break;
96   case 1: Size = Mutate_InsertByte(Data, Size, MaxSize, Rand); break;
97   case 2: Size = Mutate_ChangeByte(Data, Size, MaxSize, Rand); break;
98   case 3: Size = Mutate_ChangeBit(Data, Size, MaxSize, Rand); break;
99   case 4: Size = Mutate_ShuffleBytes(Data, Size, MaxSize, Rand); break;
100   }
101   assert(Size > 0);
102   return Size;
103 }
104
105 }  // namespace fuzzer