[libFuzzer] allow users to supply their own implementation of rand
[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 // Mutates Data in place, returns new size.
37 size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize,
38               FuzzerRandomBase &Rand) {
39   assert(MaxSize > 0);
40   assert(Size <= MaxSize);
41   if (Size == 0) {
42     for (size_t i = 0; i < MaxSize; i++)
43       Data[i] = RandCh(Rand);
44     return MaxSize;
45   }
46   assert(Size > 0);
47   size_t Idx = Rand(Size);
48   switch (Rand(3)) {
49   case 0:
50     if (Size > 1) {
51       // Erase Data[Idx].
52       memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
53       Size = Size - 1;
54     }
55     [[clang::fallthrough]];
56   case 1:
57     if (Size < MaxSize) {
58       // Insert new value at Data[Idx].
59       memmove(Data + Idx + 1, Data + Idx, Size - Idx);
60       Data[Idx] = RandCh(Rand);
61     }
62     Data[Idx] = RandCh(Rand);
63     break;
64   case 2:
65     Data[Idx] = FlipRandomBit(Data[Idx], Rand);
66     break;
67   }
68   assert(Size > 0);
69   return Size;
70 }
71
72 }  // namespace fuzzer