summaryrefslogtreecommitdiff
path: root/lib/Fuzzer/FuzzerMutate.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Fuzzer/FuzzerMutate.cpp')
-rw-r--r--lib/Fuzzer/FuzzerMutate.cpp242
1 files changed, 145 insertions, 97 deletions
diff --git a/lib/Fuzzer/FuzzerMutate.cpp b/lib/Fuzzer/FuzzerMutate.cpp
index 30e5b43c08390..65e1650bfeab6 100644
--- a/lib/Fuzzer/FuzzerMutate.cpp
+++ b/lib/Fuzzer/FuzzerMutate.cpp
@@ -13,49 +13,43 @@
#include "FuzzerInternal.h"
-#include <algorithm>
namespace fuzzer {
-struct Mutator {
- size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
- const char *Name;
-};
-
-struct DictionaryEntry {
- Unit Word;
- size_t PositionHint;
-};
-
-struct MutationDispatcher::Impl {
- std::vector<DictionaryEntry> ManualDictionary;
- std::vector<DictionaryEntry> AutoDictionary;
- std::vector<Mutator> Mutators;
- std::vector<Mutator> CurrentMutatorSequence;
- std::vector<DictionaryEntry> CurrentDictionaryEntrySequence;
- const std::vector<Unit> *Corpus = nullptr;
- FuzzerRandomBase &Rand;
-
- void Add(Mutator M) { Mutators.push_back(M); }
- Impl(FuzzerRandomBase &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_AddWordFromAutoDictionary,
- "AddFromAutoDict"});
- }
- void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; }
- size_t AddWordFromDictionary(const std::vector<DictionaryEntry> &D,
- uint8_t *Data, size_t Size, size_t MaxSize);
-};
+const size_t Dictionary::kMaxDictSize;
+
+MutationDispatcher::MutationDispatcher(Random &Rand,
+ const FuzzingOptions &Options)
+ : Rand(Rand), Options(Options) {
+ 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"},
+ });
-static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
+ if (EF->LLVMFuzzerCustomMutator)
+ Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
+ else
+ Mutators = DefaultMutators;
+
+ if (EF->LLVMFuzzerCustomCrossOver)
+ Mutators.push_back(
+ {&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
+}
+
+static char FlipRandomBit(char X, Random &Rand) {
int Bit = Rand(8);
char Mask = 1 << Bit;
char R;
@@ -67,12 +61,36 @@ static char FlipRandomBit(char X, FuzzerRandomBase &Rand) {
return R;
}
-static char RandCh(FuzzerRandomBase &Rand) {
+static char RandCh(Random &Rand) {
if (Rand.RandBool()) return Rand(256);
const char *Special = "!*'();:@&=+$,/?%#[]123ABCxyz-`~.";
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_CustomCrossOver(uint8_t *Data, size_t Size,
+ size_t MaxSize) {
+ if (!Corpus || Corpus->size() < 2 || Size == 0)
+ return 0;
+ size_t Idx = Rand(Corpus->size());
+ const Unit &Other = (*Corpus)[Idx];
+ if (Other.empty())
+ return 0;
+ MutateInPlaceHere.resize(MaxSize);
+ auto &U = MutateInPlaceHere;
+ size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
+ Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand());
+ if (!NewSize)
+ return 0;
+ assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
+ memcpy(Data, U.data(), NewSize);
+ return NewSize;
+}
+
size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
size_t MaxSize) {
assert(Size);
@@ -122,38 +140,39 @@ 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 AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
}
-size_t MutationDispatcher::Mutate_AddWordFromAutoDictionary(uint8_t *Data,
- size_t Size,
- size_t MaxSize) {
- return MDImpl->AddWordFromDictionary(MDImpl->AutoDictionary, Data, Size,
- MaxSize);
+size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
}
-size_t MutationDispatcher::Impl::AddWordFromDictionary(
- const std::vector<DictionaryEntry> &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;
- const DictionaryEntry &DE = D[Rand(D.size())];
- const Unit &Word = DE.Word;
- size_t PositionHint = DE.PositionHint;
- bool UsePositionHint = PositionHint != std::numeric_limits<size_t>::max() &&
- PositionHint + Word.size() < Size && Rand.RandBool();
- if (Rand.RandBool()) { // Insert Word.
- if (Size + Word.size() > MaxSize) return 0;
- size_t Idx = UsePositionHint ? PositionHint : Rand(Size + 1);
- memmove(Data + Idx + Word.size(), Data + Idx, Size - Idx);
- memcpy(Data + Idx, Word.data(), Word.size());
- Size += Word.size();
- } else { // Overwrite some bytes with Word.
- if (Word.size() > Size) return 0;
- size_t Idx = UsePositionHint ? PositionHint : Rand(Size - Word.size());
- memcpy(Data + Idx, Word.data(), Word.size());
+ DictionaryEntry &DE = D[Rand(D.size())];
+ const Word &W = DE.GetW();
+ bool UsePositionHint = DE.HasPositionHint() &&
+ DE.GetPositionHint() + W.size() < Size && Rand.RandBool();
+ if (Rand.RandBool()) { // Insert W.
+ if (Size + W.size() > MaxSize) return 0;
+ size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
+ memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
+ memcpy(Data + Idx, W.data(), W.size());
+ Size += W.size();
+ } else { // Overwrite some bytes with W.
+ if (W.size() > Size) return 0;
+ size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
+ memcpy(Data + Idx, W.data(), W.size());
}
- CurrentDictionaryEntrySequence.push_back(DE);
+ DE.IncUseCount();
+ CurrentDictionaryEntrySequence.push_back(&DE);
return Size;
}
@@ -192,12 +211,12 @@ 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];
if (Other.empty()) return 0;
- Unit U(MaxSize);
+ MutateInPlaceHere.resize(MaxSize);
+ auto &U = MutateInPlaceHere;
size_t NewSize =
CrossOver(Data, Size, Other.data(), Other.size(), U.data(), U.size());
assert(NewSize > 0 && "CrossOver returned empty unit");
@@ -207,30 +226,69 @@ 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 : CurrentDictionaryEntrySequence) {
+ // PersistentAutoDictionary.AddWithSuccessCountOne(DE);
+ DE->IncSuccessCount();
+ // Linear search is fine here as this happens seldom.
+ if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
+ PersistentAutoDictionary.push_back({DE->GetW(), 1});
+ }
+}
+
+void MutationDispatcher::PrintRecommendedDictionary() {
+ std::vector<DictionaryEntry> V;
+ for (auto &DE : PersistentAutoDictionary)
+ if (!ManualDictionary.ContainsWord(DE.GetW()))
+ V.push_back(DE);
+ if (V.empty()) return;
+ Printf("###### Recommended dictionary. ######\n");
+ for (auto &DE: V) {
+ Printf("\"");
+ PrintASCII(DE.GetW(), "\"");
+ Printf(" # Uses: %zd\n", DE.GetUseCount());
+ }
+ Printf("###### End of recommended dictionary. ######\n");
}
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.Word, "\"-");
+ PrintASCII(DE->GetW(), "\"-");
}
}
}
-// 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<Mutator> &Mutators) {
assert(MaxSize > 0);
assert(Size <= MaxSize);
if (Size == 0) {
for (size_t i = 0; i < MaxSize; i++)
Data[i] = RandCh(Rand);
+ if (Options.OnlyASCII)
+ ToASCII(Data, MaxSize);
return MaxSize;
}
assert(Size > 0);
@@ -238,41 +296,31 @@ 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];
+ auto M = Mutators[Rand(Mutators.size())];
size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
if (NewSize) {
- MDImpl->CurrentMutatorSequence.push_back(M);
+ if (Options.OnlyASCII)
+ ToASCII(Data, NewSize);
+ CurrentMutatorSequence.push_back(M);
return NewSize;
}
}
return Size;
}
-void MutationDispatcher::SetCorpus(const std::vector<Unit> *Corpus) {
- MDImpl->SetCorpus(Corpus);
-}
-
-void MutationDispatcher::AddWordToManualDictionary(const Unit &Word) {
- MDImpl->ManualDictionary.push_back(
- {Word, std::numeric_limits<size_t>::max()});
+void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
+ ManualDictionary.push_back(
+ {W, std::numeric_limits<size_t>::max()});
}
-void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word,
- size_t PositionHint) {
+void MutationDispatcher::AddWordToAutoDictionary(DictionaryEntry DE) {
static const size_t kMaxAutoDictSize = 1 << 14;
- if (MDImpl->AutoDictionary.size() >= kMaxAutoDictSize) return;
- MDImpl->AutoDictionary.push_back({Word, PositionHint});
+ if (TempAutoDictionary.size() >= kMaxAutoDictSize) return;
+ TempAutoDictionary.push_back(DE);
}
void MutationDispatcher::ClearAutoDictionary() {
- MDImpl->AutoDictionary.clear();
-}
-
-MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
- MDImpl = new Impl(Rand);
+ TempAutoDictionary.clear();
}
-MutationDispatcher::~MutationDispatcher() { delete MDImpl; }
-
} // namespace fuzzer