blob: 4ea8265dfb8ddf45808d48d1e7c264b3e09e72f0 [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 Serebryany14c50282015-12-19 01:09:49 +000020struct Mutator {
21 size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
22 const char *Name;
23};
Kostya Serebryany7d211662015-09-04 00:12:11 +000024
Kostya Serebryany152ac7a2016-01-07 01:49:35 +000025struct DictionaryEntry {
26 Unit Word;
27 size_t PositionHint;
28};
29
Kostya Serebryany4b358742016-01-14 02:36:44 +000030struct Dictionary : public std::vector<DictionaryEntry>{
31 bool ContainsWord(const Unit &W) const {
32 return end() !=
33 std::find_if(begin(), end(), [&](const DictionaryEntry &DE) {
34 return DE.Word == W;
35 });
36 }
37};
38
Kostya Serebryany7d211662015-09-04 00:12:11 +000039struct MutationDispatcher::Impl {
Kostya Serebryany4b358742016-01-14 02:36:44 +000040 // Dictionary provided by the user via -dict=DICT_FILE.
41 Dictionary ManualDictionary;
42 // Temporary dictionary modified by the fuzzer itself,
43 // recreated periodically.
44 Dictionary TempAutoDictionary;
45 // Persistent dictionary modified by the fuzzer, consists of
46 // entries that led to successfull discoveries in the past mutations.
47 Dictionary PersistentAutoDictionary;
48
Kostya Serebryany7d211662015-09-04 00:12:11 +000049 std::vector<Mutator> Mutators;
Kostya Serebryany14c50282015-12-19 01:09:49 +000050 std::vector<Mutator> CurrentMutatorSequence;
Kostya Serebryany4b358742016-01-14 02:36:44 +000051 Dictionary CurrentDictionaryEntrySequence;
Kostya Serebryany27ab2d72015-12-19 02:49:09 +000052 const std::vector<Unit> *Corpus = nullptr;
Kostya Serebryany152ac7a2016-01-07 01:49:35 +000053 FuzzerRandomBase &Rand;
Kostya Serebryany14c50282015-12-19 01:09:49 +000054
55 void Add(Mutator M) { Mutators.push_back(M); }
Kostya Serebryany152ac7a2016-01-07 01:49:35 +000056 Impl(FuzzerRandomBase &Rand) : Rand(Rand) {
Kostya Serebryany14c50282015-12-19 01:09:49 +000057 Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"});
58 Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"});
59 Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"});
60 Add({&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"});
61 Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"});
62 Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"});
Kostya Serebryany27ab2d72015-12-19 02:49:09 +000063 Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"});
Kostya Serebryany152ac7a2016-01-07 01:49:35 +000064 Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary,
65 "AddFromManualDict"});
Kostya Serebryany4b358742016-01-14 02:36:44 +000066 Add({&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
67 "AddFromTempAutoDict"});
68 Add({&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
69 "AddFromPersAutoDict"});
Kostya Serebryany7d211662015-09-04 00:12:11 +000070 }
Kostya Serebryany27ab2d72015-12-19 02:49:09 +000071 void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; }
Kostya Serebryany152ac7a2016-01-07 01:49:35 +000072 size_t AddWordFromDictionary(const std::vector<DictionaryEntry> &D,
73 uint8_t *Data, size_t Size, size_t MaxSize);
Kostya Serebryany7d211662015-09-04 00:12:11 +000074};
75
Kostya Serebryany404c69f2015-07-24 01:06:40 +000076static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
77 int Bit = Rand(8);
Aaron Ballmanef116982015-01-29 16:58:29 +000078 char Mask = 1 << Bit;
79 char R;
80 if (X & (1 << Bit))
81 R = X & ~Mask;
82 else
83 R = X | Mask;
84 assert(R != X);
85 return R;
86}
87
Kostya Serebryany404c69f2015-07-24 01:06:40 +000088static char RandCh(FuzzerRandomBase &Rand) {
89 if (Rand.RandBool()) return Rand(256);
Aaron Ballmanef116982015-01-29 16:58:29 +000090 const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
Kostya Serebryany404c69f2015-07-24 01:06:40 +000091 return Special[Rand(sizeof(Special) - 1)];
Aaron Ballmanef116982015-01-29 16:58:29 +000092}
93
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +000094size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
95 size_t MaxSize) {
Kostya Serebryanybf29ff22015-08-06 01:29:13 +000096 assert(Size);
Kostya Serebryany152ac7a2016-01-07 01:49:35 +000097 size_t ShuffleAmount =
98 Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
Kostya Serebryanybf29ff22015-08-06 01:29:13 +000099 size_t ShuffleStart = Rand(Size - ShuffleAmount);
100 assert(ShuffleStart + ShuffleAmount <= Size);
101 std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
102 Rand);
103 return Size;
104}
105
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +0000106size_t MutationDispatcher::Mutate_EraseByte(uint8_t *Data, size_t Size,
107 size_t MaxSize) {
Kostya Serebryany8ce74242015-08-01 01:42:51 +0000108 assert(Size);
Kostya Serebryanyb2e98972015-09-04 00:40:29 +0000109 if (Size == 1) return 0;
Kostya Serebryany8ce74242015-08-01 01:42:51 +0000110 size_t Idx = Rand(Size);
111 // Erase Data[Idx].
112 memmove(Data + Idx, Data + Idx + 1, Size - Idx - 1);
113 return Size - 1;
114}
115
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +0000116size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
117 size_t MaxSize) {
Kostya Serebryanyb2e98972015-09-04 00:40:29 +0000118 if (Size == MaxSize) return 0;
Kostya Serebryany86a5fba2015-08-01 02:23:06 +0000119 size_t Idx = Rand(Size + 1);
120 // Insert new value at Data[Idx].
121 memmove(Data + Idx + 1, Data + Idx, Size - Idx);
122 Data[Idx] = RandCh(Rand);
123 return Size + 1;
124}
125
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +0000126size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
127 size_t MaxSize) {
Kostya Serebryany86a5fba2015-08-01 02:23:06 +0000128 size_t Idx = Rand(Size);
129 Data[Idx] = RandCh(Rand);
130 return Size;
131}
132
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +0000133size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
134 size_t MaxSize) {
Kostya Serebryany86a5fba2015-08-01 02:23:06 +0000135 size_t Idx = Rand(Size);
136 Data[Idx] = FlipRandomBit(Data[Idx], Rand);
137 return Size;
138}
139
Kostya Serebryany152ac7a2016-01-07 01:49:35 +0000140size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
141 size_t Size,
142 size_t MaxSize) {
143 return MDImpl->AddWordFromDictionary(MDImpl->ManualDictionary, Data, Size,
144 MaxSize);
145}
146
Kostya Serebryany4b358742016-01-14 02:36:44 +0000147size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary(
148 uint8_t *Data, size_t Size, size_t MaxSize) {
149 return MDImpl->AddWordFromDictionary(MDImpl->TempAutoDictionary, Data, Size,
150 MaxSize);
151}
152
153size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
154 uint8_t *Data, size_t Size, size_t MaxSize) {
155 return MDImpl->AddWordFromDictionary(MDImpl->PersistentAutoDictionary, Data, Size,
Kostya Serebryany152ac7a2016-01-07 01:49:35 +0000156 MaxSize);
157}
158
159size_t MutationDispatcher::Impl::AddWordFromDictionary(
160 const std::vector<DictionaryEntry> &D, uint8_t *Data, size_t Size,
161 size_t MaxSize) {
Kostya Serebryanyb2e98972015-09-04 00:40:29 +0000162 if (D.empty()) return 0;
Kostya Serebryany152ac7a2016-01-07 01:49:35 +0000163 const DictionaryEntry &DE = D[Rand(D.size())];
164 const Unit &Word = DE.Word;
165 size_t PositionHint = DE.PositionHint;
166 bool UsePositionHint = PositionHint != std::numeric_limits<size_t>::max() &&
167 PositionHint + Word.size() < Size && Rand.RandBool();
Kostya Serebryany80eb76a2016-01-06 02:13:04 +0000168 if (Rand.RandBool()) { // Insert Word.
169 if (Size + Word.size() > MaxSize) return 0;
Kostya Serebryany152ac7a2016-01-07 01:49:35 +0000170 size_t Idx = UsePositionHint ? PositionHint : Rand(Size + 1);
Kostya Serebryany80eb76a2016-01-06 02:13:04 +0000171 memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx);
172 memcpy(Data + Idx, Word.data(), Word.size());
Kostya Serebryany41740052016-01-12 02:36:59 +0000173 Size += Word.size();
Kostya Serebryany80eb76a2016-01-06 02:13:04 +0000174 } else { // Overwrite some bytes with Word.
175 if (Word.size() > Size) return 0;
Kostya Serebryany152ac7a2016-01-07 01:49:35 +0000176 size_t Idx = UsePositionHint ? PositionHint : Rand(Size - Word.size());
Kostya Serebryany80eb76a2016-01-06 02:13:04 +0000177 memcpy(Data + Idx, Word.data(), Word.size());
Kostya Serebryany80eb76a2016-01-06 02:13:04 +0000178 }
Kostya Serebryany41740052016-01-12 02:36:59 +0000179 CurrentDictionaryEntrySequence.push_back(DE);
180 return Size;
Kostya Serebryany7d211662015-09-04 00:12:11 +0000181}
182
Kostya Serebryany25425ad2015-09-08 17:19:31 +0000183size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
184 size_t MaxSize) {
185 size_t B = Rand(Size);
186 while (B < Size && !isdigit(Data[B])) B++;
187 if (B == Size) return 0;
188 size_t E = B;
189 while (E < Size && isdigit(Data[E])) E++;
190 assert(B < E);
191 // now we have digits in [B, E).
192 // strtol and friends don't accept non-zero-teminated data, parse it manually.
193 uint64_t Val = Data[B] - '0';
194 for (size_t i = B + 1; i < E; i++)
195 Val = Val * 10 + Data[i] - '0';
196
197 // Mutate the integer value.
198 switch(Rand(5)) {
199 case 0: Val++; break;
200 case 1: Val--; break;
201 case 2: Val /= 2; break;
202 case 3: Val *= 2; break;
203 case 4: Val = Rand(Val * Val); break;
204 default: assert(0);
205 }
206 // Just replace the bytes with the new ones, don't bother moving bytes.
207 for (size_t i = B; i < E; i++) {
208 size_t Idx = E + B - i - 1;
209 assert(Idx >= B && Idx < E);
210 Data[Idx] = (Val % 10) + '0';
211 Val /= 10;
212 }
213 return Size;
214}
215
Kostya Serebryany27ab2d72015-12-19 02:49:09 +0000216size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
217 size_t MaxSize) {
218 auto Corpus = MDImpl->Corpus;
219 if (!Corpus || Corpus->size() < 2 || Size == 0) return 0;
220 size_t Idx = Rand(Corpus->size());
221 const Unit &Other = (*Corpus)[Idx];
222 if (Other.empty()) return 0;
223 Unit U(MaxSize);
224 size_t NewSize =
225 CrossOver(Data, Size, Other.data(), Other.size(), U.data(), U.size());
226 assert(NewSize > 0 && "CrossOver returned empty unit");
227 assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
228 memcpy(Data, U.data(), NewSize);
229 return NewSize;
230}
231
Kostya Serebryany14c50282015-12-19 01:09:49 +0000232void MutationDispatcher::StartMutationSequence() {
233 MDImpl->CurrentMutatorSequence.clear();
Kostya Serebryany41740052016-01-12 02:36:59 +0000234 MDImpl->CurrentDictionaryEntrySequence.clear();
Kostya Serebryany14c50282015-12-19 01:09:49 +0000235}
236
Kostya Serebryany4b358742016-01-14 02:36:44 +0000237// Copy successful dictionary entries to PersistentAutoDictionary.
238void MutationDispatcher::RecordSuccessfulMutationSequence() {
239 for (auto &DE : MDImpl->CurrentDictionaryEntrySequence)
240 // Linear search is fine here as this happens seldom.
241 if (!MDImpl->PersistentAutoDictionary.ContainsWord(DE.Word))
242 MDImpl->PersistentAutoDictionary.push_back(
243 {DE.Word, std::numeric_limits<size_t>::max()});
244}
245
246void MutationDispatcher::PrintRecommendedDictionary() {
247 std::vector<Unit> V;
248 for (auto &DE : MDImpl->PersistentAutoDictionary)
249 if (!MDImpl->ManualDictionary.ContainsWord(DE.Word))
250 V.push_back(DE.Word);
251 if (V.empty()) return;
252 Printf("###### Recommended dictionary. ######\n");
253 for (auto &U: V) {
254 Printf("\"");
255 PrintASCII(U, "\"\n");
256 }
257 Printf("###### End of recommended dictionary. ######\n");
258}
259
Kostya Serebryany14c50282015-12-19 01:09:49 +0000260void MutationDispatcher::PrintMutationSequence() {
261 Printf("MS: %zd ", MDImpl->CurrentMutatorSequence.size());
262 for (auto M : MDImpl->CurrentMutatorSequence)
263 Printf("%s-", M.Name);
Kostya Serebryany41740052016-01-12 02:36:59 +0000264 if (!MDImpl->CurrentDictionaryEntrySequence.empty()) {
265 Printf(" DE: ");
Kostya Serebryany4b358742016-01-14 02:36:44 +0000266 for (auto &DE : MDImpl->CurrentDictionaryEntrySequence) {
Kostya Serebryany41740052016-01-12 02:36:59 +0000267 Printf("\"");
268 PrintASCII(DE.Word, "\"-");
269 }
270 }
Kostya Serebryany14c50282015-12-19 01:09:49 +0000271}
272
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000273// Mutates Data in place, returns new size.
Kostya Serebryanyec2dcb12015-09-03 21:24:19 +0000274size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000275 assert(MaxSize > 0);
276 assert(Size <= MaxSize);
277 if (Size == 0) {
278 for (size_t i = 0; i < MaxSize; i++)
Kostya Serebryany404c69f2015-07-24 01:06:40 +0000279 Data[i] = RandCh(Rand);
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000280 return MaxSize;
Kostya Serebryany5b266a82015-02-04 19:10:20 +0000281 }
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000282 assert(Size > 0);
Kostya Serebryanyb2e98972015-09-04 00:40:29 +0000283 // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
284 // in which case they will return 0.
285 // Try several times before returning un-mutated data.
286 for (int Iter = 0; Iter < 10; Iter++) {
287 size_t MutatorIdx = Rand(MDImpl->Mutators.size());
Kostya Serebryany14c50282015-12-19 01:09:49 +0000288 auto M = MDImpl->Mutators[MutatorIdx];
289 size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
290 if (NewSize) {
291 MDImpl->CurrentMutatorSequence.push_back(M);
292 return NewSize;
293 }
Kostya Serebryanyb2e98972015-09-04 00:40:29 +0000294 }
Kostya Serebryanyf3424592015-05-22 22:35:31 +0000295 return Size;
Aaron Ballmanef116982015-01-29 16:58:29 +0000296}
297
Kostya Serebryany27ab2d72015-12-19 02:49:09 +0000298void MutationDispatcher::SetCorpus(const std::vector<Unit> *Corpus) {
299 MDImpl->SetCorpus(Corpus);
300}
301
Kostya Serebryany152ac7a2016-01-07 01:49:35 +0000302void MutationDispatcher::AddWordToManualDictionary(const Unit &Word) {
303 MDImpl->ManualDictionary.push_back(
304 {Word, std::numeric_limits<size_t>::max()});
305}
306
307void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word,
308 size_t PositionHint) {
Kostya Serebryanyb65805a2016-01-09 03:08:58 +0000309 static const size_t kMaxAutoDictSize = 1 << 14;
Kostya Serebryany4b358742016-01-14 02:36:44 +0000310 if (MDImpl->TempAutoDictionary.size() >= kMaxAutoDictSize) return;
311 MDImpl->TempAutoDictionary.push_back({Word, PositionHint});
Kostya Serebryany7d211662015-09-04 00:12:11 +0000312}
313
Kostya Serebryanyb65805a2016-01-09 03:08:58 +0000314void MutationDispatcher::ClearAutoDictionary() {
Kostya Serebryany4b358742016-01-14 02:36:44 +0000315 MDImpl->TempAutoDictionary.clear();
Kostya Serebryanyb65805a2016-01-09 03:08:58 +0000316}
317
Kostya Serebryany7d211662015-09-04 00:12:11 +0000318MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
Kostya Serebryany152ac7a2016-01-07 01:49:35 +0000319 MDImpl = new Impl(Rand);
Kostya Serebryany7d211662015-09-04 00:12:11 +0000320}
321
322MutationDispatcher::~MutationDispatcher() { delete MDImpl; }
323
Aaron Ballmanef116982015-01-29 16:58:29 +0000324} // namespace fuzzer