From 2634a37d754c42b29a5da2e4a6130b7047be5752 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Sat, 22 Jul 2017 00:10:29 +0000 Subject: [PATCH] [libFuzzer] reimplement experimental_len_control=1: bump the temporary max_len every time we failed to find new coverage during the last 1000 runs and 1 second. Also fix FileToVector to not load unfinished files llvm-svn: 308811 --- lib/Fuzzer/FuzzerDriver.cpp | 2 -- lib/Fuzzer/FuzzerIO.cpp | 4 +++- lib/Fuzzer/FuzzerInternal.h | 5 +++++ lib/Fuzzer/FuzzerLoop.cpp | 45 +++++++++++++++++++++---------------- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index 36d9422bc28..17891d29c5d 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -564,8 +564,6 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { Options.Verbosity = Flags.verbosity; Options.MaxLen = Flags.max_len; Options.ExperimentalLenControl = Flags.experimental_len_control; - if (Flags.experimental_len_control && Flags.max_len == kMinDefaultLen) - Options.MaxLen = 1 << 20; Options.UnitTimeoutSec = Flags.timeout; Options.ErrorExitCode = Flags.error_exitcode; Options.TimeoutExitCode = Flags.timeout_exitcode; diff --git a/lib/Fuzzer/FuzzerIO.cpp b/lib/Fuzzer/FuzzerIO.cpp index e3f609ed8a8..1a06d4420f9 100644 --- a/lib/Fuzzer/FuzzerIO.cpp +++ b/lib/Fuzzer/FuzzerIO.cpp @@ -38,7 +38,9 @@ Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) { } T.seekg(0, T.end); - size_t FileLen = T.tellg(); + auto EndPos = T.tellg(); + if (EndPos < 0) return {}; + size_t FileLen = EndPos; if (MaxSize) FileLen = std::min(FileLen, MaxSize); diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index 8602818a420..1d68c01908f 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -118,6 +118,10 @@ private: size_t TotalNumberOfRuns = 0; size_t NumberOfNewUnitsAdded = 0; + size_t LastCorpusUpdateRun = 0; + system_clock::time_point LastCorpusUpdateTime = system_clock::now(); + + bool HasMoreMallocsThanFrees = false; size_t NumberOfLeakDetectionAttempts = 0; @@ -133,6 +137,7 @@ private: size_t MaxInputLen = 0; size_t MaxMutationLen = 0; + size_t TmpMaxMutationLen = 0; std::vector UniqFeatureSetTmp; diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index b9e70b6dadd..682e4b7b05d 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -129,6 +129,7 @@ Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); MaxInputLen = MaxMutationLen = Options.MaxLen; + TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize()); AllocateCurrentUnitData(); CurrentUnitSize = 0; memset(BaseSha1, 0, sizeof(BaseSha1)); @@ -511,7 +512,7 @@ void Fuzzer::WriteToOutputCorpus(const Unit &U) { std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); WriteToFile(U, Path); if (Options.Verbosity >= 2) - Printf("Written to %s\n", Path.c_str()); + Printf("Written %zd bytes to %s\n", U.size(), Path.c_str()); } void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { @@ -532,7 +533,7 @@ void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { return; PrintStats(Text, ""); if (Options.Verbosity) { - Printf(" L: %zd ", U.size()); + Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); MD.PrintMutationSequence(); Printf("\n"); } @@ -547,6 +548,8 @@ void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { NumberOfNewUnitsAdded++; TPC.PrintNewPCs(); CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. + LastCorpusUpdateRun = TotalNumberOfRuns; + LastCorpusUpdateTime = system_clock::now(); } // Tries detecting a memory leak on the particular input that we have just @@ -588,19 +591,6 @@ void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, } } -static size_t ComputeMutationLen(size_t MaxInputSize, size_t MaxMutationLen, - Random &Rand) { - assert(MaxInputSize <= MaxMutationLen); - if (MaxInputSize == MaxMutationLen) return MaxMutationLen; - size_t Result = MaxInputSize; - size_t R = Rand.Rand(); - if ((R % (1U << 7)) == 0) - Result++; - if ((R % (1U << 15)) == 0) - Result += 10 + Result / 2; - return Min(Result, MaxMutationLen); -} - void Fuzzer::MutateAndTestOne() { MD.StartMutationSequence(); @@ -615,10 +605,8 @@ void Fuzzer::MutateAndTestOne() { assert(MaxMutationLen > 0); size_t CurrentMaxMutationLen = - Options.ExperimentalLenControl - ? ComputeMutationLen(Corpus.MaxInputSize(), MaxMutationLen, - MD.GetRand()) - : MaxMutationLen; + Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen)); + assert(CurrentMaxMutationLen > 0); for (int i = 0; i < Options.MutateDepth; i++) { if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) @@ -652,6 +640,25 @@ void Fuzzer::Loop() { if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) break; if (TimedOut()) break; + + // Update TmpMaxMutationLen + if (Options.ExperimentalLenControl) { + if (TmpMaxMutationLen < MaxMutationLen && + (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 && + duration_cast(Now - LastCorpusUpdateTime).count() >= 1)) { + LastCorpusUpdateRun = TotalNumberOfRuns; + LastCorpusUpdateTime = Now; + TmpMaxMutationLen = + Min(MaxMutationLen, + TmpMaxMutationLen + Max(size_t(4), TmpMaxMutationLen / 8)); + if (TmpMaxMutationLen <= MaxMutationLen) + Printf("#%zd\tTEMP_MAX_LEN: %zd\n", TotalNumberOfRuns, + TmpMaxMutationLen); + } + } else { + TmpMaxMutationLen = MaxMutationLen; + } + // Perform several mutations and runs. MutateAndTestOne(); }