OSDN Git Service

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