Index: lib/Fuzzer/FuzzerDriver.cpp =================================================================== --- lib/Fuzzer/FuzzerDriver.cpp +++ lib/Fuzzer/FuzzerDriver.cpp @@ -330,6 +330,7 @@ Options.SaveArtifacts = !DoPlainRun; Options.PrintNewCovPcs = Flags.print_new_cov_pcs; Options.PrintFinalStats = Flags.print_final_stats; + Options.TruncateUnits = Flags.truncate_units; unsigned Seed = Flags.seed; // Initialize Seed. Index: lib/Fuzzer/FuzzerFlags.def =================================================================== --- lib/Fuzzer/FuzzerFlags.def +++ lib/Fuzzer/FuzzerFlags.def @@ -84,6 +84,7 @@ "try to detect memory leaks during fuzzing (i.e. not only at shut down).") FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon" "reaching this limit of RSS memory usage.") +FUZZER_FLAG_INT(truncate_units, 1, "Try truncated units when loading corpus.") FUZZER_DEPRECATED_FLAG(exit_on_first) FUZZER_DEPRECATED_FLAG(save_minimized_corpus) Index: lib/Fuzzer/FuzzerInternal.h =================================================================== --- lib/Fuzzer/FuzzerInternal.h +++ lib/Fuzzer/FuzzerInternal.h @@ -306,6 +306,7 @@ bool PrintNewCovPcs = false; bool PrintFinalStats = false; bool DetectLeaks = true; + bool TruncateUnits = true; }; // Aggregates all available coverage measurements. @@ -343,6 +344,7 @@ } size_t ChooseUnitIdxToMutate(); const Unit &ChooseUnitToMutate() { return Corpus[ChooseUnitIdxToMutate()]; }; + void TruncateUnits(std::vector *NewCorpus); void Loop(); void Drill(); void ShuffleAndMinimize(); Index: lib/Fuzzer/FuzzerLoop.cpp =================================================================== --- lib/Fuzzer/FuzzerLoop.cpp +++ lib/Fuzzer/FuzzerLoop.cpp @@ -59,6 +59,7 @@ namespace fuzzer { static const size_t kMaxUnitSizeToPrint = 256; +static const size_t TruncatePoints = 100; static void MissingWeakApiFunction(const char *FnName) { Printf("ERROR: %s is not defined. Exiting.\n" @@ -353,12 +354,51 @@ }); } +// Tries random prefixes of corpus items. +// Prefix length is chosen according to exponential distribution +// to sample short lengths much more heavily. +void Fuzzer::TruncateUnits(std::vector *NewCorpus) { + size_t MaxCorpusLen = 0; + for (const auto &U : Corpus) { + MaxCorpusLen = std::max(MaxCorpusLen, U.size()); + } + + if (MaxCorpusLen <= 1) + return; + + // 50% of exponential distribution is Log[2]/lambda. + // Choose lambda so that median is MaxCorpusLen / 2. + double Lambda = 2.0 * log(2.0) / static_cast(MaxCorpusLen); + std::exponential_distribution<> Dist(Lambda); + std::vector Sizes; + Sizes.reserve(TruncatePoints); + for (size_t I = 0; I < TruncatePoints; ++I) { + Sizes.push_back(Dist(MD.GetRand().Get_mt19937())); + } + std::sort(Sizes.begin(), Sizes.end()); + + for (size_t S : Sizes) { + for (const auto &U : Corpus) { + if (S <= U.size() && RunOne(U.data(), S)) { + Unit U1(U.begin(), U.begin() + S); + NewCorpus->push_back(U1); + WriteToOutputCorpus(U1); + PrintStatusForNewUnit(U1); + } + } + } + PrintStats("TRUNC "); +} + void Fuzzer::ShuffleAndMinimize() { PrintStats("READ "); std::vector NewCorpus; if (Options.ShuffleAtStartUp) ShuffleCorpus(&Corpus); + if (Options.TruncateUnits) + TruncateUnits(&NewCorpus); + for (const auto &U : Corpus) { if (RunOne(U)) { NewCorpus.push_back(U);