void StartMutationSequence();
/// Print the current sequence of mutations.
void PrintMutationSequence();
+ /// Indicate that the current sequence of mutations was successfull.
+ void RecordSuccessfulMutationSequence();
/// Mutates data by shuffling bytes.
size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
/// Mutates data by erasing a byte.
size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
size_t MaxSize);
- /// Mutates data by adding a word from the automatic dictionary.
- size_t Mutate_AddWordFromAutoDictionary(uint8_t *Data, size_t Size,
- size_t MaxSize);
+ /// Mutates data by adding a word from the temporary automatic dictionary.
+ size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
+
+ /// Mutates data by adding a word from the persistent automatic dictionary.
+ size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
+ size_t MaxSize);
/// Tries to find an ASCII integer in Data, changes it to another ASCII int.
size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
void AddWordToAutoDictionary(const Unit &Word, size_t PositionHint);
void ClearAutoDictionary();
+ void PrintRecommendedDictionary();
void SetCorpus(const std::vector<Unit> *Corpus);
UserSuppliedFuzzer(FuzzerRandomBase *Rand);
/// Executes the target function on 'Size' bytes of 'Data'.
virtual int TargetFunction(const uint8_t *Data, size_t Size) = 0;
- virtual void StartMutationSequence() { MD.StartMutationSequence(); }
- virtual void PrintMutationSequence() { MD.PrintMutationSequence(); }
virtual void SetCorpus(const std::vector<Unit> *Corpus) {
MD.SetCorpus(Corpus);
}
PrintStats("NEW ", "");
if (Options.Verbosity) {
Printf(" L: %zd ", U.size());
- USF.PrintMutationSequence();
+ USF.GetMD().PrintMutationSequence();
Printf("\n");
}
}
void Fuzzer::ReportNewCoverage(const Unit &U) {
Corpus.push_back(U);
UnitHashesAddedToCorpus.insert(Hash(U));
+ USF.GetMD().RecordSuccessfulMutationSequence();
PrintStatusForNewUnit(U);
WriteToOutputCorpus(U);
if (Options.ExitOnFirst)
}
void Fuzzer::MutateAndTestOne() {
- USF.StartMutationSequence();
+ USF.GetMD().StartMutationSequence();
auto U = ChooseUnitToMutate();
}
PrintStats("DONE ", "\n");
+ USF.GetMD().PrintRecommendedDictionary();
}
void Fuzzer::SyncCorpus() {
size_t PositionHint;
};
+struct Dictionary : public std::vector<DictionaryEntry>{
+ bool ContainsWord(const Unit &W) const {
+ return end() !=
+ std::find_if(begin(), end(), [&](const DictionaryEntry &DE) {
+ return DE.Word == W;
+ });
+ }
+};
+
struct MutationDispatcher::Impl {
- std::vector<DictionaryEntry> ManualDictionary;
- std::vector<DictionaryEntry> AutoDictionary;
+ // 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<Mutator> Mutators;
std::vector<Mutator> CurrentMutatorSequence;
- std::vector<DictionaryEntry> CurrentDictionaryEntrySequence;
+ Dictionary CurrentDictionaryEntrySequence;
const std::vector<Unit> *Corpus = nullptr;
FuzzerRandomBase &Rand;
Add({&MutationDispatcher::Mutate_CrossOver, "CrossOver"});
Add({&MutationDispatcher::Mutate_AddWordFromManualDictionary,
"AddFromManualDict"});
- Add({&MutationDispatcher::Mutate_AddWordFromAutoDictionary,
- "AddFromAutoDict"});
+ Add({&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
+ "AddFromTempAutoDict"});
+ Add({&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
+ "AddFromPersAutoDict"});
}
void SetCorpus(const std::vector<Unit> *Corpus) { this->Corpus = Corpus; }
size_t AddWordFromDictionary(const std::vector<DictionaryEntry> &D,
MaxSize);
}
-size_t MutationDispatcher::Mutate_AddWordFromAutoDictionary(uint8_t *Data,
- size_t Size,
- size_t MaxSize) {
- return MDImpl->AddWordFromDictionary(MDImpl->AutoDictionary, Data, Size,
+size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary(
+ uint8_t *Data, size_t Size, size_t MaxSize) {
+ return MDImpl->AddWordFromDictionary(MDImpl->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);
}
MDImpl->CurrentDictionaryEntrySequence.clear();
}
+// Copy successful dictionary entries to PersistentAutoDictionary.
+void MutationDispatcher::RecordSuccessfulMutationSequence() {
+ for (auto &DE : MDImpl->CurrentDictionaryEntrySequence)
+ // Linear search is fine here as this happens seldom.
+ if (!MDImpl->PersistentAutoDictionary.ContainsWord(DE.Word))
+ MDImpl->PersistentAutoDictionary.push_back(
+ {DE.Word, std::numeric_limits<size_t>::max()});
+}
+
+void MutationDispatcher::PrintRecommendedDictionary() {
+ std::vector<Unit> V;
+ for (auto &DE : MDImpl->PersistentAutoDictionary)
+ if (!MDImpl->ManualDictionary.ContainsWord(DE.Word))
+ V.push_back(DE.Word);
+ if (V.empty()) return;
+ Printf("###### Recommended dictionary. ######\n");
+ for (auto &U: V) {
+ Printf("\"");
+ PrintASCII(U, "\"\n");
+ }
+ Printf("###### End of recommended dictionary. ######\n");
+}
+
void MutationDispatcher::PrintMutationSequence() {
Printf("MS: %zd ", MDImpl->CurrentMutatorSequence.size());
for (auto M : MDImpl->CurrentMutatorSequence)
Printf("%s-", M.Name);
if (!MDImpl->CurrentDictionaryEntrySequence.empty()) {
Printf(" DE: ");
- for (auto DE : MDImpl->CurrentDictionaryEntrySequence) {
+ for (auto &DE : MDImpl->CurrentDictionaryEntrySequence) {
Printf("\"");
PrintASCII(DE.Word, "\"-");
}
void MutationDispatcher::AddWordToAutoDictionary(const Unit &Word,
size_t PositionHint) {
static const size_t kMaxAutoDictSize = 1 << 14;
- if (MDImpl->AutoDictionary.size() >= kMaxAutoDictSize) return;
- MDImpl->AutoDictionary.push_back({Word, PositionHint});
+ if (MDImpl->TempAutoDictionary.size() >= kMaxAutoDictSize) return;
+ MDImpl->TempAutoDictionary.push_back({Word, PositionHint});
}
void MutationDispatcher::ClearAutoDictionary() {
- MDImpl->AutoDictionary.clear();
+ MDImpl->TempAutoDictionary.clear();
}
MutationDispatcher::MutationDispatcher(FuzzerRandomBase &Rand) : Rand(Rand) {
FullCoverageSetTest
MemcmpTest
NullDerefTest
+ RepeatedMemcmp
SimpleCmpTest
SimpleDictionaryTest
SimpleHashTest
TEST(FuzzerMutate, AddWordFromDictionaryWithHint1) {
TestAddWordFromDictionaryWithHint(
- &MutationDispatcher::Mutate_AddWordFromAutoDictionary, 1 << 5);
+ &MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary, 1 << 5);
}
TEST(FuzzerMutate, AddWordFromDictionaryWithHint2) {
if (Size >= 8 && memcmp(Data, "01234567", 8) == 0) {
if (Size >= 12 && memcmp(Data + 8, "ABCD", 4) == 0) {
if (Size >= 14 && memcmp(Data + 12, "XY", 2) == 0) {
- if (Size >= 16 && memcmp(Data + 14, "KLM", 3) == 0) {
+ if (Size >= 17 && memcmp(Data + 14, "KLM", 3) == 0) {
if (Size >= 27 && memcmp(Data + 17, "ABCDE-GHIJ", 10) == 0){
fprintf(stderr, "BINGO %zd\n", Size);
for (size_t i = 0; i < Size; i++) {
--- /dev/null
+
+#include <cstring>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+ int Matches = 0;
+ for (size_t i = 0; i + 2 < Size; i += 3) {
+ const char *Pat = i % 2 ? "foo" : "bar";
+ if (!memcmp(Data + i, Pat, 3))
+ Matches++;
+ }
+ if (Matches > 20) {
+ fprintf(stderr, "BINGO!\n");
+ exit(1);
+ }
+ return 0;
+}
RUN: not LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=1000000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK1
RUN: LLVMFuzzer-SimpleCmpTest-DFSan -use_traces=1 -seed=1 -runs=100 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanCmpCallback
-RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK2
+RUN: not LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=100000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK2
RUN: LLVMFuzzer-MemcmpTest-DFSan -use_traces=1 -seed=1 -runs=2 -timeout=5 -verbosity=3 2>&1 | FileCheck %s -check-prefix=CHECK_DFSanMemcmpCallback
RUN: not LLVMFuzzer-StrncmpTest-DFSan -use_traces=1 -seed=1 -runs=10000 -timeout=5 2>&1 | FileCheck %s --check-prefix=CHECK3
RUN: not LLVMFuzzer-SimpleHashTest -use_traces=1 -seed=1 -runs=10000000 2>&1 | FileCheck %s
RUN: LLVMFuzzer-SimpleHashTest -seed=1 -runs=10000000 2>&1 | FileCheck %s --check-prefix=Done10000000
+
+RUN: LLVMFuzzer-RepeatedMemcmp -use_traces=1 -seed=1 -runs=100000 2>&1 | FileCheck %s --check-prefix=RECOMMENDED_DICT
+RECOMMENDED_DICT:###### Recommended dictionary. ######
+RECOMMENDED_DICT-DAG: "foo"
+RECOMMENDED_DICT-DAG: "bar"
+RECOMMENDED_DICT:###### End of recommended dictionary. ######
+