Index: lib/Fuzzer/FuzzerInternal.h =================================================================== --- lib/Fuzzer/FuzzerInternal.h +++ lib/Fuzzer/FuzzerInternal.h @@ -205,7 +205,7 @@ class MutationDispatcher { public: - MutationDispatcher(Random &Rand) : Rand(Rand) {} + MutationDispatcher(Random &Rand); ~MutationDispatcher() {} /// Indicate that we are about to start a new sequence of mutations. void StartMutationSequence(); @@ -213,6 +213,8 @@ void PrintMutationSequence(); /// Indicate that the current sequence of mutations was successfull. void RecordSuccessfulMutationSequence(); + /// Mutates data by invoking user-provided mutator. + size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by shuffling bytes. size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize); /// Mutates data by erasing a byte. @@ -242,9 +244,12 @@ /// CrossOver Data with some other element of the corpus. size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize); - /// Applies one of the above mutations. + /// Applies one of the configured mutations. /// Returns the new size of data which could be up to MaxSize. size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize); + /// Applies one of the default mutations. Provided as a service + /// to mutation authors. + size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize); /// Creates a cross-over of two pieces of Data, returns its size. size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2, @@ -269,6 +274,11 @@ size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, size_t MaxSize); + size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize, + const std::vector &Mutators); + + // Interface to functions that may or may not be available. + const ExternalFunctions EF; Random &Rand; // Dictionary provided by the user via -dict=DICT_FILE. @@ -284,7 +294,8 @@ const std::vector *Corpus = nullptr; std::vector MutateInPlaceHere; - static Mutator Mutators[]; + std::vector Mutators; + std::vector DefaultMutators; }; class Fuzzer { @@ -471,7 +482,7 @@ static thread_local bool IsMyThread; // Interface to functions that may or may not be available. - ExternalFunctions EF; + const ExternalFunctions EF; }; }; // namespace fuzzer Index: lib/Fuzzer/FuzzerLoop.cpp =================================================================== --- lib/Fuzzer/FuzzerLoop.cpp +++ lib/Fuzzer/FuzzerLoop.cpp @@ -692,11 +692,7 @@ for (int i = 0; i < Options.MutateDepth; i++) { size_t NewSize = 0; - if (EF.LLVMFuzzerCustomMutator) - NewSize = EF.LLVMFuzzerCustomMutator(CurrentUnitData, Size, - Options.MaxLen, MD.GetRand().Rand()); - else - NewSize = MD.Mutate(CurrentUnitData, Size, Options.MaxLen); + NewSize = MD.Mutate(CurrentUnitData, Size, Options.MaxLen); assert(NewSize > 0 && "Mutator returned empty unit"); assert(NewSize <= Options.MaxLen && "Mutator return overisized unit"); @@ -816,6 +812,6 @@ size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { assert(fuzzer::F); - return fuzzer::F->GetMD().Mutate(Data, Size, MaxSize); + return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); } } // extern "C" Index: lib/Fuzzer/FuzzerMutate.cpp =================================================================== --- lib/Fuzzer/FuzzerMutate.cpp +++ lib/Fuzzer/FuzzerMutate.cpp @@ -18,21 +18,30 @@ const size_t Dictionary::kMaxDictSize; -MutationDispatcher::Mutator MutationDispatcher::Mutators[] = { - {&MutationDispatcher::Mutate_EraseByte, "EraseByte"}, - {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, - {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, - {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, - {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, - {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, - {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, - {&MutationDispatcher::Mutate_AddWordFromManualDictionary, - "AddFromManualDict"}, - {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, - "AddFromTempAutoDict"}, - {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, - "AddFromPersAutoDict"}, -}; +MutationDispatcher::MutationDispatcher(Random &Rand) : Rand(Rand) { + DefaultMutators.insert( + DefaultMutators.begin(), + { + {&MutationDispatcher::Mutate_EraseByte, "EraseByte"}, + {&MutationDispatcher::Mutate_InsertByte, "InsertByte"}, + {&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}, + {&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}, + {&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}, + {&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}, + {&MutationDispatcher::Mutate_CrossOver, "CrossOver"}, + {&MutationDispatcher::Mutate_AddWordFromManualDictionary, + "AddFromManualDict"}, + {&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, + "AddFromTempAutoDict"}, + {&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, + "AddFromPersAutoDict"}, + }); + + if (EF.LLVMFuzzerCustomMutator) { + Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"}); + } else + Mutators = DefaultMutators; +} static char FlipRandomBit(char X, Random &Rand) { int Bit = Rand(8); @@ -52,6 +61,11 @@ return Special[Rand(sizeof(Special) - 1)]; } +size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size, + size_t MaxSize) { + return EF.LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand()); +} + size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize) { assert(Size); @@ -230,8 +244,19 @@ } } -// Mutates Data in place, returns new size. size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { + return MutateImpl(Data, Size, MaxSize, Mutators); +} + +size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size, + size_t MaxSize) { + return MutateImpl(Data, Size, MaxSize, DefaultMutators); +} + +// Mutates Data in place, returns new size. +size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, + size_t MaxSize, + const std::vector &Mutators) { assert(MaxSize > 0); assert(Size <= MaxSize); if (Size == 0) { @@ -244,9 +269,7 @@ // in which case they will return 0. // Try several times before returning un-mutated data. for (int Iter = 0; Iter < 10; Iter++) { - size_t NumMutators = sizeof(Mutators) / sizeof(Mutators[0]); - size_t MutatorIdx = Rand(NumMutators); - auto M = Mutators[MutatorIdx]; + auto M = Mutators[Rand(Mutators.size())]; size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); if (NewSize) { CurrentMutatorSequence.push_back(M);