• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "FuzzerCorpus.h"
13 #include "FuzzerDefs.h"
14 #include "FuzzerExtFunctions.h"
15 #include "FuzzerIO.h"
16 #include "FuzzerMutate.h"
17 #include "FuzzerOptions.h"
18 
19 namespace fuzzer {
20 
21 const size_t Dictionary::kMaxDictSize;
22 
PrintASCII(const Word & W,const char * PrintAfter)23 static void PrintASCII(const Word &W, const char *PrintAfter) {
24   PrintASCII(W.data(), W.size(), PrintAfter);
25 }
26 
MutationDispatcher(Random & Rand,const FuzzingOptions & Options)27 MutationDispatcher::MutationDispatcher(Random &Rand,
28                                        const FuzzingOptions &Options)
29     : Rand(Rand), Options(Options) {
30   DefaultMutators.insert(
31       DefaultMutators.begin(),
32       {
33           {&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
34           {&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
35           {&MutationDispatcher::Mutate_InsertRepeatedBytes,
36            "InsertRepeatedBytes"},
37           {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
38           {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
39           {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
40           {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
41           {&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
42           {&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
43           {&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
44           {&MutationDispatcher::Mutate_AddWordFromManualDictionary,
45            "ManualDict"},
46           {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
47            "TempAutoDict"},
48           {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
49            "PersAutoDict"},
50       });
51   if(Options.UseCmp)
52     DefaultMutators.push_back(
53         {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
54 
55   if (EF->LLVMFuzzerCustomMutator)
56     Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
57   else
58     Mutators = DefaultMutators;
59 
60   if (EF->LLVMFuzzerCustomCrossOver)
61     Mutators.push_back(
62         {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
63 }
64 
RandCh(Random & Rand)65 static char RandCh(Random &Rand) {
66   if (Rand.RandBool()) return Rand(256);
67   const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
68   return Special[Rand(sizeof(Special) - 1)];
69 }
70 
Mutate_Custom(uint8_t * Data,size_t Size,size_t MaxSize)71 size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
72                                          size_t MaxSize) {
73   return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand());
74 }
75 
Mutate_CustomCrossOver(uint8_t * Data,size_t Size,size_t MaxSize)76 size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
77                                                   size_t MaxSize) {
78   if (!Corpus || Corpus->size() < 2 || Size == 0)
79     return 0;
80   size_t Idx = Rand(Corpus->size());
81   const Unit &Other = (*Corpus)[Idx];
82   if (Other.empty())
83     return 0;
84   MutateInPlaceHere.resize(MaxSize);
85   auto &U = MutateInPlaceHere;
86   size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
87       Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand());
88   if (!NewSize)
89     return 0;
90   assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
91   memcpy(Data, U.data(), NewSize);
92   return NewSize;
93 }
94 
Mutate_ShuffleBytes(uint8_t * Data,size_t Size,size_t MaxSize)95 size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
96                                                size_t MaxSize) {
97   if (Size > MaxSize) return 0;
98   assert(Size);
99   size_t ShuffleAmount =
100       Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
101   size_t ShuffleStart = Rand(Size - ShuffleAmount);
102   assert(ShuffleStart + ShuffleAmount <= Size);
103   std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
104                       Rand);
105   return Size;
106 }
107 
Mutate_EraseBytes(uint8_t * Data,size_t Size,size_t MaxSize)108 size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
109                                              size_t MaxSize) {
110   assert(Size);
111   if (Size == 1) return 0;
112   size_t N = Rand(Size / 2) + 1;
113   assert(N < Size);
114   size_t Idx = Rand(Size - N + 1);
115   // Erase Data[Idx:Idx+N].
116   memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
117   // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
118   return Size - N;
119 }
120 
Mutate_InsertByte(uint8_t * Data,size_t Size,size_t MaxSize)121 size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
122                                              size_t MaxSize) {
123   if (Size >= MaxSize) return 0;
124   size_t Idx = Rand(Size + 1);
125   // Insert new value at Data[Idx].
126   memmove(Data + Idx + 1, Data + Idx, Size - Idx);
127   Data[Idx] = RandCh(Rand);
128   return Size + 1;
129 }
130 
Mutate_InsertRepeatedBytes(uint8_t * Data,size_t Size,size_t MaxSize)131 size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
132                                                       size_t Size,
133                                                       size_t MaxSize) {
134   const size_t kMinBytesToInsert = 3;
135   if (Size + kMinBytesToInsert >= MaxSize) return 0;
136   size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
137   size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
138   assert(Size + N <= MaxSize && N);
139   size_t Idx = Rand(Size + 1);
140   // Insert new values at Data[Idx].
141   memmove(Data + Idx + N, Data + Idx, Size - Idx);
142   // Give preference to 0x00 and 0xff.
143   uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255);
144   for (size_t i = 0; i < N; i++)
145     Data[Idx + i] = Byte;
146   return Size + N;
147 }
148 
Mutate_ChangeByte(uint8_t * Data,size_t Size,size_t MaxSize)149 size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
150                                              size_t MaxSize) {
151   if (Size > MaxSize) return 0;
152   size_t Idx = Rand(Size);
153   Data[Idx] = RandCh(Rand);
154   return Size;
155 }
156 
Mutate_ChangeBit(uint8_t * Data,size_t Size,size_t MaxSize)157 size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
158                                             size_t MaxSize) {
159   if (Size > MaxSize) return 0;
160   size_t Idx = Rand(Size);
161   Data[Idx] ^= 1 << Rand(8);
162   return Size;
163 }
164 
Mutate_AddWordFromManualDictionary(uint8_t * Data,size_t Size,size_t MaxSize)165 size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
166                                                               size_t Size,
167                                                               size_t MaxSize) {
168   return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
169 }
170 
Mutate_AddWordFromTemporaryAutoDictionary(uint8_t * Data,size_t Size,size_t MaxSize)171 size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary(
172     uint8_t *Data, size_t Size, size_t MaxSize) {
173   return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
174 }
175 
ApplyDictionaryEntry(uint8_t * Data,size_t Size,size_t MaxSize,DictionaryEntry & DE)176 size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
177                                                 size_t MaxSize,
178                                                 DictionaryEntry &DE) {
179   const Word &W = DE.GetW();
180   bool UsePositionHint = DE.HasPositionHint() &&
181                          DE.GetPositionHint() + W.size() < Size &&
182                          Rand.RandBool();
183   if (Rand.RandBool()) {  // Insert W.
184     if (Size + W.size() > MaxSize) return 0;
185     size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
186     memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
187     memcpy(Data + Idx, W.data(), W.size());
188     Size += W.size();
189   } else {  // Overwrite some bytes with W.
190     if (W.size() > Size) return 0;
191     size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
192     memcpy(Data + Idx, W.data(), W.size());
193   }
194   return Size;
195 }
196 
197 // Somewhere in the past we have observed a comparison instructions
198 // with arguments Arg1 Arg2. This function tries to guess a dictionary
199 // entry that will satisfy that comparison.
200 // It first tries to find one of the arguments (possibly swapped) in the
201 // input and if it succeeds it creates a DE with a position hint.
202 // Otherwise it creates a DE with one of the arguments w/o a position hint.
203 template <class T>
MakeDictionaryEntryFromCMP(T Arg1,T Arg2,const uint8_t * Data,size_t Size)204 DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
205     T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
206   ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
207   bool HandleFirst = Rand.RandBool();
208   T ExistingBytes, DesiredBytes;
209   Word W;
210   const uint8_t *End = Data + Size;
211   for (int Arg = 0; Arg < 2; Arg++) {
212     ExistingBytes = HandleFirst ? Arg1 : Arg2;
213     DesiredBytes = HandleFirst ? Arg2 : Arg1;
214     DesiredBytes += Rand(-1, 1);
215     if (Rand.RandBool()) ExistingBytes = Bswap(ExistingBytes);
216     if (Rand.RandBool()) DesiredBytes = Bswap(DesiredBytes);
217     HandleFirst = !HandleFirst;
218     W.Set(reinterpret_cast<uint8_t*>(&DesiredBytes), sizeof(T));
219     const size_t kMaxNumPositions = 8;
220     size_t Positions[kMaxNumPositions];
221     size_t NumPositions = 0;
222     for (const uint8_t *Cur = Data;
223          Cur < End && NumPositions < kMaxNumPositions; Cur++) {
224       Cur = (uint8_t *)SearchMemory(Cur, End - Cur, &ExistingBytes, sizeof(T));
225       if (!Cur) break;
226       Positions[NumPositions++] = Cur - Data;
227     }
228     if (!NumPositions) break;
229     return DictionaryEntry(W, Positions[Rand(NumPositions)]);
230   }
231   DictionaryEntry DE(W);
232   return DE;
233 }
234 
Mutate_AddWordFromTORC(uint8_t * Data,size_t Size,size_t MaxSize)235 size_t MutationDispatcher::Mutate_AddWordFromTORC(
236     uint8_t *Data, size_t Size, size_t MaxSize) {
237   Word W;
238   DictionaryEntry DE;
239   if (Rand.RandBool()) {
240     auto X = TPC.TORC8.Get(Rand.Rand());
241     DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
242   } else {
243     auto X = TPC.TORC4.Get(Rand.Rand());
244     if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
245       DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data,
246                                       Size);
247     else
248       DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
249   }
250   Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
251   if (!Size) return 0;
252   DictionaryEntry &DERef =
253       CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
254                                 kCmpDictionaryEntriesDequeSize];
255   DERef = DE;
256   CurrentDictionaryEntrySequence.push_back(&DERef);
257   return Size;
258 }
259 
Mutate_AddWordFromPersistentAutoDictionary(uint8_t * Data,size_t Size,size_t MaxSize)260 size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
261     uint8_t *Data, size_t Size, size_t MaxSize) {
262   return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
263 }
264 
AddWordFromDictionary(Dictionary & D,uint8_t * Data,size_t Size,size_t MaxSize)265 size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
266                                                  size_t Size, size_t MaxSize) {
267   if (Size > MaxSize) return 0;
268   if (D.empty()) return 0;
269   DictionaryEntry &DE = D[Rand(D.size())];
270   Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
271   if (!Size) return 0;
272   DE.IncUseCount();
273   CurrentDictionaryEntrySequence.push_back(&DE);
274   return Size;
275 }
276 
277 // Overwrites part of To[0,ToSize) with a part of From[0,FromSize).
278 // Returns ToSize.
CopyPartOf(const uint8_t * From,size_t FromSize,uint8_t * To,size_t ToSize)279 size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,
280                                       uint8_t *To, size_t ToSize) {
281   // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).
282   size_t ToBeg = Rand(ToSize);
283   size_t CopySize = Rand(ToSize - ToBeg) + 1;
284   assert(ToBeg + CopySize <= ToSize);
285   CopySize = std::min(CopySize, FromSize);
286   size_t FromBeg = Rand(FromSize - CopySize + 1);
287   assert(FromBeg + CopySize <= FromSize);
288   memmove(To + ToBeg, From + FromBeg, CopySize);
289   return ToSize;
290 }
291 
292 // Inserts part of From[0,ToSize) into To.
293 // Returns new size of To on success or 0 on failure.
InsertPartOf(const uint8_t * From,size_t FromSize,uint8_t * To,size_t ToSize,size_t MaxToSize)294 size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,
295                                         uint8_t *To, size_t ToSize,
296                                         size_t MaxToSize) {
297   if (ToSize >= MaxToSize) return 0;
298   size_t AvailableSpace = MaxToSize - ToSize;
299   size_t MaxCopySize = std::min(AvailableSpace, FromSize);
300   size_t CopySize = Rand(MaxCopySize) + 1;
301   size_t FromBeg = Rand(FromSize - CopySize + 1);
302   assert(FromBeg + CopySize <= FromSize);
303   size_t ToInsertPos = Rand(ToSize + 1);
304   assert(ToInsertPos + CopySize <= MaxToSize);
305   size_t TailSize = ToSize - ToInsertPos;
306   if (To == From) {
307     MutateInPlaceHere.resize(MaxToSize);
308     memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);
309     memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
310     memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);
311   } else {
312     memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
313     memmove(To + ToInsertPos, From + FromBeg, CopySize);
314   }
315   return ToSize + CopySize;
316 }
317 
Mutate_CopyPart(uint8_t * Data,size_t Size,size_t MaxSize)318 size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,
319                                            size_t MaxSize) {
320   if (Size > MaxSize) return 0;
321   if (Rand.RandBool())
322     return CopyPartOf(Data, Size, Data, Size);
323   else
324     return InsertPartOf(Data, Size, Data, Size, MaxSize);
325 }
326 
Mutate_ChangeASCIIInteger(uint8_t * Data,size_t Size,size_t MaxSize)327 size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
328                                                      size_t MaxSize) {
329   if (Size > MaxSize) return 0;
330   size_t B = Rand(Size);
331   while (B < Size && !isdigit(Data[B])) B++;
332   if (B == Size) return 0;
333   size_t E = B;
334   while (E < Size && isdigit(Data[E])) E++;
335   assert(B < E);
336   // now we have digits in [B, E).
337   // strtol and friends don't accept non-zero-teminated data, parse it manually.
338   uint64_t Val = Data[B] - '0';
339   for (size_t i = B + 1; i < E; i++)
340     Val = Val * 10 + Data[i] - '0';
341 
342   // Mutate the integer value.
343   switch(Rand(5)) {
344     case 0: Val++; break;
345     case 1: Val--; break;
346     case 2: Val /= 2; break;
347     case 3: Val *= 2; break;
348     case 4: Val = Rand(Val * Val); break;
349     default: assert(0);
350   }
351   // Just replace the bytes with the new ones, don't bother moving bytes.
352   for (size_t i = B; i < E; i++) {
353     size_t Idx = E + B - i - 1;
354     assert(Idx >= B && Idx < E);
355     Data[Idx] = (Val % 10) + '0';
356     Val /= 10;
357   }
358   return Size;
359 }
360 
361 template<class T>
ChangeBinaryInteger(uint8_t * Data,size_t Size,Random & Rand)362 size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
363   if (Size < sizeof(T)) return 0;
364   size_t Off = Rand(Size - sizeof(T) + 1);
365   assert(Off + sizeof(T) <= Size);
366   T Val;
367   if (Off < 64 && !Rand(4)) {
368     Val = Size;
369     if (Rand.RandBool())
370       Val = Bswap(Val);
371   } else {
372     memcpy(&Val, Data + Off, sizeof(Val));
373     T Add = Rand(21);
374     Add -= 10;
375     if (Rand.RandBool())
376       Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
377     else
378       Val = Val + Add;               // Add assuming current endiannes.
379     if (Add == 0 || Rand.RandBool()) // Maybe negate.
380       Val = -Val;
381   }
382   memcpy(Data + Off, &Val, sizeof(Val));
383   return Size;
384 }
385 
Mutate_ChangeBinaryInteger(uint8_t * Data,size_t Size,size_t MaxSize)386 size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,
387                                                       size_t Size,
388                                                       size_t MaxSize) {
389   if (Size > MaxSize) return 0;
390   switch (Rand(4)) {
391     case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand);
392     case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand);
393     case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand);
394     case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand);
395     default: assert(0);
396   }
397   return 0;
398 }
399 
Mutate_CrossOver(uint8_t * Data,size_t Size,size_t MaxSize)400 size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
401                                             size_t MaxSize) {
402   if (Size > MaxSize) return 0;
403   if (!Corpus || Corpus->size() < 2 || Size == 0) return 0;
404   size_t Idx = Rand(Corpus->size());
405   const Unit &O = (*Corpus)[Idx];
406   if (O.empty()) return 0;
407   MutateInPlaceHere.resize(MaxSize);
408   auto &U = MutateInPlaceHere;
409   size_t NewSize = 0;
410   switch(Rand(3)) {
411     case 0:
412       NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size());
413       break;
414     case 1:
415       NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize);
416       if (NewSize)
417         break;
418       // LLVM_FALLTHROUGH;
419     case 2:
420       NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
421       break;
422     default: assert(0);
423   }
424   assert(NewSize > 0 && "CrossOver returned empty unit");
425   assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
426   memcpy(Data, U.data(), NewSize);
427   return NewSize;
428 }
429 
StartMutationSequence()430 void MutationDispatcher::StartMutationSequence() {
431   CurrentMutatorSequence.clear();
432   CurrentDictionaryEntrySequence.clear();
433 }
434 
435 // Copy successful dictionary entries to PersistentAutoDictionary.
RecordSuccessfulMutationSequence()436 void MutationDispatcher::RecordSuccessfulMutationSequence() {
437   for (auto DE : CurrentDictionaryEntrySequence) {
438     // PersistentAutoDictionary.AddWithSuccessCountOne(DE);
439     DE->IncSuccessCount();
440     // Linear search is fine here as this happens seldom.
441     if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
442       PersistentAutoDictionary.push_back({DE->GetW(), 1});
443   }
444 }
445 
PrintRecommendedDictionary()446 void MutationDispatcher::PrintRecommendedDictionary() {
447   std::vector<DictionaryEntry> V;
448   for (auto &DE : PersistentAutoDictionary)
449     if (!ManualDictionary.ContainsWord(DE.GetW()))
450       V.push_back(DE);
451   if (V.empty()) return;
452   Printf("###### Recommended dictionary. ######\n");
453   for (auto &DE: V) {
454     Printf("\"");
455     PrintASCII(DE.GetW(), "\"");
456     Printf(" # Uses: %zd\n", DE.GetUseCount());
457   }
458   Printf("###### End of recommended dictionary. ######\n");
459 }
460 
PrintMutationSequence()461 void MutationDispatcher::PrintMutationSequence() {
462   Printf("MS: %zd ", CurrentMutatorSequence.size());
463   for (auto M : CurrentMutatorSequence)
464     Printf("%s-", M.Name);
465   if (!CurrentDictionaryEntrySequence.empty()) {
466     Printf(" DE: ");
467     for (auto DE : CurrentDictionaryEntrySequence) {
468       Printf("\"");
469       PrintASCII(DE->GetW(), "\"-");
470     }
471   }
472 }
473 
Mutate(uint8_t * Data,size_t Size,size_t MaxSize)474 size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
475   return MutateImpl(Data, Size, MaxSize, Mutators);
476 }
477 
DefaultMutate(uint8_t * Data,size_t Size,size_t MaxSize)478 size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
479                                          size_t MaxSize) {
480   return MutateImpl(Data, Size, MaxSize, DefaultMutators);
481 }
482 
483 // Mutates Data in place, returns new size.
MutateImpl(uint8_t * Data,size_t Size,size_t MaxSize,const std::vector<Mutator> & Mutators)484 size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
485                                       size_t MaxSize,
486                                       const std::vector<Mutator> &Mutators) {
487   assert(MaxSize > 0);
488   if (Size == 0) {
489     for (size_t i = 0; i < MaxSize; i++)
490       Data[i] = RandCh(Rand);
491     if (Options.OnlyASCII)
492       ToASCII(Data, MaxSize);
493     return MaxSize;
494   }
495   assert(Size > 0);
496   // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
497   // in which case they will return 0.
498   // Try several times before returning un-mutated data.
499   for (int Iter = 0; Iter < 100; Iter++) {
500     auto M = Mutators[Rand(Mutators.size())];
501     size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
502     if (NewSize && NewSize <= MaxSize) {
503       if (Options.OnlyASCII)
504         ToASCII(Data, NewSize);
505       CurrentMutatorSequence.push_back(M);
506       return NewSize;
507     }
508   }
509   return std::min(Size, MaxSize);
510 }
511 
AddWordToManualDictionary(const Word & W)512 void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
513   ManualDictionary.push_back(
514       {W, std::numeric_limits<size_t>::max()});
515 }
516 
AddWordToAutoDictionary(DictionaryEntry DE)517 void MutationDispatcher::AddWordToAutoDictionary(DictionaryEntry DE) {
518   static const size_t kMaxAutoDictSize = 1 << 14;
519   if (TempAutoDictionary.size() >= kMaxAutoDictSize) return;
520   TempAutoDictionary.push_back(DE);
521 }
522 
ClearAutoDictionary()523 void MutationDispatcher::ClearAutoDictionary() {
524   TempAutoDictionary.clear();
525 }
526 
527 }  // namespace fuzzer
528