110ab2aceSGeorge Karpenkov //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
210ab2aceSGeorge Karpenkov //
310ab2aceSGeorge Karpenkov //                     The LLVM Compiler Infrastructure
410ab2aceSGeorge Karpenkov //
510ab2aceSGeorge Karpenkov // This file is distributed under the University of Illinois Open Source
610ab2aceSGeorge Karpenkov // License. See LICENSE.TXT for details.
710ab2aceSGeorge Karpenkov //
810ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
910ab2aceSGeorge Karpenkov // Fuzzer's main loop.
1010ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1110ab2aceSGeorge Karpenkov 
1210ab2aceSGeorge Karpenkov #include "FuzzerCorpus.h"
1310ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1410ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
1510ab2aceSGeorge Karpenkov #include "FuzzerMutate.h"
1610ab2aceSGeorge Karpenkov #include "FuzzerRandom.h"
1710ab2aceSGeorge Karpenkov #include "FuzzerShmem.h"
1810ab2aceSGeorge Karpenkov #include "FuzzerTracePC.h"
1910ab2aceSGeorge Karpenkov #include <algorithm>
2010ab2aceSGeorge Karpenkov #include <cstring>
2110ab2aceSGeorge Karpenkov #include <memory>
227dbc1d84SVitaly Buka #include <mutex>
2310ab2aceSGeorge Karpenkov #include <set>
2410ab2aceSGeorge Karpenkov 
2510ab2aceSGeorge Karpenkov #if defined(__has_include)
2610ab2aceSGeorge Karpenkov #if __has_include(<sanitizer / lsan_interface.h>)
2710ab2aceSGeorge Karpenkov #include <sanitizer/lsan_interface.h>
2810ab2aceSGeorge Karpenkov #endif
2910ab2aceSGeorge Karpenkov #endif
3010ab2aceSGeorge Karpenkov 
3110ab2aceSGeorge Karpenkov #define NO_SANITIZE_MEMORY
3210ab2aceSGeorge Karpenkov #if defined(__has_feature)
3310ab2aceSGeorge Karpenkov #if __has_feature(memory_sanitizer)
3410ab2aceSGeorge Karpenkov #undef NO_SANITIZE_MEMORY
3510ab2aceSGeorge Karpenkov #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
3610ab2aceSGeorge Karpenkov #endif
3710ab2aceSGeorge Karpenkov #endif
3810ab2aceSGeorge Karpenkov 
3910ab2aceSGeorge Karpenkov namespace fuzzer {
4010ab2aceSGeorge Karpenkov static const size_t kMaxUnitSizeToPrint = 256;
4110ab2aceSGeorge Karpenkov 
4210ab2aceSGeorge Karpenkov thread_local bool Fuzzer::IsMyThread;
4310ab2aceSGeorge Karpenkov 
4410ab2aceSGeorge Karpenkov SharedMemoryRegion SMR;
4510ab2aceSGeorge Karpenkov 
4610ab2aceSGeorge Karpenkov // Only one Fuzzer per process.
4710ab2aceSGeorge Karpenkov static Fuzzer *F;
4810ab2aceSGeorge Karpenkov 
4910ab2aceSGeorge Karpenkov // Leak detection is expensive, so we first check if there were more mallocs
5010ab2aceSGeorge Karpenkov // than frees (using the sanitizer malloc hooks) and only then try to call lsan.
5110ab2aceSGeorge Karpenkov struct MallocFreeTracer {
5210ab2aceSGeorge Karpenkov   void Start(int TraceLevel) {
5310ab2aceSGeorge Karpenkov     this->TraceLevel = TraceLevel;
5410ab2aceSGeorge Karpenkov     if (TraceLevel)
5510ab2aceSGeorge Karpenkov       Printf("MallocFreeTracer: START\n");
5610ab2aceSGeorge Karpenkov     Mallocs = 0;
5710ab2aceSGeorge Karpenkov     Frees = 0;
5810ab2aceSGeorge Karpenkov   }
5910ab2aceSGeorge Karpenkov   // Returns true if there were more mallocs than frees.
6010ab2aceSGeorge Karpenkov   bool Stop() {
6110ab2aceSGeorge Karpenkov     if (TraceLevel)
6210ab2aceSGeorge Karpenkov       Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
6310ab2aceSGeorge Karpenkov              Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
6410ab2aceSGeorge Karpenkov     bool Result = Mallocs > Frees;
6510ab2aceSGeorge Karpenkov     Mallocs = 0;
6610ab2aceSGeorge Karpenkov     Frees = 0;
6710ab2aceSGeorge Karpenkov     TraceLevel = 0;
6810ab2aceSGeorge Karpenkov     return Result;
6910ab2aceSGeorge Karpenkov   }
7010ab2aceSGeorge Karpenkov   std::atomic<size_t> Mallocs;
7110ab2aceSGeorge Karpenkov   std::atomic<size_t> Frees;
7210ab2aceSGeorge Karpenkov   int TraceLevel = 0;
737d22324bSVitaly Buka 
747d22324bSVitaly Buka   std::recursive_mutex TraceMutex;
757d22324bSVitaly Buka   bool TraceDisabled = false;
7610ab2aceSGeorge Karpenkov };
7710ab2aceSGeorge Karpenkov 
7810ab2aceSGeorge Karpenkov static MallocFreeTracer AllocTracer;
7910ab2aceSGeorge Karpenkov 
807d22324bSVitaly Buka // Locks printing and avoids nested hooks triggered from mallocs/frees in
817d22324bSVitaly Buka // sanitizer.
827d22324bSVitaly Buka class TraceLock {
837d22324bSVitaly Buka public:
847d22324bSVitaly Buka   TraceLock() : Lock(AllocTracer.TraceMutex) {
857d22324bSVitaly Buka     AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled;
867d22324bSVitaly Buka   }
877d22324bSVitaly Buka   ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; }
887d22324bSVitaly Buka 
897d22324bSVitaly Buka   bool IsDisabled() const {
907d22324bSVitaly Buka     // This is already inverted value.
917d22324bSVitaly Buka     return !AllocTracer.TraceDisabled;
927d22324bSVitaly Buka   }
937d22324bSVitaly Buka 
947d22324bSVitaly Buka private:
957d22324bSVitaly Buka   std::lock_guard<std::recursive_mutex> Lock;
967d22324bSVitaly Buka };
977dbc1d84SVitaly Buka 
9810ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY
9910ab2aceSGeorge Karpenkov void MallocHook(const volatile void *ptr, size_t size) {
10010ab2aceSGeorge Karpenkov   size_t N = AllocTracer.Mallocs++;
10110ab2aceSGeorge Karpenkov   F->HandleMalloc(size);
10210ab2aceSGeorge Karpenkov   if (int TraceLevel = AllocTracer.TraceLevel) {
1037d22324bSVitaly Buka     TraceLock Lock;
1047d22324bSVitaly Buka     if (Lock.IsDisabled())
1057d22324bSVitaly Buka       return;
10610ab2aceSGeorge Karpenkov     Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
10710ab2aceSGeorge Karpenkov     if (TraceLevel >= 2 && EF)
10810ab2aceSGeorge Karpenkov       EF->__sanitizer_print_stack_trace();
10910ab2aceSGeorge Karpenkov   }
11010ab2aceSGeorge Karpenkov }
11110ab2aceSGeorge Karpenkov 
11210ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY
11310ab2aceSGeorge Karpenkov void FreeHook(const volatile void *ptr) {
11410ab2aceSGeorge Karpenkov   size_t N = AllocTracer.Frees++;
11510ab2aceSGeorge Karpenkov   if (int TraceLevel = AllocTracer.TraceLevel) {
1167d22324bSVitaly Buka     TraceLock Lock;
1177d22324bSVitaly Buka     if (Lock.IsDisabled())
1187d22324bSVitaly Buka       return;
11910ab2aceSGeorge Karpenkov     Printf("FREE[%zd]   %p\n", N, ptr);
12010ab2aceSGeorge Karpenkov     if (TraceLevel >= 2 && EF)
12110ab2aceSGeorge Karpenkov       EF->__sanitizer_print_stack_trace();
12210ab2aceSGeorge Karpenkov   }
12310ab2aceSGeorge Karpenkov }
12410ab2aceSGeorge Karpenkov 
12510ab2aceSGeorge Karpenkov // Crash on a single malloc that exceeds the rss limit.
12610ab2aceSGeorge Karpenkov void Fuzzer::HandleMalloc(size_t Size) {
12710ab2aceSGeorge Karpenkov   if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb)
12810ab2aceSGeorge Karpenkov     return;
12910ab2aceSGeorge Karpenkov   Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
13010ab2aceSGeorge Karpenkov          Size);
13110ab2aceSGeorge Karpenkov   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
13210ab2aceSGeorge Karpenkov   if (EF->__sanitizer_print_stack_trace)
13310ab2aceSGeorge Karpenkov     EF->__sanitizer_print_stack_trace();
13410ab2aceSGeorge Karpenkov   DumpCurrentUnit("oom-");
13510ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: out-of-memory\n");
13610ab2aceSGeorge Karpenkov   PrintFinalStats();
13710ab2aceSGeorge Karpenkov   _Exit(Options.ErrorExitCode); // Stop right now.
13810ab2aceSGeorge Karpenkov }
13910ab2aceSGeorge Karpenkov 
14010ab2aceSGeorge Karpenkov Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
14110ab2aceSGeorge Karpenkov                FuzzingOptions Options)
14210ab2aceSGeorge Karpenkov     : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
14310ab2aceSGeorge Karpenkov   if (EF->__sanitizer_set_death_callback)
14410ab2aceSGeorge Karpenkov     EF->__sanitizer_set_death_callback(StaticDeathCallback);
14510ab2aceSGeorge Karpenkov   assert(!F);
14610ab2aceSGeorge Karpenkov   F = this;
14710ab2aceSGeorge Karpenkov   TPC.ResetMaps();
14810ab2aceSGeorge Karpenkov   IsMyThread = true;
14910ab2aceSGeorge Karpenkov   if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
15010ab2aceSGeorge Karpenkov     EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
15110ab2aceSGeorge Karpenkov   TPC.SetUseCounters(Options.UseCounters);
15210ab2aceSGeorge Karpenkov   TPC.SetUseValueProfile(Options.UseValueProfile);
153330496c3SMax Moroz   TPC.SetUseClangCoverage(Options.UseClangCoverage);
15410ab2aceSGeorge Karpenkov 
15510ab2aceSGeorge Karpenkov   if (Options.Verbosity)
15610ab2aceSGeorge Karpenkov     TPC.PrintModuleInfo();
15710ab2aceSGeorge Karpenkov   if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
15810ab2aceSGeorge Karpenkov     EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
15910ab2aceSGeorge Karpenkov   MaxInputLen = MaxMutationLen = Options.MaxLen;
16010ab2aceSGeorge Karpenkov   TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize());
16110ab2aceSGeorge Karpenkov   AllocateCurrentUnitData();
16210ab2aceSGeorge Karpenkov   CurrentUnitSize = 0;
16310ab2aceSGeorge Karpenkov   memset(BaseSha1, 0, sizeof(BaseSha1));
16410ab2aceSGeorge Karpenkov }
16510ab2aceSGeorge Karpenkov 
16610ab2aceSGeorge Karpenkov Fuzzer::~Fuzzer() {}
16710ab2aceSGeorge Karpenkov 
16810ab2aceSGeorge Karpenkov void Fuzzer::AllocateCurrentUnitData() {
1695ded0701SAlex Shlyapnikov   if (CurrentUnitData || MaxInputLen == 0)
1705ded0701SAlex Shlyapnikov     return;
17110ab2aceSGeorge Karpenkov   CurrentUnitData = new uint8_t[MaxInputLen];
17210ab2aceSGeorge Karpenkov }
17310ab2aceSGeorge Karpenkov 
17410ab2aceSGeorge Karpenkov void Fuzzer::StaticDeathCallback() {
17510ab2aceSGeorge Karpenkov   assert(F);
17610ab2aceSGeorge Karpenkov   F->DeathCallback();
17710ab2aceSGeorge Karpenkov }
17810ab2aceSGeorge Karpenkov 
17910ab2aceSGeorge Karpenkov void Fuzzer::DumpCurrentUnit(const char *Prefix) {
1805ded0701SAlex Shlyapnikov   if (!CurrentUnitData)
1815ded0701SAlex Shlyapnikov     return; // Happens when running individual inputs.
18210ab2aceSGeorge Karpenkov   MD.PrintMutationSequence();
18310ab2aceSGeorge Karpenkov   Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
18410ab2aceSGeorge Karpenkov   size_t UnitSize = CurrentUnitSize;
18510ab2aceSGeorge Karpenkov   if (UnitSize <= kMaxUnitSizeToPrint) {
18610ab2aceSGeorge Karpenkov     PrintHexArray(CurrentUnitData, UnitSize, "\n");
18710ab2aceSGeorge Karpenkov     PrintASCII(CurrentUnitData, UnitSize, "\n");
18810ab2aceSGeorge Karpenkov   }
18910ab2aceSGeorge Karpenkov   WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
19010ab2aceSGeorge Karpenkov                             Prefix);
19110ab2aceSGeorge Karpenkov }
19210ab2aceSGeorge Karpenkov 
19310ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY
19410ab2aceSGeorge Karpenkov void Fuzzer::DeathCallback() {
19510ab2aceSGeorge Karpenkov   DumpCurrentUnit("crash-");
19610ab2aceSGeorge Karpenkov   PrintFinalStats();
19710ab2aceSGeorge Karpenkov }
19810ab2aceSGeorge Karpenkov 
19910ab2aceSGeorge Karpenkov void Fuzzer::StaticAlarmCallback() {
20010ab2aceSGeorge Karpenkov   assert(F);
20110ab2aceSGeorge Karpenkov   F->AlarmCallback();
20210ab2aceSGeorge Karpenkov }
20310ab2aceSGeorge Karpenkov 
20410ab2aceSGeorge Karpenkov void Fuzzer::StaticCrashSignalCallback() {
20510ab2aceSGeorge Karpenkov   assert(F);
20610ab2aceSGeorge Karpenkov   F->CrashCallback();
20710ab2aceSGeorge Karpenkov }
20810ab2aceSGeorge Karpenkov 
20910ab2aceSGeorge Karpenkov void Fuzzer::StaticExitCallback() {
21010ab2aceSGeorge Karpenkov   assert(F);
21110ab2aceSGeorge Karpenkov   F->ExitCallback();
21210ab2aceSGeorge Karpenkov }
21310ab2aceSGeorge Karpenkov 
21410ab2aceSGeorge Karpenkov void Fuzzer::StaticInterruptCallback() {
21510ab2aceSGeorge Karpenkov   assert(F);
21610ab2aceSGeorge Karpenkov   F->InterruptCallback();
21710ab2aceSGeorge Karpenkov }
21810ab2aceSGeorge Karpenkov 
219*a2ca2dccSKostya Serebryany void Fuzzer::StaticGracefulExitCallback() {
220*a2ca2dccSKostya Serebryany   assert(F);
221*a2ca2dccSKostya Serebryany   F->GracefulExitRequested = true;
222*a2ca2dccSKostya Serebryany   Printf("INFO: signal received, trying to exit gracefully\n");
223*a2ca2dccSKostya Serebryany }
224*a2ca2dccSKostya Serebryany 
22510ab2aceSGeorge Karpenkov void Fuzzer::StaticFileSizeExceedCallback() {
22610ab2aceSGeorge Karpenkov   Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
22710ab2aceSGeorge Karpenkov   exit(1);
22810ab2aceSGeorge Karpenkov }
22910ab2aceSGeorge Karpenkov 
23010ab2aceSGeorge Karpenkov void Fuzzer::CrashCallback() {
23110ab2aceSGeorge Karpenkov   Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
23210ab2aceSGeorge Karpenkov   if (EF->__sanitizer_print_stack_trace)
23310ab2aceSGeorge Karpenkov     EF->__sanitizer_print_stack_trace();
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 
24310ab2aceSGeorge Karpenkov void Fuzzer::ExitCallback() {
24410ab2aceSGeorge Karpenkov   if (!RunningCB)
24510ab2aceSGeorge Karpenkov     return; // This exit did not come from the user callback
24610ab2aceSGeorge Karpenkov   Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
24710ab2aceSGeorge Karpenkov   if (EF->__sanitizer_print_stack_trace)
24810ab2aceSGeorge Karpenkov     EF->__sanitizer_print_stack_trace();
24910ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: fuzz target exited\n");
25010ab2aceSGeorge Karpenkov   DumpCurrentUnit("crash-");
25110ab2aceSGeorge Karpenkov   PrintFinalStats();
25210ab2aceSGeorge Karpenkov   _Exit(Options.ErrorExitCode);
25310ab2aceSGeorge Karpenkov }
25410ab2aceSGeorge Karpenkov 
255*a2ca2dccSKostya Serebryany void Fuzzer::MaybeExitGracefully() {
256*a2ca2dccSKostya Serebryany   if (!GracefulExitRequested) return;
257*a2ca2dccSKostya Serebryany   Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
258*a2ca2dccSKostya Serebryany   PrintFinalStats();
259*a2ca2dccSKostya Serebryany   _Exit(0);
260*a2ca2dccSKostya Serebryany }
261*a2ca2dccSKostya Serebryany 
26210ab2aceSGeorge Karpenkov void Fuzzer::InterruptCallback() {
26310ab2aceSGeorge Karpenkov   Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
26410ab2aceSGeorge Karpenkov   PrintFinalStats();
26510ab2aceSGeorge Karpenkov   _Exit(0); // Stop right now, don't perform any at-exit actions.
26610ab2aceSGeorge Karpenkov }
26710ab2aceSGeorge Karpenkov 
26810ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY
26910ab2aceSGeorge Karpenkov void Fuzzer::AlarmCallback() {
27010ab2aceSGeorge Karpenkov   assert(Options.UnitTimeoutSec > 0);
27110ab2aceSGeorge Karpenkov   // In Windows Alarm callback is executed by a different thread.
27210ab2aceSGeorge Karpenkov #if !LIBFUZZER_WINDOWS
2735ded0701SAlex Shlyapnikov   if (!InFuzzingThread())
2745ded0701SAlex Shlyapnikov     return;
27510ab2aceSGeorge Karpenkov #endif
27610ab2aceSGeorge Karpenkov   if (!RunningCB)
27710ab2aceSGeorge Karpenkov     return; // We have not started running units yet.
27810ab2aceSGeorge Karpenkov   size_t Seconds =
27910ab2aceSGeorge Karpenkov       duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
28010ab2aceSGeorge Karpenkov   if (Seconds == 0)
28110ab2aceSGeorge Karpenkov     return;
28210ab2aceSGeorge Karpenkov   if (Options.Verbosity >= 2)
28310ab2aceSGeorge Karpenkov     Printf("AlarmCallback %zd\n", Seconds);
28410ab2aceSGeorge Karpenkov   if (Seconds >= (size_t)Options.UnitTimeoutSec) {
28510ab2aceSGeorge Karpenkov     Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
28610ab2aceSGeorge Karpenkov     Printf("       and the timeout value is %d (use -timeout=N to change)\n",
28710ab2aceSGeorge Karpenkov            Options.UnitTimeoutSec);
28810ab2aceSGeorge Karpenkov     DumpCurrentUnit("timeout-");
28910ab2aceSGeorge Karpenkov     Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
29010ab2aceSGeorge Karpenkov            Seconds);
29110ab2aceSGeorge Karpenkov     if (EF->__sanitizer_print_stack_trace)
29210ab2aceSGeorge Karpenkov       EF->__sanitizer_print_stack_trace();
29310ab2aceSGeorge Karpenkov     Printf("SUMMARY: libFuzzer: timeout\n");
29410ab2aceSGeorge Karpenkov     PrintFinalStats();
29510ab2aceSGeorge Karpenkov     _Exit(Options.TimeoutExitCode); // Stop right now.
29610ab2aceSGeorge Karpenkov   }
29710ab2aceSGeorge Karpenkov }
29810ab2aceSGeorge Karpenkov 
29910ab2aceSGeorge Karpenkov void Fuzzer::RssLimitCallback() {
30010ab2aceSGeorge Karpenkov   Printf(
30110ab2aceSGeorge Karpenkov       "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
30210ab2aceSGeorge Karpenkov       GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
30310ab2aceSGeorge Karpenkov   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
30410ab2aceSGeorge Karpenkov   if (EF->__sanitizer_print_memory_profile)
30510ab2aceSGeorge Karpenkov     EF->__sanitizer_print_memory_profile(95, 8);
30610ab2aceSGeorge Karpenkov   DumpCurrentUnit("oom-");
30710ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: out-of-memory\n");
30810ab2aceSGeorge Karpenkov   PrintFinalStats();
30910ab2aceSGeorge Karpenkov   _Exit(Options.ErrorExitCode); // Stop right now.
31010ab2aceSGeorge Karpenkov }
31110ab2aceSGeorge Karpenkov 
31210ab2aceSGeorge Karpenkov void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
31310ab2aceSGeorge Karpenkov   size_t ExecPerSec = execPerSec();
31410ab2aceSGeorge Karpenkov   if (!Options.Verbosity)
31510ab2aceSGeorge Karpenkov     return;
31610ab2aceSGeorge Karpenkov   Printf("#%zd\t%s", TotalNumberOfRuns, Where);
31710ab2aceSGeorge Karpenkov   if (size_t N = TPC.GetTotalPCCoverage())
31810ab2aceSGeorge Karpenkov     Printf(" cov: %zd", N);
31910ab2aceSGeorge Karpenkov   if (size_t N = Corpus.NumFeatures())
32010ab2aceSGeorge Karpenkov     Printf(" ft: %zd", N);
32110ab2aceSGeorge Karpenkov   if (!Corpus.empty()) {
32210ab2aceSGeorge Karpenkov     Printf(" corp: %zd", Corpus.NumActiveUnits());
32310ab2aceSGeorge Karpenkov     if (size_t N = Corpus.SizeInBytes()) {
32410ab2aceSGeorge Karpenkov       if (N < (1 << 14))
32510ab2aceSGeorge Karpenkov         Printf("/%zdb", N);
32610ab2aceSGeorge Karpenkov       else if (N < (1 << 24))
32710ab2aceSGeorge Karpenkov         Printf("/%zdKb", N >> 10);
32810ab2aceSGeorge Karpenkov       else
32910ab2aceSGeorge Karpenkov         Printf("/%zdMb", N >> 20);
33010ab2aceSGeorge Karpenkov     }
33110ab2aceSGeorge Karpenkov   }
33210ab2aceSGeorge Karpenkov   if (Units)
33310ab2aceSGeorge Karpenkov     Printf(" units: %zd", Units);
33410ab2aceSGeorge Karpenkov 
33510ab2aceSGeorge Karpenkov   Printf(" exec/s: %zd", ExecPerSec);
33610ab2aceSGeorge Karpenkov   Printf(" rss: %zdMb", GetPeakRSSMb());
33710ab2aceSGeorge Karpenkov   Printf("%s", End);
33810ab2aceSGeorge Karpenkov }
33910ab2aceSGeorge Karpenkov 
34010ab2aceSGeorge Karpenkov void Fuzzer::PrintFinalStats() {
34110ab2aceSGeorge Karpenkov   if (Options.PrintCoverage)
34210ab2aceSGeorge Karpenkov     TPC.PrintCoverage();
34310ab2aceSGeorge Karpenkov   if (Options.DumpCoverage)
34410ab2aceSGeorge Karpenkov     TPC.DumpCoverage();
34510ab2aceSGeorge Karpenkov   if (Options.PrintCorpusStats)
34610ab2aceSGeorge Karpenkov     Corpus.PrintStats();
3475ded0701SAlex Shlyapnikov   if (!Options.PrintFinalStats)
3485ded0701SAlex Shlyapnikov     return;
34910ab2aceSGeorge Karpenkov   size_t ExecPerSec = execPerSec();
35010ab2aceSGeorge Karpenkov   Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
35110ab2aceSGeorge Karpenkov   Printf("stat::average_exec_per_sec:     %zd\n", ExecPerSec);
35210ab2aceSGeorge Karpenkov   Printf("stat::new_units_added:          %zd\n", NumberOfNewUnitsAdded);
35310ab2aceSGeorge Karpenkov   Printf("stat::slowest_unit_time_sec:    %zd\n", TimeOfLongestUnitInSeconds);
35410ab2aceSGeorge Karpenkov   Printf("stat::peak_rss_mb:              %zd\n", GetPeakRSSMb());
35510ab2aceSGeorge Karpenkov }
35610ab2aceSGeorge Karpenkov 
35710ab2aceSGeorge Karpenkov void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
35810ab2aceSGeorge Karpenkov   assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
35910ab2aceSGeorge Karpenkov   assert(MaxInputLen);
36010ab2aceSGeorge Karpenkov   this->MaxInputLen = MaxInputLen;
36110ab2aceSGeorge Karpenkov   this->MaxMutationLen = MaxInputLen;
36210ab2aceSGeorge Karpenkov   AllocateCurrentUnitData();
36310ab2aceSGeorge Karpenkov   Printf("INFO: -max_len is not provided; "
36410ab2aceSGeorge Karpenkov          "libFuzzer will not generate inputs larger than %zd bytes\n",
36510ab2aceSGeorge Karpenkov          MaxInputLen);
36610ab2aceSGeorge Karpenkov }
36710ab2aceSGeorge Karpenkov 
36810ab2aceSGeorge Karpenkov void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
36910ab2aceSGeorge Karpenkov   assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
37010ab2aceSGeorge Karpenkov   this->MaxMutationLen = MaxMutationLen;
37110ab2aceSGeorge Karpenkov }
37210ab2aceSGeorge Karpenkov 
37310ab2aceSGeorge Karpenkov void Fuzzer::CheckExitOnSrcPosOrItem() {
37410ab2aceSGeorge Karpenkov   if (!Options.ExitOnSrcPos.empty()) {
375bebcbfb4SGeorge Karpenkov     static auto *PCsSet = new Set<uintptr_t>;
37610ab2aceSGeorge Karpenkov     auto HandlePC = [&](uintptr_t PC) {
3775ded0701SAlex Shlyapnikov       if (!PCsSet->insert(PC).second)
3785ded0701SAlex Shlyapnikov         return;
37910ab2aceSGeorge Karpenkov       std::string Descr = DescribePC("%F %L", PC + 1);
38010ab2aceSGeorge Karpenkov       if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
38110ab2aceSGeorge Karpenkov         Printf("INFO: found line matching '%s', exiting.\n",
38210ab2aceSGeorge Karpenkov                Options.ExitOnSrcPos.c_str());
38310ab2aceSGeorge Karpenkov         _Exit(0);
38410ab2aceSGeorge Karpenkov       }
38510ab2aceSGeorge Karpenkov     };
38610ab2aceSGeorge Karpenkov     TPC.ForEachObservedPC(HandlePC);
38710ab2aceSGeorge Karpenkov   }
38810ab2aceSGeorge Karpenkov   if (!Options.ExitOnItem.empty()) {
38910ab2aceSGeorge Karpenkov     if (Corpus.HasUnit(Options.ExitOnItem)) {
39010ab2aceSGeorge Karpenkov       Printf("INFO: found item with checksum '%s', exiting.\n",
39110ab2aceSGeorge Karpenkov              Options.ExitOnItem.c_str());
39210ab2aceSGeorge Karpenkov       _Exit(0);
39310ab2aceSGeorge Karpenkov     }
39410ab2aceSGeorge Karpenkov   }
39510ab2aceSGeorge Karpenkov }
39610ab2aceSGeorge Karpenkov 
39710ab2aceSGeorge Karpenkov void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
3985ded0701SAlex Shlyapnikov   if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
3995ded0701SAlex Shlyapnikov     return;
400bebcbfb4SGeorge Karpenkov   Vector<Unit> AdditionalCorpus;
40110ab2aceSGeorge Karpenkov   ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
40210ab2aceSGeorge Karpenkov                          &EpochOfLastReadOfOutputCorpus, MaxSize,
40310ab2aceSGeorge Karpenkov                          /*ExitOnError*/ false);
40410ab2aceSGeorge Karpenkov   if (Options.Verbosity >= 2)
40510ab2aceSGeorge Karpenkov     Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
40610ab2aceSGeorge Karpenkov   bool Reloaded = false;
40710ab2aceSGeorge Karpenkov   for (auto &U : AdditionalCorpus) {
40810ab2aceSGeorge Karpenkov     if (U.size() > MaxSize)
40910ab2aceSGeorge Karpenkov       U.resize(MaxSize);
41010ab2aceSGeorge Karpenkov     if (!Corpus.HasUnit(U)) {
41110ab2aceSGeorge Karpenkov       if (RunOne(U.data(), U.size())) {
41210ab2aceSGeorge Karpenkov         CheckExitOnSrcPosOrItem();
41310ab2aceSGeorge Karpenkov         Reloaded = true;
41410ab2aceSGeorge Karpenkov       }
41510ab2aceSGeorge Karpenkov     }
41610ab2aceSGeorge Karpenkov   }
41710ab2aceSGeorge Karpenkov   if (Reloaded)
41810ab2aceSGeorge Karpenkov     PrintStats("RELOAD");
41910ab2aceSGeorge Karpenkov }
42010ab2aceSGeorge Karpenkov 
42110ab2aceSGeorge Karpenkov void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
42210ab2aceSGeorge Karpenkov   auto TimeOfUnit =
42310ab2aceSGeorge Karpenkov       duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
42410ab2aceSGeorge Karpenkov   if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
42510ab2aceSGeorge Karpenkov       secondsSinceProcessStartUp() >= 2)
42610ab2aceSGeorge Karpenkov     PrintStats("pulse ");
42710ab2aceSGeorge Karpenkov   if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 &&
42810ab2aceSGeorge Karpenkov       TimeOfUnit >= Options.ReportSlowUnits) {
42910ab2aceSGeorge Karpenkov     TimeOfLongestUnitInSeconds = TimeOfUnit;
43010ab2aceSGeorge Karpenkov     Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
43110ab2aceSGeorge Karpenkov     WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
43210ab2aceSGeorge Karpenkov   }
43310ab2aceSGeorge Karpenkov }
43410ab2aceSGeorge Karpenkov 
43510ab2aceSGeorge Karpenkov bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
43610ab2aceSGeorge Karpenkov                     InputInfo *II) {
4375ded0701SAlex Shlyapnikov   if (!Size)
4385ded0701SAlex Shlyapnikov     return false;
43910ab2aceSGeorge Karpenkov 
44010ab2aceSGeorge Karpenkov   ExecuteCallback(Data, Size);
44110ab2aceSGeorge Karpenkov 
44210ab2aceSGeorge Karpenkov   UniqFeatureSetTmp.clear();
44310ab2aceSGeorge Karpenkov   size_t FoundUniqFeaturesOfII = 0;
44410ab2aceSGeorge Karpenkov   size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
44510ab2aceSGeorge Karpenkov   TPC.CollectFeatures([&](size_t Feature) {
4464083d546SKostya Serebryany     Corpus.UpdateFeatureFrequency(Feature);
44710ab2aceSGeorge Karpenkov     if (Corpus.AddFeature(Feature, Size, Options.Shrink))
44810ab2aceSGeorge Karpenkov       UniqFeatureSetTmp.push_back(Feature);
44910ab2aceSGeorge Karpenkov     if (Options.ReduceInputs && II)
45010ab2aceSGeorge Karpenkov       if (std::binary_search(II->UniqFeatureSet.begin(),
45110ab2aceSGeorge Karpenkov                              II->UniqFeatureSet.end(), Feature))
45210ab2aceSGeorge Karpenkov         FoundUniqFeaturesOfII++;
45310ab2aceSGeorge Karpenkov   });
45410ab2aceSGeorge Karpenkov   PrintPulseAndReportSlowInput(Data, Size);
45510ab2aceSGeorge Karpenkov   size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
45610ab2aceSGeorge Karpenkov   if (NumNewFeatures) {
45710ab2aceSGeorge Karpenkov     TPC.UpdateObservedPCs();
45810ab2aceSGeorge Karpenkov     Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
45910ab2aceSGeorge Karpenkov                        UniqFeatureSetTmp);
46010ab2aceSGeorge Karpenkov     return true;
46110ab2aceSGeorge Karpenkov   }
46210ab2aceSGeorge Karpenkov   if (II && FoundUniqFeaturesOfII &&
46310ab2aceSGeorge Karpenkov       FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
46410ab2aceSGeorge Karpenkov       II->U.size() > Size) {
46510ab2aceSGeorge Karpenkov     Corpus.Replace(II, {Data, Data + Size});
46610ab2aceSGeorge Karpenkov     return true;
46710ab2aceSGeorge Karpenkov   }
46810ab2aceSGeorge Karpenkov   return false;
46910ab2aceSGeorge Karpenkov }
47010ab2aceSGeorge Karpenkov 
47110ab2aceSGeorge Karpenkov size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
47210ab2aceSGeorge Karpenkov   assert(InFuzzingThread());
47310ab2aceSGeorge Karpenkov   *Data = CurrentUnitData;
47410ab2aceSGeorge Karpenkov   return CurrentUnitSize;
47510ab2aceSGeorge Karpenkov }
47610ab2aceSGeorge Karpenkov 
47710ab2aceSGeorge Karpenkov void Fuzzer::CrashOnOverwrittenData() {
47810ab2aceSGeorge Karpenkov   Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n",
47910ab2aceSGeorge Karpenkov          GetPid());
48010ab2aceSGeorge Karpenkov   DumpCurrentUnit("crash-");
48110ab2aceSGeorge Karpenkov   Printf("SUMMARY: libFuzzer: out-of-memory\n");
48210ab2aceSGeorge Karpenkov   _Exit(Options.ErrorExitCode); // Stop right now.
48310ab2aceSGeorge Karpenkov }
48410ab2aceSGeorge Karpenkov 
48510ab2aceSGeorge Karpenkov // Compare two arrays, but not all bytes if the arrays are large.
48610ab2aceSGeorge Karpenkov static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
48710ab2aceSGeorge Karpenkov   const size_t Limit = 64;
48810ab2aceSGeorge Karpenkov   if (Size <= 64)
48910ab2aceSGeorge Karpenkov     return !memcmp(A, B, Size);
49010ab2aceSGeorge Karpenkov   // Compare first and last Limit/2 bytes.
49110ab2aceSGeorge Karpenkov   return !memcmp(A, B, Limit / 2) &&
49210ab2aceSGeorge Karpenkov          !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
49310ab2aceSGeorge Karpenkov }
49410ab2aceSGeorge Karpenkov 
49510ab2aceSGeorge Karpenkov void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
49610ab2aceSGeorge Karpenkov   TPC.RecordInitialStack();
49710ab2aceSGeorge Karpenkov   TotalNumberOfRuns++;
49810ab2aceSGeorge Karpenkov   assert(InFuzzingThread());
49910ab2aceSGeorge Karpenkov   if (SMR.IsClient())
50010ab2aceSGeorge Karpenkov     SMR.WriteByteArray(Data, Size);
50110ab2aceSGeorge Karpenkov   // We copy the contents of Unit into a separate heap buffer
50210ab2aceSGeorge Karpenkov   // so that we reliably find buffer overflows in it.
50310ab2aceSGeorge Karpenkov   uint8_t *DataCopy = new uint8_t[Size];
50410ab2aceSGeorge Karpenkov   memcpy(DataCopy, Data, Size);
50510ab2aceSGeorge Karpenkov   if (CurrentUnitData && CurrentUnitData != Data)
50610ab2aceSGeorge Karpenkov     memcpy(CurrentUnitData, Data, Size);
50710ab2aceSGeorge Karpenkov   CurrentUnitSize = Size;
50810ab2aceSGeorge Karpenkov   AllocTracer.Start(Options.TraceMalloc);
50910ab2aceSGeorge Karpenkov   UnitStartTime = system_clock::now();
51010ab2aceSGeorge Karpenkov   TPC.ResetMaps();
51110ab2aceSGeorge Karpenkov   RunningCB = true;
51210ab2aceSGeorge Karpenkov   int Res = CB(DataCopy, Size);
51310ab2aceSGeorge Karpenkov   RunningCB = false;
51410ab2aceSGeorge Karpenkov   UnitStopTime = system_clock::now();
51510ab2aceSGeorge Karpenkov   (void)Res;
51610ab2aceSGeorge Karpenkov   assert(Res == 0);
51710ab2aceSGeorge Karpenkov   HasMoreMallocsThanFrees = AllocTracer.Stop();
51810ab2aceSGeorge Karpenkov   if (!LooseMemeq(DataCopy, Data, Size))
51910ab2aceSGeorge Karpenkov     CrashOnOverwrittenData();
52010ab2aceSGeorge Karpenkov   CurrentUnitSize = 0;
52110ab2aceSGeorge Karpenkov   delete[] DataCopy;
52210ab2aceSGeorge Karpenkov }
52310ab2aceSGeorge Karpenkov 
52410ab2aceSGeorge Karpenkov void Fuzzer::WriteToOutputCorpus(const Unit &U) {
52510ab2aceSGeorge Karpenkov   if (Options.OnlyASCII)
52610ab2aceSGeorge Karpenkov     assert(IsASCII(U));
52710ab2aceSGeorge Karpenkov   if (Options.OutputCorpus.empty())
52810ab2aceSGeorge Karpenkov     return;
52910ab2aceSGeorge Karpenkov   std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
53010ab2aceSGeorge Karpenkov   WriteToFile(U, Path);
53110ab2aceSGeorge Karpenkov   if (Options.Verbosity >= 2)
53210ab2aceSGeorge Karpenkov     Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
53310ab2aceSGeorge Karpenkov }
53410ab2aceSGeorge Karpenkov 
53510ab2aceSGeorge Karpenkov void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
53610ab2aceSGeorge Karpenkov   if (!Options.SaveArtifacts)
53710ab2aceSGeorge Karpenkov     return;
53810ab2aceSGeorge Karpenkov   std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
53910ab2aceSGeorge Karpenkov   if (!Options.ExactArtifactPath.empty())
54010ab2aceSGeorge Karpenkov     Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
54110ab2aceSGeorge Karpenkov   WriteToFile(U, Path);
54210ab2aceSGeorge Karpenkov   Printf("artifact_prefix='%s'; Test unit written to %s\n",
54310ab2aceSGeorge Karpenkov          Options.ArtifactPrefix.c_str(), Path.c_str());
54410ab2aceSGeorge Karpenkov   if (U.size() <= kMaxUnitSizeToPrint)
54510ab2aceSGeorge Karpenkov     Printf("Base64: %s\n", Base64(U).c_str());
54610ab2aceSGeorge Karpenkov }
54710ab2aceSGeorge Karpenkov 
54810ab2aceSGeorge Karpenkov void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
54910ab2aceSGeorge Karpenkov   if (!Options.PrintNEW)
55010ab2aceSGeorge Karpenkov     return;
55110ab2aceSGeorge Karpenkov   PrintStats(Text, "");
55210ab2aceSGeorge Karpenkov   if (Options.Verbosity) {
55310ab2aceSGeorge Karpenkov     Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
55410ab2aceSGeorge Karpenkov     MD.PrintMutationSequence();
55510ab2aceSGeorge Karpenkov     Printf("\n");
55610ab2aceSGeorge Karpenkov   }
55710ab2aceSGeorge Karpenkov }
55810ab2aceSGeorge Karpenkov 
55910ab2aceSGeorge Karpenkov void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
56010ab2aceSGeorge Karpenkov   II->NumSuccessfullMutations++;
56110ab2aceSGeorge Karpenkov   MD.RecordSuccessfulMutationSequence();
5625ded0701SAlex Shlyapnikov   PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW   ");
56310ab2aceSGeorge Karpenkov   WriteToOutputCorpus(U);
56410ab2aceSGeorge Karpenkov   NumberOfNewUnitsAdded++;
56510ab2aceSGeorge Karpenkov   CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
56610ab2aceSGeorge Karpenkov   LastCorpusUpdateRun = TotalNumberOfRuns;
56710ab2aceSGeorge Karpenkov   LastCorpusUpdateTime = system_clock::now();
56810ab2aceSGeorge Karpenkov }
56910ab2aceSGeorge Karpenkov 
57010ab2aceSGeorge Karpenkov // Tries detecting a memory leak on the particular input that we have just
57110ab2aceSGeorge Karpenkov // executed before calling this function.
57210ab2aceSGeorge Karpenkov void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
57310ab2aceSGeorge Karpenkov                                      bool DuringInitialCorpusExecution) {
5745ded0701SAlex Shlyapnikov   if (!HasMoreMallocsThanFrees)
5755ded0701SAlex Shlyapnikov     return; // mallocs==frees, a leak is unlikely.
5765ded0701SAlex Shlyapnikov   if (!Options.DetectLeaks)
5775ded0701SAlex Shlyapnikov     return;
5783f26dac4SMax Moroz   if (!DuringInitialCorpusExecution &&
5795ded0701SAlex Shlyapnikov       TotalNumberOfRuns >= Options.MaxNumberOfRuns)
5805ded0701SAlex Shlyapnikov     return;
58110ab2aceSGeorge Karpenkov   if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
58210ab2aceSGeorge Karpenkov       !(EF->__lsan_do_recoverable_leak_check))
58310ab2aceSGeorge Karpenkov     return; // No lsan.
58410ab2aceSGeorge Karpenkov   // Run the target once again, but with lsan disabled so that if there is
58510ab2aceSGeorge Karpenkov   // a real leak we do not report it twice.
58610ab2aceSGeorge Karpenkov   EF->__lsan_disable();
58710ab2aceSGeorge Karpenkov   ExecuteCallback(Data, Size);
58810ab2aceSGeorge Karpenkov   EF->__lsan_enable();
5895ded0701SAlex Shlyapnikov   if (!HasMoreMallocsThanFrees)
5905ded0701SAlex Shlyapnikov     return; // a leak is unlikely.
59110ab2aceSGeorge Karpenkov   if (NumberOfLeakDetectionAttempts++ > 1000) {
59210ab2aceSGeorge Karpenkov     Options.DetectLeaks = false;
59310ab2aceSGeorge Karpenkov     Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
59410ab2aceSGeorge Karpenkov            "      Most likely the target function accumulates allocated\n"
59510ab2aceSGeorge Karpenkov            "      memory in a global state w/o actually leaking it.\n"
59610ab2aceSGeorge Karpenkov            "      You may try running this binary with -trace_malloc=[12]"
59710ab2aceSGeorge Karpenkov            "      to get a trace of mallocs and frees.\n"
59810ab2aceSGeorge Karpenkov            "      If LeakSanitizer is enabled in this process it will still\n"
59910ab2aceSGeorge Karpenkov            "      run on the process shutdown.\n");
60010ab2aceSGeorge Karpenkov     return;
60110ab2aceSGeorge Karpenkov   }
60210ab2aceSGeorge Karpenkov   // Now perform the actual lsan pass. This is expensive and we must ensure
60310ab2aceSGeorge Karpenkov   // we don't call it too often.
60410ab2aceSGeorge Karpenkov   if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
60510ab2aceSGeorge Karpenkov     if (DuringInitialCorpusExecution)
60610ab2aceSGeorge Karpenkov       Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
60710ab2aceSGeorge Karpenkov     Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
60810ab2aceSGeorge Karpenkov     CurrentUnitSize = Size;
60910ab2aceSGeorge Karpenkov     DumpCurrentUnit("leak-");
61010ab2aceSGeorge Karpenkov     PrintFinalStats();
61110ab2aceSGeorge Karpenkov     _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
61210ab2aceSGeorge Karpenkov   }
61310ab2aceSGeorge Karpenkov }
61410ab2aceSGeorge Karpenkov 
61510ab2aceSGeorge Karpenkov void Fuzzer::MutateAndTestOne() {
61610ab2aceSGeorge Karpenkov   MD.StartMutationSequence();
61710ab2aceSGeorge Karpenkov 
61810ab2aceSGeorge Karpenkov   auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
6194083d546SKostya Serebryany   if (Options.UseFeatureFrequency)
6204083d546SKostya Serebryany     Corpus.UpdateFeatureFrequencyScore(&II);
62110ab2aceSGeorge Karpenkov   const auto &U = II.U;
62210ab2aceSGeorge Karpenkov   memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
62310ab2aceSGeorge Karpenkov   assert(CurrentUnitData);
62410ab2aceSGeorge Karpenkov   size_t Size = U.size();
62510ab2aceSGeorge Karpenkov   assert(Size <= MaxInputLen && "Oversized Unit");
62610ab2aceSGeorge Karpenkov   memcpy(CurrentUnitData, U.data(), Size);
62710ab2aceSGeorge Karpenkov 
62810ab2aceSGeorge Karpenkov   assert(MaxMutationLen > 0);
62910ab2aceSGeorge Karpenkov 
63010ab2aceSGeorge Karpenkov   size_t CurrentMaxMutationLen =
63110ab2aceSGeorge Karpenkov       Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
63210ab2aceSGeorge Karpenkov   assert(CurrentMaxMutationLen > 0);
63310ab2aceSGeorge Karpenkov 
63410ab2aceSGeorge Karpenkov   for (int i = 0; i < Options.MutateDepth; i++) {
63510ab2aceSGeorge Karpenkov     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
63610ab2aceSGeorge Karpenkov       break;
637*a2ca2dccSKostya Serebryany     MaybeExitGracefully();
63810ab2aceSGeorge Karpenkov     size_t NewSize = 0;
63910ab2aceSGeorge Karpenkov     NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
64010ab2aceSGeorge Karpenkov     assert(NewSize > 0 && "Mutator returned empty unit");
6416f1c26f2SAlex Shlyapnikov     assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
64210ab2aceSGeorge Karpenkov     Size = NewSize;
64310ab2aceSGeorge Karpenkov     II.NumExecutedMutations++;
64410ab2aceSGeorge Karpenkov     if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II))
64510ab2aceSGeorge Karpenkov       ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
64610ab2aceSGeorge Karpenkov 
64710ab2aceSGeorge Karpenkov     TryDetectingAMemoryLeak(CurrentUnitData, Size,
64810ab2aceSGeorge Karpenkov                             /*DuringInitialCorpusExecution*/ false);
64910ab2aceSGeorge Karpenkov   }
65010ab2aceSGeorge Karpenkov }
65110ab2aceSGeorge Karpenkov 
6526f1c26f2SAlex Shlyapnikov void Fuzzer::PurgeAllocator() {
6535ded0701SAlex Shlyapnikov   if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
6546f1c26f2SAlex Shlyapnikov     return;
6556f1c26f2SAlex Shlyapnikov   if (duration_cast<seconds>(system_clock::now() -
6565ded0701SAlex Shlyapnikov                              LastAllocatorPurgeAttemptTime)
6575ded0701SAlex Shlyapnikov           .count() < Options.PurgeAllocatorIntervalSec)
6586f1c26f2SAlex Shlyapnikov     return;
6596f1c26f2SAlex Shlyapnikov 
6606f1c26f2SAlex Shlyapnikov   if (Options.RssLimitMb <= 0 ||
6615ded0701SAlex Shlyapnikov       GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
6626f1c26f2SAlex Shlyapnikov     EF->__sanitizer_purge_allocator();
6636f1c26f2SAlex Shlyapnikov 
6646f1c26f2SAlex Shlyapnikov   LastAllocatorPurgeAttemptTime = system_clock::now();
6656f1c26f2SAlex Shlyapnikov }
6666f1c26f2SAlex Shlyapnikov 
6673a8e3c83SKostya Serebryany void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {
6683a8e3c83SKostya Serebryany   const size_t kMaxSaneLen = 1 << 20;
6693a8e3c83SKostya Serebryany   const size_t kMinDefaultLen = 4096;
6704faeb87eSKostya Serebryany   Vector<SizedFile> SizedFiles;
6714faeb87eSKostya Serebryany   size_t MaxSize = 0;
6724faeb87eSKostya Serebryany   size_t MinSize = -1;
6734faeb87eSKostya Serebryany   size_t TotalSize = 0;
67493679be0SKostya Serebryany   size_t LastNumFiles = 0;
6754faeb87eSKostya Serebryany   for (auto &Dir : CorpusDirs) {
67693679be0SKostya Serebryany     GetSizedFilesFromDir(Dir, &SizedFiles);
67793679be0SKostya Serebryany     Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
67893679be0SKostya Serebryany            Dir.c_str());
67993679be0SKostya Serebryany     LastNumFiles = SizedFiles.size();
6803a8e3c83SKostya Serebryany   }
68193679be0SKostya Serebryany   for (auto &File : SizedFiles) {
68293679be0SKostya Serebryany     MaxSize = Max(File.Size, MaxSize);
68393679be0SKostya Serebryany     MinSize = Min(File.Size, MinSize);
68493679be0SKostya Serebryany     TotalSize += File.Size;
6854faeb87eSKostya Serebryany   }
6864faeb87eSKostya Serebryany   if (Options.MaxLen == 0)
6874faeb87eSKostya Serebryany     SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
6884faeb87eSKostya Serebryany   assert(MaxInputLen > 0);
6894faeb87eSKostya Serebryany 
69051823d3aSKostya Serebryany   // Test the callback with empty input and never try it again.
69151823d3aSKostya Serebryany   uint8_t dummy = 0;
69251823d3aSKostya Serebryany   ExecuteCallback(&dummy, 0);
69351823d3aSKostya Serebryany 
6944faeb87eSKostya Serebryany   if (SizedFiles.empty()) {
6954faeb87eSKostya Serebryany     Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
6964faeb87eSKostya Serebryany     Unit U({'\n'}); // Valid ASCII input.
6974faeb87eSKostya Serebryany     RunOne(U.data(), U.size());
6984faeb87eSKostya Serebryany   } else {
6994faeb87eSKostya Serebryany     Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
7004faeb87eSKostya Serebryany            " rss: %zdMb\n",
7014faeb87eSKostya Serebryany            SizedFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
7024faeb87eSKostya Serebryany     if (Options.ShuffleAtStartUp)
7034faeb87eSKostya Serebryany       std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand());
7044faeb87eSKostya Serebryany 
70593679be0SKostya Serebryany     if (Options.PreferSmall) {
70693679be0SKostya Serebryany       std::stable_sort(SizedFiles.begin(), SizedFiles.end());
70793679be0SKostya Serebryany       assert(SizedFiles.front().Size <= SizedFiles.back().Size);
70893679be0SKostya Serebryany     }
7094faeb87eSKostya Serebryany 
7104faeb87eSKostya Serebryany     // Load and execute inputs one by one.
7114faeb87eSKostya Serebryany     for (auto &SF : SizedFiles) {
712082e9a75SKostya Serebryany       auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
7134faeb87eSKostya Serebryany       assert(U.size() <= MaxInputLen);
7144faeb87eSKostya Serebryany       RunOne(U.data(), U.size());
7154faeb87eSKostya Serebryany       CheckExitOnSrcPosOrItem();
7164faeb87eSKostya Serebryany       TryDetectingAMemoryLeak(U.data(), U.size(),
7174faeb87eSKostya Serebryany                               /*DuringInitialCorpusExecution*/ true);
7184faeb87eSKostya Serebryany     }
7193a8e3c83SKostya Serebryany   }
7203a8e3c83SKostya Serebryany 
7214faeb87eSKostya Serebryany   PrintStats("INITED");
7224faeb87eSKostya Serebryany   if (Corpus.empty()) {
7234faeb87eSKostya Serebryany     Printf("ERROR: no interesting inputs were found. "
7244faeb87eSKostya Serebryany            "Is the code instrumented for coverage? Exiting.\n");
7254faeb87eSKostya Serebryany     exit(1);
7263a8e3c83SKostya Serebryany   }
7273a8e3c83SKostya Serebryany }
7283a8e3c83SKostya Serebryany 
7293a8e3c83SKostya Serebryany void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) {
7303a8e3c83SKostya Serebryany   ReadAndExecuteSeedCorpora(CorpusDirs);
73110ab2aceSGeorge Karpenkov   TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
7322eef816eSKostya Serebryany   TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
73310ab2aceSGeorge Karpenkov   system_clock::time_point LastCorpusReload = system_clock::now();
73410ab2aceSGeorge Karpenkov   if (Options.DoCrossOver)
73510ab2aceSGeorge Karpenkov     MD.SetCorpus(&Corpus);
73610ab2aceSGeorge Karpenkov   while (true) {
73710ab2aceSGeorge Karpenkov     auto Now = system_clock::now();
73810ab2aceSGeorge Karpenkov     if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
73910ab2aceSGeorge Karpenkov         Options.ReloadIntervalSec) {
74010ab2aceSGeorge Karpenkov       RereadOutputCorpus(MaxInputLen);
74110ab2aceSGeorge Karpenkov       LastCorpusReload = system_clock::now();
74210ab2aceSGeorge Karpenkov     }
74310ab2aceSGeorge Karpenkov     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
74410ab2aceSGeorge Karpenkov       break;
7455ded0701SAlex Shlyapnikov     if (TimedOut())
7465ded0701SAlex Shlyapnikov       break;
74710ab2aceSGeorge Karpenkov 
74810ab2aceSGeorge Karpenkov     // Update TmpMaxMutationLen
74910ab2aceSGeorge Karpenkov     if (Options.ExperimentalLenControl) {
75010ab2aceSGeorge Karpenkov       if (TmpMaxMutationLen < MaxMutationLen &&
75110ab2aceSGeorge Karpenkov           (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 &&
75210ab2aceSGeorge Karpenkov            duration_cast<seconds>(Now - LastCorpusUpdateTime).count() >= 1)) {
75310ab2aceSGeorge Karpenkov         LastCorpusUpdateRun = TotalNumberOfRuns;
75410ab2aceSGeorge Karpenkov         LastCorpusUpdateTime = Now;
75510ab2aceSGeorge Karpenkov         TmpMaxMutationLen =
75610ab2aceSGeorge Karpenkov             Min(MaxMutationLen,
75710ab2aceSGeorge Karpenkov                 TmpMaxMutationLen + Max(size_t(4), TmpMaxMutationLen / 8));
75810ab2aceSGeorge Karpenkov         if (TmpMaxMutationLen <= MaxMutationLen)
75910ab2aceSGeorge Karpenkov           Printf("#%zd\tTEMP_MAX_LEN: %zd\n", TotalNumberOfRuns,
76010ab2aceSGeorge Karpenkov                  TmpMaxMutationLen);
76110ab2aceSGeorge Karpenkov       }
76210ab2aceSGeorge Karpenkov     } else {
76310ab2aceSGeorge Karpenkov       TmpMaxMutationLen = MaxMutationLen;
76410ab2aceSGeorge Karpenkov     }
76510ab2aceSGeorge Karpenkov 
76610ab2aceSGeorge Karpenkov     // Perform several mutations and runs.
76710ab2aceSGeorge Karpenkov     MutateAndTestOne();
7686f1c26f2SAlex Shlyapnikov 
7696f1c26f2SAlex Shlyapnikov     PurgeAllocator();
77010ab2aceSGeorge Karpenkov   }
77110ab2aceSGeorge Karpenkov 
77210ab2aceSGeorge Karpenkov   PrintStats("DONE  ", "\n");
77310ab2aceSGeorge Karpenkov   MD.PrintRecommendedDictionary();
77410ab2aceSGeorge Karpenkov }
77510ab2aceSGeorge Karpenkov 
77610ab2aceSGeorge Karpenkov void Fuzzer::MinimizeCrashLoop(const Unit &U) {
7775ded0701SAlex Shlyapnikov   if (U.size() <= 1)
7785ded0701SAlex Shlyapnikov     return;
77910ab2aceSGeorge Karpenkov   while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
78010ab2aceSGeorge Karpenkov     MD.StartMutationSequence();
78110ab2aceSGeorge Karpenkov     memcpy(CurrentUnitData, U.data(), U.size());
78210ab2aceSGeorge Karpenkov     for (int i = 0; i < Options.MutateDepth; i++) {
78310ab2aceSGeorge Karpenkov       size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
78410ab2aceSGeorge Karpenkov       assert(NewSize > 0 && NewSize <= MaxMutationLen);
78510ab2aceSGeorge Karpenkov       ExecuteCallback(CurrentUnitData, NewSize);
78610ab2aceSGeorge Karpenkov       PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
78710ab2aceSGeorge Karpenkov       TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
78810ab2aceSGeorge Karpenkov                               /*DuringInitialCorpusExecution*/ false);
78910ab2aceSGeorge Karpenkov     }
79010ab2aceSGeorge Karpenkov   }
79110ab2aceSGeorge Karpenkov }
79210ab2aceSGeorge Karpenkov 
79310ab2aceSGeorge Karpenkov void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) {
79410ab2aceSGeorge Karpenkov   if (SMR.IsServer()) {
79510ab2aceSGeorge Karpenkov     SMR.WriteByteArray(Data, Size);
79610ab2aceSGeorge Karpenkov   } else if (SMR.IsClient()) {
79710ab2aceSGeorge Karpenkov     SMR.PostClient();
79810ab2aceSGeorge Karpenkov     SMR.WaitServer();
79910ab2aceSGeorge Karpenkov     size_t OtherSize = SMR.ReadByteArraySize();
80010ab2aceSGeorge Karpenkov     uint8_t *OtherData = SMR.GetByteArray();
80110ab2aceSGeorge Karpenkov     if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) {
80210ab2aceSGeorge Karpenkov       size_t i = 0;
80310ab2aceSGeorge Karpenkov       for (i = 0; i < Min(Size, OtherSize); i++)
80410ab2aceSGeorge Karpenkov         if (Data[i] != OtherData[i])
80510ab2aceSGeorge Karpenkov           break;
80610ab2aceSGeorge Karpenkov       Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; "
8075ded0701SAlex Shlyapnikov              "offset %zd\n",
8085ded0701SAlex Shlyapnikov              GetPid(), Size, OtherSize, i);
80910ab2aceSGeorge Karpenkov       DumpCurrentUnit("mismatch-");
81010ab2aceSGeorge Karpenkov       Printf("SUMMARY: libFuzzer: equivalence-mismatch\n");
81110ab2aceSGeorge Karpenkov       PrintFinalStats();
81210ab2aceSGeorge Karpenkov       _Exit(Options.ErrorExitCode);
81310ab2aceSGeorge Karpenkov     }
81410ab2aceSGeorge Karpenkov   }
81510ab2aceSGeorge Karpenkov }
81610ab2aceSGeorge Karpenkov 
81710ab2aceSGeorge Karpenkov } // namespace fuzzer
81810ab2aceSGeorge Karpenkov 
81910ab2aceSGeorge Karpenkov extern "C" {
82010ab2aceSGeorge Karpenkov 
82110ab2aceSGeorge Karpenkov size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
82210ab2aceSGeorge Karpenkov   assert(fuzzer::F);
82310ab2aceSGeorge Karpenkov   return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
82410ab2aceSGeorge Karpenkov }
82510ab2aceSGeorge Karpenkov 
82610ab2aceSGeorge Karpenkov // Experimental
82710ab2aceSGeorge Karpenkov void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {
82810ab2aceSGeorge Karpenkov   assert(fuzzer::F);
82910ab2aceSGeorge Karpenkov   fuzzer::F->AnnounceOutput(Data, Size);
83010ab2aceSGeorge Karpenkov }
83110ab2aceSGeorge Karpenkov } // extern "C"
832