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