diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index 5db60598eef..3ac9ea63603 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -12,6 +12,7 @@ #ifndef LLVM_FUZZER_INTERNAL_H #define LLVM_FUZZER_INTERNAL_H +#include #include #include #include @@ -119,10 +120,62 @@ bool ParseOneDictionaryEntry(const std::string &Str, Unit *U); // were parsed succesfully. bool ParseDictionaryFile(const std::string &Text, std::vector *Units); +class DictionaryEntry { + public: + DictionaryEntry() {} + DictionaryEntry(Word W) : W(W) {} + DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} + const Word &GetW() const { return W; } + + bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } + size_t GetPositionHint() const { + assert(HasPositionHint()); + return PositionHint; + } + void IncUseCount() { UseCount++; } + void IncSuccessCount() { SuccessCount++; } + size_t GetUseCount() const { return UseCount; } + size_t GetSuccessCount() const {return SuccessCount; } + +private: + Word W; + size_t PositionHint = std::numeric_limits::max(); + size_t UseCount = 0; + size_t SuccessCount = 0; +}; + +class Dictionary { + public: + static const size_t kMaxDictSize = 1 << 14; + + bool ContainsWord(const Word &W) const { + return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) { + return DE.GetW() == W; + }); + } + const DictionaryEntry *begin() const { return &DE[0]; } + const DictionaryEntry *end() const { return begin() + Size; } + DictionaryEntry & operator[] (size_t Idx) { + assert(Idx < Size); + return DE[Idx]; + } + void push_back(DictionaryEntry DE) { + if (Size < kMaxDictSize) + this->DE[Size++] = DE; + } + void clear() { Size = 0; } + bool empty() const { return Size == 0; } + size_t size() const { return Size; } + +private: + DictionaryEntry DE[kMaxDictSize]; + size_t Size = 0; +}; + class MutationDispatcher { public: MutationDispatcher(Random &Rand); - ~MutationDispatcher(); + ~MutationDispatcher() {} /// Indicate that we are about to start a new sequence of mutations. void StartMutationSequence(); /// Print the current sequence of mutations. @@ -172,14 +225,34 @@ public: void ClearAutoDictionary(); void PrintRecommendedDictionary(); - void SetCorpus(const std::vector *Corpus); + void SetCorpus(const std::vector *Corpus) { this->Corpus = Corpus; } Random &GetRand() { return Rand; } private: + + struct Mutator { + size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); + const char *Name; + }; + + void Add(Mutator M) { Mutators.push_back(M); } + size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, + size_t MaxSize); + Random &Rand; - struct Impl; - Impl *MDImpl; + // Dictionary provided by the user via -dict=DICT_FILE. + Dictionary ManualDictionary; + // Temporary dictionary modified by the fuzzer itself, + // recreated periodically. + Dictionary TempAutoDictionary; + // Persistent dictionary modified by the fuzzer, consists of + // entries that led to successfull discoveries in the past mutations. + Dictionary PersistentAutoDictionary; + std::vector Mutators; + std::vector CurrentMutatorSequence; + std::vector CurrentDictionaryEntrySequence; + const std::vector *Corpus = nullptr; }; class Fuzzer { diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp index d5eece68aac..ff099f17636 100644 --- a/lib/Fuzzer/FuzzerMutate.cpp +++ b/lib/Fuzzer/FuzzerMutate.cpp @@ -13,107 +13,11 @@ #include "FuzzerInternal.h" -#include namespace fuzzer { -struct Mutator { - size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); - const char *Name; -}; - -class DictionaryEntry { - public: - DictionaryEntry() {} - DictionaryEntry(Word W) : W(W) {} - DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {} - const Word &GetW() const { return W; } - - bool HasPositionHint() const { return PositionHint != std::numeric_limits::max(); } - size_t GetPositionHint() const { - assert(HasPositionHint()); - return PositionHint; - } - void IncUseCount() { UseCount++; } - void IncSuccessCount() { SuccessCount++; } - size_t GetUseCount() const { return UseCount; } - size_t GetSuccessCount() const {return SuccessCount; } - -private: - Word W; - size_t PositionHint = std::numeric_limits::max(); - size_t UseCount = 0; - size_t SuccessCount = 0; -}; - -class Dictionary { - public: - static const size_t kMaxDictSize = 1 << 14; - - bool ContainsWord(const Word &W) const { - return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) { - return DE.GetW() == W; - }); - } - const DictionaryEntry *begin() const { return &DE[0]; } - const DictionaryEntry *end() const { return begin() + Size; } - DictionaryEntry & operator[] (size_t Idx) { - assert(Idx < Size); - return DE[Idx]; - } - void push_back(DictionaryEntry DE) { - if (Size < kMaxDictSize) - this->DE[Size++] = DE; - } - void clear() { Size = 0; } - bool empty() const { return Size == 0; } - size_t size() const { return Size; } - -private: - DictionaryEntry DE[kMaxDictSize]; - size_t Size = 0; -}; - const size_t Dictionary::kMaxDictSize; - -struct MutationDispatcher::Impl { - // Dictionary provided by the user via -dict=DICT_FILE. - Dictionary ManualDictionary; - // Temporary dictionary modified by the fuzzer itself, - // recreated periodically. - Dictionary TempAutoDictionary; - // Persistent dictionary modified by the fuzzer, consists of - // entries that led to successfull discoveries in the past mutations. - Dictionary PersistentAutoDictionary; - - std::vector Mutators; - std::vector CurrentMutatorSequence; - std::vector CurrentDictionaryEntrySequence; - const std::vector *Corpus = nullptr; - Random &Rand; - - void Add(Mutator M) { Mutators.push_back(M); } - Impl(Random &Rand) : Rand(Rand) { - Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"}); - Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"}); - Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}); - Add({&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}); - Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}); - Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}); - Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"}); - Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary, - "AddFromManualDict"}); - Add({&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, - "AddFromTempAutoDict"}); - Add({&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, - "AddFromPersAutoDict"}); - } - void SetCorpus(const std::vector *Corpus) { this->Corpus = Corpus; } - size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, - size_t MaxSize); -}; - size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed) { Random R(Seed); MutationDispatcher MD(R); @@ -187,26 +91,21 @@ size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size, size_t MaxSize) { - return MDImpl->AddWordFromDictionary(MDImpl->ManualDictionary, Data, Size, - MaxSize); + return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize); } size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary( uint8_t *Data, size_t Size, size_t MaxSize) { - return MDImpl->AddWordFromDictionary(MDImpl->TempAutoDictionary, Data, Size, - MaxSize); + return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize); } size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary( uint8_t *Data, size_t Size, size_t MaxSize) { - return MDImpl->AddWordFromDictionary(MDImpl->PersistentAutoDictionary, Data, Size, - MaxSize); + return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize); } -size_t MutationDispatcher::Impl::AddWordFromDictionary(Dictionary &D, - uint8_t *Data, - size_t Size, - size_t MaxSize) { +size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data, + size_t Size, size_t MaxSize) { if (D.empty()) return 0; DictionaryEntry &DE = D[Rand(D.size())]; const Word &W = DE.GetW(); @@ -263,7 +162,6 @@ size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize) { - auto Corpus = MDImpl->Corpus; if (!Corpus || Corpus->size() < 2 || Size == 0) return 0; size_t Idx = Rand(Corpus->size()); const Unit &Other = (*Corpus)[Idx]; @@ -278,25 +176,25 @@ size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size, } void MutationDispatcher::StartMutationSequence() { - MDImpl->CurrentMutatorSequence.clear(); - MDImpl->CurrentDictionaryEntrySequence.clear(); + CurrentMutatorSequence.clear(); + CurrentDictionaryEntrySequence.clear(); } // Copy successful dictionary entries to PersistentAutoDictionary. void MutationDispatcher::RecordSuccessfulMutationSequence() { - for (auto DE : MDImpl->CurrentDictionaryEntrySequence) { - // MDImpl->PersistentAutoDictionary.AddWithSuccessCountOne(DE); + for (auto DE : CurrentDictionaryEntrySequence) { + // PersistentAutoDictionary.AddWithSuccessCountOne(DE); DE->IncSuccessCount(); // Linear search is fine here as this happens seldom. - if (!MDImpl->PersistentAutoDictionary.ContainsWord(DE->GetW())) - MDImpl->PersistentAutoDictionary.push_back({DE->GetW(), 1}); + if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) + PersistentAutoDictionary.push_back({DE->GetW(), 1}); } } void MutationDispatcher::PrintRecommendedDictionary() { std::vector V; - for (auto &DE : MDImpl->PersistentAutoDictionary) - if (!MDImpl->ManualDictionary.ContainsWord(DE.GetW())) + for (auto &DE : PersistentAutoDictionary) + if (!ManualDictionary.ContainsWord(DE.GetW())) V.push_back(DE); if (V.empty()) return; Printf("###### Recommended dictionary. ######\n"); @@ -309,12 +207,12 @@ void MutationDispatcher::PrintRecommendedDictionary() { } void MutationDispatcher::PrintMutationSequence() { - Printf("MS: %zd ", MDImpl->CurrentMutatorSequence.size()); - for (auto M : MDImpl->CurrentMutatorSequence) + Printf("MS: %zd ", CurrentMutatorSequence.size()); + for (auto M : CurrentMutatorSequence) Printf("%s-", M.Name); - if (!MDImpl->CurrentDictionaryEntrySequence.empty()) { + if (!CurrentDictionaryEntrySequence.empty()) { Printf(" DE: "); - for (auto DE : MDImpl->CurrentDictionaryEntrySequence) { + for (auto DE : CurrentDictionaryEntrySequence) { Printf("\""); PrintASCII(DE->GetW(), "\"-"); } @@ -335,41 +233,48 @@ size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) { // in which case they will return 0. // Try several times before returning un-mutated data. for (int Iter = 0; Iter < 10; Iter++) { - size_t MutatorIdx = Rand(MDImpl->Mutators.size()); - auto M = MDImpl->Mutators[MutatorIdx]; + size_t MutatorIdx = Rand(Mutators.size()); + auto M = Mutators[MutatorIdx]; size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); if (NewSize) { - MDImpl->CurrentMutatorSequence.push_back(M); + CurrentMutatorSequence.push_back(M); return NewSize; } } return Size; } -void MutationDispatcher::SetCorpus(const std::vector *Corpus) { - MDImpl->SetCorpus(Corpus); -} - void MutationDispatcher::AddWordToManualDictionary(const Word &W) { - MDImpl->ManualDictionary.push_back( + ManualDictionary.push_back( {W, std::numeric_limits::max()}); } void MutationDispatcher::AddWordToAutoDictionary(const Word &W, size_t PositionHint) { static const size_t kMaxAutoDictSize = 1 << 14; - if (MDImpl->TempAutoDictionary.size() >= kMaxAutoDictSize) return; - MDImpl->TempAutoDictionary.push_back({W, PositionHint}); + if (TempAutoDictionary.size() >= kMaxAutoDictSize) return; + TempAutoDictionary.push_back({W, PositionHint}); } void MutationDispatcher::ClearAutoDictionary() { - MDImpl->TempAutoDictionary.clear(); + TempAutoDictionary.clear(); } MutationDispatcher::MutationDispatcher(Random &Rand) : Rand(Rand) { - MDImpl = new Impl(Rand); + Add({&MutationDispatcher::Mutate_EraseByte, "EraseByte"}); + Add({&MutationDispatcher::Mutate_InsertByte, "InsertByte"}); + Add({&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"}); + Add({&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"}); + Add({&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"}); + Add({&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"}); + Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"}); + Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary, + "AddFromManualDict"}); + Add({&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, + "AddFromTempAutoDict"}); + Add({&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary, + "AddFromPersAutoDict"}); } -MutationDispatcher::~MutationDispatcher() { delete MDImpl; } } // namespace fuzzer