10b57cec5SDimitry Andric //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // Fuzzer's main loop. 90b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 100b57cec5SDimitry Andric 110b57cec5SDimitry Andric #include "FuzzerCorpus.h" 120b57cec5SDimitry Andric #include "FuzzerIO.h" 130b57cec5SDimitry Andric #include "FuzzerInternal.h" 140b57cec5SDimitry Andric #include "FuzzerMutate.h" 150b57cec5SDimitry Andric #include "FuzzerRandom.h" 160b57cec5SDimitry Andric #include "FuzzerTracePC.h" 170b57cec5SDimitry Andric #include <algorithm> 180b57cec5SDimitry Andric #include <cstring> 190b57cec5SDimitry Andric #include <memory> 200b57cec5SDimitry Andric #include <mutex> 210b57cec5SDimitry Andric #include <set> 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #if defined(__has_include) 240b57cec5SDimitry Andric #if __has_include(<sanitizer / lsan_interface.h>) 250b57cec5SDimitry Andric #include <sanitizer/lsan_interface.h> 260b57cec5SDimitry Andric #endif 270b57cec5SDimitry Andric #endif 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric #define NO_SANITIZE_MEMORY 300b57cec5SDimitry Andric #if defined(__has_feature) 310b57cec5SDimitry Andric #if __has_feature(memory_sanitizer) 320b57cec5SDimitry Andric #undef NO_SANITIZE_MEMORY 330b57cec5SDimitry Andric #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) 340b57cec5SDimitry Andric #endif 350b57cec5SDimitry Andric #endif 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric namespace fuzzer { 380b57cec5SDimitry Andric static const size_t kMaxUnitSizeToPrint = 256; 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric thread_local bool Fuzzer::IsMyThread; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric bool RunningUserCallback = false; 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric // Only one Fuzzer per process. 450b57cec5SDimitry Andric static Fuzzer *F; 460b57cec5SDimitry Andric 470b57cec5SDimitry Andric // Leak detection is expensive, so we first check if there were more mallocs 480b57cec5SDimitry Andric // than frees (using the sanitizer malloc hooks) and only then try to call lsan. 490b57cec5SDimitry Andric struct MallocFreeTracer { 500b57cec5SDimitry Andric void Start(int TraceLevel) { 510b57cec5SDimitry Andric this->TraceLevel = TraceLevel; 520b57cec5SDimitry Andric if (TraceLevel) 530b57cec5SDimitry Andric Printf("MallocFreeTracer: START\n"); 540b57cec5SDimitry Andric Mallocs = 0; 550b57cec5SDimitry Andric Frees = 0; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric // Returns true if there were more mallocs than frees. 580b57cec5SDimitry Andric bool Stop() { 590b57cec5SDimitry Andric if (TraceLevel) 600b57cec5SDimitry Andric Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(), 610b57cec5SDimitry Andric Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT"); 620b57cec5SDimitry Andric bool Result = Mallocs > Frees; 630b57cec5SDimitry Andric Mallocs = 0; 640b57cec5SDimitry Andric Frees = 0; 650b57cec5SDimitry Andric TraceLevel = 0; 660b57cec5SDimitry Andric return Result; 670b57cec5SDimitry Andric } 680b57cec5SDimitry Andric std::atomic<size_t> Mallocs; 690b57cec5SDimitry Andric std::atomic<size_t> Frees; 700b57cec5SDimitry Andric int TraceLevel = 0; 710b57cec5SDimitry Andric 720b57cec5SDimitry Andric std::recursive_mutex TraceMutex; 730b57cec5SDimitry Andric bool TraceDisabled = false; 740b57cec5SDimitry Andric }; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric static MallocFreeTracer AllocTracer; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Locks printing and avoids nested hooks triggered from mallocs/frees in 790b57cec5SDimitry Andric // sanitizer. 800b57cec5SDimitry Andric class TraceLock { 810b57cec5SDimitry Andric public: 820b57cec5SDimitry Andric TraceLock() : Lock(AllocTracer.TraceMutex) { 830b57cec5SDimitry Andric AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; 840b57cec5SDimitry Andric } 850b57cec5SDimitry Andric ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; } 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric bool IsDisabled() const { 880b57cec5SDimitry Andric // This is already inverted value. 890b57cec5SDimitry Andric return !AllocTracer.TraceDisabled; 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric private: 930b57cec5SDimitry Andric std::lock_guard<std::recursive_mutex> Lock; 940b57cec5SDimitry Andric }; 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric ATTRIBUTE_NO_SANITIZE_MEMORY 970b57cec5SDimitry Andric void MallocHook(const volatile void *ptr, size_t size) { 980b57cec5SDimitry Andric size_t N = AllocTracer.Mallocs++; 990b57cec5SDimitry Andric F->HandleMalloc(size); 1000b57cec5SDimitry Andric if (int TraceLevel = AllocTracer.TraceLevel) { 1010b57cec5SDimitry Andric TraceLock Lock; 1020b57cec5SDimitry Andric if (Lock.IsDisabled()) 1030b57cec5SDimitry Andric return; 1040b57cec5SDimitry Andric Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); 1050b57cec5SDimitry Andric if (TraceLevel >= 2 && EF) 1060b57cec5SDimitry Andric PrintStackTrace(); 1070b57cec5SDimitry Andric } 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric ATTRIBUTE_NO_SANITIZE_MEMORY 1110b57cec5SDimitry Andric void FreeHook(const volatile void *ptr) { 1120b57cec5SDimitry Andric size_t N = AllocTracer.Frees++; 1130b57cec5SDimitry Andric if (int TraceLevel = AllocTracer.TraceLevel) { 1140b57cec5SDimitry Andric TraceLock Lock; 1150b57cec5SDimitry Andric if (Lock.IsDisabled()) 1160b57cec5SDimitry Andric return; 1170b57cec5SDimitry Andric Printf("FREE[%zd] %p\n", N, ptr); 1180b57cec5SDimitry Andric if (TraceLevel >= 2 && EF) 1190b57cec5SDimitry Andric PrintStackTrace(); 1200b57cec5SDimitry Andric } 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // Crash on a single malloc that exceeds the rss limit. 1240b57cec5SDimitry Andric void Fuzzer::HandleMalloc(size_t Size) { 1250b57cec5SDimitry Andric if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb) 1260b57cec5SDimitry Andric return; 1270b57cec5SDimitry Andric Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(), 1280b57cec5SDimitry Andric Size); 1290b57cec5SDimitry Andric Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); 1300b57cec5SDimitry Andric PrintStackTrace(); 1310b57cec5SDimitry Andric DumpCurrentUnit("oom-"); 1320b57cec5SDimitry Andric Printf("SUMMARY: libFuzzer: out-of-memory\n"); 1330b57cec5SDimitry Andric PrintFinalStats(); 1340b57cec5SDimitry Andric _Exit(Options.OOMExitCode); // Stop right now. 1350b57cec5SDimitry Andric } 1360b57cec5SDimitry Andric 1370b57cec5SDimitry Andric Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, 1380b57cec5SDimitry Andric FuzzingOptions Options) 1390b57cec5SDimitry Andric : CB(CB), Corpus(Corpus), MD(MD), Options(Options) { 1400b57cec5SDimitry Andric if (EF->__sanitizer_set_death_callback) 1410b57cec5SDimitry Andric EF->__sanitizer_set_death_callback(StaticDeathCallback); 1420b57cec5SDimitry Andric assert(!F); 1430b57cec5SDimitry Andric F = this; 1440b57cec5SDimitry Andric TPC.ResetMaps(); 1450b57cec5SDimitry Andric IsMyThread = true; 1460b57cec5SDimitry Andric if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) 1470b57cec5SDimitry Andric EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); 1480b57cec5SDimitry Andric TPC.SetUseCounters(Options.UseCounters); 1490b57cec5SDimitry Andric TPC.SetUseValueProfileMask(Options.UseValueProfile); 1500b57cec5SDimitry Andric 1510b57cec5SDimitry Andric if (Options.Verbosity) 1520b57cec5SDimitry Andric TPC.PrintModuleInfo(); 1530b57cec5SDimitry Andric if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) 1540b57cec5SDimitry Andric EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); 1550b57cec5SDimitry Andric MaxInputLen = MaxMutationLen = Options.MaxLen; 1560b57cec5SDimitry Andric TmpMaxMutationLen = 0; // Will be set once we load the corpus. 1570b57cec5SDimitry Andric AllocateCurrentUnitData(); 1580b57cec5SDimitry Andric CurrentUnitSize = 0; 1590b57cec5SDimitry Andric memset(BaseSha1, 0, sizeof(BaseSha1)); 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric Fuzzer::~Fuzzer() {} 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric void Fuzzer::AllocateCurrentUnitData() { 1650b57cec5SDimitry Andric if (CurrentUnitData || MaxInputLen == 0) 1660b57cec5SDimitry Andric return; 1670b57cec5SDimitry Andric CurrentUnitData = new uint8_t[MaxInputLen]; 1680b57cec5SDimitry Andric } 1690b57cec5SDimitry Andric 1700b57cec5SDimitry Andric void Fuzzer::StaticDeathCallback() { 1710b57cec5SDimitry Andric assert(F); 1720b57cec5SDimitry Andric F->DeathCallback(); 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric void Fuzzer::DumpCurrentUnit(const char *Prefix) { 1760b57cec5SDimitry Andric if (!CurrentUnitData) 1770b57cec5SDimitry Andric return; // Happens when running individual inputs. 1780b57cec5SDimitry Andric ScopedDisableMsanInterceptorChecks S; 1790b57cec5SDimitry Andric MD.PrintMutationSequence(); 1800b57cec5SDimitry Andric Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); 1810b57cec5SDimitry Andric size_t UnitSize = CurrentUnitSize; 1820b57cec5SDimitry Andric if (UnitSize <= kMaxUnitSizeToPrint) { 1830b57cec5SDimitry Andric PrintHexArray(CurrentUnitData, UnitSize, "\n"); 1840b57cec5SDimitry Andric PrintASCII(CurrentUnitData, UnitSize, "\n"); 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, 1870b57cec5SDimitry Andric Prefix); 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric NO_SANITIZE_MEMORY 1910b57cec5SDimitry Andric void Fuzzer::DeathCallback() { 1920b57cec5SDimitry Andric DumpCurrentUnit("crash-"); 1930b57cec5SDimitry Andric PrintFinalStats(); 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric void Fuzzer::StaticAlarmCallback() { 1970b57cec5SDimitry Andric assert(F); 1980b57cec5SDimitry Andric F->AlarmCallback(); 1990b57cec5SDimitry Andric } 2000b57cec5SDimitry Andric 2010b57cec5SDimitry Andric void Fuzzer::StaticCrashSignalCallback() { 2020b57cec5SDimitry Andric assert(F); 2030b57cec5SDimitry Andric F->CrashCallback(); 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric void Fuzzer::StaticExitCallback() { 2070b57cec5SDimitry Andric assert(F); 2080b57cec5SDimitry Andric F->ExitCallback(); 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric void Fuzzer::StaticInterruptCallback() { 2120b57cec5SDimitry Andric assert(F); 2130b57cec5SDimitry Andric F->InterruptCallback(); 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric void Fuzzer::StaticGracefulExitCallback() { 2170b57cec5SDimitry Andric assert(F); 2180b57cec5SDimitry Andric F->GracefulExitRequested = true; 2190b57cec5SDimitry Andric Printf("INFO: signal received, trying to exit gracefully\n"); 2200b57cec5SDimitry Andric } 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric void Fuzzer::StaticFileSizeExceedCallback() { 2230b57cec5SDimitry Andric Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); 2240b57cec5SDimitry Andric exit(1); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric void Fuzzer::CrashCallback() { 2280b57cec5SDimitry Andric if (EF->__sanitizer_acquire_crash_state && 2290b57cec5SDimitry Andric !EF->__sanitizer_acquire_crash_state()) 2300b57cec5SDimitry Andric return; 2310b57cec5SDimitry Andric Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); 2320b57cec5SDimitry Andric PrintStackTrace(); 2330b57cec5SDimitry Andric Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" 2340b57cec5SDimitry Andric " Combine libFuzzer with AddressSanitizer or similar for better " 2350b57cec5SDimitry Andric "crash reports.\n"); 2360b57cec5SDimitry Andric Printf("SUMMARY: libFuzzer: deadly signal\n"); 2370b57cec5SDimitry Andric DumpCurrentUnit("crash-"); 2380b57cec5SDimitry Andric PrintFinalStats(); 2390b57cec5SDimitry Andric _Exit(Options.ErrorExitCode); // Stop right now. 2400b57cec5SDimitry Andric } 2410b57cec5SDimitry Andric 2420b57cec5SDimitry Andric void Fuzzer::ExitCallback() { 2430b57cec5SDimitry Andric if (!RunningUserCallback) 2440b57cec5SDimitry Andric return; // This exit did not come from the user callback 2450b57cec5SDimitry Andric if (EF->__sanitizer_acquire_crash_state && 2460b57cec5SDimitry Andric !EF->__sanitizer_acquire_crash_state()) 2470b57cec5SDimitry Andric return; 2480b57cec5SDimitry Andric Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); 2490b57cec5SDimitry Andric PrintStackTrace(); 2500b57cec5SDimitry Andric Printf("SUMMARY: libFuzzer: fuzz target exited\n"); 2510b57cec5SDimitry Andric DumpCurrentUnit("crash-"); 2520b57cec5SDimitry Andric PrintFinalStats(); 2530b57cec5SDimitry Andric _Exit(Options.ErrorExitCode); 2540b57cec5SDimitry Andric } 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric void Fuzzer::MaybeExitGracefully() { 2570b57cec5SDimitry Andric if (!F->GracefulExitRequested) return; 2580b57cec5SDimitry Andric Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid()); 2590b57cec5SDimitry Andric RmDirRecursive(TempPath(".dir")); 2600b57cec5SDimitry Andric F->PrintFinalStats(); 2610b57cec5SDimitry Andric _Exit(0); 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 2640b57cec5SDimitry Andric void Fuzzer::InterruptCallback() { 2650b57cec5SDimitry Andric Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); 2660b57cec5SDimitry Andric PrintFinalStats(); 2670b57cec5SDimitry Andric ScopedDisableMsanInterceptorChecks S; // RmDirRecursive may call opendir(). 2680b57cec5SDimitry Andric RmDirRecursive(TempPath(".dir")); 2690b57cec5SDimitry Andric // Stop right now, don't perform any at-exit actions. 2700b57cec5SDimitry Andric _Exit(Options.InterruptExitCode); 2710b57cec5SDimitry Andric } 2720b57cec5SDimitry Andric 2730b57cec5SDimitry Andric NO_SANITIZE_MEMORY 2740b57cec5SDimitry Andric void Fuzzer::AlarmCallback() { 2750b57cec5SDimitry Andric assert(Options.UnitTimeoutSec > 0); 276*68d75effSDimitry Andric // In Windows and Fuchsia, Alarm callback is executed by a different thread. 2770b57cec5SDimitry Andric // NetBSD's current behavior needs this change too. 278*68d75effSDimitry Andric #if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD && !LIBFUZZER_FUCHSIA 2790b57cec5SDimitry Andric if (!InFuzzingThread()) 2800b57cec5SDimitry Andric return; 2810b57cec5SDimitry Andric #endif 2820b57cec5SDimitry Andric if (!RunningUserCallback) 2830b57cec5SDimitry Andric return; // We have not started running units yet. 2840b57cec5SDimitry Andric size_t Seconds = 2850b57cec5SDimitry Andric duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); 2860b57cec5SDimitry Andric if (Seconds == 0) 2870b57cec5SDimitry Andric return; 2880b57cec5SDimitry Andric if (Options.Verbosity >= 2) 2890b57cec5SDimitry Andric Printf("AlarmCallback %zd\n", Seconds); 2900b57cec5SDimitry Andric if (Seconds >= (size_t)Options.UnitTimeoutSec) { 2910b57cec5SDimitry Andric if (EF->__sanitizer_acquire_crash_state && 2920b57cec5SDimitry Andric !EF->__sanitizer_acquire_crash_state()) 2930b57cec5SDimitry Andric return; 2940b57cec5SDimitry Andric Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); 2950b57cec5SDimitry Andric Printf(" and the timeout value is %d (use -timeout=N to change)\n", 2960b57cec5SDimitry Andric Options.UnitTimeoutSec); 2970b57cec5SDimitry Andric DumpCurrentUnit("timeout-"); 2980b57cec5SDimitry Andric Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), 2990b57cec5SDimitry Andric Seconds); 3000b57cec5SDimitry Andric PrintStackTrace(); 3010b57cec5SDimitry Andric Printf("SUMMARY: libFuzzer: timeout\n"); 3020b57cec5SDimitry Andric PrintFinalStats(); 3030b57cec5SDimitry Andric _Exit(Options.TimeoutExitCode); // Stop right now. 3040b57cec5SDimitry Andric } 3050b57cec5SDimitry Andric } 3060b57cec5SDimitry Andric 3070b57cec5SDimitry Andric void Fuzzer::RssLimitCallback() { 3080b57cec5SDimitry Andric if (EF->__sanitizer_acquire_crash_state && 3090b57cec5SDimitry Andric !EF->__sanitizer_acquire_crash_state()) 3100b57cec5SDimitry Andric return; 3110b57cec5SDimitry Andric Printf( 3120b57cec5SDimitry Andric "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", 3130b57cec5SDimitry Andric GetPid(), GetPeakRSSMb(), Options.RssLimitMb); 3140b57cec5SDimitry Andric Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); 3150b57cec5SDimitry Andric PrintMemoryProfile(); 3160b57cec5SDimitry Andric DumpCurrentUnit("oom-"); 3170b57cec5SDimitry Andric Printf("SUMMARY: libFuzzer: out-of-memory\n"); 3180b57cec5SDimitry Andric PrintFinalStats(); 3190b57cec5SDimitry Andric _Exit(Options.OOMExitCode); // Stop right now. 3200b57cec5SDimitry Andric } 3210b57cec5SDimitry Andric 322*68d75effSDimitry Andric void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units, 323*68d75effSDimitry Andric size_t Features) { 3240b57cec5SDimitry Andric size_t ExecPerSec = execPerSec(); 3250b57cec5SDimitry Andric if (!Options.Verbosity) 3260b57cec5SDimitry Andric return; 3270b57cec5SDimitry Andric Printf("#%zd\t%s", TotalNumberOfRuns, Where); 3280b57cec5SDimitry Andric if (size_t N = TPC.GetTotalPCCoverage()) 3290b57cec5SDimitry Andric Printf(" cov: %zd", N); 330*68d75effSDimitry Andric if (size_t N = Features ? Features : Corpus.NumFeatures()) 3310b57cec5SDimitry Andric Printf(" ft: %zd", N); 3320b57cec5SDimitry Andric if (!Corpus.empty()) { 3330b57cec5SDimitry Andric Printf(" corp: %zd", Corpus.NumActiveUnits()); 3340b57cec5SDimitry Andric if (size_t N = Corpus.SizeInBytes()) { 3350b57cec5SDimitry Andric if (N < (1 << 14)) 3360b57cec5SDimitry Andric Printf("/%zdb", N); 3370b57cec5SDimitry Andric else if (N < (1 << 24)) 3380b57cec5SDimitry Andric Printf("/%zdKb", N >> 10); 3390b57cec5SDimitry Andric else 3400b57cec5SDimitry Andric Printf("/%zdMb", N >> 20); 3410b57cec5SDimitry Andric } 3420b57cec5SDimitry Andric if (size_t FF = Corpus.NumInputsThatTouchFocusFunction()) 3430b57cec5SDimitry Andric Printf(" focus: %zd", FF); 3440b57cec5SDimitry Andric } 3450b57cec5SDimitry Andric if (TmpMaxMutationLen) 3460b57cec5SDimitry Andric Printf(" lim: %zd", TmpMaxMutationLen); 3470b57cec5SDimitry Andric if (Units) 3480b57cec5SDimitry Andric Printf(" units: %zd", Units); 3490b57cec5SDimitry Andric 3500b57cec5SDimitry Andric Printf(" exec/s: %zd", ExecPerSec); 3510b57cec5SDimitry Andric Printf(" rss: %zdMb", GetPeakRSSMb()); 3520b57cec5SDimitry Andric Printf("%s", End); 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric 3550b57cec5SDimitry Andric void Fuzzer::PrintFinalStats() { 3560b57cec5SDimitry Andric if (Options.PrintCoverage) 3570b57cec5SDimitry Andric TPC.PrintCoverage(); 3580b57cec5SDimitry Andric if (Options.PrintCorpusStats) 3590b57cec5SDimitry Andric Corpus.PrintStats(); 3600b57cec5SDimitry Andric if (!Options.PrintFinalStats) 3610b57cec5SDimitry Andric return; 3620b57cec5SDimitry Andric size_t ExecPerSec = execPerSec(); 3630b57cec5SDimitry Andric Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); 3640b57cec5SDimitry Andric Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); 3650b57cec5SDimitry Andric Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); 3660b57cec5SDimitry Andric Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); 3670b57cec5SDimitry Andric Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); 3680b57cec5SDimitry Andric } 3690b57cec5SDimitry Andric 3700b57cec5SDimitry Andric void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { 3710b57cec5SDimitry Andric assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0. 3720b57cec5SDimitry Andric assert(MaxInputLen); 3730b57cec5SDimitry Andric this->MaxInputLen = MaxInputLen; 3740b57cec5SDimitry Andric this->MaxMutationLen = MaxInputLen; 3750b57cec5SDimitry Andric AllocateCurrentUnitData(); 3760b57cec5SDimitry Andric Printf("INFO: -max_len is not provided; " 3770b57cec5SDimitry Andric "libFuzzer will not generate inputs larger than %zd bytes\n", 3780b57cec5SDimitry Andric MaxInputLen); 3790b57cec5SDimitry Andric } 3800b57cec5SDimitry Andric 3810b57cec5SDimitry Andric void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { 3820b57cec5SDimitry Andric assert(MaxMutationLen && MaxMutationLen <= MaxInputLen); 3830b57cec5SDimitry Andric this->MaxMutationLen = MaxMutationLen; 3840b57cec5SDimitry Andric } 3850b57cec5SDimitry Andric 3860b57cec5SDimitry Andric void Fuzzer::CheckExitOnSrcPosOrItem() { 3870b57cec5SDimitry Andric if (!Options.ExitOnSrcPos.empty()) { 3880b57cec5SDimitry Andric static auto *PCsSet = new Set<uintptr_t>; 3890b57cec5SDimitry Andric auto HandlePC = [&](const TracePC::PCTableEntry *TE) { 3900b57cec5SDimitry Andric if (!PCsSet->insert(TE->PC).second) 3910b57cec5SDimitry Andric return; 3920b57cec5SDimitry Andric std::string Descr = DescribePC("%F %L", TE->PC + 1); 3930b57cec5SDimitry Andric if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { 3940b57cec5SDimitry Andric Printf("INFO: found line matching '%s', exiting.\n", 3950b57cec5SDimitry Andric Options.ExitOnSrcPos.c_str()); 3960b57cec5SDimitry Andric _Exit(0); 3970b57cec5SDimitry Andric } 3980b57cec5SDimitry Andric }; 3990b57cec5SDimitry Andric TPC.ForEachObservedPC(HandlePC); 4000b57cec5SDimitry Andric } 4010b57cec5SDimitry Andric if (!Options.ExitOnItem.empty()) { 4020b57cec5SDimitry Andric if (Corpus.HasUnit(Options.ExitOnItem)) { 4030b57cec5SDimitry Andric Printf("INFO: found item with checksum '%s', exiting.\n", 4040b57cec5SDimitry Andric Options.ExitOnItem.c_str()); 4050b57cec5SDimitry Andric _Exit(0); 4060b57cec5SDimitry Andric } 4070b57cec5SDimitry Andric } 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric 4100b57cec5SDimitry Andric void Fuzzer::RereadOutputCorpus(size_t MaxSize) { 4110b57cec5SDimitry Andric if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) 4120b57cec5SDimitry Andric return; 4130b57cec5SDimitry Andric Vector<Unit> AdditionalCorpus; 4140b57cec5SDimitry Andric ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, 4150b57cec5SDimitry Andric &EpochOfLastReadOfOutputCorpus, MaxSize, 4160b57cec5SDimitry Andric /*ExitOnError*/ false); 4170b57cec5SDimitry Andric if (Options.Verbosity >= 2) 4180b57cec5SDimitry Andric Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); 4190b57cec5SDimitry Andric bool Reloaded = false; 4200b57cec5SDimitry Andric for (auto &U : AdditionalCorpus) { 4210b57cec5SDimitry Andric if (U.size() > MaxSize) 4220b57cec5SDimitry Andric U.resize(MaxSize); 4230b57cec5SDimitry Andric if (!Corpus.HasUnit(U)) { 4240b57cec5SDimitry Andric if (RunOne(U.data(), U.size())) { 4250b57cec5SDimitry Andric CheckExitOnSrcPosOrItem(); 4260b57cec5SDimitry Andric Reloaded = true; 4270b57cec5SDimitry Andric } 4280b57cec5SDimitry Andric } 4290b57cec5SDimitry Andric } 4300b57cec5SDimitry Andric if (Reloaded) 4310b57cec5SDimitry Andric PrintStats("RELOAD"); 4320b57cec5SDimitry Andric } 4330b57cec5SDimitry Andric 4340b57cec5SDimitry Andric void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { 4350b57cec5SDimitry Andric auto TimeOfUnit = 4360b57cec5SDimitry Andric duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); 4370b57cec5SDimitry Andric if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && 4380b57cec5SDimitry Andric secondsSinceProcessStartUp() >= 2) 4390b57cec5SDimitry Andric PrintStats("pulse "); 4400b57cec5SDimitry Andric if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 && 4410b57cec5SDimitry Andric TimeOfUnit >= Options.ReportSlowUnits) { 4420b57cec5SDimitry Andric TimeOfLongestUnitInSeconds = TimeOfUnit; 4430b57cec5SDimitry Andric Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); 4440b57cec5SDimitry Andric WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-"); 4450b57cec5SDimitry Andric } 4460b57cec5SDimitry Andric } 4470b57cec5SDimitry Andric 4480b57cec5SDimitry Andric static void WriteFeatureSetToFile(const std::string &FeaturesDir, 4490b57cec5SDimitry Andric const std::string &FileName, 4500b57cec5SDimitry Andric const Vector<uint32_t> &FeatureSet) { 4510b57cec5SDimitry Andric if (FeaturesDir.empty() || FeatureSet.empty()) return; 4520b57cec5SDimitry Andric WriteToFile(reinterpret_cast<const uint8_t *>(FeatureSet.data()), 4530b57cec5SDimitry Andric FeatureSet.size() * sizeof(FeatureSet[0]), 4540b57cec5SDimitry Andric DirPlusFile(FeaturesDir, FileName)); 4550b57cec5SDimitry Andric } 4560b57cec5SDimitry Andric 4570b57cec5SDimitry Andric static void RenameFeatureSetFile(const std::string &FeaturesDir, 4580b57cec5SDimitry Andric const std::string &OldFile, 4590b57cec5SDimitry Andric const std::string &NewFile) { 4600b57cec5SDimitry Andric if (FeaturesDir.empty()) return; 4610b57cec5SDimitry Andric RenameFile(DirPlusFile(FeaturesDir, OldFile), 4620b57cec5SDimitry Andric DirPlusFile(FeaturesDir, NewFile)); 4630b57cec5SDimitry Andric } 4640b57cec5SDimitry Andric 4650b57cec5SDimitry Andric bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, 4660b57cec5SDimitry Andric InputInfo *II, bool *FoundUniqFeatures) { 4670b57cec5SDimitry Andric if (!Size) 4680b57cec5SDimitry Andric return false; 4690b57cec5SDimitry Andric 4700b57cec5SDimitry Andric ExecuteCallback(Data, Size); 4710b57cec5SDimitry Andric 4720b57cec5SDimitry Andric UniqFeatureSetTmp.clear(); 4730b57cec5SDimitry Andric size_t FoundUniqFeaturesOfII = 0; 4740b57cec5SDimitry Andric size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); 4750b57cec5SDimitry Andric TPC.CollectFeatures([&](size_t Feature) { 4760b57cec5SDimitry Andric if (Corpus.AddFeature(Feature, Size, Options.Shrink)) 4770b57cec5SDimitry Andric UniqFeatureSetTmp.push_back(Feature); 4780b57cec5SDimitry Andric if (Options.ReduceInputs && II) 4790b57cec5SDimitry Andric if (std::binary_search(II->UniqFeatureSet.begin(), 4800b57cec5SDimitry Andric II->UniqFeatureSet.end(), Feature)) 4810b57cec5SDimitry Andric FoundUniqFeaturesOfII++; 4820b57cec5SDimitry Andric }); 4830b57cec5SDimitry Andric if (FoundUniqFeatures) 4840b57cec5SDimitry Andric *FoundUniqFeatures = FoundUniqFeaturesOfII; 4850b57cec5SDimitry Andric PrintPulseAndReportSlowInput(Data, Size); 4860b57cec5SDimitry Andric size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; 4870b57cec5SDimitry Andric if (NumNewFeatures) { 4880b57cec5SDimitry Andric TPC.UpdateObservedPCs(); 4890b57cec5SDimitry Andric auto NewII = Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, 4900b57cec5SDimitry Andric MayDeleteFile, TPC.ObservedFocusFunction(), 4910b57cec5SDimitry Andric UniqFeatureSetTmp, DFT, II); 4920b57cec5SDimitry Andric WriteFeatureSetToFile(Options.FeaturesDir, Sha1ToString(NewII->Sha1), 4930b57cec5SDimitry Andric NewII->UniqFeatureSet); 4940b57cec5SDimitry Andric return true; 4950b57cec5SDimitry Andric } 4960b57cec5SDimitry Andric if (II && FoundUniqFeaturesOfII && 4970b57cec5SDimitry Andric II->DataFlowTraceForFocusFunction.empty() && 4980b57cec5SDimitry Andric FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && 4990b57cec5SDimitry Andric II->U.size() > Size) { 5000b57cec5SDimitry Andric auto OldFeaturesFile = Sha1ToString(II->Sha1); 5010b57cec5SDimitry Andric Corpus.Replace(II, {Data, Data + Size}); 5020b57cec5SDimitry Andric RenameFeatureSetFile(Options.FeaturesDir, OldFeaturesFile, 5030b57cec5SDimitry Andric Sha1ToString(II->Sha1)); 5040b57cec5SDimitry Andric return true; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric return false; 5070b57cec5SDimitry Andric } 5080b57cec5SDimitry Andric 5090b57cec5SDimitry Andric size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { 5100b57cec5SDimitry Andric assert(InFuzzingThread()); 5110b57cec5SDimitry Andric *Data = CurrentUnitData; 5120b57cec5SDimitry Andric return CurrentUnitSize; 5130b57cec5SDimitry Andric } 5140b57cec5SDimitry Andric 5150b57cec5SDimitry Andric void Fuzzer::CrashOnOverwrittenData() { 516*68d75effSDimitry Andric Printf("==%d== ERROR: libFuzzer: fuzz target overwrites its const input\n", 5170b57cec5SDimitry Andric GetPid()); 518*68d75effSDimitry Andric PrintStackTrace(); 519*68d75effSDimitry Andric Printf("SUMMARY: libFuzzer: overwrites-const-input\n"); 5200b57cec5SDimitry Andric DumpCurrentUnit("crash-"); 521*68d75effSDimitry Andric PrintFinalStats(); 5220b57cec5SDimitry Andric _Exit(Options.ErrorExitCode); // Stop right now. 5230b57cec5SDimitry Andric } 5240b57cec5SDimitry Andric 5250b57cec5SDimitry Andric // Compare two arrays, but not all bytes if the arrays are large. 5260b57cec5SDimitry Andric static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { 5270b57cec5SDimitry Andric const size_t Limit = 64; 5280b57cec5SDimitry Andric if (Size <= 64) 5290b57cec5SDimitry Andric return !memcmp(A, B, Size); 5300b57cec5SDimitry Andric // Compare first and last Limit/2 bytes. 5310b57cec5SDimitry Andric return !memcmp(A, B, Limit / 2) && 5320b57cec5SDimitry Andric !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2); 5330b57cec5SDimitry Andric } 5340b57cec5SDimitry Andric 5350b57cec5SDimitry Andric void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { 5360b57cec5SDimitry Andric TPC.RecordInitialStack(); 5370b57cec5SDimitry Andric TotalNumberOfRuns++; 5380b57cec5SDimitry Andric assert(InFuzzingThread()); 5390b57cec5SDimitry Andric // We copy the contents of Unit into a separate heap buffer 5400b57cec5SDimitry Andric // so that we reliably find buffer overflows in it. 5410b57cec5SDimitry Andric uint8_t *DataCopy = new uint8_t[Size]; 5420b57cec5SDimitry Andric memcpy(DataCopy, Data, Size); 5430b57cec5SDimitry Andric if (EF->__msan_unpoison) 5440b57cec5SDimitry Andric EF->__msan_unpoison(DataCopy, Size); 5450b57cec5SDimitry Andric if (EF->__msan_unpoison_param) 5460b57cec5SDimitry Andric EF->__msan_unpoison_param(2); 5470b57cec5SDimitry Andric if (CurrentUnitData && CurrentUnitData != Data) 5480b57cec5SDimitry Andric memcpy(CurrentUnitData, Data, Size); 5490b57cec5SDimitry Andric CurrentUnitSize = Size; 5500b57cec5SDimitry Andric { 5510b57cec5SDimitry Andric ScopedEnableMsanInterceptorChecks S; 5520b57cec5SDimitry Andric AllocTracer.Start(Options.TraceMalloc); 5530b57cec5SDimitry Andric UnitStartTime = system_clock::now(); 5540b57cec5SDimitry Andric TPC.ResetMaps(); 5550b57cec5SDimitry Andric RunningUserCallback = true; 5560b57cec5SDimitry Andric int Res = CB(DataCopy, Size); 5570b57cec5SDimitry Andric RunningUserCallback = false; 5580b57cec5SDimitry Andric UnitStopTime = system_clock::now(); 5590b57cec5SDimitry Andric (void)Res; 5600b57cec5SDimitry Andric assert(Res == 0); 5610b57cec5SDimitry Andric HasMoreMallocsThanFrees = AllocTracer.Stop(); 5620b57cec5SDimitry Andric } 5630b57cec5SDimitry Andric if (!LooseMemeq(DataCopy, Data, Size)) 5640b57cec5SDimitry Andric CrashOnOverwrittenData(); 5650b57cec5SDimitry Andric CurrentUnitSize = 0; 5660b57cec5SDimitry Andric delete[] DataCopy; 5670b57cec5SDimitry Andric } 5680b57cec5SDimitry Andric 5690b57cec5SDimitry Andric std::string Fuzzer::WriteToOutputCorpus(const Unit &U) { 5700b57cec5SDimitry Andric if (Options.OnlyASCII) 5710b57cec5SDimitry Andric assert(IsASCII(U)); 5720b57cec5SDimitry Andric if (Options.OutputCorpus.empty()) 5730b57cec5SDimitry Andric return ""; 5740b57cec5SDimitry Andric std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); 5750b57cec5SDimitry Andric WriteToFile(U, Path); 5760b57cec5SDimitry Andric if (Options.Verbosity >= 2) 5770b57cec5SDimitry Andric Printf("Written %zd bytes to %s\n", U.size(), Path.c_str()); 5780b57cec5SDimitry Andric return Path; 5790b57cec5SDimitry Andric } 5800b57cec5SDimitry Andric 5810b57cec5SDimitry Andric void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { 5820b57cec5SDimitry Andric if (!Options.SaveArtifacts) 5830b57cec5SDimitry Andric return; 5840b57cec5SDimitry Andric std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); 5850b57cec5SDimitry Andric if (!Options.ExactArtifactPath.empty()) 5860b57cec5SDimitry Andric Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. 5870b57cec5SDimitry Andric WriteToFile(U, Path); 5880b57cec5SDimitry Andric Printf("artifact_prefix='%s'; Test unit written to %s\n", 5890b57cec5SDimitry Andric Options.ArtifactPrefix.c_str(), Path.c_str()); 5900b57cec5SDimitry Andric if (U.size() <= kMaxUnitSizeToPrint) 5910b57cec5SDimitry Andric Printf("Base64: %s\n", Base64(U).c_str()); 5920b57cec5SDimitry Andric } 5930b57cec5SDimitry Andric 5940b57cec5SDimitry Andric void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { 5950b57cec5SDimitry Andric if (!Options.PrintNEW) 5960b57cec5SDimitry Andric return; 5970b57cec5SDimitry Andric PrintStats(Text, ""); 5980b57cec5SDimitry Andric if (Options.Verbosity) { 5990b57cec5SDimitry Andric Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); 6000b57cec5SDimitry Andric MD.PrintMutationSequence(); 6010b57cec5SDimitry Andric Printf("\n"); 6020b57cec5SDimitry Andric } 6030b57cec5SDimitry Andric } 6040b57cec5SDimitry Andric 6050b57cec5SDimitry Andric void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { 6060b57cec5SDimitry Andric II->NumSuccessfullMutations++; 6070b57cec5SDimitry Andric MD.RecordSuccessfulMutationSequence(); 6080b57cec5SDimitry Andric PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW "); 6090b57cec5SDimitry Andric WriteToOutputCorpus(U); 6100b57cec5SDimitry Andric NumberOfNewUnitsAdded++; 6110b57cec5SDimitry Andric CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. 6120b57cec5SDimitry Andric LastCorpusUpdateRun = TotalNumberOfRuns; 6130b57cec5SDimitry Andric } 6140b57cec5SDimitry Andric 6150b57cec5SDimitry Andric // Tries detecting a memory leak on the particular input that we have just 6160b57cec5SDimitry Andric // executed before calling this function. 6170b57cec5SDimitry Andric void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, 6180b57cec5SDimitry Andric bool DuringInitialCorpusExecution) { 6190b57cec5SDimitry Andric if (!HasMoreMallocsThanFrees) 6200b57cec5SDimitry Andric return; // mallocs==frees, a leak is unlikely. 6210b57cec5SDimitry Andric if (!Options.DetectLeaks) 6220b57cec5SDimitry Andric return; 6230b57cec5SDimitry Andric if (!DuringInitialCorpusExecution && 6240b57cec5SDimitry Andric TotalNumberOfRuns >= Options.MaxNumberOfRuns) 6250b57cec5SDimitry Andric return; 6260b57cec5SDimitry Andric if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || 6270b57cec5SDimitry Andric !(EF->__lsan_do_recoverable_leak_check)) 6280b57cec5SDimitry Andric return; // No lsan. 6290b57cec5SDimitry Andric // Run the target once again, but with lsan disabled so that if there is 6300b57cec5SDimitry Andric // a real leak we do not report it twice. 6310b57cec5SDimitry Andric EF->__lsan_disable(); 6320b57cec5SDimitry Andric ExecuteCallback(Data, Size); 6330b57cec5SDimitry Andric EF->__lsan_enable(); 6340b57cec5SDimitry Andric if (!HasMoreMallocsThanFrees) 6350b57cec5SDimitry Andric return; // a leak is unlikely. 6360b57cec5SDimitry Andric if (NumberOfLeakDetectionAttempts++ > 1000) { 6370b57cec5SDimitry Andric Options.DetectLeaks = false; 6380b57cec5SDimitry Andric Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" 6390b57cec5SDimitry Andric " Most likely the target function accumulates allocated\n" 6400b57cec5SDimitry Andric " memory in a global state w/o actually leaking it.\n" 6410b57cec5SDimitry Andric " You may try running this binary with -trace_malloc=[12]" 6420b57cec5SDimitry Andric " to get a trace of mallocs and frees.\n" 6430b57cec5SDimitry Andric " If LeakSanitizer is enabled in this process it will still\n" 6440b57cec5SDimitry Andric " run on the process shutdown.\n"); 6450b57cec5SDimitry Andric return; 6460b57cec5SDimitry Andric } 6470b57cec5SDimitry Andric // Now perform the actual lsan pass. This is expensive and we must ensure 6480b57cec5SDimitry Andric // we don't call it too often. 6490b57cec5SDimitry Andric if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. 6500b57cec5SDimitry Andric if (DuringInitialCorpusExecution) 6510b57cec5SDimitry Andric Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); 6520b57cec5SDimitry Andric Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); 6530b57cec5SDimitry Andric CurrentUnitSize = Size; 6540b57cec5SDimitry Andric DumpCurrentUnit("leak-"); 6550b57cec5SDimitry Andric PrintFinalStats(); 6560b57cec5SDimitry Andric _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. 6570b57cec5SDimitry Andric } 6580b57cec5SDimitry Andric } 6590b57cec5SDimitry Andric 6600b57cec5SDimitry Andric void Fuzzer::MutateAndTestOne() { 6610b57cec5SDimitry Andric MD.StartMutationSequence(); 6620b57cec5SDimitry Andric 6630b57cec5SDimitry Andric auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); 6640b57cec5SDimitry Andric if (Options.DoCrossOver) 6650b57cec5SDimitry Andric MD.SetCrossOverWith(&Corpus.ChooseUnitToMutate(MD.GetRand()).U); 6660b57cec5SDimitry Andric const auto &U = II.U; 6670b57cec5SDimitry Andric memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); 6680b57cec5SDimitry Andric assert(CurrentUnitData); 6690b57cec5SDimitry Andric size_t Size = U.size(); 6700b57cec5SDimitry Andric assert(Size <= MaxInputLen && "Oversized Unit"); 6710b57cec5SDimitry Andric memcpy(CurrentUnitData, U.data(), Size); 6720b57cec5SDimitry Andric 6730b57cec5SDimitry Andric assert(MaxMutationLen > 0); 6740b57cec5SDimitry Andric 6750b57cec5SDimitry Andric size_t CurrentMaxMutationLen = 6760b57cec5SDimitry Andric Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen)); 6770b57cec5SDimitry Andric assert(CurrentMaxMutationLen > 0); 6780b57cec5SDimitry Andric 6790b57cec5SDimitry Andric for (int i = 0; i < Options.MutateDepth; i++) { 6800b57cec5SDimitry Andric if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 6810b57cec5SDimitry Andric break; 6820b57cec5SDimitry Andric MaybeExitGracefully(); 6830b57cec5SDimitry Andric size_t NewSize = 0; 6840b57cec5SDimitry Andric if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() && 6850b57cec5SDimitry Andric Size <= CurrentMaxMutationLen) 6860b57cec5SDimitry Andric NewSize = MD.MutateWithMask(CurrentUnitData, Size, Size, 6870b57cec5SDimitry Andric II.DataFlowTraceForFocusFunction); 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric // If MutateWithMask either failed or wasn't called, call default Mutate. 6900b57cec5SDimitry Andric if (!NewSize) 6910b57cec5SDimitry Andric NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); 6920b57cec5SDimitry Andric assert(NewSize > 0 && "Mutator returned empty unit"); 6930b57cec5SDimitry Andric assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit"); 6940b57cec5SDimitry Andric Size = NewSize; 6950b57cec5SDimitry Andric II.NumExecutedMutations++; 6960b57cec5SDimitry Andric 6970b57cec5SDimitry Andric bool FoundUniqFeatures = false; 6980b57cec5SDimitry Andric bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II, 6990b57cec5SDimitry Andric &FoundUniqFeatures); 7000b57cec5SDimitry Andric TryDetectingAMemoryLeak(CurrentUnitData, Size, 7010b57cec5SDimitry Andric /*DuringInitialCorpusExecution*/ false); 7020b57cec5SDimitry Andric if (NewCov) { 7030b57cec5SDimitry Andric ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); 7040b57cec5SDimitry Andric break; // We will mutate this input more in the next rounds. 7050b57cec5SDimitry Andric } 7060b57cec5SDimitry Andric if (Options.ReduceDepth && !FoundUniqFeatures) 7070b57cec5SDimitry Andric break; 7080b57cec5SDimitry Andric } 7090b57cec5SDimitry Andric } 7100b57cec5SDimitry Andric 7110b57cec5SDimitry Andric void Fuzzer::PurgeAllocator() { 7120b57cec5SDimitry Andric if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator) 7130b57cec5SDimitry Andric return; 7140b57cec5SDimitry Andric if (duration_cast<seconds>(system_clock::now() - 7150b57cec5SDimitry Andric LastAllocatorPurgeAttemptTime) 7160b57cec5SDimitry Andric .count() < Options.PurgeAllocatorIntervalSec) 7170b57cec5SDimitry Andric return; 7180b57cec5SDimitry Andric 7190b57cec5SDimitry Andric if (Options.RssLimitMb <= 0 || 7200b57cec5SDimitry Andric GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2) 7210b57cec5SDimitry Andric EF->__sanitizer_purge_allocator(); 7220b57cec5SDimitry Andric 7230b57cec5SDimitry Andric LastAllocatorPurgeAttemptTime = system_clock::now(); 7240b57cec5SDimitry Andric } 7250b57cec5SDimitry Andric 7260b57cec5SDimitry Andric void Fuzzer::ReadAndExecuteSeedCorpora(Vector<SizedFile> &CorporaFiles) { 7270b57cec5SDimitry Andric const size_t kMaxSaneLen = 1 << 20; 7280b57cec5SDimitry Andric const size_t kMinDefaultLen = 4096; 7290b57cec5SDimitry Andric size_t MaxSize = 0; 7300b57cec5SDimitry Andric size_t MinSize = -1; 7310b57cec5SDimitry Andric size_t TotalSize = 0; 7320b57cec5SDimitry Andric for (auto &File : CorporaFiles) { 7330b57cec5SDimitry Andric MaxSize = Max(File.Size, MaxSize); 7340b57cec5SDimitry Andric MinSize = Min(File.Size, MinSize); 7350b57cec5SDimitry Andric TotalSize += File.Size; 7360b57cec5SDimitry Andric } 7370b57cec5SDimitry Andric if (Options.MaxLen == 0) 7380b57cec5SDimitry Andric SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen)); 7390b57cec5SDimitry Andric assert(MaxInputLen > 0); 7400b57cec5SDimitry Andric 7410b57cec5SDimitry Andric // Test the callback with empty input and never try it again. 7420b57cec5SDimitry Andric uint8_t dummy = 0; 7430b57cec5SDimitry Andric ExecuteCallback(&dummy, 0); 7440b57cec5SDimitry Andric 7450b57cec5SDimitry Andric if (CorporaFiles.empty()) { 7460b57cec5SDimitry Andric Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); 7470b57cec5SDimitry Andric Unit U({'\n'}); // Valid ASCII input. 7480b57cec5SDimitry Andric RunOne(U.data(), U.size()); 7490b57cec5SDimitry Andric } else { 7500b57cec5SDimitry Andric Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb" 7510b57cec5SDimitry Andric " rss: %zdMb\n", 7520b57cec5SDimitry Andric CorporaFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb()); 7530b57cec5SDimitry Andric if (Options.ShuffleAtStartUp) 7540b57cec5SDimitry Andric std::shuffle(CorporaFiles.begin(), CorporaFiles.end(), MD.GetRand()); 7550b57cec5SDimitry Andric 7560b57cec5SDimitry Andric if (Options.PreferSmall) { 7570b57cec5SDimitry Andric std::stable_sort(CorporaFiles.begin(), CorporaFiles.end()); 7580b57cec5SDimitry Andric assert(CorporaFiles.front().Size <= CorporaFiles.back().Size); 7590b57cec5SDimitry Andric } 7600b57cec5SDimitry Andric 7610b57cec5SDimitry Andric // Load and execute inputs one by one. 7620b57cec5SDimitry Andric for (auto &SF : CorporaFiles) { 7630b57cec5SDimitry Andric auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false); 7640b57cec5SDimitry Andric assert(U.size() <= MaxInputLen); 7650b57cec5SDimitry Andric RunOne(U.data(), U.size()); 7660b57cec5SDimitry Andric CheckExitOnSrcPosOrItem(); 7670b57cec5SDimitry Andric TryDetectingAMemoryLeak(U.data(), U.size(), 7680b57cec5SDimitry Andric /*DuringInitialCorpusExecution*/ true); 7690b57cec5SDimitry Andric } 7700b57cec5SDimitry Andric } 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric PrintStats("INITED"); 7730b57cec5SDimitry Andric if (!Options.FocusFunction.empty()) 7740b57cec5SDimitry Andric Printf("INFO: %zd/%zd inputs touch the focus function\n", 7750b57cec5SDimitry Andric Corpus.NumInputsThatTouchFocusFunction(), Corpus.size()); 7760b57cec5SDimitry Andric if (!Options.DataFlowTrace.empty()) 7770b57cec5SDimitry Andric Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n", 7780b57cec5SDimitry Andric Corpus.NumInputsWithDataFlowTrace(), Corpus.size()); 7790b57cec5SDimitry Andric 7800b57cec5SDimitry Andric if (Corpus.empty() && Options.MaxNumberOfRuns) { 7810b57cec5SDimitry Andric Printf("ERROR: no interesting inputs were found. " 7820b57cec5SDimitry Andric "Is the code instrumented for coverage? Exiting.\n"); 7830b57cec5SDimitry Andric exit(1); 7840b57cec5SDimitry Andric } 7850b57cec5SDimitry Andric } 7860b57cec5SDimitry Andric 7870b57cec5SDimitry Andric void Fuzzer::Loop(Vector<SizedFile> &CorporaFiles) { 7880b57cec5SDimitry Andric auto FocusFunctionOrAuto = Options.FocusFunction; 7890b57cec5SDimitry Andric DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles, 7900b57cec5SDimitry Andric MD.GetRand()); 7910b57cec5SDimitry Andric TPC.SetFocusFunction(FocusFunctionOrAuto); 7920b57cec5SDimitry Andric ReadAndExecuteSeedCorpora(CorporaFiles); 7930b57cec5SDimitry Andric DFT.Clear(); // No need for DFT any more. 7940b57cec5SDimitry Andric TPC.SetPrintNewPCs(Options.PrintNewCovPcs); 7950b57cec5SDimitry Andric TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs); 7960b57cec5SDimitry Andric system_clock::time_point LastCorpusReload = system_clock::now(); 7970b57cec5SDimitry Andric 7980b57cec5SDimitry Andric TmpMaxMutationLen = 7990b57cec5SDimitry Andric Min(MaxMutationLen, Max(size_t(4), Corpus.MaxInputSize())); 8000b57cec5SDimitry Andric 8010b57cec5SDimitry Andric while (true) { 8020b57cec5SDimitry Andric auto Now = system_clock::now(); 8030b57cec5SDimitry Andric if (!Options.StopFile.empty() && 8040b57cec5SDimitry Andric !FileToVector(Options.StopFile, 1, false).empty()) 8050b57cec5SDimitry Andric break; 8060b57cec5SDimitry Andric if (duration_cast<seconds>(Now - LastCorpusReload).count() >= 8070b57cec5SDimitry Andric Options.ReloadIntervalSec) { 8080b57cec5SDimitry Andric RereadOutputCorpus(MaxInputLen); 8090b57cec5SDimitry Andric LastCorpusReload = system_clock::now(); 8100b57cec5SDimitry Andric } 8110b57cec5SDimitry Andric if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 8120b57cec5SDimitry Andric break; 8130b57cec5SDimitry Andric if (TimedOut()) 8140b57cec5SDimitry Andric break; 8150b57cec5SDimitry Andric 8160b57cec5SDimitry Andric // Update TmpMaxMutationLen 8170b57cec5SDimitry Andric if (Options.LenControl) { 8180b57cec5SDimitry Andric if (TmpMaxMutationLen < MaxMutationLen && 8190b57cec5SDimitry Andric TotalNumberOfRuns - LastCorpusUpdateRun > 8200b57cec5SDimitry Andric Options.LenControl * Log(TmpMaxMutationLen)) { 8210b57cec5SDimitry Andric TmpMaxMutationLen = 8220b57cec5SDimitry Andric Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen)); 8230b57cec5SDimitry Andric LastCorpusUpdateRun = TotalNumberOfRuns; 8240b57cec5SDimitry Andric } 8250b57cec5SDimitry Andric } else { 8260b57cec5SDimitry Andric TmpMaxMutationLen = MaxMutationLen; 8270b57cec5SDimitry Andric } 8280b57cec5SDimitry Andric 8290b57cec5SDimitry Andric // Perform several mutations and runs. 8300b57cec5SDimitry Andric MutateAndTestOne(); 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric PurgeAllocator(); 8330b57cec5SDimitry Andric } 8340b57cec5SDimitry Andric 8350b57cec5SDimitry Andric PrintStats("DONE ", "\n"); 8360b57cec5SDimitry Andric MD.PrintRecommendedDictionary(); 8370b57cec5SDimitry Andric } 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric void Fuzzer::MinimizeCrashLoop(const Unit &U) { 8400b57cec5SDimitry Andric if (U.size() <= 1) 8410b57cec5SDimitry Andric return; 8420b57cec5SDimitry Andric while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { 8430b57cec5SDimitry Andric MD.StartMutationSequence(); 8440b57cec5SDimitry Andric memcpy(CurrentUnitData, U.data(), U.size()); 8450b57cec5SDimitry Andric for (int i = 0; i < Options.MutateDepth; i++) { 8460b57cec5SDimitry Andric size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); 8470b57cec5SDimitry Andric assert(NewSize > 0 && NewSize <= MaxMutationLen); 8480b57cec5SDimitry Andric ExecuteCallback(CurrentUnitData, NewSize); 8490b57cec5SDimitry Andric PrintPulseAndReportSlowInput(CurrentUnitData, NewSize); 8500b57cec5SDimitry Andric TryDetectingAMemoryLeak(CurrentUnitData, NewSize, 8510b57cec5SDimitry Andric /*DuringInitialCorpusExecution*/ false); 8520b57cec5SDimitry Andric } 8530b57cec5SDimitry Andric } 8540b57cec5SDimitry Andric } 8550b57cec5SDimitry Andric 8560b57cec5SDimitry Andric } // namespace fuzzer 8570b57cec5SDimitry Andric 8580b57cec5SDimitry Andric extern "C" { 8590b57cec5SDimitry Andric 8600b57cec5SDimitry Andric ATTRIBUTE_INTERFACE size_t 8610b57cec5SDimitry Andric LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { 8620b57cec5SDimitry Andric assert(fuzzer::F); 8630b57cec5SDimitry Andric return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); 8640b57cec5SDimitry Andric } 8650b57cec5SDimitry Andric 8660b57cec5SDimitry Andric } // extern "C" 867