110ab2aceSGeorge Karpenkov //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // Fuzzer's main loop.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1010ab2aceSGeorge Karpenkov 
1110ab2aceSGeorge Karpenkov #include "FuzzerCorpus.h"
1210ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1310ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
1410ab2aceSGeorge Karpenkov #include "FuzzerMutate.h"
15750369e2SDokyung Song #include "FuzzerPlatform.h"
1610ab2aceSGeorge Karpenkov #include "FuzzerRandom.h"
1710ab2aceSGeorge Karpenkov #include "FuzzerTracePC.h"
1810ab2aceSGeorge Karpenkov #include <algorithm>
1910ab2aceSGeorge Karpenkov #include <cstring>
2010ab2aceSGeorge Karpenkov #include <memory>
217dbc1d84SVitaly Buka #include <mutex>
2210ab2aceSGeorge Karpenkov #include <set>
2310ab2aceSGeorge Karpenkov 
2410ab2aceSGeorge Karpenkov #if defined(__has_include)
2510ab2aceSGeorge Karpenkov #if __has_include(<sanitizer / lsan_interface.h>)
2610ab2aceSGeorge Karpenkov #include <sanitizer/lsan_interface.h>
2710ab2aceSGeorge Karpenkov #endif
2810ab2aceSGeorge Karpenkov #endif
2910ab2aceSGeorge Karpenkov 
3010ab2aceSGeorge Karpenkov #define NO_SANITIZE_MEMORY
3110ab2aceSGeorge Karpenkov #if defined(__has_feature)
3210ab2aceSGeorge Karpenkov #if __has_feature(memory_sanitizer)
3310ab2aceSGeorge Karpenkov #undef NO_SANITIZE_MEMORY
3410ab2aceSGeorge Karpenkov #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
3510ab2aceSGeorge Karpenkov #endif
3610ab2aceSGeorge Karpenkov #endif
3710ab2aceSGeorge Karpenkov 
3810ab2aceSGeorge Karpenkov namespace fuzzer {
3910ab2aceSGeorge Karpenkov static const size_t kMaxUnitSizeToPrint = 256;
4010ab2aceSGeorge Karpenkov 
4110ab2aceSGeorge Karpenkov thread_local bool Fuzzer::IsMyThread;
4210ab2aceSGeorge Karpenkov 
4343a22969SMatt Morehouse bool RunningUserCallback = false;
4443a22969SMatt Morehouse 
4510ab2aceSGeorge Karpenkov // Only one Fuzzer per process.
4610ab2aceSGeorge Karpenkov static Fuzzer *F;
4710ab2aceSGeorge Karpenkov 
4810ab2aceSGeorge Karpenkov // Leak detection is expensive, so we first check if there were more mallocs
4910ab2aceSGeorge Karpenkov // than frees (using the sanitizer malloc hooks) and only then try to call lsan.
5010ab2aceSGeorge Karpenkov struct MallocFreeTracer {
Startfuzzer::MallocFreeTracer5110ab2aceSGeorge Karpenkov   void Start(int TraceLevel) {
5210ab2aceSGeorge Karpenkov     this->TraceLevel = TraceLevel;
5310ab2aceSGeorge Karpenkov     if (TraceLevel)
5410ab2aceSGeorge Karpenkov       Printf("MallocFreeTracer: START\n");
5510ab2aceSGeorge Karpenkov     Mallocs = 0;
5610ab2aceSGeorge Karpenkov     Frees = 0;
5710ab2aceSGeorge Karpenkov   }
5810ab2aceSGeorge Karpenkov   // Returns true if there were more mallocs than frees.
Stopfuzzer::MallocFreeTracer5910ab2aceSGeorge Karpenkov   bool Stop() {
6010ab2aceSGeorge Karpenkov     if (TraceLevel)
6110ab2aceSGeorge Karpenkov       Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
6210ab2aceSGeorge Karpenkov              Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
6310ab2aceSGeorge Karpenkov     bool Result = Mallocs > Frees;
6410ab2aceSGeorge Karpenkov     Mallocs = 0;
6510ab2aceSGeorge Karpenkov     Frees = 0;
6610ab2aceSGeorge Karpenkov     TraceLevel = 0;
6710ab2aceSGeorge Karpenkov     return Result;
6810ab2aceSGeorge Karpenkov   }
6910ab2aceSGeorge Karpenkov   std::atomic<size_t> Mallocs;
7010ab2aceSGeorge Karpenkov   std::atomic<size_t> Frees;
7110ab2aceSGeorge Karpenkov   int TraceLevel = 0;
727d22324bSVitaly Buka 
737d22324bSVitaly Buka   std::recursive_mutex TraceMutex;
747d22324bSVitaly Buka   bool TraceDisabled = false;
7510ab2aceSGeorge Karpenkov };
7610ab2aceSGeorge Karpenkov 
7710ab2aceSGeorge Karpenkov static MallocFreeTracer AllocTracer;
7810ab2aceSGeorge Karpenkov 
797d22324bSVitaly Buka // Locks printing and avoids nested hooks triggered from mallocs/frees in
807d22324bSVitaly Buka // sanitizer.
817d22324bSVitaly Buka class TraceLock {
827d22324bSVitaly Buka public:
TraceLock()837d22324bSVitaly Buka   TraceLock() : Lock(AllocTracer.TraceMutex) {
847d22324bSVitaly Buka     AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled;
857d22324bSVitaly Buka   }
~TraceLock()867d22324bSVitaly Buka   ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; }
877d22324bSVitaly Buka 
IsDisabled() const887d22324bSVitaly Buka   bool IsDisabled() const {
897d22324bSVitaly Buka     // This is already inverted value.
907d22324bSVitaly Buka     return !AllocTracer.TraceDisabled;
917d22324bSVitaly Buka   }
927d22324bSVitaly Buka 
937d22324bSVitaly Buka private:
947d22324bSVitaly Buka   std::lock_guard<std::recursive_mutex> Lock;
957d22324bSVitaly Buka };
967dbc1d84SVitaly Buka 
9710ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY
MallocHook(const volatile void * ptr,size_t size)9810ab2aceSGeorge Karpenkov void MallocHook(const volatile void *ptr, size_t size) {
9910ab2aceSGeorge Karpenkov   size_t N = AllocTracer.Mallocs++;
10010ab2aceSGeorge Karpenkov   F->HandleMalloc(size);
10110ab2aceSGeorge Karpenkov   if (int TraceLevel = AllocTracer.TraceLevel) {
1027d22324bSVitaly Buka     TraceLock Lock;
1037d22324bSVitaly Buka     if (Lock.IsDisabled())
1047d22324bSVitaly Buka       return;
10510ab2aceSGeorge Karpenkov     Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
10610ab2aceSGeorge Karpenkov     if (TraceLevel >= 2 && EF)
10714cf71a3SMatt Morehouse       PrintStackTrace();
10810ab2aceSGeorge Karpenkov   }
10910ab2aceSGeorge Karpenkov }
11010ab2aceSGeorge Karpenkov 
11110ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY
FreeHook(const volatile void * ptr)11210ab2aceSGeorge Karpenkov void FreeHook(const volatile void *ptr) {
11310ab2aceSGeorge Karpenkov   size_t N = AllocTracer.Frees++;
11410ab2aceSGeorge Karpenkov   if (int TraceLevel = AllocTracer.TraceLevel) {
1157d22324bSVitaly Buka     TraceLock Lock;
1167d22324bSVitaly Buka     if (Lock.IsDisabled())
1177d22324bSVitaly Buka       return;
11810ab2aceSGeorge Karpenkov     Printf("FREE[%zd]   %p\n", N, ptr);
11910ab2aceSGeorge Karpenkov     if (TraceLevel >= 2 && EF)
12014cf71a3SMatt Morehouse       PrintStackTrace();
12110ab2aceSGeorge Karpenkov   }
12210ab2aceSGeorge Karpenkov }
12310ab2aceSGeorge Karpenkov 
12410ab2aceSGeorge Karpenkov // Crash on a single malloc that exceeds the rss limit.
HandleMalloc(size_t Size)12510ab2aceSGeorge Karpenkov void Fuzzer::HandleMalloc(size_t Size) {
126de9bafb1SKostya Serebryany   if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb)
12710ab2aceSGeorge Karpenkov     return;
12810ab2aceSGeorge Karpenkov   Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
12910ab2aceSGeorge Karpenkov          Size);
13010ab2aceSGeorge Karpenkov   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
13114cf71a3SMatt Morehouse   PrintStackTrace();
13210ab2aceSGeorge Karpenkov   DumpCurrentUnit("oom-");
13310ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: out-of-memory\n");
13410ab2aceSGeorge Karpenkov   PrintFinalStats();
1350fda9dcbSKostya Serebryany   _Exit(Options.OOMExitCode); // Stop right now.
13610ab2aceSGeorge Karpenkov }
13710ab2aceSGeorge Karpenkov 
Fuzzer(UserCallback CB,InputCorpus & Corpus,MutationDispatcher & MD,FuzzingOptions Options)13810ab2aceSGeorge Karpenkov Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
13910ab2aceSGeorge Karpenkov                FuzzingOptions Options)
14010ab2aceSGeorge Karpenkov     : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
14110ab2aceSGeorge Karpenkov   if (EF->__sanitizer_set_death_callback)
14210ab2aceSGeorge Karpenkov     EF->__sanitizer_set_death_callback(StaticDeathCallback);
14310ab2aceSGeorge Karpenkov   assert(!F);
14410ab2aceSGeorge Karpenkov   F = this;
14510ab2aceSGeorge Karpenkov   TPC.ResetMaps();
14610ab2aceSGeorge Karpenkov   IsMyThread = true;
14710ab2aceSGeorge Karpenkov   if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
14810ab2aceSGeorge Karpenkov     EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
14910ab2aceSGeorge Karpenkov   TPC.SetUseCounters(Options.UseCounters);
15051ddb883SKostya Serebryany   TPC.SetUseValueProfileMask(Options.UseValueProfile);
15110ab2aceSGeorge Karpenkov 
15210ab2aceSGeorge Karpenkov   if (Options.Verbosity)
15310ab2aceSGeorge Karpenkov     TPC.PrintModuleInfo();
15410ab2aceSGeorge Karpenkov   if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
15510ab2aceSGeorge Karpenkov     EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
15610ab2aceSGeorge Karpenkov   MaxInputLen = MaxMutationLen = Options.MaxLen;
157b6ca1e72SKostya Serebryany   TmpMaxMutationLen = 0;  // Will be set once we load the corpus.
15810ab2aceSGeorge Karpenkov   AllocateCurrentUnitData();
15910ab2aceSGeorge Karpenkov   CurrentUnitSize = 0;
16010ab2aceSGeorge Karpenkov   memset(BaseSha1, 0, sizeof(BaseSha1));
16110ab2aceSGeorge Karpenkov }
16210ab2aceSGeorge Karpenkov 
~Fuzzer()16310ab2aceSGeorge Karpenkov Fuzzer::~Fuzzer() {}
16410ab2aceSGeorge Karpenkov 
AllocateCurrentUnitData()16510ab2aceSGeorge Karpenkov void Fuzzer::AllocateCurrentUnitData() {
1665ded0701SAlex Shlyapnikov   if (CurrentUnitData || MaxInputLen == 0)
1675ded0701SAlex Shlyapnikov     return;
16810ab2aceSGeorge Karpenkov   CurrentUnitData = new uint8_t[MaxInputLen];
16910ab2aceSGeorge Karpenkov }
17010ab2aceSGeorge Karpenkov 
StaticDeathCallback()17110ab2aceSGeorge Karpenkov void Fuzzer::StaticDeathCallback() {
17210ab2aceSGeorge Karpenkov   assert(F);
17310ab2aceSGeorge Karpenkov   F->DeathCallback();
17410ab2aceSGeorge Karpenkov }
17510ab2aceSGeorge Karpenkov 
DumpCurrentUnit(const char * Prefix)17610ab2aceSGeorge Karpenkov void Fuzzer::DumpCurrentUnit(const char *Prefix) {
1775ded0701SAlex Shlyapnikov   if (!CurrentUnitData)
1785ded0701SAlex Shlyapnikov     return; // Happens when running individual inputs.
179a34c65e8SMatt Morehouse   ScopedDisableMsanInterceptorChecks S;
180c5d72517SMarco Vanotti   MD.PrintMutationSequence();
18110ab2aceSGeorge Karpenkov   Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
18210ab2aceSGeorge Karpenkov   size_t UnitSize = CurrentUnitSize;
18310ab2aceSGeorge Karpenkov   if (UnitSize <= kMaxUnitSizeToPrint) {
18410ab2aceSGeorge Karpenkov     PrintHexArray(CurrentUnitData, UnitSize, "\n");
18510ab2aceSGeorge Karpenkov     PrintASCII(CurrentUnitData, UnitSize, "\n");
18610ab2aceSGeorge Karpenkov   }
18710ab2aceSGeorge Karpenkov   WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
18810ab2aceSGeorge Karpenkov                             Prefix);
18910ab2aceSGeorge Karpenkov }
19010ab2aceSGeorge Karpenkov 
19110ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY
DeathCallback()19210ab2aceSGeorge Karpenkov void Fuzzer::DeathCallback() {
19310ab2aceSGeorge Karpenkov   DumpCurrentUnit("crash-");
19410ab2aceSGeorge Karpenkov   PrintFinalStats();
19510ab2aceSGeorge Karpenkov }
19610ab2aceSGeorge Karpenkov 
StaticAlarmCallback()19710ab2aceSGeorge Karpenkov void Fuzzer::StaticAlarmCallback() {
19810ab2aceSGeorge Karpenkov   assert(F);
19910ab2aceSGeorge Karpenkov   F->AlarmCallback();
20010ab2aceSGeorge Karpenkov }
20110ab2aceSGeorge Karpenkov 
StaticCrashSignalCallback()20210ab2aceSGeorge Karpenkov void Fuzzer::StaticCrashSignalCallback() {
20310ab2aceSGeorge Karpenkov   assert(F);
20410ab2aceSGeorge Karpenkov   F->CrashCallback();
20510ab2aceSGeorge Karpenkov }
20610ab2aceSGeorge Karpenkov 
StaticExitCallback()20710ab2aceSGeorge Karpenkov void Fuzzer::StaticExitCallback() {
20810ab2aceSGeorge Karpenkov   assert(F);
20910ab2aceSGeorge Karpenkov   F->ExitCallback();
21010ab2aceSGeorge Karpenkov }
21110ab2aceSGeorge Karpenkov 
StaticInterruptCallback()21210ab2aceSGeorge Karpenkov void Fuzzer::StaticInterruptCallback() {
21310ab2aceSGeorge Karpenkov   assert(F);
21410ab2aceSGeorge Karpenkov   F->InterruptCallback();
21510ab2aceSGeorge Karpenkov }
21610ab2aceSGeorge Karpenkov 
StaticGracefulExitCallback()217a2ca2dccSKostya Serebryany void Fuzzer::StaticGracefulExitCallback() {
218a2ca2dccSKostya Serebryany   assert(F);
219a2ca2dccSKostya Serebryany   F->GracefulExitRequested = true;
220a2ca2dccSKostya Serebryany   Printf("INFO: signal received, trying to exit gracefully\n");
221a2ca2dccSKostya Serebryany }
222a2ca2dccSKostya Serebryany 
StaticFileSizeExceedCallback()22310ab2aceSGeorge Karpenkov void Fuzzer::StaticFileSizeExceedCallback() {
22410ab2aceSGeorge Karpenkov   Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
22510ab2aceSGeorge Karpenkov   exit(1);
22610ab2aceSGeorge Karpenkov }
22710ab2aceSGeorge Karpenkov 
CrashCallback()22810ab2aceSGeorge Karpenkov void Fuzzer::CrashCallback() {
22915df273eSJulian Lettner   if (EF->__sanitizer_acquire_crash_state &&
23015df273eSJulian Lettner       !EF->__sanitizer_acquire_crash_state())
23115df273eSJulian Lettner     return;
23210ab2aceSGeorge Karpenkov   Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
23314cf71a3SMatt Morehouse   PrintStackTrace();
23410ab2aceSGeorge Karpenkov   Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
23510ab2aceSGeorge Karpenkov          "      Combine libFuzzer with AddressSanitizer or similar for better "
23610ab2aceSGeorge Karpenkov          "crash reports.\n");
23710ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: deadly signal\n");
23810ab2aceSGeorge Karpenkov   DumpCurrentUnit("crash-");
23910ab2aceSGeorge Karpenkov   PrintFinalStats();
24010ab2aceSGeorge Karpenkov   _Exit(Options.ErrorExitCode); // Stop right now.
24110ab2aceSGeorge Karpenkov }
24210ab2aceSGeorge Karpenkov 
ExitCallback()24310ab2aceSGeorge Karpenkov void Fuzzer::ExitCallback() {
24443a22969SMatt Morehouse   if (!RunningUserCallback)
24510ab2aceSGeorge Karpenkov     return; // This exit did not come from the user callback
24652fd1690SMatt Morehouse   if (EF->__sanitizer_acquire_crash_state &&
24752fd1690SMatt Morehouse       !EF->__sanitizer_acquire_crash_state())
24852fd1690SMatt Morehouse     return;
24910ab2aceSGeorge Karpenkov   Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
25014cf71a3SMatt Morehouse   PrintStackTrace();
25110ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: fuzz target exited\n");
25210ab2aceSGeorge Karpenkov   DumpCurrentUnit("crash-");
25310ab2aceSGeorge Karpenkov   PrintFinalStats();
25410ab2aceSGeorge Karpenkov   _Exit(Options.ErrorExitCode);
25510ab2aceSGeorge Karpenkov }
25610ab2aceSGeorge Karpenkov 
MaybeExitGracefully()257a2ca2dccSKostya Serebryany void Fuzzer::MaybeExitGracefully() {
258f762a115SKostya Serebryany   if (!F->GracefulExitRequested) return;
259a2ca2dccSKostya Serebryany   Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
2604f3c3bbbSYuanfang Chen   RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
261f762a115SKostya Serebryany   F->PrintFinalStats();
262a2ca2dccSKostya Serebryany   _Exit(0);
263a2ca2dccSKostya Serebryany }
264a2ca2dccSKostya Serebryany 
InterruptCallback()26510ab2aceSGeorge Karpenkov void Fuzzer::InterruptCallback() {
26610ab2aceSGeorge Karpenkov   Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
26710ab2aceSGeorge Karpenkov   PrintFinalStats();
2681b76063aSMatt Morehouse   ScopedDisableMsanInterceptorChecks S; // RmDirRecursive may call opendir().
2694f3c3bbbSYuanfang Chen   RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
2700fda9dcbSKostya Serebryany   // Stop right now, don't perform any at-exit actions.
2710fda9dcbSKostya Serebryany   _Exit(Options.InterruptExitCode);
27210ab2aceSGeorge Karpenkov }
27310ab2aceSGeorge Karpenkov 
27410ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY
AlarmCallback()27510ab2aceSGeorge Karpenkov void Fuzzer::AlarmCallback() {
27610ab2aceSGeorge Karpenkov   assert(Options.UnitTimeoutSec > 0);
277e7bfce78SJake Ehrlich   // In Windows and Fuchsia, Alarm callback is executed by a different thread.
2782e61186cSKamil Rytarowski   // NetBSD's current behavior needs this change too.
279e7bfce78SJake Ehrlich #if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD && !LIBFUZZER_FUCHSIA
2805ded0701SAlex Shlyapnikov   if (!InFuzzingThread())
2815ded0701SAlex Shlyapnikov     return;
28210ab2aceSGeorge Karpenkov #endif
28343a22969SMatt Morehouse   if (!RunningUserCallback)
28410ab2aceSGeorge Karpenkov     return; // We have not started running units yet.
28510ab2aceSGeorge Karpenkov   size_t Seconds =
28610ab2aceSGeorge Karpenkov       duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
28710ab2aceSGeorge Karpenkov   if (Seconds == 0)
28810ab2aceSGeorge Karpenkov     return;
28910ab2aceSGeorge Karpenkov   if (Options.Verbosity >= 2)
29010ab2aceSGeorge Karpenkov     Printf("AlarmCallback %zd\n", Seconds);
29110ab2aceSGeorge Karpenkov   if (Seconds >= (size_t)Options.UnitTimeoutSec) {
29252fd1690SMatt Morehouse     if (EF->__sanitizer_acquire_crash_state &&
29352fd1690SMatt Morehouse         !EF->__sanitizer_acquire_crash_state())
29452fd1690SMatt Morehouse       return;
29510ab2aceSGeorge Karpenkov     Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
29610ab2aceSGeorge Karpenkov     Printf("       and the timeout value is %d (use -timeout=N to change)\n",
29710ab2aceSGeorge Karpenkov            Options.UnitTimeoutSec);
29810ab2aceSGeorge Karpenkov     DumpCurrentUnit("timeout-");
29910ab2aceSGeorge Karpenkov     Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
30010ab2aceSGeorge Karpenkov            Seconds);
30114cf71a3SMatt Morehouse     PrintStackTrace();
30210ab2aceSGeorge Karpenkov     Printf("SUMMARY: libFuzzer: timeout\n");
30310ab2aceSGeorge Karpenkov     PrintFinalStats();
30410ab2aceSGeorge Karpenkov     _Exit(Options.TimeoutExitCode); // Stop right now.
30510ab2aceSGeorge Karpenkov   }
30610ab2aceSGeorge Karpenkov }
30710ab2aceSGeorge Karpenkov 
RssLimitCallback()30810ab2aceSGeorge Karpenkov void Fuzzer::RssLimitCallback() {
30952fd1690SMatt Morehouse   if (EF->__sanitizer_acquire_crash_state &&
31052fd1690SMatt Morehouse       !EF->__sanitizer_acquire_crash_state())
31152fd1690SMatt Morehouse     return;
31210ab2aceSGeorge Karpenkov   Printf(
31310ab2aceSGeorge Karpenkov       "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
31410ab2aceSGeorge Karpenkov       GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
31510ab2aceSGeorge Karpenkov   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
31614cf71a3SMatt Morehouse   PrintMemoryProfile();
31710ab2aceSGeorge Karpenkov   DumpCurrentUnit("oom-");
31810ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: out-of-memory\n");
31910ab2aceSGeorge Karpenkov   PrintFinalStats();
3200fda9dcbSKostya Serebryany   _Exit(Options.OOMExitCode); // Stop right now.
32110ab2aceSGeorge Karpenkov }
32210ab2aceSGeorge Karpenkov 
PrintStats(const char * Where,const char * End,size_t Units,size_t Features)32374cec618SMax Moroz void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units,
32474cec618SMax Moroz                         size_t Features) {
32510ab2aceSGeorge Karpenkov   size_t ExecPerSec = execPerSec();
32610ab2aceSGeorge Karpenkov   if (!Options.Verbosity)
32710ab2aceSGeorge Karpenkov     return;
32810ab2aceSGeorge Karpenkov   Printf("#%zd\t%s", TotalNumberOfRuns, Where);
32910ab2aceSGeorge Karpenkov   if (size_t N = TPC.GetTotalPCCoverage())
33010ab2aceSGeorge Karpenkov     Printf(" cov: %zd", N);
33174cec618SMax Moroz   if (size_t N = Features ? Features : Corpus.NumFeatures())
33210ab2aceSGeorge Karpenkov     Printf(" ft: %zd", N);
33310ab2aceSGeorge Karpenkov   if (!Corpus.empty()) {
33410ab2aceSGeorge Karpenkov     Printf(" corp: %zd", Corpus.NumActiveUnits());
33510ab2aceSGeorge Karpenkov     if (size_t N = Corpus.SizeInBytes()) {
33610ab2aceSGeorge Karpenkov       if (N < (1 << 14))
33710ab2aceSGeorge Karpenkov         Printf("/%zdb", N);
33810ab2aceSGeorge Karpenkov       else if (N < (1 << 24))
33910ab2aceSGeorge Karpenkov         Printf("/%zdKb", N >> 10);
34010ab2aceSGeorge Karpenkov       else
34110ab2aceSGeorge Karpenkov         Printf("/%zdMb", N >> 20);
34210ab2aceSGeorge Karpenkov     }
343e9c6f06cSKostya Serebryany     if (size_t FF = Corpus.NumInputsThatTouchFocusFunction())
344e9c6f06cSKostya Serebryany       Printf(" focus: %zd", FF);
34510ab2aceSGeorge Karpenkov   }
346ddf352b9SMatt Morehouse   if (TmpMaxMutationLen)
347ddf352b9SMatt Morehouse     Printf(" lim: %zd", TmpMaxMutationLen);
34810ab2aceSGeorge Karpenkov   if (Units)
34910ab2aceSGeorge Karpenkov     Printf(" units: %zd", Units);
35010ab2aceSGeorge Karpenkov 
35110ab2aceSGeorge Karpenkov   Printf(" exec/s: %zd", ExecPerSec);
35210ab2aceSGeorge Karpenkov   Printf(" rss: %zdMb", GetPeakRSSMb());
35310ab2aceSGeorge Karpenkov   Printf("%s", End);
35410ab2aceSGeorge Karpenkov }
35510ab2aceSGeorge Karpenkov 
PrintFinalStats()35610ab2aceSGeorge Karpenkov void Fuzzer::PrintFinalStats() {
357dc62d5ecSMax Moroz   if (Options.PrintFullCoverage)
358dc62d5ecSMax Moroz     TPC.PrintCoverage(/*PrintAllCounters=*/true);
35910ab2aceSGeorge Karpenkov   if (Options.PrintCoverage)
360dc62d5ecSMax Moroz     TPC.PrintCoverage(/*PrintAllCounters=*/false);
36110ab2aceSGeorge Karpenkov   if (Options.PrintCorpusStats)
36210ab2aceSGeorge Karpenkov     Corpus.PrintStats();
3635ded0701SAlex Shlyapnikov   if (!Options.PrintFinalStats)
3645ded0701SAlex Shlyapnikov     return;
36510ab2aceSGeorge Karpenkov   size_t ExecPerSec = execPerSec();
36610ab2aceSGeorge Karpenkov   Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
36710ab2aceSGeorge Karpenkov   Printf("stat::average_exec_per_sec:     %zd\n", ExecPerSec);
36810ab2aceSGeorge Karpenkov   Printf("stat::new_units_added:          %zd\n", NumberOfNewUnitsAdded);
36910ab2aceSGeorge Karpenkov   Printf("stat::slowest_unit_time_sec:    %zd\n", TimeOfLongestUnitInSeconds);
37010ab2aceSGeorge Karpenkov   Printf("stat::peak_rss_mb:              %zd\n", GetPeakRSSMb());
37110ab2aceSGeorge Karpenkov }
37210ab2aceSGeorge Karpenkov 
SetMaxInputLen(size_t MaxInputLen)37310ab2aceSGeorge Karpenkov void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
37410ab2aceSGeorge Karpenkov   assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
37510ab2aceSGeorge Karpenkov   assert(MaxInputLen);
37610ab2aceSGeorge Karpenkov   this->MaxInputLen = MaxInputLen;
37710ab2aceSGeorge Karpenkov   this->MaxMutationLen = MaxInputLen;
37810ab2aceSGeorge Karpenkov   AllocateCurrentUnitData();
37910ab2aceSGeorge Karpenkov   Printf("INFO: -max_len is not provided; "
38010ab2aceSGeorge Karpenkov          "libFuzzer will not generate inputs larger than %zd bytes\n",
38110ab2aceSGeorge Karpenkov          MaxInputLen);
38210ab2aceSGeorge Karpenkov }
38310ab2aceSGeorge Karpenkov 
SetMaxMutationLen(size_t MaxMutationLen)38410ab2aceSGeorge Karpenkov void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
38510ab2aceSGeorge Karpenkov   assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
38610ab2aceSGeorge Karpenkov   this->MaxMutationLen = MaxMutationLen;
38710ab2aceSGeorge Karpenkov }
38810ab2aceSGeorge Karpenkov 
CheckExitOnSrcPosOrItem()38910ab2aceSGeorge Karpenkov void Fuzzer::CheckExitOnSrcPosOrItem() {
39010ab2aceSGeorge Karpenkov   if (!Options.ExitOnSrcPos.empty()) {
3917c921753SKostya Serebryany     static auto *PCsSet = new std::set<uintptr_t>;
39296f81bc6SKostya Serebryany     auto HandlePC = [&](const TracePC::PCTableEntry *TE) {
39396f81bc6SKostya Serebryany       if (!PCsSet->insert(TE->PC).second)
3945ded0701SAlex Shlyapnikov         return;
39596f81bc6SKostya Serebryany       std::string Descr = DescribePC("%F %L", TE->PC + 1);
39610ab2aceSGeorge Karpenkov       if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
39710ab2aceSGeorge Karpenkov         Printf("INFO: found line matching '%s', exiting.\n",
39810ab2aceSGeorge Karpenkov                Options.ExitOnSrcPos.c_str());
39910ab2aceSGeorge Karpenkov         _Exit(0);
40010ab2aceSGeorge Karpenkov       }
40110ab2aceSGeorge Karpenkov     };
40210ab2aceSGeorge Karpenkov     TPC.ForEachObservedPC(HandlePC);
40310ab2aceSGeorge Karpenkov   }
40410ab2aceSGeorge Karpenkov   if (!Options.ExitOnItem.empty()) {
40510ab2aceSGeorge Karpenkov     if (Corpus.HasUnit(Options.ExitOnItem)) {
40610ab2aceSGeorge Karpenkov       Printf("INFO: found item with checksum '%s', exiting.\n",
40710ab2aceSGeorge Karpenkov              Options.ExitOnItem.c_str());
40810ab2aceSGeorge Karpenkov       _Exit(0);
40910ab2aceSGeorge Karpenkov     }
41010ab2aceSGeorge Karpenkov   }
41110ab2aceSGeorge Karpenkov }
41210ab2aceSGeorge Karpenkov 
RereadOutputCorpus(size_t MaxSize)41310ab2aceSGeorge Karpenkov void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
4145ded0701SAlex Shlyapnikov   if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
4155ded0701SAlex Shlyapnikov     return;
4167c921753SKostya Serebryany   std::vector<Unit> AdditionalCorpus;
4177c921753SKostya Serebryany   std::vector<std::string> AdditionalCorpusPaths;
418827ccc93SAlexey Vishnyakov   ReadDirToVectorOfUnits(
419827ccc93SAlexey Vishnyakov       Options.OutputCorpus.c_str(), &AdditionalCorpus,
42010ab2aceSGeorge Karpenkov       &EpochOfLastReadOfOutputCorpus, MaxSize,
421827ccc93SAlexey Vishnyakov       /*ExitOnError*/ false,
422827ccc93SAlexey Vishnyakov       (Options.Verbosity >= 2 ? &AdditionalCorpusPaths : nullptr));
42310ab2aceSGeorge Karpenkov   if (Options.Verbosity >= 2)
42410ab2aceSGeorge Karpenkov     Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
42510ab2aceSGeorge Karpenkov   bool Reloaded = false;
426827ccc93SAlexey Vishnyakov   for (size_t i = 0; i != AdditionalCorpus.size(); ++i) {
427827ccc93SAlexey Vishnyakov     auto &U = AdditionalCorpus[i];
42810ab2aceSGeorge Karpenkov     if (U.size() > MaxSize)
42910ab2aceSGeorge Karpenkov       U.resize(MaxSize);
43010ab2aceSGeorge Karpenkov     if (!Corpus.HasUnit(U)) {
43110ab2aceSGeorge Karpenkov       if (RunOne(U.data(), U.size())) {
43210ab2aceSGeorge Karpenkov         CheckExitOnSrcPosOrItem();
43310ab2aceSGeorge Karpenkov         Reloaded = true;
434827ccc93SAlexey Vishnyakov         if (Options.Verbosity >= 2)
435827ccc93SAlexey Vishnyakov           Printf("Reloaded %s\n", AdditionalCorpusPaths[i].c_str());
43610ab2aceSGeorge Karpenkov       }
43710ab2aceSGeorge Karpenkov     }
43810ab2aceSGeorge Karpenkov   }
43910ab2aceSGeorge Karpenkov   if (Reloaded)
44010ab2aceSGeorge Karpenkov     PrintStats("RELOAD");
44110ab2aceSGeorge Karpenkov }
44210ab2aceSGeorge Karpenkov 
PrintPulseAndReportSlowInput(const uint8_t * Data,size_t Size)44310ab2aceSGeorge Karpenkov void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
44410ab2aceSGeorge Karpenkov   auto TimeOfUnit =
44510ab2aceSGeorge Karpenkov       duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
44610ab2aceSGeorge Karpenkov   if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
44710ab2aceSGeorge Karpenkov       secondsSinceProcessStartUp() >= 2)
44810ab2aceSGeorge Karpenkov     PrintStats("pulse ");
4496708186cSAaron Green   auto Threshhold =
4506708186cSAaron Green       static_cast<long>(static_cast<double>(TimeOfLongestUnitInSeconds) * 1.1);
4516708186cSAaron Green   if (TimeOfUnit > Threshhold && TimeOfUnit >= Options.ReportSlowUnits) {
45210ab2aceSGeorge Karpenkov     TimeOfLongestUnitInSeconds = TimeOfUnit;
45310ab2aceSGeorge Karpenkov     Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
45410ab2aceSGeorge Karpenkov     WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
45510ab2aceSGeorge Karpenkov   }
45610ab2aceSGeorge Karpenkov }
45710ab2aceSGeorge Karpenkov 
WriteFeatureSetToFile(const std::string & FeaturesDir,const std::string & FileName,const std::vector<uint32_t> & FeatureSet)4584614cc3dSKostya Serebryany static void WriteFeatureSetToFile(const std::string &FeaturesDir,
4595e67abd9SKostya Serebryany                                   const std::string &FileName,
4607c921753SKostya Serebryany                                   const std::vector<uint32_t> &FeatureSet) {
4614614cc3dSKostya Serebryany   if (FeaturesDir.empty() || FeatureSet.empty()) return;
4624614cc3dSKostya Serebryany   WriteToFile(reinterpret_cast<const uint8_t *>(FeatureSet.data()),
4634614cc3dSKostya Serebryany               FeatureSet.size() * sizeof(FeatureSet[0]),
4645e67abd9SKostya Serebryany               DirPlusFile(FeaturesDir, FileName));
4654614cc3dSKostya Serebryany }
4664614cc3dSKostya Serebryany 
RenameFeatureSetFile(const std::string & FeaturesDir,const std::string & OldFile,const std::string & NewFile)4674614cc3dSKostya Serebryany static void RenameFeatureSetFile(const std::string &FeaturesDir,
4684614cc3dSKostya Serebryany                                  const std::string &OldFile,
4694614cc3dSKostya Serebryany                                  const std::string &NewFile) {
4704614cc3dSKostya Serebryany   if (FeaturesDir.empty()) return;
4714614cc3dSKostya Serebryany   RenameFile(DirPlusFile(FeaturesDir, OldFile),
4724614cc3dSKostya Serebryany              DirPlusFile(FeaturesDir, NewFile));
4734614cc3dSKostya Serebryany }
4744614cc3dSKostya Serebryany 
WriteEdgeToMutationGraphFile(const std::string & MutationGraphFile,const InputInfo * II,const InputInfo * BaseII,const std::string & MS)4751bb1eac6SDokyung Song static void WriteEdgeToMutationGraphFile(const std::string &MutationGraphFile,
4761bb1eac6SDokyung Song                                          const InputInfo *II,
4771bb1eac6SDokyung Song                                          const InputInfo *BaseII,
4781bb1eac6SDokyung Song                                          const std::string &MS) {
4791bb1eac6SDokyung Song   if (MutationGraphFile.empty())
4801bb1eac6SDokyung Song     return;
4811bb1eac6SDokyung Song 
4821bb1eac6SDokyung Song   std::string Sha1 = Sha1ToString(II->Sha1);
4831bb1eac6SDokyung Song 
4841bb1eac6SDokyung Song   std::string OutputString;
4851bb1eac6SDokyung Song 
4861bb1eac6SDokyung Song   // Add a new vertex.
4871bb1eac6SDokyung Song   OutputString.append("\"");
4881bb1eac6SDokyung Song   OutputString.append(Sha1);
4891bb1eac6SDokyung Song   OutputString.append("\"\n");
4901bb1eac6SDokyung Song 
4911bb1eac6SDokyung Song   // Add a new edge if there is base input.
4921bb1eac6SDokyung Song   if (BaseII) {
4931bb1eac6SDokyung Song     std::string BaseSha1 = Sha1ToString(BaseII->Sha1);
4941bb1eac6SDokyung Song     OutputString.append("\"");
4951bb1eac6SDokyung Song     OutputString.append(BaseSha1);
4961bb1eac6SDokyung Song     OutputString.append("\" -> \"");
4971bb1eac6SDokyung Song     OutputString.append(Sha1);
4981bb1eac6SDokyung Song     OutputString.append("\" [label=\"");
4991bb1eac6SDokyung Song     OutputString.append(MS);
5001bb1eac6SDokyung Song     OutputString.append("\"];\n");
5011bb1eac6SDokyung Song   }
5021bb1eac6SDokyung Song 
5031bb1eac6SDokyung Song   AppendToFile(OutputString, MutationGraphFile);
5041bb1eac6SDokyung Song }
5051bb1eac6SDokyung Song 
RunOne(const uint8_t * Data,size_t Size,bool MayDeleteFile,InputInfo * II,bool ForceAddToCorpus,bool * FoundUniqFeatures)50610ab2aceSGeorge Karpenkov bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
50762673c43SDokyung Song                     InputInfo *II, bool ForceAddToCorpus,
50862673c43SDokyung Song                     bool *FoundUniqFeatures) {
5095ded0701SAlex Shlyapnikov   if (!Size)
5105ded0701SAlex Shlyapnikov     return false;
5116708186cSAaron Green   // Largest input length should be INT_MAX.
5126708186cSAaron Green   assert(Size < std::numeric_limits<uint32_t>::max());
51310ab2aceSGeorge Karpenkov 
514*92fb3101SKostya Serebryany   if(!ExecuteCallback(Data, Size)) return false;
5155cda4dc7SDokyung Song   auto TimeOfUnit = duration_cast<microseconds>(UnitStopTime - UnitStartTime);
51610ab2aceSGeorge Karpenkov 
51710ab2aceSGeorge Karpenkov   UniqFeatureSetTmp.clear();
51810ab2aceSGeorge Karpenkov   size_t FoundUniqFeaturesOfII = 0;
51910ab2aceSGeorge Karpenkov   size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
5206708186cSAaron Green   TPC.CollectFeatures([&](uint32_t Feature) {
5216708186cSAaron Green     if (Corpus.AddFeature(Feature, static_cast<uint32_t>(Size), Options.Shrink))
52210ab2aceSGeorge Karpenkov       UniqFeatureSetTmp.push_back(Feature);
523e2e38fcaSMatt Morehouse     if (Options.Entropic)
524e2e38fcaSMatt Morehouse       Corpus.UpdateFeatureFrequency(II, Feature);
52562673c43SDokyung Song     if (Options.ReduceInputs && II && !II->NeverReduce)
52610ab2aceSGeorge Karpenkov       if (std::binary_search(II->UniqFeatureSet.begin(),
52710ab2aceSGeorge Karpenkov                              II->UniqFeatureSet.end(), Feature))
52810ab2aceSGeorge Karpenkov         FoundUniqFeaturesOfII++;
52910ab2aceSGeorge Karpenkov   });
530ad05ee05SKostya Serebryany   if (FoundUniqFeatures)
531ad05ee05SKostya Serebryany     *FoundUniqFeatures = FoundUniqFeaturesOfII;
53210ab2aceSGeorge Karpenkov   PrintPulseAndReportSlowInput(Data, Size);
53310ab2aceSGeorge Karpenkov   size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
53462673c43SDokyung Song   if (NumNewFeatures || ForceAddToCorpus) {
53510ab2aceSGeorge Karpenkov     TPC.UpdateObservedPCs();
53662673c43SDokyung Song     auto NewII =
53762673c43SDokyung Song         Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
53862673c43SDokyung Song                            TPC.ObservedFocusFunction(), ForceAddToCorpus,
5395cda4dc7SDokyung Song                            TimeOfUnit, UniqFeatureSetTmp, DFT, II);
5405e67abd9SKostya Serebryany     WriteFeatureSetToFile(Options.FeaturesDir, Sha1ToString(NewII->Sha1),
5414614cc3dSKostya Serebryany                           NewII->UniqFeatureSet);
5421bb1eac6SDokyung Song     WriteEdgeToMutationGraphFile(Options.MutationGraphFile, NewII, II,
543c5d72517SMarco Vanotti                                  MD.MutationSequence());
54410ab2aceSGeorge Karpenkov     return true;
54510ab2aceSGeorge Karpenkov   }
54610ab2aceSGeorge Karpenkov   if (II && FoundUniqFeaturesOfII &&
54767af9923SKostya Serebryany       II->DataFlowTraceForFocusFunction.empty() &&
54810ab2aceSGeorge Karpenkov       FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
54910ab2aceSGeorge Karpenkov       II->U.size() > Size) {
5504614cc3dSKostya Serebryany     auto OldFeaturesFile = Sha1ToString(II->Sha1);
5519e7b7303SPZ Read     Corpus.Replace(II, {Data, Data + Size}, TimeOfUnit);
5524614cc3dSKostya Serebryany     RenameFeatureSetFile(Options.FeaturesDir, OldFeaturesFile,
5534614cc3dSKostya Serebryany                          Sha1ToString(II->Sha1));
55410ab2aceSGeorge Karpenkov     return true;
55510ab2aceSGeorge Karpenkov   }
55610ab2aceSGeorge Karpenkov   return false;
55710ab2aceSGeorge Karpenkov }
55810ab2aceSGeorge Karpenkov 
TPCUpdateObservedPCs()559dc62d5ecSMax Moroz void Fuzzer::TPCUpdateObservedPCs() { TPC.UpdateObservedPCs(); }
560dc62d5ecSMax Moroz 
GetCurrentUnitInFuzzingThead(const uint8_t ** Data) const56110ab2aceSGeorge Karpenkov size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
56210ab2aceSGeorge Karpenkov   assert(InFuzzingThread());
56310ab2aceSGeorge Karpenkov   *Data = CurrentUnitData;
56410ab2aceSGeorge Karpenkov   return CurrentUnitSize;
56510ab2aceSGeorge Karpenkov }
56610ab2aceSGeorge Karpenkov 
CrashOnOverwrittenData()56710ab2aceSGeorge Karpenkov void Fuzzer::CrashOnOverwrittenData() {
568da3cf616SMitch Phillips   Printf("==%d== ERROR: libFuzzer: fuzz target overwrites its const input\n",
56910ab2aceSGeorge Karpenkov          GetPid());
570d1e222e5SMitch Phillips   PrintStackTrace();
571d1e222e5SMitch Phillips   Printf("SUMMARY: libFuzzer: overwrites-const-input\n");
57210ab2aceSGeorge Karpenkov   DumpCurrentUnit("crash-");
573d1e222e5SMitch Phillips   PrintFinalStats();
57410ab2aceSGeorge Karpenkov   _Exit(Options.ErrorExitCode); // Stop right now.
57510ab2aceSGeorge Karpenkov }
57610ab2aceSGeorge Karpenkov 
57710ab2aceSGeorge Karpenkov // Compare two arrays, but not all bytes if the arrays are large.
LooseMemeq(const uint8_t * A,const uint8_t * B,size_t Size)57810ab2aceSGeorge Karpenkov static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
57910ab2aceSGeorge Karpenkov   const size_t Limit = 64;
58010ab2aceSGeorge Karpenkov   if (Size <= 64)
58110ab2aceSGeorge Karpenkov     return !memcmp(A, B, Size);
58210ab2aceSGeorge Karpenkov   // Compare first and last Limit/2 bytes.
58310ab2aceSGeorge Karpenkov   return !memcmp(A, B, Limit / 2) &&
58410ab2aceSGeorge Karpenkov          !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
58510ab2aceSGeorge Karpenkov }
58610ab2aceSGeorge Karpenkov 
5875908c7caSJonas Paulsson // This method is not inlined because it would cause a test to fail where it
5885908c7caSJonas Paulsson // is part of the stack unwinding. See D97975 for details.
ExecuteCallback(const uint8_t * Data,size_t Size)589*92fb3101SKostya Serebryany ATTRIBUTE_NOINLINE bool Fuzzer::ExecuteCallback(const uint8_t *Data,
5904b82f614SMatt Morehouse                                                 size_t Size) {
59110ab2aceSGeorge Karpenkov   TPC.RecordInitialStack();
59210ab2aceSGeorge Karpenkov   TotalNumberOfRuns++;
59310ab2aceSGeorge Karpenkov   assert(InFuzzingThread());
59410ab2aceSGeorge Karpenkov   // We copy the contents of Unit into a separate heap buffer
59510ab2aceSGeorge Karpenkov   // so that we reliably find buffer overflows in it.
59610ab2aceSGeorge Karpenkov   uint8_t *DataCopy = new uint8_t[Size];
59710ab2aceSGeorge Karpenkov   memcpy(DataCopy, Data, Size);
598a34c65e8SMatt Morehouse   if (EF->__msan_unpoison)
599a34c65e8SMatt Morehouse     EF->__msan_unpoison(DataCopy, Size);
6003478494cSMatt Morehouse   if (EF->__msan_unpoison_param)
6013478494cSMatt Morehouse     EF->__msan_unpoison_param(2);
60210ab2aceSGeorge Karpenkov   if (CurrentUnitData && CurrentUnitData != Data)
60310ab2aceSGeorge Karpenkov     memcpy(CurrentUnitData, Data, Size);
60410ab2aceSGeorge Karpenkov   CurrentUnitSize = Size;
605*92fb3101SKostya Serebryany   int CBRes = 0;
606a34c65e8SMatt Morehouse   {
607a34c65e8SMatt Morehouse     ScopedEnableMsanInterceptorChecks S;
60810ab2aceSGeorge Karpenkov     AllocTracer.Start(Options.TraceMalloc);
60910ab2aceSGeorge Karpenkov     UnitStartTime = system_clock::now();
61010ab2aceSGeorge Karpenkov     TPC.ResetMaps();
61143a22969SMatt Morehouse     RunningUserCallback = true;
612*92fb3101SKostya Serebryany     CBRes = CB(DataCopy, Size);
61343a22969SMatt Morehouse     RunningUserCallback = false;
61410ab2aceSGeorge Karpenkov     UnitStopTime = system_clock::now();
615*92fb3101SKostya Serebryany     assert(CBRes == 0 || CBRes == -1);
61610ab2aceSGeorge Karpenkov     HasMoreMallocsThanFrees = AllocTracer.Stop();
617a34c65e8SMatt Morehouse   }
61810ab2aceSGeorge Karpenkov   if (!LooseMemeq(DataCopy, Data, Size))
61910ab2aceSGeorge Karpenkov     CrashOnOverwrittenData();
62010ab2aceSGeorge Karpenkov   CurrentUnitSize = 0;
62110ab2aceSGeorge Karpenkov   delete[] DataCopy;
622*92fb3101SKostya Serebryany   return CBRes == 0;
62310ab2aceSGeorge Karpenkov }
62410ab2aceSGeorge Karpenkov 
WriteToOutputCorpus(const Unit & U)62563f48717SKostya Serebryany std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
62610ab2aceSGeorge Karpenkov   if (Options.OnlyASCII)
62710ab2aceSGeorge Karpenkov     assert(IsASCII(U));
62810ab2aceSGeorge Karpenkov   if (Options.OutputCorpus.empty())
62963f48717SKostya Serebryany     return "";
63010ab2aceSGeorge Karpenkov   std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
63110ab2aceSGeorge Karpenkov   WriteToFile(U, Path);
63210ab2aceSGeorge Karpenkov   if (Options.Verbosity >= 2)
63310ab2aceSGeorge Karpenkov     Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
63463f48717SKostya Serebryany   return Path;
63510ab2aceSGeorge Karpenkov }
63610ab2aceSGeorge Karpenkov 
WriteUnitToFileWithPrefix(const Unit & U,const char * Prefix)63710ab2aceSGeorge Karpenkov void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
63810ab2aceSGeorge Karpenkov   if (!Options.SaveArtifacts)
63910ab2aceSGeorge Karpenkov     return;
64010ab2aceSGeorge Karpenkov   std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
64110ab2aceSGeorge Karpenkov   if (!Options.ExactArtifactPath.empty())
64210ab2aceSGeorge Karpenkov     Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
64310ab2aceSGeorge Karpenkov   WriteToFile(U, Path);
64410ab2aceSGeorge Karpenkov   Printf("artifact_prefix='%s'; Test unit written to %s\n",
64510ab2aceSGeorge Karpenkov          Options.ArtifactPrefix.c_str(), Path.c_str());
64610ab2aceSGeorge Karpenkov   if (U.size() <= kMaxUnitSizeToPrint)
64710ab2aceSGeorge Karpenkov     Printf("Base64: %s\n", Base64(U).c_str());
64810ab2aceSGeorge Karpenkov }
64910ab2aceSGeorge Karpenkov 
PrintStatusForNewUnit(const Unit & U,const char * Text)65010ab2aceSGeorge Karpenkov void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
65110ab2aceSGeorge Karpenkov   if (!Options.PrintNEW)
65210ab2aceSGeorge Karpenkov     return;
65310ab2aceSGeorge Karpenkov   PrintStats(Text, "");
65410ab2aceSGeorge Karpenkov   if (Options.Verbosity) {
65510ab2aceSGeorge Karpenkov     Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
656c5d72517SMarco Vanotti     MD.PrintMutationSequence(Options.Verbosity >= 2);
65710ab2aceSGeorge Karpenkov     Printf("\n");
65810ab2aceSGeorge Karpenkov   }
65910ab2aceSGeorge Karpenkov }
66010ab2aceSGeorge Karpenkov 
ReportNewCoverage(InputInfo * II,const Unit & U)66110ab2aceSGeorge Karpenkov void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
66210ab2aceSGeorge Karpenkov   II->NumSuccessfullMutations++;
66310ab2aceSGeorge Karpenkov   MD.RecordSuccessfulMutationSequence();
6645ded0701SAlex Shlyapnikov   PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW   ");
66510ab2aceSGeorge Karpenkov   WriteToOutputCorpus(U);
66610ab2aceSGeorge Karpenkov   NumberOfNewUnitsAdded++;
66710ab2aceSGeorge Karpenkov   CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
66810ab2aceSGeorge Karpenkov   LastCorpusUpdateRun = TotalNumberOfRuns;
66910ab2aceSGeorge Karpenkov }
67010ab2aceSGeorge Karpenkov 
67110ab2aceSGeorge Karpenkov // Tries detecting a memory leak on the particular input that we have just
67210ab2aceSGeorge Karpenkov // executed before calling this function.
TryDetectingAMemoryLeak(const uint8_t * Data,size_t Size,bool DuringInitialCorpusExecution)67310ab2aceSGeorge Karpenkov void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
67410ab2aceSGeorge Karpenkov                                      bool DuringInitialCorpusExecution) {
6755ded0701SAlex Shlyapnikov   if (!HasMoreMallocsThanFrees)
6765ded0701SAlex Shlyapnikov     return; // mallocs==frees, a leak is unlikely.
6775ded0701SAlex Shlyapnikov   if (!Options.DetectLeaks)
6785ded0701SAlex Shlyapnikov     return;
6793f26dac4SMax Moroz   if (!DuringInitialCorpusExecution &&
6805ded0701SAlex Shlyapnikov       TotalNumberOfRuns >= Options.MaxNumberOfRuns)
6815ded0701SAlex Shlyapnikov     return;
68210ab2aceSGeorge Karpenkov   if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
68310ab2aceSGeorge Karpenkov       !(EF->__lsan_do_recoverable_leak_check))
68410ab2aceSGeorge Karpenkov     return; // No lsan.
68510ab2aceSGeorge Karpenkov   // Run the target once again, but with lsan disabled so that if there is
68610ab2aceSGeorge Karpenkov   // a real leak we do not report it twice.
68710ab2aceSGeorge Karpenkov   EF->__lsan_disable();
68810ab2aceSGeorge Karpenkov   ExecuteCallback(Data, Size);
68910ab2aceSGeorge Karpenkov   EF->__lsan_enable();
6905ded0701SAlex Shlyapnikov   if (!HasMoreMallocsThanFrees)
6915ded0701SAlex Shlyapnikov     return; // a leak is unlikely.
69210ab2aceSGeorge Karpenkov   if (NumberOfLeakDetectionAttempts++ > 1000) {
69310ab2aceSGeorge Karpenkov     Options.DetectLeaks = false;
69410ab2aceSGeorge Karpenkov     Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
69510ab2aceSGeorge Karpenkov            "      Most likely the target function accumulates allocated\n"
69610ab2aceSGeorge Karpenkov            "      memory in a global state w/o actually leaking it.\n"
69710ab2aceSGeorge Karpenkov            "      You may try running this binary with -trace_malloc=[12]"
69810ab2aceSGeorge Karpenkov            "      to get a trace of mallocs and frees.\n"
69910ab2aceSGeorge Karpenkov            "      If LeakSanitizer is enabled in this process it will still\n"
70010ab2aceSGeorge Karpenkov            "      run on the process shutdown.\n");
70110ab2aceSGeorge Karpenkov     return;
70210ab2aceSGeorge Karpenkov   }
70310ab2aceSGeorge Karpenkov   // Now perform the actual lsan pass. This is expensive and we must ensure
70410ab2aceSGeorge Karpenkov   // we don't call it too often.
70510ab2aceSGeorge Karpenkov   if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
70610ab2aceSGeorge Karpenkov     if (DuringInitialCorpusExecution)
70710ab2aceSGeorge Karpenkov       Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
70810ab2aceSGeorge Karpenkov     Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
70910ab2aceSGeorge Karpenkov     CurrentUnitSize = Size;
71010ab2aceSGeorge Karpenkov     DumpCurrentUnit("leak-");
71110ab2aceSGeorge Karpenkov     PrintFinalStats();
71210ab2aceSGeorge Karpenkov     _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
71310ab2aceSGeorge Karpenkov   }
71410ab2aceSGeorge Karpenkov }
71510ab2aceSGeorge Karpenkov 
MutateAndTestOne()71610ab2aceSGeorge Karpenkov void Fuzzer::MutateAndTestOne() {
71710ab2aceSGeorge Karpenkov   MD.StartMutationSequence();
71810ab2aceSGeorge Karpenkov 
71910ab2aceSGeorge Karpenkov   auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
720b53243e1SDokyung Song   if (Options.DoCrossOver) {
721b53243e1SDokyung Song     auto &CrossOverII = Corpus.ChooseUnitToCrossOverWith(
722b53243e1SDokyung Song         MD.GetRand(), Options.CrossOverUniformDist);
723b53243e1SDokyung Song     MD.SetCrossOverWith(&CrossOverII.U);
724b53243e1SDokyung Song   }
72510ab2aceSGeorge Karpenkov   const auto &U = II.U;
72610ab2aceSGeorge Karpenkov   memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
72710ab2aceSGeorge Karpenkov   assert(CurrentUnitData);
72810ab2aceSGeorge Karpenkov   size_t Size = U.size();
72910ab2aceSGeorge Karpenkov   assert(Size <= MaxInputLen && "Oversized Unit");
73010ab2aceSGeorge Karpenkov   memcpy(CurrentUnitData, U.data(), Size);
73110ab2aceSGeorge Karpenkov 
73210ab2aceSGeorge Karpenkov   assert(MaxMutationLen > 0);
73310ab2aceSGeorge Karpenkov 
73410ab2aceSGeorge Karpenkov   size_t CurrentMaxMutationLen =
73510ab2aceSGeorge Karpenkov       Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
73610ab2aceSGeorge Karpenkov   assert(CurrentMaxMutationLen > 0);
73710ab2aceSGeorge Karpenkov 
73810ab2aceSGeorge Karpenkov   for (int i = 0; i < Options.MutateDepth; i++) {
73910ab2aceSGeorge Karpenkov     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
74010ab2aceSGeorge Karpenkov       break;
741a2ca2dccSKostya Serebryany     MaybeExitGracefully();
74210ab2aceSGeorge Karpenkov     size_t NewSize = 0;
7436b87e0c1SKostya Serebryany     if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() &&
7446b87e0c1SKostya Serebryany         Size <= CurrentMaxMutationLen)
7456b87e0c1SKostya Serebryany       NewSize = MD.MutateWithMask(CurrentUnitData, Size, Size,
7466b87e0c1SKostya Serebryany                                   II.DataFlowTraceForFocusFunction);
7479d5e7ee2SMax Moroz 
7489d5e7ee2SMax Moroz     // If MutateWithMask either failed or wasn't called, call default Mutate.
7499d5e7ee2SMax Moroz     if (!NewSize)
75010ab2aceSGeorge Karpenkov       NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
75110ab2aceSGeorge Karpenkov     assert(NewSize > 0 && "Mutator returned empty unit");
7526f1c26f2SAlex Shlyapnikov     assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
75310ab2aceSGeorge Karpenkov     Size = NewSize;
75410ab2aceSGeorge Karpenkov     II.NumExecutedMutations++;
755e2e38fcaSMatt Morehouse     Corpus.IncrementNumExecutedMutations();
75610ab2aceSGeorge Karpenkov 
757ad05ee05SKostya Serebryany     bool FoundUniqFeatures = false;
758ad05ee05SKostya Serebryany     bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II,
75962673c43SDokyung Song                          /*ForceAddToCorpus*/ false, &FoundUniqFeatures);
76010ab2aceSGeorge Karpenkov     TryDetectingAMemoryLeak(CurrentUnitData, Size,
76110ab2aceSGeorge Karpenkov                             /*DuringInitialCorpusExecution*/ false);
762ad05ee05SKostya Serebryany     if (NewCov) {
763947838c9SMatt Morehouse       ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
764ad05ee05SKostya Serebryany       break;  // We will mutate this input more in the next rounds.
765ad05ee05SKostya Serebryany     }
766ad05ee05SKostya Serebryany     if (Options.ReduceDepth && !FoundUniqFeatures)
767ad05ee05SKostya Serebryany       break;
76810ab2aceSGeorge Karpenkov   }
769e2e38fcaSMatt Morehouse 
770e2e38fcaSMatt Morehouse   II.NeedsEnergyUpdate = true;
77110ab2aceSGeorge Karpenkov }
77210ab2aceSGeorge Karpenkov 
PurgeAllocator()7736f1c26f2SAlex Shlyapnikov void Fuzzer::PurgeAllocator() {
7745ded0701SAlex Shlyapnikov   if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
7756f1c26f2SAlex Shlyapnikov     return;
7766f1c26f2SAlex Shlyapnikov   if (duration_cast<seconds>(system_clock::now() -
7775ded0701SAlex Shlyapnikov                              LastAllocatorPurgeAttemptTime)
7785ded0701SAlex Shlyapnikov           .count() < Options.PurgeAllocatorIntervalSec)
7796f1c26f2SAlex Shlyapnikov     return;
7806f1c26f2SAlex Shlyapnikov 
7816f1c26f2SAlex Shlyapnikov   if (Options.RssLimitMb <= 0 ||
7825ded0701SAlex Shlyapnikov       GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
7836f1c26f2SAlex Shlyapnikov     EF->__sanitizer_purge_allocator();
7846f1c26f2SAlex Shlyapnikov 
7856f1c26f2SAlex Shlyapnikov   LastAllocatorPurgeAttemptTime = system_clock::now();
7866f1c26f2SAlex Shlyapnikov }
7876f1c26f2SAlex Shlyapnikov 
ReadAndExecuteSeedCorpora(std::vector<SizedFile> & CorporaFiles)7887c921753SKostya Serebryany void Fuzzer::ReadAndExecuteSeedCorpora(std::vector<SizedFile> &CorporaFiles) {
7893a8e3c83SKostya Serebryany   const size_t kMaxSaneLen = 1 << 20;
7903a8e3c83SKostya Serebryany   const size_t kMinDefaultLen = 4096;
7914faeb87eSKostya Serebryany   size_t MaxSize = 0;
7924faeb87eSKostya Serebryany   size_t MinSize = -1;
7934faeb87eSKostya Serebryany   size_t TotalSize = 0;
7944c7353c5SKostya Serebryany   for (auto &File : CorporaFiles) {
79593679be0SKostya Serebryany     MaxSize = Max(File.Size, MaxSize);
79693679be0SKostya Serebryany     MinSize = Min(File.Size, MinSize);
79793679be0SKostya Serebryany     TotalSize += File.Size;
7984faeb87eSKostya Serebryany   }
7994faeb87eSKostya Serebryany   if (Options.MaxLen == 0)
8004faeb87eSKostya Serebryany     SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
8014faeb87eSKostya Serebryany   assert(MaxInputLen > 0);
8024faeb87eSKostya Serebryany 
80351823d3aSKostya Serebryany   // Test the callback with empty input and never try it again.
80451823d3aSKostya Serebryany   uint8_t dummy = 0;
80551823d3aSKostya Serebryany   ExecuteCallback(&dummy, 0);
80651823d3aSKostya Serebryany 
8074c7353c5SKostya Serebryany   if (CorporaFiles.empty()) {
8084faeb87eSKostya Serebryany     Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
8094faeb87eSKostya Serebryany     Unit U({'\n'}); // Valid ASCII input.
8104faeb87eSKostya Serebryany     RunOne(U.data(), U.size());
8114faeb87eSKostya Serebryany   } else {
8124faeb87eSKostya Serebryany     Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
8134faeb87eSKostya Serebryany            " rss: %zdMb\n",
8144c7353c5SKostya Serebryany            CorporaFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
8154faeb87eSKostya Serebryany     if (Options.ShuffleAtStartUp)
8164c7353c5SKostya Serebryany       std::shuffle(CorporaFiles.begin(), CorporaFiles.end(), MD.GetRand());
8174faeb87eSKostya Serebryany 
81893679be0SKostya Serebryany     if (Options.PreferSmall) {
8194c7353c5SKostya Serebryany       std::stable_sort(CorporaFiles.begin(), CorporaFiles.end());
8204c7353c5SKostya Serebryany       assert(CorporaFiles.front().Size <= CorporaFiles.back().Size);
82193679be0SKostya Serebryany     }
8224faeb87eSKostya Serebryany 
8234faeb87eSKostya Serebryany     // Load and execute inputs one by one.
8244c7353c5SKostya Serebryany     for (auto &SF : CorporaFiles) {
825082e9a75SKostya Serebryany       auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
8264faeb87eSKostya Serebryany       assert(U.size() <= MaxInputLen);
82762673c43SDokyung Song       RunOne(U.data(), U.size(), /*MayDeleteFile*/ false, /*II*/ nullptr,
82862673c43SDokyung Song              /*ForceAddToCorpus*/ Options.KeepSeed,
82962673c43SDokyung Song              /*FoundUniqFeatures*/ nullptr);
8304faeb87eSKostya Serebryany       CheckExitOnSrcPosOrItem();
8314faeb87eSKostya Serebryany       TryDetectingAMemoryLeak(U.data(), U.size(),
8324faeb87eSKostya Serebryany                               /*DuringInitialCorpusExecution*/ true);
8334faeb87eSKostya Serebryany     }
8343a8e3c83SKostya Serebryany   }
8353a8e3c83SKostya Serebryany 
8364faeb87eSKostya Serebryany   PrintStats("INITED");
83707647571SMax Moroz   if (!Options.FocusFunction.empty()) {
838e9c6f06cSKostya Serebryany     Printf("INFO: %zd/%zd inputs touch the focus function\n",
839e9c6f06cSKostya Serebryany            Corpus.NumInputsThatTouchFocusFunction(), Corpus.size());
84067af9923SKostya Serebryany     if (!Options.DataFlowTrace.empty())
84167af9923SKostya Serebryany       Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n",
84207647571SMax Moroz              Corpus.NumInputsWithDataFlowTrace(),
84307647571SMax Moroz              Corpus.NumInputsThatTouchFocusFunction());
84407647571SMax Moroz   }
845e9c6f06cSKostya Serebryany 
846fe97441cSMax Moroz   if (Corpus.empty() && Options.MaxNumberOfRuns) {
847*92fb3101SKostya Serebryany     Printf("WARNING: no interesting inputs were found so far. "
848*92fb3101SKostya Serebryany            "Is the code instrumented for coverage?\n"
849*92fb3101SKostya Serebryany            "This may also happen if the target rejected all inputs we tried so "
850*92fb3101SKostya Serebryany            "far\n");
851*92fb3101SKostya Serebryany     // The remaining logic requires that the corpus is not empty,
852*92fb3101SKostya Serebryany     // so we add one fake input to the in-memory corpus.
853*92fb3101SKostya Serebryany     Corpus.AddToCorpus({'\n'}, /*NumFeatures=*/1, /*MayDeleteFile=*/true,
854*92fb3101SKostya Serebryany                        /*HasFocusFunction=*/false, /*NeverReduce=*/false,
855*92fb3101SKostya Serebryany                        /*TimeOfUnit=*/duration_cast<microseconds>(0s), {0}, DFT,
856*92fb3101SKostya Serebryany                        /*BaseII*/ nullptr);
8573a8e3c83SKostya Serebryany   }
8583a8e3c83SKostya Serebryany }
8593a8e3c83SKostya Serebryany 
Loop(std::vector<SizedFile> & CorporaFiles)8607c921753SKostya Serebryany void Fuzzer::Loop(std::vector<SizedFile> &CorporaFiles) {
861060f4b48SKostya Serebryany   auto FocusFunctionOrAuto = Options.FocusFunction;
862060f4b48SKostya Serebryany   DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles,
863060f4b48SKostya Serebryany            MD.GetRand());
864060f4b48SKostya Serebryany   TPC.SetFocusFunction(FocusFunctionOrAuto);
8654c7353c5SKostya Serebryany   ReadAndExecuteSeedCorpora(CorporaFiles);
86667af9923SKostya Serebryany   DFT.Clear();  // No need for DFT any more.
86710ab2aceSGeorge Karpenkov   TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
8682eef816eSKostya Serebryany   TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
86910ab2aceSGeorge Karpenkov   system_clock::time_point LastCorpusReload = system_clock::now();
870b6ca1e72SKostya Serebryany 
871b6ca1e72SKostya Serebryany   TmpMaxMutationLen =
872b6ca1e72SKostya Serebryany       Min(MaxMutationLen, Max(size_t(4), Corpus.MaxInputSize()));
873b6ca1e72SKostya Serebryany 
87410ab2aceSGeorge Karpenkov   while (true) {
87510ab2aceSGeorge Karpenkov     auto Now = system_clock::now();
876db88fc56SKostya Serebryany     if (!Options.StopFile.empty() &&
877db88fc56SKostya Serebryany         !FileToVector(Options.StopFile, 1, false).empty())
878db88fc56SKostya Serebryany       break;
87910ab2aceSGeorge Karpenkov     if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
88010ab2aceSGeorge Karpenkov         Options.ReloadIntervalSec) {
88110ab2aceSGeorge Karpenkov       RereadOutputCorpus(MaxInputLen);
88210ab2aceSGeorge Karpenkov       LastCorpusReload = system_clock::now();
88310ab2aceSGeorge Karpenkov     }
88410ab2aceSGeorge Karpenkov     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
88510ab2aceSGeorge Karpenkov       break;
8865ded0701SAlex Shlyapnikov     if (TimedOut())
8875ded0701SAlex Shlyapnikov       break;
88810ab2aceSGeorge Karpenkov 
88910ab2aceSGeorge Karpenkov     // Update TmpMaxMutationLen
89036c89b3cSMatt Morehouse     if (Options.LenControl) {
89110ab2aceSGeorge Karpenkov       if (TmpMaxMutationLen < MaxMutationLen &&
892e9ed2327SKostya Serebryany           TotalNumberOfRuns - LastCorpusUpdateRun >
89336c89b3cSMatt Morehouse               Options.LenControl * Log(TmpMaxMutationLen)) {
89410ab2aceSGeorge Karpenkov         TmpMaxMutationLen =
895e9ed2327SKostya Serebryany             Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen));
896e9ed2327SKostya Serebryany         LastCorpusUpdateRun = TotalNumberOfRuns;
89710ab2aceSGeorge Karpenkov       }
89810ab2aceSGeorge Karpenkov     } else {
89910ab2aceSGeorge Karpenkov       TmpMaxMutationLen = MaxMutationLen;
90010ab2aceSGeorge Karpenkov     }
90110ab2aceSGeorge Karpenkov 
90210ab2aceSGeorge Karpenkov     // Perform several mutations and runs.
90310ab2aceSGeorge Karpenkov     MutateAndTestOne();
9046f1c26f2SAlex Shlyapnikov 
9056f1c26f2SAlex Shlyapnikov     PurgeAllocator();
90610ab2aceSGeorge Karpenkov   }
90710ab2aceSGeorge Karpenkov 
90810ab2aceSGeorge Karpenkov   PrintStats("DONE  ", "\n");
909c5d72517SMarco Vanotti   MD.PrintRecommendedDictionary();
91010ab2aceSGeorge Karpenkov }
91110ab2aceSGeorge Karpenkov 
MinimizeCrashLoop(const Unit & U)91210ab2aceSGeorge Karpenkov void Fuzzer::MinimizeCrashLoop(const Unit &U) {
9135ded0701SAlex Shlyapnikov   if (U.size() <= 1)
9145ded0701SAlex Shlyapnikov     return;
91510ab2aceSGeorge Karpenkov   while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
91610ab2aceSGeorge Karpenkov     MD.StartMutationSequence();
91710ab2aceSGeorge Karpenkov     memcpy(CurrentUnitData, U.data(), U.size());
91810ab2aceSGeorge Karpenkov     for (int i = 0; i < Options.MutateDepth; i++) {
91910ab2aceSGeorge Karpenkov       size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
92010ab2aceSGeorge Karpenkov       assert(NewSize > 0 && NewSize <= MaxMutationLen);
92110ab2aceSGeorge Karpenkov       ExecuteCallback(CurrentUnitData, NewSize);
92210ab2aceSGeorge Karpenkov       PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
92310ab2aceSGeorge Karpenkov       TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
92410ab2aceSGeorge Karpenkov                               /*DuringInitialCorpusExecution*/ false);
92510ab2aceSGeorge Karpenkov     }
92610ab2aceSGeorge Karpenkov   }
92710ab2aceSGeorge Karpenkov }
92810ab2aceSGeorge Karpenkov 
92910ab2aceSGeorge Karpenkov } // namespace fuzzer
93010ab2aceSGeorge Karpenkov 
93110ab2aceSGeorge Karpenkov extern "C" {
93210ab2aceSGeorge Karpenkov 
933b795c31dSJonathan Metzman ATTRIBUTE_INTERFACE size_t
LLVMFuzzerMutate(uint8_t * Data,size_t Size,size_t MaxSize)934eac2b47bSPetr Hosek LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
93510ab2aceSGeorge Karpenkov   assert(fuzzer::F);
93610ab2aceSGeorge Karpenkov   return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
93710ab2aceSGeorge Karpenkov }
93810ab2aceSGeorge Karpenkov 
93910ab2aceSGeorge Karpenkov } // extern "C"
940