diff options
| author | Max Moroz <mmoroz@chromium.org> | 2018-07-16 17:50:46 +0000 |
|---|---|---|
| committer | Max Moroz <mmoroz@chromium.org> | 2018-07-16 17:50:46 +0000 |
| commit | 8a5083df53127a463ff07388c804cc1b108bb278 (patch) | |
| tree | 6f8c35eb50c31cabce30f65b457fcb70a0f9f7cb | |
| parent | 0876a889f78f0d0db0e7921e32be078b4961212f (diff) | |
| download | bcm5719-llvm-8a5083df53127a463ff07388c804cc1b108bb278.tar.gz bcm5719-llvm-8a5083df53127a463ff07388c804cc1b108bb278.zip | |
[libFuzzer] Mutation tracking and logging implemented.
Summary:
Code now exists to track number of mutations that are used in fuzzing in total
and ones that produce new coverage. The stats are currently being dumped to the
command line.
Patch by Kodé Williams (@kodewilliams).
Reviewers: metzman, Dor1s, morehouse, kcc
Reviewed By: Dor1s, morehouse, kcc
Subscribers: delcypher, kubamracek, kcc, morehouse, llvm-commits, #sanitizers, mgorny
Differential Revision: https://reviews.llvm.org/D48054
llvm-svn: 337194
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerDriver.cpp | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerFlags.def | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerLoop.cpp | 2 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerMutate.cpp | 27 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerMutate.h | 9 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerOptions.h | 1 | ||||
| -rw-r--r-- | compiler-rt/test/fuzzer/fuzzer-mutationstats.test | 5 |
7 files changed, 41 insertions, 5 deletions
diff --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp index 9375925b2c9..eb849fcd07f 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp @@ -615,6 +615,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.PrintNewCovPcs = Flags.print_pcs; Options.PrintNewCovFuncs = Flags.print_funcs; Options.PrintFinalStats = Flags.print_final_stats; + Options.PrintMutationStats = Flags.print_mutation_stats; Options.PrintCorpusStats = Flags.print_corpus_stats; Options.PrintCoverage = Flags.print_coverage; Options.PrintUnstableStats = Flags.print_unstable_stats; diff --git a/compiler-rt/lib/fuzzer/FuzzerFlags.def b/compiler-rt/lib/fuzzer/FuzzerFlags.def index e50b82ab70a..dc92758e4b7 100644 --- a/compiler-rt/lib/fuzzer/FuzzerFlags.def +++ b/compiler-rt/lib/fuzzer/FuzzerFlags.def @@ -155,3 +155,4 @@ FUZZER_DEPRECATED_FLAG(use_equivalence_server) FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") FUZZER_DEPRECATED_FLAG(use_clang_coverage) FUZZER_FLAG_STRING(data_flow_trace, "Experimental: use the data flow trace") +FUZZER_FLAG_INT(print_mutation_stats, 0, "Experimental") diff --git a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp index ba61c15f01b..5497c1f61e3 100644 --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp @@ -358,6 +358,8 @@ void Fuzzer::PrintFinalStats() { TPC.DumpCoverage(); if (Options.PrintCorpusStats) Corpus.PrintStats(); + if (Options.PrintMutationStats) + MD.PrintMutationStats(); if (!Options.PrintFinalStats) return; size_t ExecPerSec = execPerSec(); diff --git a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp index 865e598fdc8..e260aa3fe93 100644 --- a/compiler-rt/lib/fuzzer/FuzzerMutate.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerMutate.cpp @@ -465,6 +465,7 @@ void MutationDispatcher::RecordSuccessfulMutationSequence() { if (!PersistentAutoDictionary.ContainsWord(DE->GetW())) PersistentAutoDictionary.push_back({DE->GetW(), 1}); } + RecordUsefulMutations(); } void MutationDispatcher::PrintRecommendedDictionary() { @@ -486,7 +487,7 @@ void MutationDispatcher::PrintRecommendedDictionary() { void MutationDispatcher::PrintMutationSequence() { Printf("MS: %zd ", CurrentMutatorSequence.size()); for (auto M : CurrentMutatorSequence) - Printf("%s-", M.Name); + Printf("%s-", M->Name); if (!CurrentDictionaryEntrySequence.empty()) { Printf(" DE: "); for (auto DE : CurrentDictionaryEntrySequence) { @@ -514,12 +515,13 @@ size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size, // in which case they will return 0. // Try several times before returning un-mutated data. for (int Iter = 0; Iter < 100; Iter++) { - auto M = Mutators[Rand(Mutators.size())]; - size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize); + auto M = &Mutators[Rand(Mutators.size())]; + size_t NewSize = (this->*(M->Fn))(Data, Size, MaxSize); if (NewSize && NewSize <= MaxSize) { if (Options.OnlyASCII) ToASCII(Data, NewSize); CurrentMutatorSequence.push_back(M); + M->TotalCount++; return NewSize; } } @@ -532,4 +534,23 @@ void MutationDispatcher::AddWordToManualDictionary(const Word &W) { {W, std::numeric_limits<size_t>::max()}); } +void MutationDispatcher::RecordUsefulMutations() { + for (auto M : CurrentMutatorSequence) + M->UsefulCount++; +} + +void MutationDispatcher::PrintMutationStats() { + Printf("\nstat::mutation_usefulness: "); + for (size_t i = 0; i < Mutators.size(); i++) { + double UsefulPercentage = + Mutators[i].TotalCount + ? (100.0 * Mutators[i].UsefulCount) / Mutators[i].TotalCount + : 0; + Printf("%.3f", UsefulPercentage); + if (i < Mutators.size() - 1) + Printf(","); + } + Printf("\n"); +} + } // namespace fuzzer diff --git a/compiler-rt/lib/fuzzer/FuzzerMutate.h b/compiler-rt/lib/fuzzer/FuzzerMutate.h index 996d756cd59..c0647ea78d7 100644 --- a/compiler-rt/lib/fuzzer/FuzzerMutate.h +++ b/compiler-rt/lib/fuzzer/FuzzerMutate.h @@ -86,11 +86,16 @@ public: Random &GetRand() { return Rand; } -private: + void PrintMutationStats(); + + void RecordUsefulMutations(); +private: struct Mutator { size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max); const char *Name; + uint64_t UsefulCount; + uint64_t TotalCount; }; size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size, @@ -128,8 +133,8 @@ private: // entries that led to successful discoveries in the past mutations. Dictionary PersistentAutoDictionary; - Vector<Mutator> CurrentMutatorSequence; Vector<DictionaryEntry *> CurrentDictionaryEntrySequence; + Vector<Mutator *> CurrentMutatorSequence; static const size_t kCmpDictionaryEntriesDequeSize = 16; DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize]; diff --git a/compiler-rt/lib/fuzzer/FuzzerOptions.h b/compiler-rt/lib/fuzzer/FuzzerOptions.h index e32b7d59b85..daa9104f5c5 100644 --- a/compiler-rt/lib/fuzzer/FuzzerOptions.h +++ b/compiler-rt/lib/fuzzer/FuzzerOptions.h @@ -52,6 +52,7 @@ struct FuzzingOptions { bool PrintNewCovPcs = false; int PrintNewCovFuncs = 0; bool PrintFinalStats = false; + bool PrintMutationStats = false; bool PrintCorpusStats = false; bool PrintCoverage = false; bool PrintUnstableStats = false; diff --git a/compiler-rt/test/fuzzer/fuzzer-mutationstats.test b/compiler-rt/test/fuzzer/fuzzer-mutationstats.test new file mode 100644 index 00000000000..95743a818d1 --- /dev/null +++ b/compiler-rt/test/fuzzer/fuzzer-mutationstats.test @@ -0,0 +1,5 @@ +RUN: %cpp_compiler %S/SimpleTest.cpp -o %t-MutationStatsTest +RUN: not %run %t-MutationStatsTest -print_mutation_stats=1 2>&1 | FileCheck %s + +# Ensures there are some non-zero values in the usefulness percentages printed. +CHECK: stat::mutation_usefulness: {{[0-9]+\.[0-9]+}} |

