[libFuzzer] more refactoring of the Mutator and adding tests to it
[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 namespace fuzzer {
17
18 static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
19   int Bit = Rand(8);
20   char Mask = 1 << Bit;
21   char R;
22   if (X & (1 << Bit))
23     R = X & ~Mask;
24   else
25     R = X | Mask;
26   assert(R != X);
27   return R;
28 }
29
30 static char RandCh(FuzzerRandomBase &Rand) {
31   if (Rand.RandBool()) return Rand(256);
32   const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
33   return Special[Rand(sizeof(Special) - 1)];
34 }
35
36 size_t Mutate_EraseByte(uint8_t *Data, size_t Size, size_t MaxSize,
37                         FuzzerRandomBase &Rand) {
38   assert(Size);
39   if (Size == 1) return Size;
40   size_t Idx = Rand(Size);
41   // Erase Data[Idx].
42   memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
43   return Size - 1;
44 }
45
46 size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize,
47                          FuzzerRandomBase &Rand) {
48   if (Size == MaxSize) return Size;
49   size_t Idx = Rand(Size + 1);
50   // Insert new value at Data[Idx].
51   memmove(Data + Idx + 1, Data + Idx, Size - Idx);
52   Data[Idx] = RandCh(Rand);
53   return Size + 1;
54 }
55
56 size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize,
57                          FuzzerRandomBase &Rand) {
58   size_t Idx = Rand(Size);
59   Data[Idx] = RandCh(Rand);
60   return Size;
61 }
62
63 size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize,
64                         FuzzerRandomBase &Rand) {
65   size_t Idx = Rand(Size);
66   Data[Idx] = FlipRandomBit(Data[Idx], Rand);
67   return Size;
68 }
69
70 // Mutates Data in place, returns new size.
71 size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
72               FuzzerRandomBase &Rand) {
73   assert(MaxSize > 0);
74   assert(Size <= MaxSize);
75   if (Size == 0) {
76     for (size_t i = 0; i < MaxSize; i++)
77       Data[i] = RandCh(Rand);
78     return MaxSize;
79   }
80   assert(Size > 0);
81   switch (Rand(4)) {
82   case 0: Size = Mutate_EraseByte(Data, Size, MaxSize, Rand); break;
83   case 1: Size = Mutate_InsertByte(Data, Size, MaxSize, Rand); break;
84   case 2: Size = Mutate_ChangeByte(Data, Size, MaxSize, Rand); break;
85   case 3: Size = Mutate_ChangeBit(Data, Size, MaxSize, Rand); break;
86   }
87   assert(Size > 0);
88   return Size;
89 }
90
91 }  // namespace fuzzer