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