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> 2210ab2aceSGeorge Karpenkov #include <set> 2310ab2aceSGeorge Karpenkov 2410ab2aceSGeorge Karpenkov #if defined(__has_include) 2510ab2aceSGeorge Karpenkov #if __has_include(<sanitizer / lsan_interface.h>) 2610ab2aceSGeorge Karpenkov #include <sanitizer/lsan_interface.h> 2710ab2aceSGeorge Karpenkov #endif 2810ab2aceSGeorge Karpenkov #endif 2910ab2aceSGeorge Karpenkov 3010ab2aceSGeorge Karpenkov #define NO_SANITIZE_MEMORY 3110ab2aceSGeorge Karpenkov #if defined(__has_feature) 3210ab2aceSGeorge Karpenkov #if __has_feature(memory_sanitizer) 3310ab2aceSGeorge Karpenkov #undef NO_SANITIZE_MEMORY 3410ab2aceSGeorge Karpenkov #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory)) 3510ab2aceSGeorge Karpenkov #endif 3610ab2aceSGeorge Karpenkov #endif 3710ab2aceSGeorge Karpenkov 3810ab2aceSGeorge Karpenkov namespace fuzzer { 3910ab2aceSGeorge Karpenkov static const size_t kMaxUnitSizeToPrint = 256; 4010ab2aceSGeorge Karpenkov 4110ab2aceSGeorge Karpenkov thread_local bool Fuzzer::IsMyThread; 4210ab2aceSGeorge Karpenkov 4310ab2aceSGeorge Karpenkov SharedMemoryRegion SMR; 4410ab2aceSGeorge Karpenkov 4510ab2aceSGeorge Karpenkov // Only one Fuzzer per process. 4610ab2aceSGeorge Karpenkov static Fuzzer *F; 4710ab2aceSGeorge Karpenkov 4810ab2aceSGeorge Karpenkov // Leak detection is expensive, so we first check if there were more mallocs 4910ab2aceSGeorge Karpenkov // than frees (using the sanitizer malloc hooks) and only then try to call lsan. 5010ab2aceSGeorge Karpenkov struct MallocFreeTracer { 5110ab2aceSGeorge Karpenkov void Start(int TraceLevel) { 5210ab2aceSGeorge Karpenkov this->TraceLevel = TraceLevel; 5310ab2aceSGeorge Karpenkov if (TraceLevel) 5410ab2aceSGeorge Karpenkov Printf("MallocFreeTracer: START\n"); 5510ab2aceSGeorge Karpenkov Mallocs = 0; 5610ab2aceSGeorge Karpenkov Frees = 0; 5710ab2aceSGeorge Karpenkov } 5810ab2aceSGeorge Karpenkov // Returns true if there were more mallocs than frees. 5910ab2aceSGeorge Karpenkov bool Stop() { 6010ab2aceSGeorge Karpenkov if (TraceLevel) 6110ab2aceSGeorge Karpenkov Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(), 6210ab2aceSGeorge Karpenkov Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT"); 6310ab2aceSGeorge Karpenkov bool Result = Mallocs > Frees; 6410ab2aceSGeorge Karpenkov Mallocs = 0; 6510ab2aceSGeorge Karpenkov Frees = 0; 6610ab2aceSGeorge Karpenkov TraceLevel = 0; 6710ab2aceSGeorge Karpenkov return Result; 6810ab2aceSGeorge Karpenkov } 6910ab2aceSGeorge Karpenkov std::atomic<size_t> Mallocs; 7010ab2aceSGeorge Karpenkov std::atomic<size_t> Frees; 7110ab2aceSGeorge Karpenkov int TraceLevel = 0; 7210ab2aceSGeorge Karpenkov }; 7310ab2aceSGeorge Karpenkov 7410ab2aceSGeorge Karpenkov static MallocFreeTracer AllocTracer; 7510ab2aceSGeorge Karpenkov 7610ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY 7710ab2aceSGeorge Karpenkov void MallocHook(const volatile void *ptr, size_t size) { 7810ab2aceSGeorge Karpenkov size_t N = AllocTracer.Mallocs++; 7910ab2aceSGeorge Karpenkov F->HandleMalloc(size); 8010ab2aceSGeorge Karpenkov if (int TraceLevel = AllocTracer.TraceLevel) { 8110ab2aceSGeorge Karpenkov Printf("MALLOC[%zd] %p %zd\n", N, ptr, size); 8210ab2aceSGeorge Karpenkov if (TraceLevel >= 2 && EF) 8310ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 8410ab2aceSGeorge Karpenkov } 8510ab2aceSGeorge Karpenkov } 8610ab2aceSGeorge Karpenkov 8710ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY 8810ab2aceSGeorge Karpenkov void FreeHook(const volatile void *ptr) { 8910ab2aceSGeorge Karpenkov size_t N = AllocTracer.Frees++; 9010ab2aceSGeorge Karpenkov if (int TraceLevel = AllocTracer.TraceLevel) { 9110ab2aceSGeorge Karpenkov Printf("FREE[%zd] %p\n", N, ptr); 9210ab2aceSGeorge Karpenkov if (TraceLevel >= 2 && EF) 9310ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 9410ab2aceSGeorge Karpenkov } 9510ab2aceSGeorge Karpenkov } 9610ab2aceSGeorge Karpenkov 9710ab2aceSGeorge Karpenkov // Crash on a single malloc that exceeds the rss limit. 9810ab2aceSGeorge Karpenkov void Fuzzer::HandleMalloc(size_t Size) { 9910ab2aceSGeorge Karpenkov if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb) 10010ab2aceSGeorge Karpenkov return; 10110ab2aceSGeorge Karpenkov Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(), 10210ab2aceSGeorge Karpenkov Size); 10310ab2aceSGeorge Karpenkov Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); 10410ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_stack_trace) 10510ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 10610ab2aceSGeorge Karpenkov DumpCurrentUnit("oom-"); 10710ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: out-of-memory\n"); 10810ab2aceSGeorge Karpenkov PrintFinalStats(); 10910ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now. 11010ab2aceSGeorge Karpenkov } 11110ab2aceSGeorge Karpenkov 11210ab2aceSGeorge Karpenkov Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, 11310ab2aceSGeorge Karpenkov FuzzingOptions Options) 11410ab2aceSGeorge Karpenkov : CB(CB), Corpus(Corpus), MD(MD), Options(Options) { 11510ab2aceSGeorge Karpenkov if (EF->__sanitizer_set_death_callback) 11610ab2aceSGeorge Karpenkov EF->__sanitizer_set_death_callback(StaticDeathCallback); 11710ab2aceSGeorge Karpenkov assert(!F); 11810ab2aceSGeorge Karpenkov F = this; 11910ab2aceSGeorge Karpenkov TPC.ResetMaps(); 12010ab2aceSGeorge Karpenkov IsMyThread = true; 12110ab2aceSGeorge Karpenkov if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks) 12210ab2aceSGeorge Karpenkov EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook); 12310ab2aceSGeorge Karpenkov TPC.SetUseCounters(Options.UseCounters); 12410ab2aceSGeorge Karpenkov TPC.SetUseValueProfile(Options.UseValueProfile); 125330496c3SMax Moroz TPC.SetUseClangCoverage(Options.UseClangCoverage); 12610ab2aceSGeorge Karpenkov 12710ab2aceSGeorge Karpenkov if (Options.Verbosity) 12810ab2aceSGeorge Karpenkov TPC.PrintModuleInfo(); 12910ab2aceSGeorge Karpenkov if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) 13010ab2aceSGeorge Karpenkov EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); 13110ab2aceSGeorge Karpenkov MaxInputLen = MaxMutationLen = Options.MaxLen; 13210ab2aceSGeorge Karpenkov TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize()); 13310ab2aceSGeorge Karpenkov AllocateCurrentUnitData(); 13410ab2aceSGeorge Karpenkov CurrentUnitSize = 0; 13510ab2aceSGeorge Karpenkov memset(BaseSha1, 0, sizeof(BaseSha1)); 13610ab2aceSGeorge Karpenkov } 13710ab2aceSGeorge Karpenkov 13810ab2aceSGeorge Karpenkov Fuzzer::~Fuzzer() { } 13910ab2aceSGeorge Karpenkov 14010ab2aceSGeorge Karpenkov void Fuzzer::AllocateCurrentUnitData() { 14110ab2aceSGeorge Karpenkov if (CurrentUnitData || MaxInputLen == 0) return; 14210ab2aceSGeorge Karpenkov CurrentUnitData = new uint8_t[MaxInputLen]; 14310ab2aceSGeorge Karpenkov } 14410ab2aceSGeorge Karpenkov 14510ab2aceSGeorge Karpenkov void Fuzzer::StaticDeathCallback() { 14610ab2aceSGeorge Karpenkov assert(F); 14710ab2aceSGeorge Karpenkov F->DeathCallback(); 14810ab2aceSGeorge Karpenkov } 14910ab2aceSGeorge Karpenkov 15010ab2aceSGeorge Karpenkov void Fuzzer::DumpCurrentUnit(const char *Prefix) { 15110ab2aceSGeorge Karpenkov if (!CurrentUnitData) return; // Happens when running individual inputs. 15210ab2aceSGeorge Karpenkov MD.PrintMutationSequence(); 15310ab2aceSGeorge Karpenkov Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); 15410ab2aceSGeorge Karpenkov size_t UnitSize = CurrentUnitSize; 15510ab2aceSGeorge Karpenkov if (UnitSize <= kMaxUnitSizeToPrint) { 15610ab2aceSGeorge Karpenkov PrintHexArray(CurrentUnitData, UnitSize, "\n"); 15710ab2aceSGeorge Karpenkov PrintASCII(CurrentUnitData, UnitSize, "\n"); 15810ab2aceSGeorge Karpenkov } 15910ab2aceSGeorge Karpenkov WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, 16010ab2aceSGeorge Karpenkov Prefix); 16110ab2aceSGeorge Karpenkov } 16210ab2aceSGeorge Karpenkov 16310ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY 16410ab2aceSGeorge Karpenkov void Fuzzer::DeathCallback() { 16510ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 16610ab2aceSGeorge Karpenkov PrintFinalStats(); 16710ab2aceSGeorge Karpenkov } 16810ab2aceSGeorge Karpenkov 16910ab2aceSGeorge Karpenkov void Fuzzer::StaticAlarmCallback() { 17010ab2aceSGeorge Karpenkov assert(F); 17110ab2aceSGeorge Karpenkov F->AlarmCallback(); 17210ab2aceSGeorge Karpenkov } 17310ab2aceSGeorge Karpenkov 17410ab2aceSGeorge Karpenkov void Fuzzer::StaticCrashSignalCallback() { 17510ab2aceSGeorge Karpenkov assert(F); 17610ab2aceSGeorge Karpenkov F->CrashCallback(); 17710ab2aceSGeorge Karpenkov } 17810ab2aceSGeorge Karpenkov 17910ab2aceSGeorge Karpenkov void Fuzzer::StaticExitCallback() { 18010ab2aceSGeorge Karpenkov assert(F); 18110ab2aceSGeorge Karpenkov F->ExitCallback(); 18210ab2aceSGeorge Karpenkov } 18310ab2aceSGeorge Karpenkov 18410ab2aceSGeorge Karpenkov void Fuzzer::StaticInterruptCallback() { 18510ab2aceSGeorge Karpenkov assert(F); 18610ab2aceSGeorge Karpenkov F->InterruptCallback(); 18710ab2aceSGeorge Karpenkov } 18810ab2aceSGeorge Karpenkov 18910ab2aceSGeorge Karpenkov void Fuzzer::StaticFileSizeExceedCallback() { 19010ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); 19110ab2aceSGeorge Karpenkov exit(1); 19210ab2aceSGeorge Karpenkov } 19310ab2aceSGeorge Karpenkov 19410ab2aceSGeorge Karpenkov void Fuzzer::CrashCallback() { 19510ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); 19610ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_stack_trace) 19710ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 19810ab2aceSGeorge Karpenkov Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" 19910ab2aceSGeorge Karpenkov " Combine libFuzzer with AddressSanitizer or similar for better " 20010ab2aceSGeorge Karpenkov "crash reports.\n"); 20110ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: deadly signal\n"); 20210ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 20310ab2aceSGeorge Karpenkov PrintFinalStats(); 20410ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now. 20510ab2aceSGeorge Karpenkov } 20610ab2aceSGeorge Karpenkov 20710ab2aceSGeorge Karpenkov void Fuzzer::ExitCallback() { 20810ab2aceSGeorge Karpenkov if (!RunningCB) 20910ab2aceSGeorge Karpenkov return; // This exit did not come from the user callback 21010ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); 21110ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_stack_trace) 21210ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 21310ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: fuzz target exited\n"); 21410ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 21510ab2aceSGeorge Karpenkov PrintFinalStats(); 21610ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); 21710ab2aceSGeorge Karpenkov } 21810ab2aceSGeorge Karpenkov 21910ab2aceSGeorge Karpenkov 22010ab2aceSGeorge Karpenkov void Fuzzer::InterruptCallback() { 22110ab2aceSGeorge Karpenkov Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); 22210ab2aceSGeorge Karpenkov PrintFinalStats(); 22310ab2aceSGeorge Karpenkov _Exit(0); // Stop right now, don't perform any at-exit actions. 22410ab2aceSGeorge Karpenkov } 22510ab2aceSGeorge Karpenkov 22610ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY 22710ab2aceSGeorge Karpenkov void Fuzzer::AlarmCallback() { 22810ab2aceSGeorge Karpenkov assert(Options.UnitTimeoutSec > 0); 22910ab2aceSGeorge Karpenkov // In Windows Alarm callback is executed by a different thread. 23010ab2aceSGeorge Karpenkov #if !LIBFUZZER_WINDOWS 23110ab2aceSGeorge Karpenkov if (!InFuzzingThread()) return; 23210ab2aceSGeorge Karpenkov #endif 23310ab2aceSGeorge Karpenkov if (!RunningCB) 23410ab2aceSGeorge Karpenkov return; // We have not started running units yet. 23510ab2aceSGeorge Karpenkov size_t Seconds = 23610ab2aceSGeorge Karpenkov duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); 23710ab2aceSGeorge Karpenkov if (Seconds == 0) 23810ab2aceSGeorge Karpenkov return; 23910ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2) 24010ab2aceSGeorge Karpenkov Printf("AlarmCallback %zd\n", Seconds); 24110ab2aceSGeorge Karpenkov if (Seconds >= (size_t)Options.UnitTimeoutSec) { 24210ab2aceSGeorge Karpenkov Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); 24310ab2aceSGeorge Karpenkov Printf(" and the timeout value is %d (use -timeout=N to change)\n", 24410ab2aceSGeorge Karpenkov Options.UnitTimeoutSec); 24510ab2aceSGeorge Karpenkov DumpCurrentUnit("timeout-"); 24610ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), 24710ab2aceSGeorge Karpenkov Seconds); 24810ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_stack_trace) 24910ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 25010ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: timeout\n"); 25110ab2aceSGeorge Karpenkov PrintFinalStats(); 25210ab2aceSGeorge Karpenkov _Exit(Options.TimeoutExitCode); // Stop right now. 25310ab2aceSGeorge Karpenkov } 25410ab2aceSGeorge Karpenkov } 25510ab2aceSGeorge Karpenkov 25610ab2aceSGeorge Karpenkov void Fuzzer::RssLimitCallback() { 25710ab2aceSGeorge Karpenkov Printf( 25810ab2aceSGeorge Karpenkov "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", 25910ab2aceSGeorge Karpenkov GetPid(), GetPeakRSSMb(), Options.RssLimitMb); 26010ab2aceSGeorge Karpenkov Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); 26110ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_memory_profile) 26210ab2aceSGeorge Karpenkov EF->__sanitizer_print_memory_profile(95, 8); 26310ab2aceSGeorge Karpenkov DumpCurrentUnit("oom-"); 26410ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: out-of-memory\n"); 26510ab2aceSGeorge Karpenkov PrintFinalStats(); 26610ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now. 26710ab2aceSGeorge Karpenkov } 26810ab2aceSGeorge Karpenkov 26910ab2aceSGeorge Karpenkov void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { 27010ab2aceSGeorge Karpenkov size_t ExecPerSec = execPerSec(); 27110ab2aceSGeorge Karpenkov if (!Options.Verbosity) 27210ab2aceSGeorge Karpenkov return; 27310ab2aceSGeorge Karpenkov Printf("#%zd\t%s", TotalNumberOfRuns, Where); 27410ab2aceSGeorge Karpenkov if (size_t N = TPC.GetTotalPCCoverage()) 27510ab2aceSGeorge Karpenkov Printf(" cov: %zd", N); 27610ab2aceSGeorge Karpenkov if (size_t N = Corpus.NumFeatures()) 27710ab2aceSGeorge Karpenkov Printf( " ft: %zd", N); 27810ab2aceSGeorge Karpenkov if (!Corpus.empty()) { 27910ab2aceSGeorge Karpenkov Printf(" corp: %zd", Corpus.NumActiveUnits()); 28010ab2aceSGeorge Karpenkov if (size_t N = Corpus.SizeInBytes()) { 28110ab2aceSGeorge Karpenkov if (N < (1<<14)) 28210ab2aceSGeorge Karpenkov Printf("/%zdb", N); 28310ab2aceSGeorge Karpenkov else if (N < (1 << 24)) 28410ab2aceSGeorge Karpenkov Printf("/%zdKb", N >> 10); 28510ab2aceSGeorge Karpenkov else 28610ab2aceSGeorge Karpenkov Printf("/%zdMb", N >> 20); 28710ab2aceSGeorge Karpenkov } 28810ab2aceSGeorge Karpenkov } 28910ab2aceSGeorge Karpenkov if (Units) 29010ab2aceSGeorge Karpenkov Printf(" units: %zd", Units); 29110ab2aceSGeorge Karpenkov 29210ab2aceSGeorge Karpenkov Printf(" exec/s: %zd", ExecPerSec); 29310ab2aceSGeorge Karpenkov Printf(" rss: %zdMb", GetPeakRSSMb()); 29410ab2aceSGeorge Karpenkov Printf("%s", End); 29510ab2aceSGeorge Karpenkov } 29610ab2aceSGeorge Karpenkov 29710ab2aceSGeorge Karpenkov void Fuzzer::PrintFinalStats() { 29810ab2aceSGeorge Karpenkov if (Options.PrintCoverage) 29910ab2aceSGeorge Karpenkov TPC.PrintCoverage(); 30010ab2aceSGeorge Karpenkov if (Options.DumpCoverage) 30110ab2aceSGeorge Karpenkov TPC.DumpCoverage(); 30210ab2aceSGeorge Karpenkov if (Options.PrintCorpusStats) 30310ab2aceSGeorge Karpenkov Corpus.PrintStats(); 30410ab2aceSGeorge Karpenkov if (!Options.PrintFinalStats) return; 30510ab2aceSGeorge Karpenkov size_t ExecPerSec = execPerSec(); 30610ab2aceSGeorge Karpenkov Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); 30710ab2aceSGeorge Karpenkov Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); 30810ab2aceSGeorge Karpenkov Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); 30910ab2aceSGeorge Karpenkov Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); 31010ab2aceSGeorge Karpenkov Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); 31110ab2aceSGeorge Karpenkov } 31210ab2aceSGeorge Karpenkov 31310ab2aceSGeorge Karpenkov void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { 31410ab2aceSGeorge Karpenkov assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0. 31510ab2aceSGeorge Karpenkov assert(MaxInputLen); 31610ab2aceSGeorge Karpenkov this->MaxInputLen = MaxInputLen; 31710ab2aceSGeorge Karpenkov this->MaxMutationLen = MaxInputLen; 31810ab2aceSGeorge Karpenkov AllocateCurrentUnitData(); 31910ab2aceSGeorge Karpenkov Printf("INFO: -max_len is not provided; " 32010ab2aceSGeorge Karpenkov "libFuzzer will not generate inputs larger than %zd bytes\n", 32110ab2aceSGeorge Karpenkov MaxInputLen); 32210ab2aceSGeorge Karpenkov } 32310ab2aceSGeorge Karpenkov 32410ab2aceSGeorge Karpenkov void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { 32510ab2aceSGeorge Karpenkov assert(MaxMutationLen && MaxMutationLen <= MaxInputLen); 32610ab2aceSGeorge Karpenkov this->MaxMutationLen = MaxMutationLen; 32710ab2aceSGeorge Karpenkov } 32810ab2aceSGeorge Karpenkov 32910ab2aceSGeorge Karpenkov void Fuzzer::CheckExitOnSrcPosOrItem() { 33010ab2aceSGeorge Karpenkov if (!Options.ExitOnSrcPos.empty()) { 331bebcbfb4SGeorge Karpenkov static auto *PCsSet = new Set<uintptr_t>; 33210ab2aceSGeorge Karpenkov auto HandlePC = [&](uintptr_t PC) { 33310ab2aceSGeorge Karpenkov if (!PCsSet->insert(PC).second) return; 33410ab2aceSGeorge Karpenkov std::string Descr = DescribePC("%F %L", PC + 1); 33510ab2aceSGeorge Karpenkov if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { 33610ab2aceSGeorge Karpenkov Printf("INFO: found line matching '%s', exiting.\n", 33710ab2aceSGeorge Karpenkov Options.ExitOnSrcPos.c_str()); 33810ab2aceSGeorge Karpenkov _Exit(0); 33910ab2aceSGeorge Karpenkov } 34010ab2aceSGeorge Karpenkov }; 34110ab2aceSGeorge Karpenkov TPC.ForEachObservedPC(HandlePC); 34210ab2aceSGeorge Karpenkov } 34310ab2aceSGeorge Karpenkov if (!Options.ExitOnItem.empty()) { 34410ab2aceSGeorge Karpenkov if (Corpus.HasUnit(Options.ExitOnItem)) { 34510ab2aceSGeorge Karpenkov Printf("INFO: found item with checksum '%s', exiting.\n", 34610ab2aceSGeorge Karpenkov Options.ExitOnItem.c_str()); 34710ab2aceSGeorge Karpenkov _Exit(0); 34810ab2aceSGeorge Karpenkov } 34910ab2aceSGeorge Karpenkov } 35010ab2aceSGeorge Karpenkov } 35110ab2aceSGeorge Karpenkov 35210ab2aceSGeorge Karpenkov void Fuzzer::RereadOutputCorpus(size_t MaxSize) { 35310ab2aceSGeorge Karpenkov if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; 354bebcbfb4SGeorge Karpenkov Vector<Unit> AdditionalCorpus; 35510ab2aceSGeorge Karpenkov ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, 35610ab2aceSGeorge Karpenkov &EpochOfLastReadOfOutputCorpus, MaxSize, 35710ab2aceSGeorge Karpenkov /*ExitOnError*/ false); 35810ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2) 35910ab2aceSGeorge Karpenkov Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); 36010ab2aceSGeorge Karpenkov bool Reloaded = false; 36110ab2aceSGeorge Karpenkov for (auto &U : AdditionalCorpus) { 36210ab2aceSGeorge Karpenkov if (U.size() > MaxSize) 36310ab2aceSGeorge Karpenkov U.resize(MaxSize); 36410ab2aceSGeorge Karpenkov if (!Corpus.HasUnit(U)) { 36510ab2aceSGeorge Karpenkov if (RunOne(U.data(), U.size())) { 36610ab2aceSGeorge Karpenkov CheckExitOnSrcPosOrItem(); 36710ab2aceSGeorge Karpenkov Reloaded = true; 36810ab2aceSGeorge Karpenkov } 36910ab2aceSGeorge Karpenkov } 37010ab2aceSGeorge Karpenkov } 37110ab2aceSGeorge Karpenkov if (Reloaded) 37210ab2aceSGeorge Karpenkov PrintStats("RELOAD"); 37310ab2aceSGeorge Karpenkov } 37410ab2aceSGeorge Karpenkov 37510ab2aceSGeorge Karpenkov void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { 37610ab2aceSGeorge Karpenkov auto TimeOfUnit = 37710ab2aceSGeorge Karpenkov duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); 37810ab2aceSGeorge Karpenkov if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && 37910ab2aceSGeorge Karpenkov secondsSinceProcessStartUp() >= 2) 38010ab2aceSGeorge Karpenkov PrintStats("pulse "); 38110ab2aceSGeorge Karpenkov if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 && 38210ab2aceSGeorge Karpenkov TimeOfUnit >= Options.ReportSlowUnits) { 38310ab2aceSGeorge Karpenkov TimeOfLongestUnitInSeconds = TimeOfUnit; 38410ab2aceSGeorge Karpenkov Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); 38510ab2aceSGeorge Karpenkov WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-"); 38610ab2aceSGeorge Karpenkov } 38710ab2aceSGeorge Karpenkov } 38810ab2aceSGeorge Karpenkov 38910ab2aceSGeorge Karpenkov bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, 39010ab2aceSGeorge Karpenkov InputInfo *II) { 39110ab2aceSGeorge Karpenkov if (!Size) return false; 39210ab2aceSGeorge Karpenkov 39310ab2aceSGeorge Karpenkov ExecuteCallback(Data, Size); 39410ab2aceSGeorge Karpenkov 39510ab2aceSGeorge Karpenkov UniqFeatureSetTmp.clear(); 39610ab2aceSGeorge Karpenkov size_t FoundUniqFeaturesOfII = 0; 39710ab2aceSGeorge Karpenkov size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); 39810ab2aceSGeorge Karpenkov TPC.CollectFeatures([&](size_t Feature) { 399*4083d546SKostya Serebryany Corpus.UpdateFeatureFrequency(Feature); 40010ab2aceSGeorge Karpenkov if (Corpus.AddFeature(Feature, Size, Options.Shrink)) 40110ab2aceSGeorge Karpenkov UniqFeatureSetTmp.push_back(Feature); 40210ab2aceSGeorge Karpenkov if (Options.ReduceInputs && II) 40310ab2aceSGeorge Karpenkov if (std::binary_search(II->UniqFeatureSet.begin(), 40410ab2aceSGeorge Karpenkov II->UniqFeatureSet.end(), Feature)) 40510ab2aceSGeorge Karpenkov FoundUniqFeaturesOfII++; 40610ab2aceSGeorge Karpenkov }); 40710ab2aceSGeorge Karpenkov PrintPulseAndReportSlowInput(Data, Size); 40810ab2aceSGeorge Karpenkov size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; 40910ab2aceSGeorge Karpenkov if (NumNewFeatures) { 41010ab2aceSGeorge Karpenkov TPC.UpdateObservedPCs(); 41110ab2aceSGeorge Karpenkov Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, 41210ab2aceSGeorge Karpenkov UniqFeatureSetTmp); 41310ab2aceSGeorge Karpenkov return true; 41410ab2aceSGeorge Karpenkov } 41510ab2aceSGeorge Karpenkov if (II && FoundUniqFeaturesOfII && 41610ab2aceSGeorge Karpenkov FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && 41710ab2aceSGeorge Karpenkov II->U.size() > Size) { 41810ab2aceSGeorge Karpenkov Corpus.Replace(II, {Data, Data + Size}); 41910ab2aceSGeorge Karpenkov return true; 42010ab2aceSGeorge Karpenkov } 42110ab2aceSGeorge Karpenkov return false; 42210ab2aceSGeorge Karpenkov } 42310ab2aceSGeorge Karpenkov 42410ab2aceSGeorge Karpenkov size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { 42510ab2aceSGeorge Karpenkov assert(InFuzzingThread()); 42610ab2aceSGeorge Karpenkov *Data = CurrentUnitData; 42710ab2aceSGeorge Karpenkov return CurrentUnitSize; 42810ab2aceSGeorge Karpenkov } 42910ab2aceSGeorge Karpenkov 43010ab2aceSGeorge Karpenkov void Fuzzer::CrashOnOverwrittenData() { 43110ab2aceSGeorge Karpenkov Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n", 43210ab2aceSGeorge Karpenkov GetPid()); 43310ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 43410ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: out-of-memory\n"); 43510ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now. 43610ab2aceSGeorge Karpenkov } 43710ab2aceSGeorge Karpenkov 43810ab2aceSGeorge Karpenkov // Compare two arrays, but not all bytes if the arrays are large. 43910ab2aceSGeorge Karpenkov static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { 44010ab2aceSGeorge Karpenkov const size_t Limit = 64; 44110ab2aceSGeorge Karpenkov if (Size <= 64) 44210ab2aceSGeorge Karpenkov return !memcmp(A, B, Size); 44310ab2aceSGeorge Karpenkov // Compare first and last Limit/2 bytes. 44410ab2aceSGeorge Karpenkov return !memcmp(A, B, Limit / 2) && 44510ab2aceSGeorge Karpenkov !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2); 44610ab2aceSGeorge Karpenkov } 44710ab2aceSGeorge Karpenkov 44810ab2aceSGeorge Karpenkov void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { 44910ab2aceSGeorge Karpenkov TPC.RecordInitialStack(); 45010ab2aceSGeorge Karpenkov TotalNumberOfRuns++; 45110ab2aceSGeorge Karpenkov assert(InFuzzingThread()); 45210ab2aceSGeorge Karpenkov if (SMR.IsClient()) 45310ab2aceSGeorge Karpenkov SMR.WriteByteArray(Data, Size); 45410ab2aceSGeorge Karpenkov // We copy the contents of Unit into a separate heap buffer 45510ab2aceSGeorge Karpenkov // so that we reliably find buffer overflows in it. 45610ab2aceSGeorge Karpenkov uint8_t *DataCopy = new uint8_t[Size]; 45710ab2aceSGeorge Karpenkov memcpy(DataCopy, Data, Size); 45810ab2aceSGeorge Karpenkov if (CurrentUnitData && CurrentUnitData != Data) 45910ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, Data, Size); 46010ab2aceSGeorge Karpenkov CurrentUnitSize = Size; 46110ab2aceSGeorge Karpenkov AllocTracer.Start(Options.TraceMalloc); 46210ab2aceSGeorge Karpenkov UnitStartTime = system_clock::now(); 46310ab2aceSGeorge Karpenkov TPC.ResetMaps(); 46410ab2aceSGeorge Karpenkov RunningCB = true; 46510ab2aceSGeorge Karpenkov int Res = CB(DataCopy, Size); 46610ab2aceSGeorge Karpenkov RunningCB = false; 46710ab2aceSGeorge Karpenkov UnitStopTime = system_clock::now(); 46810ab2aceSGeorge Karpenkov (void)Res; 46910ab2aceSGeorge Karpenkov assert(Res == 0); 47010ab2aceSGeorge Karpenkov HasMoreMallocsThanFrees = AllocTracer.Stop(); 47110ab2aceSGeorge Karpenkov if (!LooseMemeq(DataCopy, Data, Size)) 47210ab2aceSGeorge Karpenkov CrashOnOverwrittenData(); 47310ab2aceSGeorge Karpenkov CurrentUnitSize = 0; 47410ab2aceSGeorge Karpenkov delete[] DataCopy; 47510ab2aceSGeorge Karpenkov } 47610ab2aceSGeorge Karpenkov 47710ab2aceSGeorge Karpenkov void Fuzzer::WriteToOutputCorpus(const Unit &U) { 47810ab2aceSGeorge Karpenkov if (Options.OnlyASCII) 47910ab2aceSGeorge Karpenkov assert(IsASCII(U)); 48010ab2aceSGeorge Karpenkov if (Options.OutputCorpus.empty()) 48110ab2aceSGeorge Karpenkov return; 48210ab2aceSGeorge Karpenkov std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); 48310ab2aceSGeorge Karpenkov WriteToFile(U, Path); 48410ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2) 48510ab2aceSGeorge Karpenkov Printf("Written %zd bytes to %s\n", U.size(), Path.c_str()); 48610ab2aceSGeorge Karpenkov } 48710ab2aceSGeorge Karpenkov 48810ab2aceSGeorge Karpenkov void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { 48910ab2aceSGeorge Karpenkov if (!Options.SaveArtifacts) 49010ab2aceSGeorge Karpenkov return; 49110ab2aceSGeorge Karpenkov std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); 49210ab2aceSGeorge Karpenkov if (!Options.ExactArtifactPath.empty()) 49310ab2aceSGeorge Karpenkov Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. 49410ab2aceSGeorge Karpenkov WriteToFile(U, Path); 49510ab2aceSGeorge Karpenkov Printf("artifact_prefix='%s'; Test unit written to %s\n", 49610ab2aceSGeorge Karpenkov Options.ArtifactPrefix.c_str(), Path.c_str()); 49710ab2aceSGeorge Karpenkov if (U.size() <= kMaxUnitSizeToPrint) 49810ab2aceSGeorge Karpenkov Printf("Base64: %s\n", Base64(U).c_str()); 49910ab2aceSGeorge Karpenkov } 50010ab2aceSGeorge Karpenkov 50110ab2aceSGeorge Karpenkov void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { 50210ab2aceSGeorge Karpenkov if (!Options.PrintNEW) 50310ab2aceSGeorge Karpenkov return; 50410ab2aceSGeorge Karpenkov PrintStats(Text, ""); 50510ab2aceSGeorge Karpenkov if (Options.Verbosity) { 50610ab2aceSGeorge Karpenkov Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); 50710ab2aceSGeorge Karpenkov MD.PrintMutationSequence(); 50810ab2aceSGeorge Karpenkov Printf("\n"); 50910ab2aceSGeorge Karpenkov } 51010ab2aceSGeorge Karpenkov } 51110ab2aceSGeorge Karpenkov 51210ab2aceSGeorge Karpenkov void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { 51310ab2aceSGeorge Karpenkov II->NumSuccessfullMutations++; 51410ab2aceSGeorge Karpenkov MD.RecordSuccessfulMutationSequence(); 51510ab2aceSGeorge Karpenkov PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : 51610ab2aceSGeorge Karpenkov "NEW "); 51710ab2aceSGeorge Karpenkov WriteToOutputCorpus(U); 51810ab2aceSGeorge Karpenkov NumberOfNewUnitsAdded++; 51910ab2aceSGeorge Karpenkov CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. 52010ab2aceSGeorge Karpenkov LastCorpusUpdateRun = TotalNumberOfRuns; 52110ab2aceSGeorge Karpenkov LastCorpusUpdateTime = system_clock::now(); 52210ab2aceSGeorge Karpenkov } 52310ab2aceSGeorge Karpenkov 52410ab2aceSGeorge Karpenkov // Tries detecting a memory leak on the particular input that we have just 52510ab2aceSGeorge Karpenkov // executed before calling this function. 52610ab2aceSGeorge Karpenkov void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, 52710ab2aceSGeorge Karpenkov bool DuringInitialCorpusExecution) { 52810ab2aceSGeorge Karpenkov if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. 52910ab2aceSGeorge Karpenkov if (!Options.DetectLeaks) return; 5303f26dac4SMax Moroz if (!DuringInitialCorpusExecution && 5313f26dac4SMax Moroz TotalNumberOfRuns >= Options.MaxNumberOfRuns) return; 53210ab2aceSGeorge Karpenkov if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || 53310ab2aceSGeorge Karpenkov !(EF->__lsan_do_recoverable_leak_check)) 53410ab2aceSGeorge Karpenkov return; // No lsan. 53510ab2aceSGeorge Karpenkov // Run the target once again, but with lsan disabled so that if there is 53610ab2aceSGeorge Karpenkov // a real leak we do not report it twice. 53710ab2aceSGeorge Karpenkov EF->__lsan_disable(); 53810ab2aceSGeorge Karpenkov ExecuteCallback(Data, Size); 53910ab2aceSGeorge Karpenkov EF->__lsan_enable(); 54010ab2aceSGeorge Karpenkov if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. 54110ab2aceSGeorge Karpenkov if (NumberOfLeakDetectionAttempts++ > 1000) { 54210ab2aceSGeorge Karpenkov Options.DetectLeaks = false; 54310ab2aceSGeorge Karpenkov Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" 54410ab2aceSGeorge Karpenkov " Most likely the target function accumulates allocated\n" 54510ab2aceSGeorge Karpenkov " memory in a global state w/o actually leaking it.\n" 54610ab2aceSGeorge Karpenkov " You may try running this binary with -trace_malloc=[12]" 54710ab2aceSGeorge Karpenkov " to get a trace of mallocs and frees.\n" 54810ab2aceSGeorge Karpenkov " If LeakSanitizer is enabled in this process it will still\n" 54910ab2aceSGeorge Karpenkov " run on the process shutdown.\n"); 55010ab2aceSGeorge Karpenkov return; 55110ab2aceSGeorge Karpenkov } 55210ab2aceSGeorge Karpenkov // Now perform the actual lsan pass. This is expensive and we must ensure 55310ab2aceSGeorge Karpenkov // we don't call it too often. 55410ab2aceSGeorge Karpenkov if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. 55510ab2aceSGeorge Karpenkov if (DuringInitialCorpusExecution) 55610ab2aceSGeorge Karpenkov Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); 55710ab2aceSGeorge Karpenkov Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); 55810ab2aceSGeorge Karpenkov CurrentUnitSize = Size; 55910ab2aceSGeorge Karpenkov DumpCurrentUnit("leak-"); 56010ab2aceSGeorge Karpenkov PrintFinalStats(); 56110ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. 56210ab2aceSGeorge Karpenkov } 56310ab2aceSGeorge Karpenkov } 56410ab2aceSGeorge Karpenkov 56510ab2aceSGeorge Karpenkov void Fuzzer::MutateAndTestOne() { 56610ab2aceSGeorge Karpenkov MD.StartMutationSequence(); 56710ab2aceSGeorge Karpenkov 56810ab2aceSGeorge Karpenkov auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); 569*4083d546SKostya Serebryany if (Options.UseFeatureFrequency) 570*4083d546SKostya Serebryany Corpus.UpdateFeatureFrequencyScore(&II); 57110ab2aceSGeorge Karpenkov const auto &U = II.U; 57210ab2aceSGeorge Karpenkov memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); 57310ab2aceSGeorge Karpenkov assert(CurrentUnitData); 57410ab2aceSGeorge Karpenkov size_t Size = U.size(); 57510ab2aceSGeorge Karpenkov assert(Size <= MaxInputLen && "Oversized Unit"); 57610ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, U.data(), Size); 57710ab2aceSGeorge Karpenkov 57810ab2aceSGeorge Karpenkov assert(MaxMutationLen > 0); 57910ab2aceSGeorge Karpenkov 58010ab2aceSGeorge Karpenkov size_t CurrentMaxMutationLen = 58110ab2aceSGeorge Karpenkov Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen)); 58210ab2aceSGeorge Karpenkov assert(CurrentMaxMutationLen > 0); 58310ab2aceSGeorge Karpenkov 58410ab2aceSGeorge Karpenkov for (int i = 0; i < Options.MutateDepth; i++) { 58510ab2aceSGeorge Karpenkov if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 58610ab2aceSGeorge Karpenkov break; 58710ab2aceSGeorge Karpenkov size_t NewSize = 0; 58810ab2aceSGeorge Karpenkov NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); 58910ab2aceSGeorge Karpenkov assert(NewSize > 0 && "Mutator returned empty unit"); 59010ab2aceSGeorge Karpenkov assert(NewSize <= CurrentMaxMutationLen && "Mutator return overisized unit"); 59110ab2aceSGeorge Karpenkov Size = NewSize; 59210ab2aceSGeorge Karpenkov II.NumExecutedMutations++; 59310ab2aceSGeorge Karpenkov if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II)) 59410ab2aceSGeorge Karpenkov ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); 59510ab2aceSGeorge Karpenkov 59610ab2aceSGeorge Karpenkov TryDetectingAMemoryLeak(CurrentUnitData, Size, 59710ab2aceSGeorge Karpenkov /*DuringInitialCorpusExecution*/ false); 59810ab2aceSGeorge Karpenkov } 59910ab2aceSGeorge Karpenkov } 60010ab2aceSGeorge Karpenkov 6013a8e3c83SKostya Serebryany void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) { 6023a8e3c83SKostya Serebryany const size_t kMaxSaneLen = 1 << 20; 6033a8e3c83SKostya Serebryany const size_t kMinDefaultLen = 4096; 6044faeb87eSKostya Serebryany Vector<SizedFile> SizedFiles; 6054faeb87eSKostya Serebryany size_t MaxSize = 0; 6064faeb87eSKostya Serebryany size_t MinSize = -1; 6074faeb87eSKostya Serebryany size_t TotalSize = 0; 60893679be0SKostya Serebryany size_t LastNumFiles = 0; 6094faeb87eSKostya Serebryany for (auto &Dir : CorpusDirs) { 61093679be0SKostya Serebryany GetSizedFilesFromDir(Dir, &SizedFiles); 61193679be0SKostya Serebryany Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles, 61293679be0SKostya Serebryany Dir.c_str()); 61393679be0SKostya Serebryany LastNumFiles = SizedFiles.size(); 6143a8e3c83SKostya Serebryany } 61593679be0SKostya Serebryany for (auto &File : SizedFiles) { 61693679be0SKostya Serebryany MaxSize = Max(File.Size, MaxSize); 61793679be0SKostya Serebryany MinSize = Min(File.Size, MinSize); 61893679be0SKostya Serebryany TotalSize += File.Size; 6194faeb87eSKostya Serebryany } 6204faeb87eSKostya Serebryany if (Options.MaxLen == 0) 6214faeb87eSKostya Serebryany SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen)); 6224faeb87eSKostya Serebryany assert(MaxInputLen > 0); 6234faeb87eSKostya Serebryany 6244faeb87eSKostya Serebryany if (SizedFiles.empty()) { 6254faeb87eSKostya Serebryany Printf("INFO: A corpus is not provided, starting from an empty corpus\n"); 6264faeb87eSKostya Serebryany Unit U({'\n'}); // Valid ASCII input. 6274faeb87eSKostya Serebryany RunOne(U.data(), U.size()); 6284faeb87eSKostya Serebryany } else { 6294faeb87eSKostya Serebryany Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb" 6304faeb87eSKostya Serebryany " rss: %zdMb\n", 6314faeb87eSKostya Serebryany SizedFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb()); 6324faeb87eSKostya Serebryany if (Options.ShuffleAtStartUp) 6334faeb87eSKostya Serebryany std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand()); 6344faeb87eSKostya Serebryany 63593679be0SKostya Serebryany if (Options.PreferSmall) { 63693679be0SKostya Serebryany std::stable_sort(SizedFiles.begin(), SizedFiles.end()); 63793679be0SKostya Serebryany assert(SizedFiles.front().Size <= SizedFiles.back().Size); 63893679be0SKostya Serebryany } 6394faeb87eSKostya Serebryany 6404faeb87eSKostya Serebryany // Load and execute inputs one by one. 6414faeb87eSKostya Serebryany for (auto &SF : SizedFiles) { 642082e9a75SKostya Serebryany auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false); 6434faeb87eSKostya Serebryany assert(U.size() <= MaxInputLen); 6444faeb87eSKostya Serebryany RunOne(U.data(), U.size()); 6454faeb87eSKostya Serebryany CheckExitOnSrcPosOrItem(); 6464faeb87eSKostya Serebryany TryDetectingAMemoryLeak(U.data(), U.size(), 6474faeb87eSKostya Serebryany /*DuringInitialCorpusExecution*/ true); 6484faeb87eSKostya Serebryany } 6493a8e3c83SKostya Serebryany } 6503a8e3c83SKostya Serebryany 6514faeb87eSKostya Serebryany // Test the callback with empty input and never try it again. 6524faeb87eSKostya Serebryany uint8_t dummy; 6534faeb87eSKostya Serebryany ExecuteCallback(&dummy, 0); 6544faeb87eSKostya Serebryany 6554faeb87eSKostya Serebryany PrintStats("INITED"); 6564faeb87eSKostya Serebryany if (Corpus.empty()) { 6574faeb87eSKostya Serebryany Printf("ERROR: no interesting inputs were found. " 6584faeb87eSKostya Serebryany "Is the code instrumented for coverage? Exiting.\n"); 6594faeb87eSKostya Serebryany exit(1); 6603a8e3c83SKostya Serebryany } 6613a8e3c83SKostya Serebryany } 6623a8e3c83SKostya Serebryany 6633a8e3c83SKostya Serebryany void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) { 6643a8e3c83SKostya Serebryany ReadAndExecuteSeedCorpora(CorpusDirs); 66510ab2aceSGeorge Karpenkov TPC.SetPrintNewPCs(Options.PrintNewCovPcs); 6662eef816eSKostya Serebryany TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs); 66710ab2aceSGeorge Karpenkov system_clock::time_point LastCorpusReload = system_clock::now(); 66810ab2aceSGeorge Karpenkov if (Options.DoCrossOver) 66910ab2aceSGeorge Karpenkov MD.SetCorpus(&Corpus); 67010ab2aceSGeorge Karpenkov while (true) { 67110ab2aceSGeorge Karpenkov auto Now = system_clock::now(); 67210ab2aceSGeorge Karpenkov if (duration_cast<seconds>(Now - LastCorpusReload).count() >= 67310ab2aceSGeorge Karpenkov Options.ReloadIntervalSec) { 67410ab2aceSGeorge Karpenkov RereadOutputCorpus(MaxInputLen); 67510ab2aceSGeorge Karpenkov LastCorpusReload = system_clock::now(); 67610ab2aceSGeorge Karpenkov } 67710ab2aceSGeorge Karpenkov if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 67810ab2aceSGeorge Karpenkov break; 67910ab2aceSGeorge Karpenkov if (TimedOut()) break; 68010ab2aceSGeorge Karpenkov 68110ab2aceSGeorge Karpenkov // Update TmpMaxMutationLen 68210ab2aceSGeorge Karpenkov if (Options.ExperimentalLenControl) { 68310ab2aceSGeorge Karpenkov if (TmpMaxMutationLen < MaxMutationLen && 68410ab2aceSGeorge Karpenkov (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 && 68510ab2aceSGeorge Karpenkov duration_cast<seconds>(Now - LastCorpusUpdateTime).count() >= 1)) { 68610ab2aceSGeorge Karpenkov LastCorpusUpdateRun = TotalNumberOfRuns; 68710ab2aceSGeorge Karpenkov LastCorpusUpdateTime = Now; 68810ab2aceSGeorge Karpenkov TmpMaxMutationLen = 68910ab2aceSGeorge Karpenkov Min(MaxMutationLen, 69010ab2aceSGeorge Karpenkov TmpMaxMutationLen + Max(size_t(4), TmpMaxMutationLen / 8)); 69110ab2aceSGeorge Karpenkov if (TmpMaxMutationLen <= MaxMutationLen) 69210ab2aceSGeorge Karpenkov Printf("#%zd\tTEMP_MAX_LEN: %zd\n", TotalNumberOfRuns, 69310ab2aceSGeorge Karpenkov TmpMaxMutationLen); 69410ab2aceSGeorge Karpenkov } 69510ab2aceSGeorge Karpenkov } else { 69610ab2aceSGeorge Karpenkov TmpMaxMutationLen = MaxMutationLen; 69710ab2aceSGeorge Karpenkov } 69810ab2aceSGeorge Karpenkov 69910ab2aceSGeorge Karpenkov // Perform several mutations and runs. 70010ab2aceSGeorge Karpenkov MutateAndTestOne(); 70110ab2aceSGeorge Karpenkov } 70210ab2aceSGeorge Karpenkov 70310ab2aceSGeorge Karpenkov PrintStats("DONE ", "\n"); 70410ab2aceSGeorge Karpenkov MD.PrintRecommendedDictionary(); 70510ab2aceSGeorge Karpenkov } 70610ab2aceSGeorge Karpenkov 70710ab2aceSGeorge Karpenkov void Fuzzer::MinimizeCrashLoop(const Unit &U) { 70810ab2aceSGeorge Karpenkov if (U.size() <= 1) return; 70910ab2aceSGeorge Karpenkov while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { 71010ab2aceSGeorge Karpenkov MD.StartMutationSequence(); 71110ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, U.data(), U.size()); 71210ab2aceSGeorge Karpenkov for (int i = 0; i < Options.MutateDepth; i++) { 71310ab2aceSGeorge Karpenkov size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); 71410ab2aceSGeorge Karpenkov assert(NewSize > 0 && NewSize <= MaxMutationLen); 71510ab2aceSGeorge Karpenkov ExecuteCallback(CurrentUnitData, NewSize); 71610ab2aceSGeorge Karpenkov PrintPulseAndReportSlowInput(CurrentUnitData, NewSize); 71710ab2aceSGeorge Karpenkov TryDetectingAMemoryLeak(CurrentUnitData, NewSize, 71810ab2aceSGeorge Karpenkov /*DuringInitialCorpusExecution*/ false); 71910ab2aceSGeorge Karpenkov } 72010ab2aceSGeorge Karpenkov } 72110ab2aceSGeorge Karpenkov } 72210ab2aceSGeorge Karpenkov 72310ab2aceSGeorge Karpenkov void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) { 72410ab2aceSGeorge Karpenkov if (SMR.IsServer()) { 72510ab2aceSGeorge Karpenkov SMR.WriteByteArray(Data, Size); 72610ab2aceSGeorge Karpenkov } else if (SMR.IsClient()) { 72710ab2aceSGeorge Karpenkov SMR.PostClient(); 72810ab2aceSGeorge Karpenkov SMR.WaitServer(); 72910ab2aceSGeorge Karpenkov size_t OtherSize = SMR.ReadByteArraySize(); 73010ab2aceSGeorge Karpenkov uint8_t *OtherData = SMR.GetByteArray(); 73110ab2aceSGeorge Karpenkov if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) { 73210ab2aceSGeorge Karpenkov size_t i = 0; 73310ab2aceSGeorge Karpenkov for (i = 0; i < Min(Size, OtherSize); i++) 73410ab2aceSGeorge Karpenkov if (Data[i] != OtherData[i]) 73510ab2aceSGeorge Karpenkov break; 73610ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; " 73710ab2aceSGeorge Karpenkov "offset %zd\n", GetPid(), Size, OtherSize, i); 73810ab2aceSGeorge Karpenkov DumpCurrentUnit("mismatch-"); 73910ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: equivalence-mismatch\n"); 74010ab2aceSGeorge Karpenkov PrintFinalStats(); 74110ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); 74210ab2aceSGeorge Karpenkov } 74310ab2aceSGeorge Karpenkov } 74410ab2aceSGeorge Karpenkov } 74510ab2aceSGeorge Karpenkov 74610ab2aceSGeorge Karpenkov } // namespace fuzzer 74710ab2aceSGeorge Karpenkov 74810ab2aceSGeorge Karpenkov extern "C" { 74910ab2aceSGeorge Karpenkov 75010ab2aceSGeorge Karpenkov size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { 75110ab2aceSGeorge Karpenkov assert(fuzzer::F); 75210ab2aceSGeorge Karpenkov return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); 75310ab2aceSGeorge Karpenkov } 75410ab2aceSGeorge Karpenkov 75510ab2aceSGeorge Karpenkov // Experimental 75610ab2aceSGeorge Karpenkov void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { 75710ab2aceSGeorge Karpenkov assert(fuzzer::F); 75810ab2aceSGeorge Karpenkov fuzzer::F->AnnounceOutput(Data, Size); 75910ab2aceSGeorge Karpenkov } 76010ab2aceSGeorge Karpenkov } // extern "C" 761