blob: 70fa88da30a3391ef7f67badb0c3003e4c04ef0f [file] [log] [blame]
Aaron Ballmanef116982015-01-29 16:58:29 +00001//===- 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
Kostya Serebryanyf3424592015-05-22 22:35:31 +000012#include <cstring>
13
Aaron Ballmanef116982015-01-29 16:58:29 +000014#include "FuzzerInternal.h"
15
Kostya Serebryanybf29ff22015-08-06 01:29:13 +000016#include <algorithm>
17
Aaron Ballmanef116982015-01-29 16:58:29 +000018namespace fuzzer {
19
Kostya Serebryany7d211662015-09-04 00:12:11 +000020typedef size_t (MutationDispatcher::*Mutator)(uint8_t *Data, size_t Size,
21 size_t Max);
22
23struct MutationDispatcher::Impl {
24 std::vector<Unit> Dictionary;
25 std::vector<Mutator> Mutators;
26 Impl() {
27 Mutators.push_back(&MutationDispatcher::Mutate_EraseByte);
28 Mutators.push_back(&MutationDispatcher::Mutate_InsertByte);
29 Mutators.push_back(&MutationDispatcher::Mutate_ChangeByte);
30 Mutators.push_back(&MutationDispatcher::Mutate_ChangeBit);
31 Mutators.push_back(&MutationDispatcher::Mutate_ShuffleBytes);
32 }
33 void AddWordToDictionary(const uint8_t *Word, size_t Size) {
34 if (Dictionary.empty()) {
35 Mutators.push_back(&MutationDispatcher::Mutate_AddWordFromDictionary);
36 }
37 Dictionary.push_back(Unit(Word, Word + Size));
38 }
39};
40
41
Kostya Serebryany404c69f2015-07-24 01:06:40 +000042static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
43 int Bit = Rand(8);
Aaron Ballmanef116982015-01-29 16:58:29 +000044 char Mask = 1 << Bit;
45 char R;
46 if (X & (1 << Bit))
47 R = X & ~Mask;
48 else
49 R = X | Mask;
50 assert(R != X);
51 return R;
52}
53
Kostya Serebryany404c69f2015-07-24 01:06:40 +000054static char RandCh(FuzzerRandomBase &Rand) {
55 if (Rand.RandBool()) return Rand(256);
Aaron Ballmanef116982015-01-29 16:58:29 +000056 const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
Kostya Serebryany404c69f2015-07-24 01:06:40 +000057 return Special[Rand(sizeof(Special) - 1)];
Aaron Ballmanef116982015-01-29 16:58:29 +000058}
59
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +000060size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
61 size_t MaxSize) {
Kostya Serebryanybf29ff22015-08-06 01:29:13 +000062 assert(Size);
63 size_t ShuffleAmount = Rand(std::min(Size, 8UL)) + 1; // [1,8] and <= Size.
64 size_t ShuffleStart = Rand(Size - ShuffleAmount);
65 assert(ShuffleStart + ShuffleAmount <= Size);
66 std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
67 Rand);
68 return Size;
69}
70
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +000071size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size,
72 size_t MaxSize) {
Kostya Serebryany8ce74242015-08-01 01:42:51 +000073 assert(Size);
74 if (Size == 1) return Size;
75 size_t Idx = Rand(Size);
76 // Erase Data[Idx].
77 memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
78 return Size - 1;
79}
80
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +000081size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
82 size_t MaxSize) {
Kostya Serebryany86a5fba2015-08-01 02:23:06 +000083 if (Size == MaxSize) return Size;
84 size_t Idx = Rand(Size + 1);
85 // Insert new value at Data[Idx].
86 memmove(Data + Idx + 1, Data + Idx, Size - Idx);
87 Data[Idx] = RandCh(Rand);
88 return Size + 1;
89}
90
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +000091size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
92 size_t MaxSize) {
Kostya Serebryany86a5fba2015-08-01 02:23:06 +000093 size_t Idx = Rand(Size);
94 Data[Idx] = RandCh(Rand);
95 return Size;
96}
97
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +000098size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
99 size_t MaxSize) {
Kostya Serebryany86a5fba2015-08-01 02:23:06 +0000100 size_t Idx = Rand(Size);
101 Data[Idx] = FlipRandomBit(Data[Idx], Rand);
102 return Size;
103}
104
Kostya Serebryany7d211662015-09-04 00:12:11 +0000105size_t MutationDispatcher::Mutate_AddWordFromDictionary(uint8_t *Data,
106 size_t Size,
107 size_t MaxSize) {
108 auto &D = MDImpl->Dictionary;
109 if (D.empty()) return Size; // FIXME: indicate failure.
110 const Unit &Word = D[Rand(D.size())];
111 if (Size + Word.size() > MaxSize) return Size;
112 size_t Idx = Rand(Size + 1);
113 memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx);
114 memcpy(Data + Idx, Word.data(), Word.size());
115 return Size + Word.size();
116}
117
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000118// Mutates Data in place, returns new size.
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +0000119size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000120 assert(MaxSize > 0);
121 assert(Size <= MaxSize);
122 if (Size == 0) {
123 for (size_t i = 0; i < MaxSize; i++)
Kostya Serebryany404c69f2015-07-24 01:06:40 +0000124 Data[i] = RandCh(Rand);
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000125 return MaxSize;
Kostya Serebryany5b266a82015-02-04 19:10:20 +0000126 }
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000127 assert(Size > 0);
Kostya Serebryany7d211662015-09-04 00:12:11 +0000128 size_t MutatorIdx = Rand(MDImpl->Mutators.size());
129 Size = (this->*(MDImpl->Mutators[MutatorIdx]))(Data, Size, MaxSize);
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000130 assert(Size > 0);
131 return Size;
Aaron Ballmanef116982015-01-29 16:58:29 +0000132}
133
Kostya Serebryany7d211662015-09-04 00:12:11 +0000134void MutationDispatcher::AddWordToDictionary(const uint8_t *Word, size_t Size) {
135 MDImpl->AddWordToDictionary(Word, Size);
136}
137
138MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
139 MDImpl = new Impl;
140}
141
142MutationDispatcher::~MutationDispatcher() { delete MDImpl; }
143
Aaron Ballmanef116982015-01-29 16:58:29 +0000144} // namespace fuzzer