brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.3 KiB · 4587f86 Raw
597 lines · cpp
1//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8// Mutate a test input.9//===----------------------------------------------------------------------===//10 11#include "FuzzerDefs.h"12#include "FuzzerExtFunctions.h"13#include "FuzzerIO.h"14#include "FuzzerMutate.h"15#include "FuzzerOptions.h"16#include "FuzzerTracePC.h"17 18namespace fuzzer {19 20const size_t Dictionary::kMaxDictSize;21static const size_t kMaxMutationsToPrint = 10;22 23static void PrintASCII(const Word &W, const char *PrintAfter) {24  PrintASCII(W.data(), W.size(), PrintAfter);25}26 27MutationDispatcher::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_AddWordFromPersistentAutoDictionary,47           "PersAutoDict"},48      });49  if(Options.UseCmp)50    DefaultMutators.push_back(51        {&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});52 53  if (EF->LLVMFuzzerCustomMutator)54    Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});55  else56    Mutators = DefaultMutators;57 58  if (EF->LLVMFuzzerCustomCrossOver)59    Mutators.push_back(60        {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});61}62 63static char RandCh(Random &Rand) {64  if (Rand.RandBool())65    return static_cast<char>(Rand(256));66  const char Special[] = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";67  return Special[Rand(sizeof(Special) - 1)];68}69 70size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,71                                         size_t MaxSize) {72  if (EF->__msan_unpoison)73    EF->__msan_unpoison(Data, Size);74  if (EF->__msan_unpoison_param)75    EF->__msan_unpoison_param(4);76  return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize,77                                     Rand.Rand<unsigned int>());78}79 80size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,81                                                  size_t MaxSize) {82  if (Size == 0)83    return 0;84  if (!CrossOverWith) return 0;85  const Unit &Other = *CrossOverWith;86  if (Other.empty())87    return 0;88  CustomCrossOverInPlaceHere.resize(MaxSize);89  auto &U = CustomCrossOverInPlaceHere;90 91  if (EF->__msan_unpoison) {92    EF->__msan_unpoison(Data, Size);93    EF->__msan_unpoison(Other.data(), Other.size());94    EF->__msan_unpoison(U.data(), U.size());95  }96  if (EF->__msan_unpoison_param)97    EF->__msan_unpoison_param(7);98  size_t NewSize = EF->LLVMFuzzerCustomCrossOver(99      Data, Size, Other.data(), Other.size(), U.data(), U.size(),100      Rand.Rand<unsigned int>());101 102  if (!NewSize)103    return 0;104  assert(NewSize <= MaxSize && "CustomCrossOver returned oversized unit");105  memcpy(Data, U.data(), NewSize);106  return NewSize;107}108 109size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,110                                               size_t MaxSize) {111  if (Size > MaxSize || Size == 0) return 0;112  size_t ShuffleAmount =113      Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.114  size_t ShuffleStart = Rand(Size - ShuffleAmount);115  assert(ShuffleStart + ShuffleAmount <= Size);116  std::shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount, Rand);117  return Size;118}119 120size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,121                                             size_t MaxSize) {122  if (Size <= 1) return 0;123  size_t N = Rand(Size / 2) + 1;124  assert(N < Size);125  size_t Idx = Rand(Size - N + 1);126  // Erase Data[Idx:Idx+N].127  memmove(Data + Idx, Data + Idx + N, Size - Idx - N);128  // Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);129  return Size - N;130}131 132size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,133                                             size_t MaxSize) {134  if (Size >= MaxSize) return 0;135  size_t Idx = Rand(Size + 1);136  // Insert new value at Data[Idx].137  memmove(Data + Idx + 1, Data + Idx, Size - Idx);138  Data[Idx] = RandCh(Rand);139  return Size + 1;140}141 142size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,143                                                      size_t Size,144                                                      size_t MaxSize) {145  const size_t kMinBytesToInsert = 3;146  if (Size + kMinBytesToInsert >= MaxSize) return 0;147  size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);148  size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;149  assert(Size + N <= MaxSize && N);150  size_t Idx = Rand(Size + 1);151  // Insert new values at Data[Idx].152  memmove(Data + Idx + N, Data + Idx, Size - Idx);153  // Give preference to 0x00 and 0xff.154  uint8_t Byte = static_cast<uint8_t>(155      Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255));156  for (size_t i = 0; i < N; i++)157    Data[Idx + i] = Byte;158  return Size + N;159}160 161size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,162                                             size_t MaxSize) {163  if (Size > MaxSize) return 0;164  size_t Idx = Rand(Size);165  Data[Idx] = RandCh(Rand);166  return Size;167}168 169size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,170                                            size_t MaxSize) {171  if (Size > MaxSize) return 0;172  size_t Idx = Rand(Size);173  Data[Idx] ^= 1 << Rand(8);174  return Size;175}176 177size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,178                                                              size_t Size,179                                                              size_t MaxSize) {180  return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);181}182 183size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,184                                                size_t MaxSize,185                                                DictionaryEntry &DE) {186  const Word &W = DE.GetW();187  bool UsePositionHint = DE.HasPositionHint() &&188                         DE.GetPositionHint() + W.size() < Size &&189                         Rand.RandBool();190  if (Rand.RandBool()) {  // Insert W.191    if (Size + W.size() > MaxSize) return 0;192    size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);193    memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);194    memcpy(Data + Idx, W.data(), W.size());195    Size += W.size();196  } else {  // Overwrite some bytes with W.197    if (W.size() > Size) return 0;198    size_t Idx =199        UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1 - W.size());200    memcpy(Data + Idx, W.data(), W.size());201  }202  return Size;203}204 205// Somewhere in the past we have observed a comparison instructions206// with arguments Arg1 Arg2. This function tries to guess a dictionary207// entry that will satisfy that comparison.208// It first tries to find one of the arguments (possibly swapped) in the209// input and if it succeeds it creates a DE with a position hint.210// Otherwise it creates a DE with one of the arguments w/o a position hint.211DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(212    const void *Arg1, const void *Arg2,213    const void *Arg1Mutation, const void *Arg2Mutation,214    size_t ArgSize, const uint8_t *Data,215    size_t Size) {216  bool HandleFirst = Rand.RandBool();217  const void *ExistingBytes, *DesiredBytes;218  Word W;219  const uint8_t *End = Data + Size;220  for (int Arg = 0; Arg < 2; Arg++) {221    ExistingBytes = HandleFirst ? Arg1 : Arg2;222    DesiredBytes = HandleFirst ? Arg2Mutation : Arg1Mutation;223    HandleFirst = !HandleFirst;224    W.Set(reinterpret_cast<const uint8_t*>(DesiredBytes), ArgSize);225    const size_t kMaxNumPositions = 8;226    size_t Positions[kMaxNumPositions];227    size_t NumPositions = 0;228    for (const uint8_t *Cur = Data;229         Cur < End && NumPositions < kMaxNumPositions; Cur++) {230      Cur =231          (const uint8_t *)SearchMemory(Cur, End - Cur, ExistingBytes, ArgSize);232      if (!Cur) break;233      Positions[NumPositions++] = Cur - Data;234    }235    if (!NumPositions) continue;236    return DictionaryEntry(W, Positions[Rand(NumPositions)]);237  }238  DictionaryEntry DE(W);239  return DE;240}241 242 243template <class T>244DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(245    T Arg1, T Arg2, const uint8_t *Data, size_t Size) {246  if (Rand.RandBool()) Arg1 = Bswap(Arg1);247  if (Rand.RandBool()) Arg2 = Bswap(Arg2);248  T Arg1Mutation = static_cast<T>(Arg1 + Rand(-1, 1));249  T Arg2Mutation = static_cast<T>(Arg2 + Rand(-1, 1));250  return MakeDictionaryEntryFromCMP(&Arg1, &Arg2, &Arg1Mutation, &Arg2Mutation,251                                    sizeof(Arg1), Data, Size);252}253 254DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(255    const Word &Arg1, const Word &Arg2, const uint8_t *Data, size_t Size) {256  return MakeDictionaryEntryFromCMP(Arg1.data(), Arg2.data(), Arg1.data(),257                                    Arg2.data(), Arg1.size(), Data, Size);258}259 260size_t MutationDispatcher::Mutate_AddWordFromTORC(261    uint8_t *Data, size_t Size, size_t MaxSize) {262  Word W;263  DictionaryEntry DE;264  switch (Rand(4)) {265  case 0: {266    auto X = TPC.TORC8.Get(Rand.Rand<size_t>());267    DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);268  } break;269  case 1: {270    auto X = TPC.TORC4.Get(Rand.Rand<size_t>());271    if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())272      DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data, Size);273    else274      DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);275  } break;276  case 2: {277    auto X = TPC.TORCW.Get(Rand.Rand<size_t>());278    DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);279  } break;280  case 3: if (Options.UseMemmem) {281      auto X = TPC.MMT.Get(Rand.Rand<size_t>());282      DE = DictionaryEntry(X);283  } break;284  default:285    assert(0);286  }287  if (!DE.GetW().size()) return 0;288  Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);289  if (!Size) return 0;290  DictionaryEntry &DERef =291      CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %292                                kCmpDictionaryEntriesDequeSize];293  DERef = DE;294  CurrentDictionaryEntrySequence.push_back(&DERef);295  return Size;296}297 298size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(299    uint8_t *Data, size_t Size, size_t MaxSize) {300  return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);301}302 303size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,304                                                 size_t Size, size_t MaxSize) {305  if (Size > MaxSize) return 0;306  if (D.empty()) return 0;307  DictionaryEntry &DE = D[Rand(D.size())];308  Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);309  if (!Size) return 0;310  DE.IncUseCount();311  CurrentDictionaryEntrySequence.push_back(&DE);312  return Size;313}314 315// Overwrites part of To[0,ToSize) with a part of From[0,FromSize).316// Returns ToSize.317size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,318                                      uint8_t *To, size_t ToSize) {319  // Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).320  size_t ToBeg = Rand(ToSize);321  size_t CopySize = Rand(ToSize - ToBeg) + 1;322  assert(ToBeg + CopySize <= ToSize);323  CopySize = std::min(CopySize, FromSize);324  size_t FromBeg = Rand(FromSize - CopySize + 1);325  assert(FromBeg + CopySize <= FromSize);326  memmove(To + ToBeg, From + FromBeg, CopySize);327  return ToSize;328}329 330// Inserts part of From[0,ToSize) into To.331// Returns new size of To on success or 0 on failure.332size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,333                                        uint8_t *To, size_t ToSize,334                                        size_t MaxToSize) {335  if (ToSize >= MaxToSize) return 0;336  size_t AvailableSpace = MaxToSize - ToSize;337  size_t MaxCopySize = std::min(AvailableSpace, FromSize);338  size_t CopySize = Rand(MaxCopySize) + 1;339  size_t FromBeg = Rand(FromSize - CopySize + 1);340  assert(FromBeg + CopySize <= FromSize);341  size_t ToInsertPos = Rand(ToSize + 1);342  assert(ToInsertPos + CopySize <= MaxToSize);343  size_t TailSize = ToSize - ToInsertPos;344  if (To == From) {345    MutateInPlaceHere.resize(MaxToSize);346    memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);347    memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);348    memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);349  } else {350    memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);351    memmove(To + ToInsertPos, From + FromBeg, CopySize);352  }353  return ToSize + CopySize;354}355 356size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,357                                           size_t MaxSize) {358  if (Size > MaxSize || Size == 0) return 0;359  // If Size == MaxSize, `InsertPartOf(...)` will360  // fail so there's no point using it in this case.361  if (Size == MaxSize || Rand.RandBool())362    return CopyPartOf(Data, Size, Data, Size);363  else364    return InsertPartOf(Data, Size, Data, Size, MaxSize);365}366 367size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,368                                                     size_t MaxSize) {369  if (Size > MaxSize) return 0;370  size_t B = Rand(Size);371  while (B < Size && !isdigit(Data[B])) B++;372  if (B == Size) return 0;373  size_t E = B;374  while (E < Size && isdigit(Data[E])) E++;375  assert(B < E);376  // now we have digits in [B, E).377  // strtol and friends don't accept non-zero-teminated data, parse it manually.378  uint64_t Val = Data[B] - '0';379  for (size_t i = B + 1; i < E; i++)380    Val = Val * 10 + Data[i] - '0';381 382  // Mutate the integer value.383  switch(Rand(5)) {384    case 0: Val++; break;385    case 1: Val--; break;386    case 2: Val /= 2; break;387    case 3: Val *= 2; break;388    case 4: Val = Rand(Val * Val); break;389    default: assert(0);390  }391  // Just replace the bytes with the new ones, don't bother moving bytes.392  for (size_t i = B; i < E; i++) {393    size_t Idx = E + B - i - 1;394    assert(Idx >= B && Idx < E);395    Data[Idx] = (Val % 10) + '0';396    Val /= 10;397  }398  return Size;399}400 401template<class T>402size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {403  if (Size < sizeof(T)) return 0;404  size_t Off = Rand(Size - sizeof(T) + 1);405  assert(Off + sizeof(T) <= Size);406  T Val;407  if (Off < 64 && !Rand(4)) {408    Val = static_cast<T>(Size);409    if (Rand.RandBool())410      Val = Bswap(Val);411  } else {412    memcpy(&Val, Data + Off, sizeof(Val));413    T Add = static_cast<T>(Rand(21));414    Add -= 10;415    if (Rand.RandBool())416      Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endianness.417    else418      Val = Val + Add;               // Add assuming current endianness.419    if (Add == 0 || Rand.RandBool()) // Maybe negate.420      Val = -Val;421  }422  memcpy(Data + Off, &Val, sizeof(Val));423  return Size;424}425 426size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,427                                                      size_t Size,428                                                      size_t MaxSize) {429  if (Size > MaxSize) return 0;430  switch (Rand(4)) {431    case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand);432    case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand);433    case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand);434    case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand);435    default: assert(0);436  }437  return 0;438}439 440size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,441                                            size_t MaxSize) {442  if (Size > MaxSize) return 0;443  if (Size == 0) return 0;444  if (!CrossOverWith) return 0;445  const Unit &O = *CrossOverWith;446  if (O.empty()) return 0;447  size_t NewSize = 0;448  switch(Rand(3)) {449    case 0:450      MutateInPlaceHere.resize(MaxSize);451      NewSize = CrossOver(Data, Size, O.data(), O.size(),452                          MutateInPlaceHere.data(), MaxSize);453      memcpy(Data, MutateInPlaceHere.data(), NewSize);454      break;455    case 1:456      NewSize = InsertPartOf(O.data(), O.size(), Data, Size, MaxSize);457      if (!NewSize)458        NewSize = CopyPartOf(O.data(), O.size(), Data, Size);459      break;460    case 2:461      NewSize = CopyPartOf(O.data(), O.size(), Data, Size);462      break;463    default: assert(0);464  }465  assert(NewSize > 0 && "CrossOver returned empty unit");466  assert(NewSize <= MaxSize && "CrossOver returned oversized unit");467  return NewSize;468}469 470void MutationDispatcher::StartMutationSequence() {471  CurrentMutatorSequence.clear();472  CurrentDictionaryEntrySequence.clear();473}474 475// Copy successful dictionary entries to PersistentAutoDictionary.476void MutationDispatcher::RecordSuccessfulMutationSequence() {477  for (auto DE : CurrentDictionaryEntrySequence) {478    // PersistentAutoDictionary.AddWithSuccessCountOne(DE);479    DE->IncSuccessCount();480    assert(DE->GetW().size());481    // Linear search is fine here as this happens seldom.482    if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))483      PersistentAutoDictionary.push_back(*DE);484  }485}486 487void MutationDispatcher::PrintRecommendedDictionary() {488  std::vector<DictionaryEntry> V;489  for (auto &DE : PersistentAutoDictionary)490    if (!ManualDictionary.ContainsWord(DE.GetW()))491      V.push_back(DE);492  if (V.empty()) return;493  Printf("###### Recommended dictionary. ######\n");494  for (auto &DE: V) {495    assert(DE.GetW().size());496    Printf("\"");497    PrintASCII(DE.GetW(), "\"");498    Printf(" # Uses: %zd\n", DE.GetUseCount());499  }500  Printf("###### End of recommended dictionary. ######\n");501}502 503void MutationDispatcher::PrintMutationSequence(bool Verbose) {504  Printf("MS: %zd ", CurrentMutatorSequence.size());505  size_t EntriesToPrint =506      Verbose ? CurrentMutatorSequence.size()507              : std::min(kMaxMutationsToPrint, CurrentMutatorSequence.size());508  for (size_t i = 0; i < EntriesToPrint; i++)509    Printf("%s-", CurrentMutatorSequence[i].Name);510  if (!CurrentDictionaryEntrySequence.empty()) {511    Printf(" DE: ");512    EntriesToPrint = Verbose ? CurrentDictionaryEntrySequence.size()513                             : std::min(kMaxMutationsToPrint,514                                        CurrentDictionaryEntrySequence.size());515    for (size_t i = 0; i < EntriesToPrint; i++) {516      Printf("\"");517      PrintASCII(CurrentDictionaryEntrySequence[i]->GetW(), "\"-");518    }519  }520}521 522std::string MutationDispatcher::MutationSequence() {523  std::string MS;524  for (const auto &M : CurrentMutatorSequence) {525    MS += M.Name;526    MS += "-";527  }528  return MS;529}530 531size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {532  return MutateImpl(Data, Size, MaxSize, Mutators);533}534 535size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,536                                         size_t MaxSize) {537  return MutateImpl(Data, Size, MaxSize, DefaultMutators);538}539 540// Mutates Data in place, returns new size.541size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,542                                      size_t MaxSize,543                                      std::vector<Mutator> &Mutators) {544  assert(MaxSize > 0);545  // Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),546  // in which case they will return 0.547  // Try several times before returning un-mutated data.548  for (int Iter = 0; Iter < 100; Iter++) {549    auto M = Mutators[Rand(Mutators.size())];550    size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);551    if (NewSize && NewSize <= MaxSize) {552      if (Options.OnlyASCII)553        ToASCII(Data, NewSize);554      CurrentMutatorSequence.push_back(M);555      return NewSize;556    }557  }558  *Data = ' ';559  return 1;   // Fallback, should not happen frequently.560}561 562// Mask represents the set of Data bytes that are worth mutating.563size_t MutationDispatcher::MutateWithMask(uint8_t *Data, size_t Size,564                                          size_t MaxSize,565                                          const std::vector<uint8_t> &Mask) {566  size_t MaskedSize = std::min(Size, Mask.size());567  // * Copy the worthy bytes into a temporary array T568  // * Mutate T569  // * Copy T back.570  // This is totally unoptimized.571  auto &T = MutateWithMaskTemp;572  if (T.size() < Size)573    T.resize(Size);574  size_t OneBits = 0;575  for (size_t I = 0; I < MaskedSize; I++)576    if (Mask[I])577      T[OneBits++] = Data[I];578 579  if (!OneBits) return 0;580  assert(!T.empty());581  size_t NewSize = Mutate(T.data(), OneBits, OneBits);582  assert(NewSize <= OneBits);583  (void)NewSize;584  // Even if NewSize < OneBits we still use all OneBits bytes.585  for (size_t I = 0, J = 0; I < MaskedSize; I++)586    if (Mask[I])587      Data[I] = T[J++];588  return Size;589}590 591void MutationDispatcher::AddWordToManualDictionary(const Word &W) {592  ManualDictionary.push_back(593      {W, std::numeric_limits<size_t>::max()});594}595 596}  // namespace fuzzer597