diff options
| author | Kostya Serebryany <kcc@google.com> | 2017-03-17 01:40:09 +0000 |
|---|---|---|
| committer | Kostya Serebryany <kcc@google.com> | 2017-03-17 01:40:09 +0000 |
| commit | f7e610eda1c3526e8cf4eacd4e1f3f2405fb6d3e (patch) | |
| tree | 3da2bf17933ce9d5c4145b2fc35fa5c05eca1e68 /llvm | |
| parent | a52c8d0dafa436159de225b2d7c82f9b2d6ad650 (diff) | |
| download | bcm5719-llvm-f7e610eda1c3526e8cf4eacd4e1f3f2405fb6d3e.tar.gz bcm5719-llvm-f7e610eda1c3526e8cf4eacd4e1f3f2405fb6d3e.zip | |
[libFuzzer] Experimenting with dictionary minimization.
Summary:
Tracking issue: https://github.com/google/oss-fuzz/issues/331
Reviewers: kcc
Reviewed By: kcc
Differential Revision: https://reviews.llvm.org/D30940
llvm-svn: 298031
Diffstat (limited to 'llvm')
| -rw-r--r-- | llvm/lib/Fuzzer/FuzzerDriver.cpp | 81 | ||||
| -rw-r--r-- | llvm/lib/Fuzzer/FuzzerFlags.def | 1 |
2 files changed, 82 insertions, 0 deletions
diff --git a/llvm/lib/Fuzzer/FuzzerDriver.cpp b/llvm/lib/Fuzzer/FuzzerDriver.cpp index c5de16b1251..1a97a0bf68d 100644 --- a/llvm/lib/Fuzzer/FuzzerDriver.cpp +++ b/llvm/lib/Fuzzer/FuzzerDriver.cpp @@ -355,6 +355,74 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { return 0; } +int AnalyzeDictionary(Fuzzer *F, const std::vector<Unit>& Dict, + UnitVector& Corpus) { + Printf("Started dictionary minimization (up to %d tests)\n", + Dict.size() * Corpus.size() * 2); + + // Scores and usage count for each dictionary unit. + std::vector<int> Scores(Dict.size()); + std::vector<int> Usages(Dict.size()); + + std::vector<size_t> InitialFeatures; + std::vector<size_t> ModifiedFeatures; + for (auto &C : Corpus) { + // Get coverage for the testcase without modifications. + F->ExecuteCallback(C.data(), C.size()); + InitialFeatures.clear(); + TPC.CollectFeatures([&](size_t Feature) -> bool { + InitialFeatures.push_back(Feature); + return true; + }); + + for (size_t i = 0; i < Dict.size(); ++i) { + auto Data = C; + auto StartPos = std::search(Data.begin(), Data.end(), + Dict[i].begin(), Dict[i].end()); + // Skip dictionary unit, if the testcase does not contain it. + if (StartPos == Data.end()) + continue; + + ++Usages[i]; + while (StartPos != Data.end()) { + // Replace all occurrences of dictionary unit in the testcase. + auto EndPos = StartPos + Dict[i].size(); + for (auto It = StartPos; It != EndPos; ++It) + *It ^= 0xFF; + + StartPos = std::search(EndPos, Data.end(), + Dict[i].begin(), Dict[i].end()); + } + + // Get coverage for testcase with masked occurrences of dictionary unit. + F->ExecuteCallback(Data.data(), Data.size()); + ModifiedFeatures.clear(); + TPC.CollectFeatures([&](size_t Feature) -> bool { + ModifiedFeatures.push_back(Feature); + return true; + }); + + if (InitialFeatures == ModifiedFeatures) + --Scores[i]; + else + Scores[i] += 2; + } + } + + Printf("###### Useless dictionary elements. ######\n"); + for (size_t i = 0; i < Dict.size(); ++i) { + // Dictionary units with positive score are treated as useful ones. + if (Scores[i] > 0) + continue; + + Printf("\""); + PrintASCII(Dict[i].data(), Dict[i].size(), "\""); + Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]); + } + Printf("###### End of useless dictionary elements. ######\n"); + return 0; +} + int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { using namespace fuzzer; assert(argc && argv && "Argument pointers cannot be nullptr"); @@ -546,6 +614,19 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { TemporaryMaxLen, /*ExitOnError=*/false); } + if (Flags.analyze_dict) { + if (Dictionary.empty() || Inputs->empty()) { + Printf("ERROR: can't analyze dict without dict and corpus provided\n"); + return 1; + } + if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) { + Printf("Dictionary analysis failed\n"); + exit(1); + } + Printf("Dictionary analysis suceeded\n"); + exit(0); + } + if (Options.MaxLen == 0) { size_t MaxLen = 0; for (auto &U : InitialCorpus) diff --git a/llvm/lib/Fuzzer/FuzzerFlags.def b/llvm/lib/Fuzzer/FuzzerFlags.def index 7b8d38bb6da..4428344321f 100644 --- a/llvm/lib/Fuzzer/FuzzerFlags.def +++ b/llvm/lib/Fuzzer/FuzzerFlags.def @@ -108,6 +108,7 @@ FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum" FUZZER_FLAG_STRING(run_equivalence_server, "Experimental") FUZZER_FLAG_STRING(use_equivalence_server, "Experimental") +FUZZER_FLAG_INT(analyze_dict, 0, "Experimental") FUZZER_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) |

