xref: /openbsd-src/gnu/llvm/compiler-rt/lib/fuzzer/FuzzerLoop.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick // Fuzzer's main loop.
93cab2bb3Spatrick //===----------------------------------------------------------------------===//
103cab2bb3Spatrick 
113cab2bb3Spatrick #include "FuzzerCorpus.h"
123cab2bb3Spatrick #include "FuzzerIO.h"
133cab2bb3Spatrick #include "FuzzerInternal.h"
143cab2bb3Spatrick #include "FuzzerMutate.h"
151f9cb04fSpatrick #include "FuzzerPlatform.h"
163cab2bb3Spatrick #include "FuzzerRandom.h"
173cab2bb3Spatrick #include "FuzzerTracePC.h"
183cab2bb3Spatrick #include <algorithm>
193cab2bb3Spatrick #include <cstring>
203cab2bb3Spatrick #include <memory>
213cab2bb3Spatrick #include <mutex>
223cab2bb3Spatrick #include <set>
233cab2bb3Spatrick 
243cab2bb3Spatrick #if defined(__has_include)
253cab2bb3Spatrick #if __has_include(<sanitizer / lsan_interface.h>)
263cab2bb3Spatrick #include <sanitizer/lsan_interface.h>
273cab2bb3Spatrick #endif
283cab2bb3Spatrick #endif
293cab2bb3Spatrick 
303cab2bb3Spatrick #define NO_SANITIZE_MEMORY
313cab2bb3Spatrick #if defined(__has_feature)
323cab2bb3Spatrick #if __has_feature(memory_sanitizer)
333cab2bb3Spatrick #undef NO_SANITIZE_MEMORY
343cab2bb3Spatrick #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
353cab2bb3Spatrick #endif
363cab2bb3Spatrick #endif
373cab2bb3Spatrick 
383cab2bb3Spatrick namespace fuzzer {
393cab2bb3Spatrick static const size_t kMaxUnitSizeToPrint = 256;
403cab2bb3Spatrick 
413cab2bb3Spatrick thread_local bool Fuzzer::IsMyThread;
423cab2bb3Spatrick 
433cab2bb3Spatrick bool RunningUserCallback = false;
443cab2bb3Spatrick 
453cab2bb3Spatrick // Only one Fuzzer per process.
463cab2bb3Spatrick static Fuzzer *F;
473cab2bb3Spatrick 
483cab2bb3Spatrick // Leak detection is expensive, so we first check if there were more mallocs
493cab2bb3Spatrick // than frees (using the sanitizer malloc hooks) and only then try to call lsan.
503cab2bb3Spatrick struct MallocFreeTracer {
Startfuzzer::MallocFreeTracer513cab2bb3Spatrick   void Start(int TraceLevel) {
523cab2bb3Spatrick     this->TraceLevel = TraceLevel;
533cab2bb3Spatrick     if (TraceLevel)
543cab2bb3Spatrick       Printf("MallocFreeTracer: START\n");
553cab2bb3Spatrick     Mallocs = 0;
563cab2bb3Spatrick     Frees = 0;
573cab2bb3Spatrick   }
583cab2bb3Spatrick   // Returns true if there were more mallocs than frees.
Stopfuzzer::MallocFreeTracer593cab2bb3Spatrick   bool Stop() {
603cab2bb3Spatrick     if (TraceLevel)
613cab2bb3Spatrick       Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
623cab2bb3Spatrick              Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
633cab2bb3Spatrick     bool Result = Mallocs > Frees;
643cab2bb3Spatrick     Mallocs = 0;
653cab2bb3Spatrick     Frees = 0;
663cab2bb3Spatrick     TraceLevel = 0;
673cab2bb3Spatrick     return Result;
683cab2bb3Spatrick   }
693cab2bb3Spatrick   std::atomic<size_t> Mallocs;
703cab2bb3Spatrick   std::atomic<size_t> Frees;
713cab2bb3Spatrick   int TraceLevel = 0;
723cab2bb3Spatrick 
733cab2bb3Spatrick   std::recursive_mutex TraceMutex;
743cab2bb3Spatrick   bool TraceDisabled = false;
753cab2bb3Spatrick };
763cab2bb3Spatrick 
773cab2bb3Spatrick static MallocFreeTracer AllocTracer;
783cab2bb3Spatrick 
793cab2bb3Spatrick // Locks printing and avoids nested hooks triggered from mallocs/frees in
803cab2bb3Spatrick // sanitizer.
813cab2bb3Spatrick class TraceLock {
823cab2bb3Spatrick public:
TraceLock()833cab2bb3Spatrick   TraceLock() : Lock(AllocTracer.TraceMutex) {
843cab2bb3Spatrick     AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled;
853cab2bb3Spatrick   }
~TraceLock()863cab2bb3Spatrick   ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; }
873cab2bb3Spatrick 
IsDisabled() const883cab2bb3Spatrick   bool IsDisabled() const {
893cab2bb3Spatrick     // This is already inverted value.
903cab2bb3Spatrick     return !AllocTracer.TraceDisabled;
913cab2bb3Spatrick   }
923cab2bb3Spatrick 
933cab2bb3Spatrick private:
943cab2bb3Spatrick   std::lock_guard<std::recursive_mutex> Lock;
953cab2bb3Spatrick };
963cab2bb3Spatrick 
973cab2bb3Spatrick ATTRIBUTE_NO_SANITIZE_MEMORY
MallocHook(const volatile void * ptr,size_t size)983cab2bb3Spatrick void MallocHook(const volatile void *ptr, size_t size) {
993cab2bb3Spatrick   size_t N = AllocTracer.Mallocs++;
1003cab2bb3Spatrick   F->HandleMalloc(size);
1013cab2bb3Spatrick   if (int TraceLevel = AllocTracer.TraceLevel) {
1023cab2bb3Spatrick     TraceLock Lock;
1033cab2bb3Spatrick     if (Lock.IsDisabled())
1043cab2bb3Spatrick       return;
1053cab2bb3Spatrick     Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
1063cab2bb3Spatrick     if (TraceLevel >= 2 && EF)
1073cab2bb3Spatrick       PrintStackTrace();
1083cab2bb3Spatrick   }
1093cab2bb3Spatrick }
1103cab2bb3Spatrick 
1113cab2bb3Spatrick ATTRIBUTE_NO_SANITIZE_MEMORY
FreeHook(const volatile void * ptr)1123cab2bb3Spatrick void FreeHook(const volatile void *ptr) {
1133cab2bb3Spatrick   size_t N = AllocTracer.Frees++;
1143cab2bb3Spatrick   if (int TraceLevel = AllocTracer.TraceLevel) {
1153cab2bb3Spatrick     TraceLock Lock;
1163cab2bb3Spatrick     if (Lock.IsDisabled())
1173cab2bb3Spatrick       return;
1183cab2bb3Spatrick     Printf("FREE[%zd]   %p\n", N, ptr);
1193cab2bb3Spatrick     if (TraceLevel >= 2 && EF)
1203cab2bb3Spatrick       PrintStackTrace();
1213cab2bb3Spatrick   }
1223cab2bb3Spatrick }
1233cab2bb3Spatrick 
1243cab2bb3Spatrick // Crash on a single malloc that exceeds the rss limit.
HandleMalloc(size_t Size)1253cab2bb3Spatrick void Fuzzer::HandleMalloc(size_t Size) {
1263cab2bb3Spatrick   if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb)
1273cab2bb3Spatrick     return;
1283cab2bb3Spatrick   Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
1293cab2bb3Spatrick          Size);
1303cab2bb3Spatrick   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
1313cab2bb3Spatrick   PrintStackTrace();
1323cab2bb3Spatrick   DumpCurrentUnit("oom-");
1333cab2bb3Spatrick   Printf("SUMMARY: libFuzzer: out-of-memory\n");
1343cab2bb3Spatrick   PrintFinalStats();
1353cab2bb3Spatrick   _Exit(Options.OOMExitCode); // Stop right now.
1363cab2bb3Spatrick }
1373cab2bb3Spatrick 
Fuzzer(UserCallback CB,InputCorpus & Corpus,MutationDispatcher & MD,FuzzingOptions Options)1383cab2bb3Spatrick Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
1393cab2bb3Spatrick                FuzzingOptions Options)
1403cab2bb3Spatrick     : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
1413cab2bb3Spatrick   if (EF->__sanitizer_set_death_callback)
1423cab2bb3Spatrick     EF->__sanitizer_set_death_callback(StaticDeathCallback);
1433cab2bb3Spatrick   assert(!F);
1443cab2bb3Spatrick   F = this;
1453cab2bb3Spatrick   TPC.ResetMaps();
1463cab2bb3Spatrick   IsMyThread = true;
1473cab2bb3Spatrick   if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
1483cab2bb3Spatrick     EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
1493cab2bb3Spatrick   TPC.SetUseCounters(Options.UseCounters);
1503cab2bb3Spatrick   TPC.SetUseValueProfileMask(Options.UseValueProfile);
1513cab2bb3Spatrick 
1523cab2bb3Spatrick   if (Options.Verbosity)
1533cab2bb3Spatrick     TPC.PrintModuleInfo();
1543cab2bb3Spatrick   if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
1553cab2bb3Spatrick     EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
1563cab2bb3Spatrick   MaxInputLen = MaxMutationLen = Options.MaxLen;
1573cab2bb3Spatrick   TmpMaxMutationLen = 0;  // Will be set once we load the corpus.
1583cab2bb3Spatrick   AllocateCurrentUnitData();
1593cab2bb3Spatrick   CurrentUnitSize = 0;
1603cab2bb3Spatrick   memset(BaseSha1, 0, sizeof(BaseSha1));
1613cab2bb3Spatrick }
1623cab2bb3Spatrick 
~Fuzzer()1633cab2bb3Spatrick Fuzzer::~Fuzzer() {}
1643cab2bb3Spatrick 
AllocateCurrentUnitData()1653cab2bb3Spatrick void Fuzzer::AllocateCurrentUnitData() {
1663cab2bb3Spatrick   if (CurrentUnitData || MaxInputLen == 0)
1673cab2bb3Spatrick     return;
1683cab2bb3Spatrick   CurrentUnitData = new uint8_t[MaxInputLen];
1693cab2bb3Spatrick }
1703cab2bb3Spatrick 
StaticDeathCallback()1713cab2bb3Spatrick void Fuzzer::StaticDeathCallback() {
1723cab2bb3Spatrick   assert(F);
1733cab2bb3Spatrick   F->DeathCallback();
1743cab2bb3Spatrick }
1753cab2bb3Spatrick 
DumpCurrentUnit(const char * Prefix)1763cab2bb3Spatrick void Fuzzer::DumpCurrentUnit(const char *Prefix) {
1773cab2bb3Spatrick   if (!CurrentUnitData)
1783cab2bb3Spatrick     return; // Happens when running individual inputs.
1793cab2bb3Spatrick   ScopedDisableMsanInterceptorChecks S;
1803cab2bb3Spatrick   MD.PrintMutationSequence();
1813cab2bb3Spatrick   Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
1823cab2bb3Spatrick   size_t UnitSize = CurrentUnitSize;
1833cab2bb3Spatrick   if (UnitSize <= kMaxUnitSizeToPrint) {
1843cab2bb3Spatrick     PrintHexArray(CurrentUnitData, UnitSize, "\n");
1853cab2bb3Spatrick     PrintASCII(CurrentUnitData, UnitSize, "\n");
1863cab2bb3Spatrick   }
1873cab2bb3Spatrick   WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
1883cab2bb3Spatrick                             Prefix);
1893cab2bb3Spatrick }
1903cab2bb3Spatrick 
1913cab2bb3Spatrick NO_SANITIZE_MEMORY
DeathCallback()1923cab2bb3Spatrick void Fuzzer::DeathCallback() {
1933cab2bb3Spatrick   DumpCurrentUnit("crash-");
1943cab2bb3Spatrick   PrintFinalStats();
1953cab2bb3Spatrick }
1963cab2bb3Spatrick 
StaticAlarmCallback()1973cab2bb3Spatrick void Fuzzer::StaticAlarmCallback() {
1983cab2bb3Spatrick   assert(F);
1993cab2bb3Spatrick   F->AlarmCallback();
2003cab2bb3Spatrick }
2013cab2bb3Spatrick 
StaticCrashSignalCallback()2023cab2bb3Spatrick void Fuzzer::StaticCrashSignalCallback() {
2033cab2bb3Spatrick   assert(F);
2043cab2bb3Spatrick   F->CrashCallback();
2053cab2bb3Spatrick }
2063cab2bb3Spatrick 
StaticExitCallback()2073cab2bb3Spatrick void Fuzzer::StaticExitCallback() {
2083cab2bb3Spatrick   assert(F);
2093cab2bb3Spatrick   F->ExitCallback();
2103cab2bb3Spatrick }
2113cab2bb3Spatrick 
StaticInterruptCallback()2123cab2bb3Spatrick void Fuzzer::StaticInterruptCallback() {
2133cab2bb3Spatrick   assert(F);
2143cab2bb3Spatrick   F->InterruptCallback();
2153cab2bb3Spatrick }
2163cab2bb3Spatrick 
StaticGracefulExitCallback()2173cab2bb3Spatrick void Fuzzer::StaticGracefulExitCallback() {
2183cab2bb3Spatrick   assert(F);
2193cab2bb3Spatrick   F->GracefulExitRequested = true;
2203cab2bb3Spatrick   Printf("INFO: signal received, trying to exit gracefully\n");
2213cab2bb3Spatrick }
2223cab2bb3Spatrick 
StaticFileSizeExceedCallback()2233cab2bb3Spatrick void Fuzzer::StaticFileSizeExceedCallback() {
2243cab2bb3Spatrick   Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
2253cab2bb3Spatrick   exit(1);
2263cab2bb3Spatrick }
2273cab2bb3Spatrick 
CrashCallback()2283cab2bb3Spatrick void Fuzzer::CrashCallback() {
2293cab2bb3Spatrick   if (EF->__sanitizer_acquire_crash_state &&
2303cab2bb3Spatrick       !EF->__sanitizer_acquire_crash_state())
2313cab2bb3Spatrick     return;
2323cab2bb3Spatrick   Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
2333cab2bb3Spatrick   PrintStackTrace();
2343cab2bb3Spatrick   Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
2353cab2bb3Spatrick          "      Combine libFuzzer with AddressSanitizer or similar for better "
2363cab2bb3Spatrick          "crash reports.\n");
2373cab2bb3Spatrick   Printf("SUMMARY: libFuzzer: deadly signal\n");
2383cab2bb3Spatrick   DumpCurrentUnit("crash-");
2393cab2bb3Spatrick   PrintFinalStats();
2403cab2bb3Spatrick   _Exit(Options.ErrorExitCode); // Stop right now.
2413cab2bb3Spatrick }
2423cab2bb3Spatrick 
ExitCallback()2433cab2bb3Spatrick void Fuzzer::ExitCallback() {
2443cab2bb3Spatrick   if (!RunningUserCallback)
2453cab2bb3Spatrick     return; // This exit did not come from the user callback
2463cab2bb3Spatrick   if (EF->__sanitizer_acquire_crash_state &&
2473cab2bb3Spatrick       !EF->__sanitizer_acquire_crash_state())
2483cab2bb3Spatrick     return;
2493cab2bb3Spatrick   Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
2503cab2bb3Spatrick   PrintStackTrace();
2513cab2bb3Spatrick   Printf("SUMMARY: libFuzzer: fuzz target exited\n");
2523cab2bb3Spatrick   DumpCurrentUnit("crash-");
2533cab2bb3Spatrick   PrintFinalStats();
2543cab2bb3Spatrick   _Exit(Options.ErrorExitCode);
2553cab2bb3Spatrick }
2563cab2bb3Spatrick 
MaybeExitGracefully()2573cab2bb3Spatrick void Fuzzer::MaybeExitGracefully() {
2583cab2bb3Spatrick   if (!F->GracefulExitRequested) return;
2593cab2bb3Spatrick   Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
2601f9cb04fSpatrick   RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
2613cab2bb3Spatrick   F->PrintFinalStats();
2623cab2bb3Spatrick   _Exit(0);
2633cab2bb3Spatrick }
2643cab2bb3Spatrick 
InterruptExitCode()265*810390e3Srobert int Fuzzer::InterruptExitCode() {
266*810390e3Srobert   assert(F);
267*810390e3Srobert   return F->Options.InterruptExitCode;
268*810390e3Srobert }
269*810390e3Srobert 
InterruptCallback()2703cab2bb3Spatrick void Fuzzer::InterruptCallback() {
2713cab2bb3Spatrick   Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
2723cab2bb3Spatrick   PrintFinalStats();
2733cab2bb3Spatrick   ScopedDisableMsanInterceptorChecks S; // RmDirRecursive may call opendir().
2741f9cb04fSpatrick   RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
2753cab2bb3Spatrick   // Stop right now, don't perform any at-exit actions.
2763cab2bb3Spatrick   _Exit(Options.InterruptExitCode);
2773cab2bb3Spatrick }
2783cab2bb3Spatrick 
2793cab2bb3Spatrick NO_SANITIZE_MEMORY
AlarmCallback()2803cab2bb3Spatrick void Fuzzer::AlarmCallback() {
2813cab2bb3Spatrick   assert(Options.UnitTimeoutSec > 0);
2823cab2bb3Spatrick   // In Windows and Fuchsia, Alarm callback is executed by a different thread.
2833cab2bb3Spatrick   // NetBSD's current behavior needs this change too.
2843cab2bb3Spatrick #if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD && !LIBFUZZER_FUCHSIA
2853cab2bb3Spatrick   if (!InFuzzingThread())
2863cab2bb3Spatrick     return;
2873cab2bb3Spatrick #endif
2883cab2bb3Spatrick   if (!RunningUserCallback)
2893cab2bb3Spatrick     return; // We have not started running units yet.
2903cab2bb3Spatrick   size_t Seconds =
2913cab2bb3Spatrick       duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
2923cab2bb3Spatrick   if (Seconds == 0)
2933cab2bb3Spatrick     return;
2943cab2bb3Spatrick   if (Options.Verbosity >= 2)
2953cab2bb3Spatrick     Printf("AlarmCallback %zd\n", Seconds);
2963cab2bb3Spatrick   if (Seconds >= (size_t)Options.UnitTimeoutSec) {
2973cab2bb3Spatrick     if (EF->__sanitizer_acquire_crash_state &&
2983cab2bb3Spatrick         !EF->__sanitizer_acquire_crash_state())
2993cab2bb3Spatrick       return;
3003cab2bb3Spatrick     Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
3013cab2bb3Spatrick     Printf("       and the timeout value is %d (use -timeout=N to change)\n",
3023cab2bb3Spatrick            Options.UnitTimeoutSec);
3033cab2bb3Spatrick     DumpCurrentUnit("timeout-");
3043cab2bb3Spatrick     Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
3053cab2bb3Spatrick            Seconds);
3063cab2bb3Spatrick     PrintStackTrace();
3073cab2bb3Spatrick     Printf("SUMMARY: libFuzzer: timeout\n");
3083cab2bb3Spatrick     PrintFinalStats();
3093cab2bb3Spatrick     _Exit(Options.TimeoutExitCode); // Stop right now.
3103cab2bb3Spatrick   }
3113cab2bb3Spatrick }
3123cab2bb3Spatrick 
RssLimitCallback()3133cab2bb3Spatrick void Fuzzer::RssLimitCallback() {
3143cab2bb3Spatrick   if (EF->__sanitizer_acquire_crash_state &&
3153cab2bb3Spatrick       !EF->__sanitizer_acquire_crash_state())
3163cab2bb3Spatrick     return;
3173cab2bb3Spatrick   Printf(
3183cab2bb3Spatrick       "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
3193cab2bb3Spatrick       GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
3203cab2bb3Spatrick   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
3213cab2bb3Spatrick   PrintMemoryProfile();
3223cab2bb3Spatrick   DumpCurrentUnit("oom-");
3233cab2bb3Spatrick   Printf("SUMMARY: libFuzzer: out-of-memory\n");
3243cab2bb3Spatrick   PrintFinalStats();
3253cab2bb3Spatrick   _Exit(Options.OOMExitCode); // Stop right now.
3263cab2bb3Spatrick }
3273cab2bb3Spatrick 
PrintStats(const char * Where,const char * End,size_t Units,size_t Features)3283cab2bb3Spatrick void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units,
3293cab2bb3Spatrick                         size_t Features) {
3303cab2bb3Spatrick   size_t ExecPerSec = execPerSec();
3313cab2bb3Spatrick   if (!Options.Verbosity)
3323cab2bb3Spatrick     return;
3333cab2bb3Spatrick   Printf("#%zd\t%s", TotalNumberOfRuns, Where);
3343cab2bb3Spatrick   if (size_t N = TPC.GetTotalPCCoverage())
3353cab2bb3Spatrick     Printf(" cov: %zd", N);
3363cab2bb3Spatrick   if (size_t N = Features ? Features : Corpus.NumFeatures())
3373cab2bb3Spatrick     Printf(" ft: %zd", N);
3383cab2bb3Spatrick   if (!Corpus.empty()) {
3393cab2bb3Spatrick     Printf(" corp: %zd", Corpus.NumActiveUnits());
3403cab2bb3Spatrick     if (size_t N = Corpus.SizeInBytes()) {
3413cab2bb3Spatrick       if (N < (1 << 14))
3423cab2bb3Spatrick         Printf("/%zdb", N);
3433cab2bb3Spatrick       else if (N < (1 << 24))
3443cab2bb3Spatrick         Printf("/%zdKb", N >> 10);
3453cab2bb3Spatrick       else
3463cab2bb3Spatrick         Printf("/%zdMb", N >> 20);
3473cab2bb3Spatrick     }
3483cab2bb3Spatrick     if (size_t FF = Corpus.NumInputsThatTouchFocusFunction())
3493cab2bb3Spatrick       Printf(" focus: %zd", FF);
3503cab2bb3Spatrick   }
3513cab2bb3Spatrick   if (TmpMaxMutationLen)
3523cab2bb3Spatrick     Printf(" lim: %zd", TmpMaxMutationLen);
3533cab2bb3Spatrick   if (Units)
3543cab2bb3Spatrick     Printf(" units: %zd", Units);
3553cab2bb3Spatrick 
3563cab2bb3Spatrick   Printf(" exec/s: %zd", ExecPerSec);
3573cab2bb3Spatrick   Printf(" rss: %zdMb", GetPeakRSSMb());
3583cab2bb3Spatrick   Printf("%s", End);
3593cab2bb3Spatrick }
3603cab2bb3Spatrick 
PrintFinalStats()3613cab2bb3Spatrick void Fuzzer::PrintFinalStats() {
362d89ec533Spatrick   if (Options.PrintFullCoverage)
363d89ec533Spatrick     TPC.PrintCoverage(/*PrintAllCounters=*/true);
3643cab2bb3Spatrick   if (Options.PrintCoverage)
365d89ec533Spatrick     TPC.PrintCoverage(/*PrintAllCounters=*/false);
3663cab2bb3Spatrick   if (Options.PrintCorpusStats)
3673cab2bb3Spatrick     Corpus.PrintStats();
3683cab2bb3Spatrick   if (!Options.PrintFinalStats)
3693cab2bb3Spatrick     return;
3703cab2bb3Spatrick   size_t ExecPerSec = execPerSec();
3713cab2bb3Spatrick   Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
3723cab2bb3Spatrick   Printf("stat::average_exec_per_sec:     %zd\n", ExecPerSec);
3733cab2bb3Spatrick   Printf("stat::new_units_added:          %zd\n", NumberOfNewUnitsAdded);
3743cab2bb3Spatrick   Printf("stat::slowest_unit_time_sec:    %zd\n", TimeOfLongestUnitInSeconds);
3753cab2bb3Spatrick   Printf("stat::peak_rss_mb:              %zd\n", GetPeakRSSMb());
3763cab2bb3Spatrick }
3773cab2bb3Spatrick 
SetMaxInputLen(size_t MaxInputLen)3783cab2bb3Spatrick void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
3793cab2bb3Spatrick   assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
3803cab2bb3Spatrick   assert(MaxInputLen);
3813cab2bb3Spatrick   this->MaxInputLen = MaxInputLen;
3823cab2bb3Spatrick   this->MaxMutationLen = MaxInputLen;
3833cab2bb3Spatrick   AllocateCurrentUnitData();
3843cab2bb3Spatrick   Printf("INFO: -max_len is not provided; "
3853cab2bb3Spatrick          "libFuzzer will not generate inputs larger than %zd bytes\n",
3863cab2bb3Spatrick          MaxInputLen);
3873cab2bb3Spatrick }
3883cab2bb3Spatrick 
SetMaxMutationLen(size_t MaxMutationLen)3893cab2bb3Spatrick void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
3903cab2bb3Spatrick   assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
3913cab2bb3Spatrick   this->MaxMutationLen = MaxMutationLen;
3923cab2bb3Spatrick }
3933cab2bb3Spatrick 
CheckExitOnSrcPosOrItem()3943cab2bb3Spatrick void Fuzzer::CheckExitOnSrcPosOrItem() {
3953cab2bb3Spatrick   if (!Options.ExitOnSrcPos.empty()) {
396*810390e3Srobert     static auto *PCsSet = new std::set<uintptr_t>;
3973cab2bb3Spatrick     auto HandlePC = [&](const TracePC::PCTableEntry *TE) {
3983cab2bb3Spatrick       if (!PCsSet->insert(TE->PC).second)
3993cab2bb3Spatrick         return;
4003cab2bb3Spatrick       std::string Descr = DescribePC("%F %L", TE->PC + 1);
4013cab2bb3Spatrick       if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
4023cab2bb3Spatrick         Printf("INFO: found line matching '%s', exiting.\n",
4033cab2bb3Spatrick                Options.ExitOnSrcPos.c_str());
4043cab2bb3Spatrick         _Exit(0);
4053cab2bb3Spatrick       }
4063cab2bb3Spatrick     };
4073cab2bb3Spatrick     TPC.ForEachObservedPC(HandlePC);
4083cab2bb3Spatrick   }
4093cab2bb3Spatrick   if (!Options.ExitOnItem.empty()) {
4103cab2bb3Spatrick     if (Corpus.HasUnit(Options.ExitOnItem)) {
4113cab2bb3Spatrick       Printf("INFO: found item with checksum '%s', exiting.\n",
4123cab2bb3Spatrick              Options.ExitOnItem.c_str());
4133cab2bb3Spatrick       _Exit(0);
4143cab2bb3Spatrick     }
4153cab2bb3Spatrick   }
4163cab2bb3Spatrick }
4173cab2bb3Spatrick 
RereadOutputCorpus(size_t MaxSize)4183cab2bb3Spatrick void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
4193cab2bb3Spatrick   if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
4203cab2bb3Spatrick     return;
421*810390e3Srobert   std::vector<Unit> AdditionalCorpus;
422*810390e3Srobert   std::vector<std::string> AdditionalCorpusPaths;
423d89ec533Spatrick   ReadDirToVectorOfUnits(
424d89ec533Spatrick       Options.OutputCorpus.c_str(), &AdditionalCorpus,
4253cab2bb3Spatrick       &EpochOfLastReadOfOutputCorpus, MaxSize,
426d89ec533Spatrick       /*ExitOnError*/ false,
427d89ec533Spatrick       (Options.Verbosity >= 2 ? &AdditionalCorpusPaths : nullptr));
4283cab2bb3Spatrick   if (Options.Verbosity >= 2)
4293cab2bb3Spatrick     Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
4303cab2bb3Spatrick   bool Reloaded = false;
431d89ec533Spatrick   for (size_t i = 0; i != AdditionalCorpus.size(); ++i) {
432d89ec533Spatrick     auto &U = AdditionalCorpus[i];
4333cab2bb3Spatrick     if (U.size() > MaxSize)
4343cab2bb3Spatrick       U.resize(MaxSize);
4353cab2bb3Spatrick     if (!Corpus.HasUnit(U)) {
4363cab2bb3Spatrick       if (RunOne(U.data(), U.size())) {
4373cab2bb3Spatrick         CheckExitOnSrcPosOrItem();
4383cab2bb3Spatrick         Reloaded = true;
439d89ec533Spatrick         if (Options.Verbosity >= 2)
440d89ec533Spatrick           Printf("Reloaded %s\n", AdditionalCorpusPaths[i].c_str());
4413cab2bb3Spatrick       }
4423cab2bb3Spatrick     }
4433cab2bb3Spatrick   }
4443cab2bb3Spatrick   if (Reloaded)
4453cab2bb3Spatrick     PrintStats("RELOAD");
4463cab2bb3Spatrick }
4473cab2bb3Spatrick 
PrintPulseAndReportSlowInput(const uint8_t * Data,size_t Size)4483cab2bb3Spatrick void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
4493cab2bb3Spatrick   auto TimeOfUnit =
4503cab2bb3Spatrick       duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
4513cab2bb3Spatrick   if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
4523cab2bb3Spatrick       secondsSinceProcessStartUp() >= 2)
4533cab2bb3Spatrick     PrintStats("pulse ");
454d89ec533Spatrick   auto Threshhold =
455d89ec533Spatrick       static_cast<long>(static_cast<double>(TimeOfLongestUnitInSeconds) * 1.1);
456d89ec533Spatrick   if (TimeOfUnit > Threshhold && TimeOfUnit >= Options.ReportSlowUnits) {
4573cab2bb3Spatrick     TimeOfLongestUnitInSeconds = TimeOfUnit;
4583cab2bb3Spatrick     Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
4593cab2bb3Spatrick     WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
4603cab2bb3Spatrick   }
4613cab2bb3Spatrick }
4623cab2bb3Spatrick 
WriteFeatureSetToFile(const std::string & FeaturesDir,const std::string & FileName,const std::vector<uint32_t> & FeatureSet)4633cab2bb3Spatrick static void WriteFeatureSetToFile(const std::string &FeaturesDir,
4643cab2bb3Spatrick                                   const std::string &FileName,
465*810390e3Srobert                                   const std::vector<uint32_t> &FeatureSet) {
4663cab2bb3Spatrick   if (FeaturesDir.empty() || FeatureSet.empty()) return;
4673cab2bb3Spatrick   WriteToFile(reinterpret_cast<const uint8_t *>(FeatureSet.data()),
4683cab2bb3Spatrick               FeatureSet.size() * sizeof(FeatureSet[0]),
4693cab2bb3Spatrick               DirPlusFile(FeaturesDir, FileName));
4703cab2bb3Spatrick }
4713cab2bb3Spatrick 
RenameFeatureSetFile(const std::string & FeaturesDir,const std::string & OldFile,const std::string & NewFile)4723cab2bb3Spatrick static void RenameFeatureSetFile(const std::string &FeaturesDir,
4733cab2bb3Spatrick                                  const std::string &OldFile,
4743cab2bb3Spatrick                                  const std::string &NewFile) {
4753cab2bb3Spatrick   if (FeaturesDir.empty()) return;
4763cab2bb3Spatrick   RenameFile(DirPlusFile(FeaturesDir, OldFile),
4773cab2bb3Spatrick              DirPlusFile(FeaturesDir, NewFile));
4783cab2bb3Spatrick }
4793cab2bb3Spatrick 
WriteEdgeToMutationGraphFile(const std::string & MutationGraphFile,const InputInfo * II,const InputInfo * BaseII,const std::string & MS)480d89ec533Spatrick static void WriteEdgeToMutationGraphFile(const std::string &MutationGraphFile,
481d89ec533Spatrick                                          const InputInfo *II,
482d89ec533Spatrick                                          const InputInfo *BaseII,
483d89ec533Spatrick                                          const std::string &MS) {
484d89ec533Spatrick   if (MutationGraphFile.empty())
485d89ec533Spatrick     return;
486d89ec533Spatrick 
487d89ec533Spatrick   std::string Sha1 = Sha1ToString(II->Sha1);
488d89ec533Spatrick 
489d89ec533Spatrick   std::string OutputString;
490d89ec533Spatrick 
491d89ec533Spatrick   // Add a new vertex.
492d89ec533Spatrick   OutputString.append("\"");
493d89ec533Spatrick   OutputString.append(Sha1);
494d89ec533Spatrick   OutputString.append("\"\n");
495d89ec533Spatrick 
496d89ec533Spatrick   // Add a new edge if there is base input.
497d89ec533Spatrick   if (BaseII) {
498d89ec533Spatrick     std::string BaseSha1 = Sha1ToString(BaseII->Sha1);
499d89ec533Spatrick     OutputString.append("\"");
500d89ec533Spatrick     OutputString.append(BaseSha1);
501d89ec533Spatrick     OutputString.append("\" -> \"");
502d89ec533Spatrick     OutputString.append(Sha1);
503d89ec533Spatrick     OutputString.append("\" [label=\"");
504d89ec533Spatrick     OutputString.append(MS);
505d89ec533Spatrick     OutputString.append("\"];\n");
506d89ec533Spatrick   }
507d89ec533Spatrick 
508d89ec533Spatrick   AppendToFile(OutputString, MutationGraphFile);
509d89ec533Spatrick }
510d89ec533Spatrick 
RunOne(const uint8_t * Data,size_t Size,bool MayDeleteFile,InputInfo * II,bool ForceAddToCorpus,bool * FoundUniqFeatures)5113cab2bb3Spatrick bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
512d89ec533Spatrick                     InputInfo *II, bool ForceAddToCorpus,
513d89ec533Spatrick                     bool *FoundUniqFeatures) {
5143cab2bb3Spatrick   if (!Size)
5153cab2bb3Spatrick     return false;
516d89ec533Spatrick   // Largest input length should be INT_MAX.
517d89ec533Spatrick   assert(Size < std::numeric_limits<uint32_t>::max());
5183cab2bb3Spatrick 
519*810390e3Srobert   if(!ExecuteCallback(Data, Size)) return false;
520d89ec533Spatrick   auto TimeOfUnit = duration_cast<microseconds>(UnitStopTime - UnitStartTime);
5213cab2bb3Spatrick 
5223cab2bb3Spatrick   UniqFeatureSetTmp.clear();
5233cab2bb3Spatrick   size_t FoundUniqFeaturesOfII = 0;
5243cab2bb3Spatrick   size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
525d89ec533Spatrick   TPC.CollectFeatures([&](uint32_t Feature) {
526d89ec533Spatrick     if (Corpus.AddFeature(Feature, static_cast<uint32_t>(Size), Options.Shrink))
5273cab2bb3Spatrick       UniqFeatureSetTmp.push_back(Feature);
5281f9cb04fSpatrick     if (Options.Entropic)
5291f9cb04fSpatrick       Corpus.UpdateFeatureFrequency(II, Feature);
530d89ec533Spatrick     if (Options.ReduceInputs && II && !II->NeverReduce)
5313cab2bb3Spatrick       if (std::binary_search(II->UniqFeatureSet.begin(),
5323cab2bb3Spatrick                              II->UniqFeatureSet.end(), Feature))
5333cab2bb3Spatrick         FoundUniqFeaturesOfII++;
5343cab2bb3Spatrick   });
5353cab2bb3Spatrick   if (FoundUniqFeatures)
5363cab2bb3Spatrick     *FoundUniqFeatures = FoundUniqFeaturesOfII;
5373cab2bb3Spatrick   PrintPulseAndReportSlowInput(Data, Size);
5383cab2bb3Spatrick   size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
539d89ec533Spatrick   if (NumNewFeatures || ForceAddToCorpus) {
5403cab2bb3Spatrick     TPC.UpdateObservedPCs();
541d89ec533Spatrick     auto NewII =
542d89ec533Spatrick         Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
543d89ec533Spatrick                            TPC.ObservedFocusFunction(), ForceAddToCorpus,
544d89ec533Spatrick                            TimeOfUnit, UniqFeatureSetTmp, DFT, II);
5453cab2bb3Spatrick     WriteFeatureSetToFile(Options.FeaturesDir, Sha1ToString(NewII->Sha1),
5463cab2bb3Spatrick                           NewII->UniqFeatureSet);
547d89ec533Spatrick     WriteEdgeToMutationGraphFile(Options.MutationGraphFile, NewII, II,
548d89ec533Spatrick                                  MD.MutationSequence());
5493cab2bb3Spatrick     return true;
5503cab2bb3Spatrick   }
5513cab2bb3Spatrick   if (II && FoundUniqFeaturesOfII &&
5523cab2bb3Spatrick       II->DataFlowTraceForFocusFunction.empty() &&
5533cab2bb3Spatrick       FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
5543cab2bb3Spatrick       II->U.size() > Size) {
5553cab2bb3Spatrick     auto OldFeaturesFile = Sha1ToString(II->Sha1);
556*810390e3Srobert     Corpus.Replace(II, {Data, Data + Size}, TimeOfUnit);
5573cab2bb3Spatrick     RenameFeatureSetFile(Options.FeaturesDir, OldFeaturesFile,
5583cab2bb3Spatrick                          Sha1ToString(II->Sha1));
5593cab2bb3Spatrick     return true;
5603cab2bb3Spatrick   }
5613cab2bb3Spatrick   return false;
5623cab2bb3Spatrick }
5633cab2bb3Spatrick 
TPCUpdateObservedPCs()564d89ec533Spatrick void Fuzzer::TPCUpdateObservedPCs() { TPC.UpdateObservedPCs(); }
565d89ec533Spatrick 
GetCurrentUnitInFuzzingThead(const uint8_t ** Data) const5663cab2bb3Spatrick size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
5673cab2bb3Spatrick   assert(InFuzzingThread());
5683cab2bb3Spatrick   *Data = CurrentUnitData;
5693cab2bb3Spatrick   return CurrentUnitSize;
5703cab2bb3Spatrick }
5713cab2bb3Spatrick 
CrashOnOverwrittenData()5723cab2bb3Spatrick void Fuzzer::CrashOnOverwrittenData() {
5733cab2bb3Spatrick   Printf("==%d== ERROR: libFuzzer: fuzz target overwrites its const input\n",
5743cab2bb3Spatrick          GetPid());
5753cab2bb3Spatrick   PrintStackTrace();
5763cab2bb3Spatrick   Printf("SUMMARY: libFuzzer: overwrites-const-input\n");
5773cab2bb3Spatrick   DumpCurrentUnit("crash-");
5783cab2bb3Spatrick   PrintFinalStats();
5793cab2bb3Spatrick   _Exit(Options.ErrorExitCode); // Stop right now.
5803cab2bb3Spatrick }
5813cab2bb3Spatrick 
5823cab2bb3Spatrick // Compare two arrays, but not all bytes if the arrays are large.
LooseMemeq(const uint8_t * A,const uint8_t * B,size_t Size)5833cab2bb3Spatrick static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
5843cab2bb3Spatrick   const size_t Limit = 64;
5853cab2bb3Spatrick   if (Size <= 64)
5863cab2bb3Spatrick     return !memcmp(A, B, Size);
5873cab2bb3Spatrick   // Compare first and last Limit/2 bytes.
5883cab2bb3Spatrick   return !memcmp(A, B, Limit / 2) &&
5893cab2bb3Spatrick          !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
5903cab2bb3Spatrick }
5913cab2bb3Spatrick 
592d89ec533Spatrick // This method is not inlined because it would cause a test to fail where it
593d89ec533Spatrick // is part of the stack unwinding. See D97975 for details.
ExecuteCallback(const uint8_t * Data,size_t Size)594*810390e3Srobert ATTRIBUTE_NOINLINE bool Fuzzer::ExecuteCallback(const uint8_t *Data,
595d89ec533Spatrick                                                 size_t Size) {
5963cab2bb3Spatrick   TPC.RecordInitialStack();
5973cab2bb3Spatrick   TotalNumberOfRuns++;
5983cab2bb3Spatrick   assert(InFuzzingThread());
5993cab2bb3Spatrick   // We copy the contents of Unit into a separate heap buffer
6003cab2bb3Spatrick   // so that we reliably find buffer overflows in it.
6013cab2bb3Spatrick   uint8_t *DataCopy = new uint8_t[Size];
6023cab2bb3Spatrick   memcpy(DataCopy, Data, Size);
6033cab2bb3Spatrick   if (EF->__msan_unpoison)
6043cab2bb3Spatrick     EF->__msan_unpoison(DataCopy, Size);
6053cab2bb3Spatrick   if (EF->__msan_unpoison_param)
6063cab2bb3Spatrick     EF->__msan_unpoison_param(2);
6073cab2bb3Spatrick   if (CurrentUnitData && CurrentUnitData != Data)
6083cab2bb3Spatrick     memcpy(CurrentUnitData, Data, Size);
6093cab2bb3Spatrick   CurrentUnitSize = Size;
610*810390e3Srobert   int CBRes = 0;
6113cab2bb3Spatrick   {
6123cab2bb3Spatrick     ScopedEnableMsanInterceptorChecks S;
6133cab2bb3Spatrick     AllocTracer.Start(Options.TraceMalloc);
6143cab2bb3Spatrick     UnitStartTime = system_clock::now();
6153cab2bb3Spatrick     TPC.ResetMaps();
6163cab2bb3Spatrick     RunningUserCallback = true;
617*810390e3Srobert     CBRes = CB(DataCopy, Size);
6183cab2bb3Spatrick     RunningUserCallback = false;
6193cab2bb3Spatrick     UnitStopTime = system_clock::now();
620*810390e3Srobert     assert(CBRes == 0 || CBRes == -1);
6213cab2bb3Spatrick     HasMoreMallocsThanFrees = AllocTracer.Stop();
6223cab2bb3Spatrick   }
6233cab2bb3Spatrick   if (!LooseMemeq(DataCopy, Data, Size))
6243cab2bb3Spatrick     CrashOnOverwrittenData();
6253cab2bb3Spatrick   CurrentUnitSize = 0;
6263cab2bb3Spatrick   delete[] DataCopy;
627*810390e3Srobert   return CBRes == 0;
6283cab2bb3Spatrick }
6293cab2bb3Spatrick 
WriteToOutputCorpus(const Unit & U)6303cab2bb3Spatrick std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
6313cab2bb3Spatrick   if (Options.OnlyASCII)
6323cab2bb3Spatrick     assert(IsASCII(U));
6333cab2bb3Spatrick   if (Options.OutputCorpus.empty())
6343cab2bb3Spatrick     return "";
6353cab2bb3Spatrick   std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
6363cab2bb3Spatrick   WriteToFile(U, Path);
6373cab2bb3Spatrick   if (Options.Verbosity >= 2)
6383cab2bb3Spatrick     Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
6393cab2bb3Spatrick   return Path;
6403cab2bb3Spatrick }
6413cab2bb3Spatrick 
WriteUnitToFileWithPrefix(const Unit & U,const char * Prefix)6423cab2bb3Spatrick void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
6433cab2bb3Spatrick   if (!Options.SaveArtifacts)
6443cab2bb3Spatrick     return;
6453cab2bb3Spatrick   std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
6463cab2bb3Spatrick   if (!Options.ExactArtifactPath.empty())
6473cab2bb3Spatrick     Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
6483cab2bb3Spatrick   WriteToFile(U, Path);
6493cab2bb3Spatrick   Printf("artifact_prefix='%s'; Test unit written to %s\n",
6503cab2bb3Spatrick          Options.ArtifactPrefix.c_str(), Path.c_str());
6513cab2bb3Spatrick   if (U.size() <= kMaxUnitSizeToPrint)
6523cab2bb3Spatrick     Printf("Base64: %s\n", Base64(U).c_str());
6533cab2bb3Spatrick }
6543cab2bb3Spatrick 
PrintStatusForNewUnit(const Unit & U,const char * Text)6553cab2bb3Spatrick void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
6563cab2bb3Spatrick   if (!Options.PrintNEW)
6573cab2bb3Spatrick     return;
6583cab2bb3Spatrick   PrintStats(Text, "");
6593cab2bb3Spatrick   if (Options.Verbosity) {
6603cab2bb3Spatrick     Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
661d89ec533Spatrick     MD.PrintMutationSequence(Options.Verbosity >= 2);
6623cab2bb3Spatrick     Printf("\n");
6633cab2bb3Spatrick   }
6643cab2bb3Spatrick }
6653cab2bb3Spatrick 
ReportNewCoverage(InputInfo * II,const Unit & U)6663cab2bb3Spatrick void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
6673cab2bb3Spatrick   II->NumSuccessfullMutations++;
6683cab2bb3Spatrick   MD.RecordSuccessfulMutationSequence();
6693cab2bb3Spatrick   PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW   ");
6703cab2bb3Spatrick   WriteToOutputCorpus(U);
6713cab2bb3Spatrick   NumberOfNewUnitsAdded++;
6723cab2bb3Spatrick   CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
6733cab2bb3Spatrick   LastCorpusUpdateRun = TotalNumberOfRuns;
6743cab2bb3Spatrick }
6753cab2bb3Spatrick 
6763cab2bb3Spatrick // Tries detecting a memory leak on the particular input that we have just
6773cab2bb3Spatrick // executed before calling this function.
TryDetectingAMemoryLeak(const uint8_t * Data,size_t Size,bool DuringInitialCorpusExecution)6783cab2bb3Spatrick void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
6793cab2bb3Spatrick                                      bool DuringInitialCorpusExecution) {
6803cab2bb3Spatrick   if (!HasMoreMallocsThanFrees)
6813cab2bb3Spatrick     return; // mallocs==frees, a leak is unlikely.
6823cab2bb3Spatrick   if (!Options.DetectLeaks)
6833cab2bb3Spatrick     return;
6843cab2bb3Spatrick   if (!DuringInitialCorpusExecution &&
6853cab2bb3Spatrick       TotalNumberOfRuns >= Options.MaxNumberOfRuns)
6863cab2bb3Spatrick     return;
6873cab2bb3Spatrick   if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
6883cab2bb3Spatrick       !(EF->__lsan_do_recoverable_leak_check))
6893cab2bb3Spatrick     return; // No lsan.
6903cab2bb3Spatrick   // Run the target once again, but with lsan disabled so that if there is
6913cab2bb3Spatrick   // a real leak we do not report it twice.
6923cab2bb3Spatrick   EF->__lsan_disable();
6933cab2bb3Spatrick   ExecuteCallback(Data, Size);
6943cab2bb3Spatrick   EF->__lsan_enable();
6953cab2bb3Spatrick   if (!HasMoreMallocsThanFrees)
6963cab2bb3Spatrick     return; // a leak is unlikely.
6973cab2bb3Spatrick   if (NumberOfLeakDetectionAttempts++ > 1000) {
6983cab2bb3Spatrick     Options.DetectLeaks = false;
6993cab2bb3Spatrick     Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
7003cab2bb3Spatrick            "      Most likely the target function accumulates allocated\n"
7013cab2bb3Spatrick            "      memory in a global state w/o actually leaking it.\n"
7023cab2bb3Spatrick            "      You may try running this binary with -trace_malloc=[12]"
7033cab2bb3Spatrick            "      to get a trace of mallocs and frees.\n"
7043cab2bb3Spatrick            "      If LeakSanitizer is enabled in this process it will still\n"
7053cab2bb3Spatrick            "      run on the process shutdown.\n");
7063cab2bb3Spatrick     return;
7073cab2bb3Spatrick   }
7083cab2bb3Spatrick   // Now perform the actual lsan pass. This is expensive and we must ensure
7093cab2bb3Spatrick   // we don't call it too often.
7103cab2bb3Spatrick   if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
7113cab2bb3Spatrick     if (DuringInitialCorpusExecution)
7123cab2bb3Spatrick       Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
7133cab2bb3Spatrick     Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
7143cab2bb3Spatrick     CurrentUnitSize = Size;
7153cab2bb3Spatrick     DumpCurrentUnit("leak-");
7163cab2bb3Spatrick     PrintFinalStats();
7173cab2bb3Spatrick     _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
7183cab2bb3Spatrick   }
7193cab2bb3Spatrick }
7203cab2bb3Spatrick 
MutateAndTestOne()7213cab2bb3Spatrick void Fuzzer::MutateAndTestOne() {
7223cab2bb3Spatrick   MD.StartMutationSequence();
7233cab2bb3Spatrick 
7243cab2bb3Spatrick   auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
725d89ec533Spatrick   if (Options.DoCrossOver) {
726d89ec533Spatrick     auto &CrossOverII = Corpus.ChooseUnitToCrossOverWith(
727d89ec533Spatrick         MD.GetRand(), Options.CrossOverUniformDist);
728d89ec533Spatrick     MD.SetCrossOverWith(&CrossOverII.U);
729d89ec533Spatrick   }
7303cab2bb3Spatrick   const auto &U = II.U;
7313cab2bb3Spatrick   memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
7323cab2bb3Spatrick   assert(CurrentUnitData);
7333cab2bb3Spatrick   size_t Size = U.size();
7343cab2bb3Spatrick   assert(Size <= MaxInputLen && "Oversized Unit");
7353cab2bb3Spatrick   memcpy(CurrentUnitData, U.data(), Size);
7363cab2bb3Spatrick 
7373cab2bb3Spatrick   assert(MaxMutationLen > 0);
7383cab2bb3Spatrick 
7393cab2bb3Spatrick   size_t CurrentMaxMutationLen =
7403cab2bb3Spatrick       Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
7413cab2bb3Spatrick   assert(CurrentMaxMutationLen > 0);
7423cab2bb3Spatrick 
7433cab2bb3Spatrick   for (int i = 0; i < Options.MutateDepth; i++) {
7443cab2bb3Spatrick     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
7453cab2bb3Spatrick       break;
7463cab2bb3Spatrick     MaybeExitGracefully();
7473cab2bb3Spatrick     size_t NewSize = 0;
7483cab2bb3Spatrick     if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() &&
7493cab2bb3Spatrick         Size <= CurrentMaxMutationLen)
7503cab2bb3Spatrick       NewSize = MD.MutateWithMask(CurrentUnitData, Size, Size,
7513cab2bb3Spatrick                                   II.DataFlowTraceForFocusFunction);
7523cab2bb3Spatrick 
7533cab2bb3Spatrick     // If MutateWithMask either failed or wasn't called, call default Mutate.
7543cab2bb3Spatrick     if (!NewSize)
7553cab2bb3Spatrick       NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
7563cab2bb3Spatrick     assert(NewSize > 0 && "Mutator returned empty unit");
7573cab2bb3Spatrick     assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
7583cab2bb3Spatrick     Size = NewSize;
7593cab2bb3Spatrick     II.NumExecutedMutations++;
7601f9cb04fSpatrick     Corpus.IncrementNumExecutedMutations();
7613cab2bb3Spatrick 
7623cab2bb3Spatrick     bool FoundUniqFeatures = false;
7633cab2bb3Spatrick     bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II,
764d89ec533Spatrick                          /*ForceAddToCorpus*/ false, &FoundUniqFeatures);
7653cab2bb3Spatrick     TryDetectingAMemoryLeak(CurrentUnitData, Size,
7663cab2bb3Spatrick                             /*DuringInitialCorpusExecution*/ false);
7673cab2bb3Spatrick     if (NewCov) {
7683cab2bb3Spatrick       ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
7693cab2bb3Spatrick       break;  // We will mutate this input more in the next rounds.
7703cab2bb3Spatrick     }
7713cab2bb3Spatrick     if (Options.ReduceDepth && !FoundUniqFeatures)
7723cab2bb3Spatrick       break;
7733cab2bb3Spatrick   }
7741f9cb04fSpatrick 
7751f9cb04fSpatrick   II.NeedsEnergyUpdate = true;
7763cab2bb3Spatrick }
7773cab2bb3Spatrick 
PurgeAllocator()7783cab2bb3Spatrick void Fuzzer::PurgeAllocator() {
7793cab2bb3Spatrick   if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
7803cab2bb3Spatrick     return;
7813cab2bb3Spatrick   if (duration_cast<seconds>(system_clock::now() -
7823cab2bb3Spatrick                              LastAllocatorPurgeAttemptTime)
7833cab2bb3Spatrick           .count() < Options.PurgeAllocatorIntervalSec)
7843cab2bb3Spatrick     return;
7853cab2bb3Spatrick 
7863cab2bb3Spatrick   if (Options.RssLimitMb <= 0 ||
7873cab2bb3Spatrick       GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
7883cab2bb3Spatrick     EF->__sanitizer_purge_allocator();
7893cab2bb3Spatrick 
7903cab2bb3Spatrick   LastAllocatorPurgeAttemptTime = system_clock::now();
7913cab2bb3Spatrick }
7923cab2bb3Spatrick 
ReadAndExecuteSeedCorpora(std::vector<SizedFile> & CorporaFiles)793*810390e3Srobert void Fuzzer::ReadAndExecuteSeedCorpora(std::vector<SizedFile> &CorporaFiles) {
7943cab2bb3Spatrick   const size_t kMaxSaneLen = 1 << 20;
7953cab2bb3Spatrick   const size_t kMinDefaultLen = 4096;
7963cab2bb3Spatrick   size_t MaxSize = 0;
7973cab2bb3Spatrick   size_t MinSize = -1;
7983cab2bb3Spatrick   size_t TotalSize = 0;
7993cab2bb3Spatrick   for (auto &File : CorporaFiles) {
8003cab2bb3Spatrick     MaxSize = Max(File.Size, MaxSize);
8013cab2bb3Spatrick     MinSize = Min(File.Size, MinSize);
8023cab2bb3Spatrick     TotalSize += File.Size;
8033cab2bb3Spatrick   }
8043cab2bb3Spatrick   if (Options.MaxLen == 0)
8053cab2bb3Spatrick     SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
8063cab2bb3Spatrick   assert(MaxInputLen > 0);
8073cab2bb3Spatrick 
8083cab2bb3Spatrick   // Test the callback with empty input and never try it again.
8093cab2bb3Spatrick   uint8_t dummy = 0;
8103cab2bb3Spatrick   ExecuteCallback(&dummy, 0);
8113cab2bb3Spatrick 
8123cab2bb3Spatrick   if (CorporaFiles.empty()) {
8133cab2bb3Spatrick     Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
8143cab2bb3Spatrick     Unit U({'\n'}); // Valid ASCII input.
8153cab2bb3Spatrick     RunOne(U.data(), U.size());
8163cab2bb3Spatrick   } else {
8173cab2bb3Spatrick     Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
8183cab2bb3Spatrick            " rss: %zdMb\n",
8193cab2bb3Spatrick            CorporaFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
8203cab2bb3Spatrick     if (Options.ShuffleAtStartUp)
8213cab2bb3Spatrick       std::shuffle(CorporaFiles.begin(), CorporaFiles.end(), MD.GetRand());
8223cab2bb3Spatrick 
8233cab2bb3Spatrick     if (Options.PreferSmall) {
8243cab2bb3Spatrick       std::stable_sort(CorporaFiles.begin(), CorporaFiles.end());
8253cab2bb3Spatrick       assert(CorporaFiles.front().Size <= CorporaFiles.back().Size);
8263cab2bb3Spatrick     }
8273cab2bb3Spatrick 
8283cab2bb3Spatrick     // Load and execute inputs one by one.
8293cab2bb3Spatrick     for (auto &SF : CorporaFiles) {
8303cab2bb3Spatrick       auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
8313cab2bb3Spatrick       assert(U.size() <= MaxInputLen);
832d89ec533Spatrick       RunOne(U.data(), U.size(), /*MayDeleteFile*/ false, /*II*/ nullptr,
833d89ec533Spatrick              /*ForceAddToCorpus*/ Options.KeepSeed,
834d89ec533Spatrick              /*FoundUniqFeatures*/ nullptr);
8353cab2bb3Spatrick       CheckExitOnSrcPosOrItem();
8363cab2bb3Spatrick       TryDetectingAMemoryLeak(U.data(), U.size(),
8373cab2bb3Spatrick                               /*DuringInitialCorpusExecution*/ true);
8383cab2bb3Spatrick     }
8393cab2bb3Spatrick   }
8403cab2bb3Spatrick 
8413cab2bb3Spatrick   PrintStats("INITED");
8421f9cb04fSpatrick   if (!Options.FocusFunction.empty()) {
8433cab2bb3Spatrick     Printf("INFO: %zd/%zd inputs touch the focus function\n",
8443cab2bb3Spatrick            Corpus.NumInputsThatTouchFocusFunction(), Corpus.size());
8453cab2bb3Spatrick     if (!Options.DataFlowTrace.empty())
8463cab2bb3Spatrick       Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n",
8471f9cb04fSpatrick              Corpus.NumInputsWithDataFlowTrace(),
8481f9cb04fSpatrick              Corpus.NumInputsThatTouchFocusFunction());
8491f9cb04fSpatrick   }
8503cab2bb3Spatrick 
8513cab2bb3Spatrick   if (Corpus.empty() && Options.MaxNumberOfRuns) {
852*810390e3Srobert     Printf("WARNING: no interesting inputs were found so far. "
853*810390e3Srobert            "Is the code instrumented for coverage?\n"
854*810390e3Srobert            "This may also happen if the target rejected all inputs we tried so "
855*810390e3Srobert            "far\n");
856*810390e3Srobert     // The remaining logic requires that the corpus is not empty,
857*810390e3Srobert     // so we add one fake input to the in-memory corpus.
858*810390e3Srobert     Corpus.AddToCorpus({'\n'}, /*NumFeatures=*/1, /*MayDeleteFile=*/true,
859*810390e3Srobert                        /*HasFocusFunction=*/false, /*NeverReduce=*/false,
860*810390e3Srobert                        /*TimeOfUnit=*/duration_cast<microseconds>(0s), {0}, DFT,
861*810390e3Srobert                        /*BaseII*/ nullptr);
8623cab2bb3Spatrick   }
8633cab2bb3Spatrick }
8643cab2bb3Spatrick 
Loop(std::vector<SizedFile> & CorporaFiles)865*810390e3Srobert void Fuzzer::Loop(std::vector<SizedFile> &CorporaFiles) {
8663cab2bb3Spatrick   auto FocusFunctionOrAuto = Options.FocusFunction;
8673cab2bb3Spatrick   DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles,
8683cab2bb3Spatrick            MD.GetRand());
8693cab2bb3Spatrick   TPC.SetFocusFunction(FocusFunctionOrAuto);
8703cab2bb3Spatrick   ReadAndExecuteSeedCorpora(CorporaFiles);
8713cab2bb3Spatrick   DFT.Clear();  // No need for DFT any more.
8723cab2bb3Spatrick   TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
8733cab2bb3Spatrick   TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
8743cab2bb3Spatrick   system_clock::time_point LastCorpusReload = system_clock::now();
8753cab2bb3Spatrick 
8763cab2bb3Spatrick   TmpMaxMutationLen =
8773cab2bb3Spatrick       Min(MaxMutationLen, Max(size_t(4), Corpus.MaxInputSize()));
8783cab2bb3Spatrick 
8793cab2bb3Spatrick   while (true) {
8803cab2bb3Spatrick     auto Now = system_clock::now();
8813cab2bb3Spatrick     if (!Options.StopFile.empty() &&
8823cab2bb3Spatrick         !FileToVector(Options.StopFile, 1, false).empty())
8833cab2bb3Spatrick       break;
8843cab2bb3Spatrick     if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
8853cab2bb3Spatrick         Options.ReloadIntervalSec) {
8863cab2bb3Spatrick       RereadOutputCorpus(MaxInputLen);
8873cab2bb3Spatrick       LastCorpusReload = system_clock::now();
8883cab2bb3Spatrick     }
8893cab2bb3Spatrick     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
8903cab2bb3Spatrick       break;
8913cab2bb3Spatrick     if (TimedOut())
8923cab2bb3Spatrick       break;
8933cab2bb3Spatrick 
8943cab2bb3Spatrick     // Update TmpMaxMutationLen
8953cab2bb3Spatrick     if (Options.LenControl) {
8963cab2bb3Spatrick       if (TmpMaxMutationLen < MaxMutationLen &&
8973cab2bb3Spatrick           TotalNumberOfRuns - LastCorpusUpdateRun >
8983cab2bb3Spatrick               Options.LenControl * Log(TmpMaxMutationLen)) {
8993cab2bb3Spatrick         TmpMaxMutationLen =
9003cab2bb3Spatrick             Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen));
9013cab2bb3Spatrick         LastCorpusUpdateRun = TotalNumberOfRuns;
9023cab2bb3Spatrick       }
9033cab2bb3Spatrick     } else {
9043cab2bb3Spatrick       TmpMaxMutationLen = MaxMutationLen;
9053cab2bb3Spatrick     }
9063cab2bb3Spatrick 
9073cab2bb3Spatrick     // Perform several mutations and runs.
9083cab2bb3Spatrick     MutateAndTestOne();
9093cab2bb3Spatrick 
9103cab2bb3Spatrick     PurgeAllocator();
9113cab2bb3Spatrick   }
9123cab2bb3Spatrick 
9133cab2bb3Spatrick   PrintStats("DONE  ", "\n");
9143cab2bb3Spatrick   MD.PrintRecommendedDictionary();
9153cab2bb3Spatrick }
9163cab2bb3Spatrick 
MinimizeCrashLoop(const Unit & U)9173cab2bb3Spatrick void Fuzzer::MinimizeCrashLoop(const Unit &U) {
9183cab2bb3Spatrick   if (U.size() <= 1)
9193cab2bb3Spatrick     return;
9203cab2bb3Spatrick   while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
9213cab2bb3Spatrick     MD.StartMutationSequence();
9223cab2bb3Spatrick     memcpy(CurrentUnitData, U.data(), U.size());
9233cab2bb3Spatrick     for (int i = 0; i < Options.MutateDepth; i++) {
9243cab2bb3Spatrick       size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
9253cab2bb3Spatrick       assert(NewSize > 0 && NewSize <= MaxMutationLen);
9263cab2bb3Spatrick       ExecuteCallback(CurrentUnitData, NewSize);
9273cab2bb3Spatrick       PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
9283cab2bb3Spatrick       TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
9293cab2bb3Spatrick                               /*DuringInitialCorpusExecution*/ false);
9303cab2bb3Spatrick     }
9313cab2bb3Spatrick   }
9323cab2bb3Spatrick }
9333cab2bb3Spatrick 
9343cab2bb3Spatrick } // namespace fuzzer
9353cab2bb3Spatrick 
9363cab2bb3Spatrick extern "C" {
9373cab2bb3Spatrick 
9383cab2bb3Spatrick ATTRIBUTE_INTERFACE size_t
LLVMFuzzerMutate(uint8_t * Data,size_t Size,size_t MaxSize)9393cab2bb3Spatrick LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
9403cab2bb3Spatrick   assert(fuzzer::F);
9413cab2bb3Spatrick   return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
9423cab2bb3Spatrick }
9433cab2bb3Spatrick 
9443cab2bb3Spatrick } // extern "C"
945