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