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); 12510ab2aceSGeorge Karpenkov 12610ab2aceSGeorge Karpenkov if (Options.Verbosity) 12710ab2aceSGeorge Karpenkov TPC.PrintModuleInfo(); 12810ab2aceSGeorge Karpenkov if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec) 12910ab2aceSGeorge Karpenkov EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus); 13010ab2aceSGeorge Karpenkov MaxInputLen = MaxMutationLen = Options.MaxLen; 13110ab2aceSGeorge Karpenkov TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize()); 13210ab2aceSGeorge Karpenkov AllocateCurrentUnitData(); 13310ab2aceSGeorge Karpenkov CurrentUnitSize = 0; 13410ab2aceSGeorge Karpenkov memset(BaseSha1, 0, sizeof(BaseSha1)); 13510ab2aceSGeorge Karpenkov } 13610ab2aceSGeorge Karpenkov 13710ab2aceSGeorge Karpenkov Fuzzer::~Fuzzer() { } 13810ab2aceSGeorge Karpenkov 13910ab2aceSGeorge Karpenkov void Fuzzer::AllocateCurrentUnitData() { 14010ab2aceSGeorge Karpenkov if (CurrentUnitData || MaxInputLen == 0) return; 14110ab2aceSGeorge Karpenkov CurrentUnitData = new uint8_t[MaxInputLen]; 14210ab2aceSGeorge Karpenkov } 14310ab2aceSGeorge Karpenkov 14410ab2aceSGeorge Karpenkov void Fuzzer::StaticDeathCallback() { 14510ab2aceSGeorge Karpenkov assert(F); 14610ab2aceSGeorge Karpenkov F->DeathCallback(); 14710ab2aceSGeorge Karpenkov } 14810ab2aceSGeorge Karpenkov 14910ab2aceSGeorge Karpenkov void Fuzzer::DumpCurrentUnit(const char *Prefix) { 15010ab2aceSGeorge Karpenkov if (!CurrentUnitData) return; // Happens when running individual inputs. 15110ab2aceSGeorge Karpenkov MD.PrintMutationSequence(); 15210ab2aceSGeorge Karpenkov Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str()); 15310ab2aceSGeorge Karpenkov size_t UnitSize = CurrentUnitSize; 15410ab2aceSGeorge Karpenkov if (UnitSize <= kMaxUnitSizeToPrint) { 15510ab2aceSGeorge Karpenkov PrintHexArray(CurrentUnitData, UnitSize, "\n"); 15610ab2aceSGeorge Karpenkov PrintASCII(CurrentUnitData, UnitSize, "\n"); 15710ab2aceSGeorge Karpenkov } 15810ab2aceSGeorge Karpenkov WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize}, 15910ab2aceSGeorge Karpenkov Prefix); 16010ab2aceSGeorge Karpenkov } 16110ab2aceSGeorge Karpenkov 16210ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY 16310ab2aceSGeorge Karpenkov void Fuzzer::DeathCallback() { 16410ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 16510ab2aceSGeorge Karpenkov PrintFinalStats(); 16610ab2aceSGeorge Karpenkov } 16710ab2aceSGeorge Karpenkov 16810ab2aceSGeorge Karpenkov void Fuzzer::StaticAlarmCallback() { 16910ab2aceSGeorge Karpenkov assert(F); 17010ab2aceSGeorge Karpenkov F->AlarmCallback(); 17110ab2aceSGeorge Karpenkov } 17210ab2aceSGeorge Karpenkov 17310ab2aceSGeorge Karpenkov void Fuzzer::StaticCrashSignalCallback() { 17410ab2aceSGeorge Karpenkov assert(F); 17510ab2aceSGeorge Karpenkov F->CrashCallback(); 17610ab2aceSGeorge Karpenkov } 17710ab2aceSGeorge Karpenkov 17810ab2aceSGeorge Karpenkov void Fuzzer::StaticExitCallback() { 17910ab2aceSGeorge Karpenkov assert(F); 18010ab2aceSGeorge Karpenkov F->ExitCallback(); 18110ab2aceSGeorge Karpenkov } 18210ab2aceSGeorge Karpenkov 18310ab2aceSGeorge Karpenkov void Fuzzer::StaticInterruptCallback() { 18410ab2aceSGeorge Karpenkov assert(F); 18510ab2aceSGeorge Karpenkov F->InterruptCallback(); 18610ab2aceSGeorge Karpenkov } 18710ab2aceSGeorge Karpenkov 18810ab2aceSGeorge Karpenkov void Fuzzer::StaticFileSizeExceedCallback() { 18910ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid()); 19010ab2aceSGeorge Karpenkov exit(1); 19110ab2aceSGeorge Karpenkov } 19210ab2aceSGeorge Karpenkov 19310ab2aceSGeorge Karpenkov void Fuzzer::CrashCallback() { 19410ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid()); 19510ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_stack_trace) 19610ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 19710ab2aceSGeorge Karpenkov Printf("NOTE: libFuzzer has rudimentary signal handlers.\n" 19810ab2aceSGeorge Karpenkov " Combine libFuzzer with AddressSanitizer or similar for better " 19910ab2aceSGeorge Karpenkov "crash reports.\n"); 20010ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: deadly signal\n"); 20110ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 20210ab2aceSGeorge Karpenkov PrintFinalStats(); 20310ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now. 20410ab2aceSGeorge Karpenkov } 20510ab2aceSGeorge Karpenkov 20610ab2aceSGeorge Karpenkov void Fuzzer::ExitCallback() { 20710ab2aceSGeorge Karpenkov if (!RunningCB) 20810ab2aceSGeorge Karpenkov return; // This exit did not come from the user callback 20910ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid()); 21010ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_stack_trace) 21110ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 21210ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: fuzz target exited\n"); 21310ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 21410ab2aceSGeorge Karpenkov PrintFinalStats(); 21510ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); 21610ab2aceSGeorge Karpenkov } 21710ab2aceSGeorge Karpenkov 21810ab2aceSGeorge Karpenkov 21910ab2aceSGeorge Karpenkov void Fuzzer::InterruptCallback() { 22010ab2aceSGeorge Karpenkov Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid()); 22110ab2aceSGeorge Karpenkov PrintFinalStats(); 22210ab2aceSGeorge Karpenkov _Exit(0); // Stop right now, don't perform any at-exit actions. 22310ab2aceSGeorge Karpenkov } 22410ab2aceSGeorge Karpenkov 22510ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY 22610ab2aceSGeorge Karpenkov void Fuzzer::AlarmCallback() { 22710ab2aceSGeorge Karpenkov assert(Options.UnitTimeoutSec > 0); 22810ab2aceSGeorge Karpenkov // In Windows Alarm callback is executed by a different thread. 22910ab2aceSGeorge Karpenkov #if !LIBFUZZER_WINDOWS 23010ab2aceSGeorge Karpenkov if (!InFuzzingThread()) return; 23110ab2aceSGeorge Karpenkov #endif 23210ab2aceSGeorge Karpenkov if (!RunningCB) 23310ab2aceSGeorge Karpenkov return; // We have not started running units yet. 23410ab2aceSGeorge Karpenkov size_t Seconds = 23510ab2aceSGeorge Karpenkov duration_cast<seconds>(system_clock::now() - UnitStartTime).count(); 23610ab2aceSGeorge Karpenkov if (Seconds == 0) 23710ab2aceSGeorge Karpenkov return; 23810ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2) 23910ab2aceSGeorge Karpenkov Printf("AlarmCallback %zd\n", Seconds); 24010ab2aceSGeorge Karpenkov if (Seconds >= (size_t)Options.UnitTimeoutSec) { 24110ab2aceSGeorge Karpenkov Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds); 24210ab2aceSGeorge Karpenkov Printf(" and the timeout value is %d (use -timeout=N to change)\n", 24310ab2aceSGeorge Karpenkov Options.UnitTimeoutSec); 24410ab2aceSGeorge Karpenkov DumpCurrentUnit("timeout-"); 24510ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(), 24610ab2aceSGeorge Karpenkov Seconds); 24710ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_stack_trace) 24810ab2aceSGeorge Karpenkov EF->__sanitizer_print_stack_trace(); 24910ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: timeout\n"); 25010ab2aceSGeorge Karpenkov PrintFinalStats(); 25110ab2aceSGeorge Karpenkov _Exit(Options.TimeoutExitCode); // Stop right now. 25210ab2aceSGeorge Karpenkov } 25310ab2aceSGeorge Karpenkov } 25410ab2aceSGeorge Karpenkov 25510ab2aceSGeorge Karpenkov void Fuzzer::RssLimitCallback() { 25610ab2aceSGeorge Karpenkov Printf( 25710ab2aceSGeorge Karpenkov "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n", 25810ab2aceSGeorge Karpenkov GetPid(), GetPeakRSSMb(), Options.RssLimitMb); 25910ab2aceSGeorge Karpenkov Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n"); 26010ab2aceSGeorge Karpenkov if (EF->__sanitizer_print_memory_profile) 26110ab2aceSGeorge Karpenkov EF->__sanitizer_print_memory_profile(95, 8); 26210ab2aceSGeorge Karpenkov DumpCurrentUnit("oom-"); 26310ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: out-of-memory\n"); 26410ab2aceSGeorge Karpenkov PrintFinalStats(); 26510ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now. 26610ab2aceSGeorge Karpenkov } 26710ab2aceSGeorge Karpenkov 26810ab2aceSGeorge Karpenkov void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) { 26910ab2aceSGeorge Karpenkov size_t ExecPerSec = execPerSec(); 27010ab2aceSGeorge Karpenkov if (!Options.Verbosity) 27110ab2aceSGeorge Karpenkov return; 27210ab2aceSGeorge Karpenkov Printf("#%zd\t%s", TotalNumberOfRuns, Where); 27310ab2aceSGeorge Karpenkov if (size_t N = TPC.GetTotalPCCoverage()) 27410ab2aceSGeorge Karpenkov Printf(" cov: %zd", N); 27510ab2aceSGeorge Karpenkov if (size_t N = Corpus.NumFeatures()) 27610ab2aceSGeorge Karpenkov Printf( " ft: %zd", N); 27710ab2aceSGeorge Karpenkov if (!Corpus.empty()) { 27810ab2aceSGeorge Karpenkov Printf(" corp: %zd", Corpus.NumActiveUnits()); 27910ab2aceSGeorge Karpenkov if (size_t N = Corpus.SizeInBytes()) { 28010ab2aceSGeorge Karpenkov if (N < (1<<14)) 28110ab2aceSGeorge Karpenkov Printf("/%zdb", N); 28210ab2aceSGeorge Karpenkov else if (N < (1 << 24)) 28310ab2aceSGeorge Karpenkov Printf("/%zdKb", N >> 10); 28410ab2aceSGeorge Karpenkov else 28510ab2aceSGeorge Karpenkov Printf("/%zdMb", N >> 20); 28610ab2aceSGeorge Karpenkov } 28710ab2aceSGeorge Karpenkov } 28810ab2aceSGeorge Karpenkov if (Units) 28910ab2aceSGeorge Karpenkov Printf(" units: %zd", Units); 29010ab2aceSGeorge Karpenkov 29110ab2aceSGeorge Karpenkov Printf(" exec/s: %zd", ExecPerSec); 29210ab2aceSGeorge Karpenkov Printf(" rss: %zdMb", GetPeakRSSMb()); 29310ab2aceSGeorge Karpenkov Printf("%s", End); 29410ab2aceSGeorge Karpenkov } 29510ab2aceSGeorge Karpenkov 29610ab2aceSGeorge Karpenkov void Fuzzer::PrintFinalStats() { 29710ab2aceSGeorge Karpenkov if (Options.PrintCoverage) 29810ab2aceSGeorge Karpenkov TPC.PrintCoverage(); 29910ab2aceSGeorge Karpenkov if (Options.DumpCoverage) 30010ab2aceSGeorge Karpenkov TPC.DumpCoverage(); 30110ab2aceSGeorge Karpenkov if (Options.PrintCorpusStats) 30210ab2aceSGeorge Karpenkov Corpus.PrintStats(); 30310ab2aceSGeorge Karpenkov if (!Options.PrintFinalStats) return; 30410ab2aceSGeorge Karpenkov size_t ExecPerSec = execPerSec(); 30510ab2aceSGeorge Karpenkov Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns); 30610ab2aceSGeorge Karpenkov Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec); 30710ab2aceSGeorge Karpenkov Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded); 30810ab2aceSGeorge Karpenkov Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds); 30910ab2aceSGeorge Karpenkov Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb()); 31010ab2aceSGeorge Karpenkov } 31110ab2aceSGeorge Karpenkov 31210ab2aceSGeorge Karpenkov void Fuzzer::SetMaxInputLen(size_t MaxInputLen) { 31310ab2aceSGeorge Karpenkov assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0. 31410ab2aceSGeorge Karpenkov assert(MaxInputLen); 31510ab2aceSGeorge Karpenkov this->MaxInputLen = MaxInputLen; 31610ab2aceSGeorge Karpenkov this->MaxMutationLen = MaxInputLen; 31710ab2aceSGeorge Karpenkov AllocateCurrentUnitData(); 31810ab2aceSGeorge Karpenkov Printf("INFO: -max_len is not provided; " 31910ab2aceSGeorge Karpenkov "libFuzzer will not generate inputs larger than %zd bytes\n", 32010ab2aceSGeorge Karpenkov MaxInputLen); 32110ab2aceSGeorge Karpenkov } 32210ab2aceSGeorge Karpenkov 32310ab2aceSGeorge Karpenkov void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) { 32410ab2aceSGeorge Karpenkov assert(MaxMutationLen && MaxMutationLen <= MaxInputLen); 32510ab2aceSGeorge Karpenkov this->MaxMutationLen = MaxMutationLen; 32610ab2aceSGeorge Karpenkov } 32710ab2aceSGeorge Karpenkov 32810ab2aceSGeorge Karpenkov void Fuzzer::CheckExitOnSrcPosOrItem() { 32910ab2aceSGeorge Karpenkov if (!Options.ExitOnSrcPos.empty()) { 33010ab2aceSGeorge Karpenkov static auto *PCsSet = new std::set<uintptr_t>; 33110ab2aceSGeorge Karpenkov auto HandlePC = [&](uintptr_t PC) { 33210ab2aceSGeorge Karpenkov if (!PCsSet->insert(PC).second) return; 33310ab2aceSGeorge Karpenkov std::string Descr = DescribePC("%F %L", PC + 1); 33410ab2aceSGeorge Karpenkov if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) { 33510ab2aceSGeorge Karpenkov Printf("INFO: found line matching '%s', exiting.\n", 33610ab2aceSGeorge Karpenkov Options.ExitOnSrcPos.c_str()); 33710ab2aceSGeorge Karpenkov _Exit(0); 33810ab2aceSGeorge Karpenkov } 33910ab2aceSGeorge Karpenkov }; 34010ab2aceSGeorge Karpenkov TPC.ForEachObservedPC(HandlePC); 34110ab2aceSGeorge Karpenkov } 34210ab2aceSGeorge Karpenkov if (!Options.ExitOnItem.empty()) { 34310ab2aceSGeorge Karpenkov if (Corpus.HasUnit(Options.ExitOnItem)) { 34410ab2aceSGeorge Karpenkov Printf("INFO: found item with checksum '%s', exiting.\n", 34510ab2aceSGeorge Karpenkov Options.ExitOnItem.c_str()); 34610ab2aceSGeorge Karpenkov _Exit(0); 34710ab2aceSGeorge Karpenkov } 34810ab2aceSGeorge Karpenkov } 34910ab2aceSGeorge Karpenkov } 35010ab2aceSGeorge Karpenkov 35110ab2aceSGeorge Karpenkov void Fuzzer::RereadOutputCorpus(size_t MaxSize) { 35210ab2aceSGeorge Karpenkov if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return; 35310ab2aceSGeorge Karpenkov std::vector<Unit> AdditionalCorpus; 35410ab2aceSGeorge Karpenkov ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus, 35510ab2aceSGeorge Karpenkov &EpochOfLastReadOfOutputCorpus, MaxSize, 35610ab2aceSGeorge Karpenkov /*ExitOnError*/ false); 35710ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2) 35810ab2aceSGeorge Karpenkov Printf("Reload: read %zd new units.\n", AdditionalCorpus.size()); 35910ab2aceSGeorge Karpenkov bool Reloaded = false; 36010ab2aceSGeorge Karpenkov for (auto &U : AdditionalCorpus) { 36110ab2aceSGeorge Karpenkov if (U.size() > MaxSize) 36210ab2aceSGeorge Karpenkov U.resize(MaxSize); 36310ab2aceSGeorge Karpenkov if (!Corpus.HasUnit(U)) { 36410ab2aceSGeorge Karpenkov if (RunOne(U.data(), U.size())) { 36510ab2aceSGeorge Karpenkov CheckExitOnSrcPosOrItem(); 36610ab2aceSGeorge Karpenkov Reloaded = true; 36710ab2aceSGeorge Karpenkov } 36810ab2aceSGeorge Karpenkov } 36910ab2aceSGeorge Karpenkov } 37010ab2aceSGeorge Karpenkov if (Reloaded) 37110ab2aceSGeorge Karpenkov PrintStats("RELOAD"); 37210ab2aceSGeorge Karpenkov } 37310ab2aceSGeorge Karpenkov 37410ab2aceSGeorge Karpenkov void Fuzzer::ShuffleCorpus(UnitVector *V) { 37510ab2aceSGeorge Karpenkov std::shuffle(V->begin(), V->end(), MD.GetRand()); 37610ab2aceSGeorge Karpenkov if (Options.PreferSmall) 37710ab2aceSGeorge Karpenkov std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) { 37810ab2aceSGeorge Karpenkov return A.size() < B.size(); 37910ab2aceSGeorge Karpenkov }); 38010ab2aceSGeorge Karpenkov } 38110ab2aceSGeorge Karpenkov 38210ab2aceSGeorge Karpenkov void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) { 38310ab2aceSGeorge Karpenkov Printf("#0\tREAD units: %zd\n", InitialCorpus->size()); 38410ab2aceSGeorge Karpenkov if (Options.ShuffleAtStartUp) 38510ab2aceSGeorge Karpenkov ShuffleCorpus(InitialCorpus); 38610ab2aceSGeorge Karpenkov 38710ab2aceSGeorge Karpenkov // Test the callback with empty input and never try it again. 38810ab2aceSGeorge Karpenkov uint8_t dummy; 38910ab2aceSGeorge Karpenkov ExecuteCallback(&dummy, 0); 39010ab2aceSGeorge Karpenkov 391*f65cf64fSKostya Serebryany for (auto &U : *InitialCorpus) { 39210ab2aceSGeorge Karpenkov RunOne(U.data(), U.size()); 39310ab2aceSGeorge Karpenkov CheckExitOnSrcPosOrItem(); 39410ab2aceSGeorge Karpenkov TryDetectingAMemoryLeak(U.data(), U.size(), 39510ab2aceSGeorge Karpenkov /*DuringInitialCorpusExecution*/ true); 396*f65cf64fSKostya Serebryany U.clear(); 39710ab2aceSGeorge Karpenkov } 39810ab2aceSGeorge Karpenkov PrintStats("INITED"); 39910ab2aceSGeorge Karpenkov if (Corpus.empty()) { 40010ab2aceSGeorge Karpenkov Printf("ERROR: no interesting inputs were found. " 40110ab2aceSGeorge Karpenkov "Is the code instrumented for coverage? Exiting.\n"); 40210ab2aceSGeorge Karpenkov exit(1); 40310ab2aceSGeorge Karpenkov } 40410ab2aceSGeorge Karpenkov } 40510ab2aceSGeorge Karpenkov 40610ab2aceSGeorge Karpenkov void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) { 40710ab2aceSGeorge Karpenkov auto TimeOfUnit = 40810ab2aceSGeorge Karpenkov duration_cast<seconds>(UnitStopTime - UnitStartTime).count(); 40910ab2aceSGeorge Karpenkov if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) && 41010ab2aceSGeorge Karpenkov secondsSinceProcessStartUp() >= 2) 41110ab2aceSGeorge Karpenkov PrintStats("pulse "); 41210ab2aceSGeorge Karpenkov if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 && 41310ab2aceSGeorge Karpenkov TimeOfUnit >= Options.ReportSlowUnits) { 41410ab2aceSGeorge Karpenkov TimeOfLongestUnitInSeconds = TimeOfUnit; 41510ab2aceSGeorge Karpenkov Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds); 41610ab2aceSGeorge Karpenkov WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-"); 41710ab2aceSGeorge Karpenkov } 41810ab2aceSGeorge Karpenkov } 41910ab2aceSGeorge Karpenkov 42010ab2aceSGeorge Karpenkov bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile, 42110ab2aceSGeorge Karpenkov InputInfo *II) { 42210ab2aceSGeorge Karpenkov if (!Size) return false; 42310ab2aceSGeorge Karpenkov 42410ab2aceSGeorge Karpenkov ExecuteCallback(Data, Size); 42510ab2aceSGeorge Karpenkov 42610ab2aceSGeorge Karpenkov UniqFeatureSetTmp.clear(); 42710ab2aceSGeorge Karpenkov size_t FoundUniqFeaturesOfII = 0; 42810ab2aceSGeorge Karpenkov size_t NumUpdatesBefore = Corpus.NumFeatureUpdates(); 42910ab2aceSGeorge Karpenkov TPC.CollectFeatures([&](size_t Feature) { 43010ab2aceSGeorge Karpenkov if (Corpus.AddFeature(Feature, Size, Options.Shrink)) 43110ab2aceSGeorge Karpenkov UniqFeatureSetTmp.push_back(Feature); 43210ab2aceSGeorge Karpenkov if (Options.ReduceInputs && II) 43310ab2aceSGeorge Karpenkov if (std::binary_search(II->UniqFeatureSet.begin(), 43410ab2aceSGeorge Karpenkov II->UniqFeatureSet.end(), Feature)) 43510ab2aceSGeorge Karpenkov FoundUniqFeaturesOfII++; 43610ab2aceSGeorge Karpenkov }); 43710ab2aceSGeorge Karpenkov PrintPulseAndReportSlowInput(Data, Size); 43810ab2aceSGeorge Karpenkov size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore; 43910ab2aceSGeorge Karpenkov if (NumNewFeatures) { 44010ab2aceSGeorge Karpenkov TPC.UpdateObservedPCs(); 44110ab2aceSGeorge Karpenkov Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile, 44210ab2aceSGeorge Karpenkov UniqFeatureSetTmp); 44310ab2aceSGeorge Karpenkov return true; 44410ab2aceSGeorge Karpenkov } 44510ab2aceSGeorge Karpenkov if (II && FoundUniqFeaturesOfII && 44610ab2aceSGeorge Karpenkov FoundUniqFeaturesOfII == II->UniqFeatureSet.size() && 44710ab2aceSGeorge Karpenkov II->U.size() > Size) { 44810ab2aceSGeorge Karpenkov Corpus.Replace(II, {Data, Data + Size}); 44910ab2aceSGeorge Karpenkov return true; 45010ab2aceSGeorge Karpenkov } 45110ab2aceSGeorge Karpenkov return false; 45210ab2aceSGeorge Karpenkov } 45310ab2aceSGeorge Karpenkov 45410ab2aceSGeorge Karpenkov size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const { 45510ab2aceSGeorge Karpenkov assert(InFuzzingThread()); 45610ab2aceSGeorge Karpenkov *Data = CurrentUnitData; 45710ab2aceSGeorge Karpenkov return CurrentUnitSize; 45810ab2aceSGeorge Karpenkov } 45910ab2aceSGeorge Karpenkov 46010ab2aceSGeorge Karpenkov void Fuzzer::CrashOnOverwrittenData() { 46110ab2aceSGeorge Karpenkov Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n", 46210ab2aceSGeorge Karpenkov GetPid()); 46310ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-"); 46410ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: out-of-memory\n"); 46510ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now. 46610ab2aceSGeorge Karpenkov } 46710ab2aceSGeorge Karpenkov 46810ab2aceSGeorge Karpenkov // Compare two arrays, but not all bytes if the arrays are large. 46910ab2aceSGeorge Karpenkov static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) { 47010ab2aceSGeorge Karpenkov const size_t Limit = 64; 47110ab2aceSGeorge Karpenkov if (Size <= 64) 47210ab2aceSGeorge Karpenkov return !memcmp(A, B, Size); 47310ab2aceSGeorge Karpenkov // Compare first and last Limit/2 bytes. 47410ab2aceSGeorge Karpenkov return !memcmp(A, B, Limit / 2) && 47510ab2aceSGeorge Karpenkov !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2); 47610ab2aceSGeorge Karpenkov } 47710ab2aceSGeorge Karpenkov 47810ab2aceSGeorge Karpenkov void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) { 47910ab2aceSGeorge Karpenkov TPC.RecordInitialStack(); 48010ab2aceSGeorge Karpenkov TotalNumberOfRuns++; 48110ab2aceSGeorge Karpenkov assert(InFuzzingThread()); 48210ab2aceSGeorge Karpenkov if (SMR.IsClient()) 48310ab2aceSGeorge Karpenkov SMR.WriteByteArray(Data, Size); 48410ab2aceSGeorge Karpenkov // We copy the contents of Unit into a separate heap buffer 48510ab2aceSGeorge Karpenkov // so that we reliably find buffer overflows in it. 48610ab2aceSGeorge Karpenkov uint8_t *DataCopy = new uint8_t[Size]; 48710ab2aceSGeorge Karpenkov memcpy(DataCopy, Data, Size); 48810ab2aceSGeorge Karpenkov if (CurrentUnitData && CurrentUnitData != Data) 48910ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, Data, Size); 49010ab2aceSGeorge Karpenkov CurrentUnitSize = Size; 49110ab2aceSGeorge Karpenkov AllocTracer.Start(Options.TraceMalloc); 49210ab2aceSGeorge Karpenkov UnitStartTime = system_clock::now(); 49310ab2aceSGeorge Karpenkov TPC.ResetMaps(); 49410ab2aceSGeorge Karpenkov RunningCB = true; 49510ab2aceSGeorge Karpenkov int Res = CB(DataCopy, Size); 49610ab2aceSGeorge Karpenkov RunningCB = false; 49710ab2aceSGeorge Karpenkov UnitStopTime = system_clock::now(); 49810ab2aceSGeorge Karpenkov (void)Res; 49910ab2aceSGeorge Karpenkov assert(Res == 0); 50010ab2aceSGeorge Karpenkov HasMoreMallocsThanFrees = AllocTracer.Stop(); 50110ab2aceSGeorge Karpenkov if (!LooseMemeq(DataCopy, Data, Size)) 50210ab2aceSGeorge Karpenkov CrashOnOverwrittenData(); 50310ab2aceSGeorge Karpenkov CurrentUnitSize = 0; 50410ab2aceSGeorge Karpenkov delete[] DataCopy; 50510ab2aceSGeorge Karpenkov } 50610ab2aceSGeorge Karpenkov 50710ab2aceSGeorge Karpenkov void Fuzzer::WriteToOutputCorpus(const Unit &U) { 50810ab2aceSGeorge Karpenkov if (Options.OnlyASCII) 50910ab2aceSGeorge Karpenkov assert(IsASCII(U)); 51010ab2aceSGeorge Karpenkov if (Options.OutputCorpus.empty()) 51110ab2aceSGeorge Karpenkov return; 51210ab2aceSGeorge Karpenkov std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U)); 51310ab2aceSGeorge Karpenkov WriteToFile(U, Path); 51410ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2) 51510ab2aceSGeorge Karpenkov Printf("Written %zd bytes to %s\n", U.size(), Path.c_str()); 51610ab2aceSGeorge Karpenkov } 51710ab2aceSGeorge Karpenkov 51810ab2aceSGeorge Karpenkov void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) { 51910ab2aceSGeorge Karpenkov if (!Options.SaveArtifacts) 52010ab2aceSGeorge Karpenkov return; 52110ab2aceSGeorge Karpenkov std::string Path = Options.ArtifactPrefix + Prefix + Hash(U); 52210ab2aceSGeorge Karpenkov if (!Options.ExactArtifactPath.empty()) 52310ab2aceSGeorge Karpenkov Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix. 52410ab2aceSGeorge Karpenkov WriteToFile(U, Path); 52510ab2aceSGeorge Karpenkov Printf("artifact_prefix='%s'; Test unit written to %s\n", 52610ab2aceSGeorge Karpenkov Options.ArtifactPrefix.c_str(), Path.c_str()); 52710ab2aceSGeorge Karpenkov if (U.size() <= kMaxUnitSizeToPrint) 52810ab2aceSGeorge Karpenkov Printf("Base64: %s\n", Base64(U).c_str()); 52910ab2aceSGeorge Karpenkov } 53010ab2aceSGeorge Karpenkov 53110ab2aceSGeorge Karpenkov void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) { 53210ab2aceSGeorge Karpenkov if (!Options.PrintNEW) 53310ab2aceSGeorge Karpenkov return; 53410ab2aceSGeorge Karpenkov PrintStats(Text, ""); 53510ab2aceSGeorge Karpenkov if (Options.Verbosity) { 53610ab2aceSGeorge Karpenkov Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize()); 53710ab2aceSGeorge Karpenkov MD.PrintMutationSequence(); 53810ab2aceSGeorge Karpenkov Printf("\n"); 53910ab2aceSGeorge Karpenkov } 54010ab2aceSGeorge Karpenkov } 54110ab2aceSGeorge Karpenkov 54210ab2aceSGeorge Karpenkov void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) { 54310ab2aceSGeorge Karpenkov II->NumSuccessfullMutations++; 54410ab2aceSGeorge Karpenkov MD.RecordSuccessfulMutationSequence(); 54510ab2aceSGeorge Karpenkov PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : 54610ab2aceSGeorge Karpenkov "NEW "); 54710ab2aceSGeorge Karpenkov WriteToOutputCorpus(U); 54810ab2aceSGeorge Karpenkov NumberOfNewUnitsAdded++; 54910ab2aceSGeorge Karpenkov CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus. 55010ab2aceSGeorge Karpenkov LastCorpusUpdateRun = TotalNumberOfRuns; 55110ab2aceSGeorge Karpenkov LastCorpusUpdateTime = system_clock::now(); 55210ab2aceSGeorge Karpenkov } 55310ab2aceSGeorge Karpenkov 55410ab2aceSGeorge Karpenkov // Tries detecting a memory leak on the particular input that we have just 55510ab2aceSGeorge Karpenkov // executed before calling this function. 55610ab2aceSGeorge Karpenkov void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, 55710ab2aceSGeorge Karpenkov bool DuringInitialCorpusExecution) { 55810ab2aceSGeorge Karpenkov if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely. 55910ab2aceSGeorge Karpenkov if (!Options.DetectLeaks) return; 56010ab2aceSGeorge Karpenkov if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) || 56110ab2aceSGeorge Karpenkov !(EF->__lsan_do_recoverable_leak_check)) 56210ab2aceSGeorge Karpenkov return; // No lsan. 56310ab2aceSGeorge Karpenkov // Run the target once again, but with lsan disabled so that if there is 56410ab2aceSGeorge Karpenkov // a real leak we do not report it twice. 56510ab2aceSGeorge Karpenkov EF->__lsan_disable(); 56610ab2aceSGeorge Karpenkov ExecuteCallback(Data, Size); 56710ab2aceSGeorge Karpenkov EF->__lsan_enable(); 56810ab2aceSGeorge Karpenkov if (!HasMoreMallocsThanFrees) return; // a leak is unlikely. 56910ab2aceSGeorge Karpenkov if (NumberOfLeakDetectionAttempts++ > 1000) { 57010ab2aceSGeorge Karpenkov Options.DetectLeaks = false; 57110ab2aceSGeorge Karpenkov Printf("INFO: libFuzzer disabled leak detection after every mutation.\n" 57210ab2aceSGeorge Karpenkov " Most likely the target function accumulates allocated\n" 57310ab2aceSGeorge Karpenkov " memory in a global state w/o actually leaking it.\n" 57410ab2aceSGeorge Karpenkov " You may try running this binary with -trace_malloc=[12]" 57510ab2aceSGeorge Karpenkov " to get a trace of mallocs and frees.\n" 57610ab2aceSGeorge Karpenkov " If LeakSanitizer is enabled in this process it will still\n" 57710ab2aceSGeorge Karpenkov " run on the process shutdown.\n"); 57810ab2aceSGeorge Karpenkov return; 57910ab2aceSGeorge Karpenkov } 58010ab2aceSGeorge Karpenkov // Now perform the actual lsan pass. This is expensive and we must ensure 58110ab2aceSGeorge Karpenkov // we don't call it too often. 58210ab2aceSGeorge Karpenkov if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it. 58310ab2aceSGeorge Karpenkov if (DuringInitialCorpusExecution) 58410ab2aceSGeorge Karpenkov Printf("\nINFO: a leak has been found in the initial corpus.\n\n"); 58510ab2aceSGeorge Karpenkov Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n"); 58610ab2aceSGeorge Karpenkov CurrentUnitSize = Size; 58710ab2aceSGeorge Karpenkov DumpCurrentUnit("leak-"); 58810ab2aceSGeorge Karpenkov PrintFinalStats(); 58910ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on. 59010ab2aceSGeorge Karpenkov } 59110ab2aceSGeorge Karpenkov } 59210ab2aceSGeorge Karpenkov 59310ab2aceSGeorge Karpenkov void Fuzzer::MutateAndTestOne() { 59410ab2aceSGeorge Karpenkov MD.StartMutationSequence(); 59510ab2aceSGeorge Karpenkov 59610ab2aceSGeorge Karpenkov auto &II = Corpus.ChooseUnitToMutate(MD.GetRand()); 59710ab2aceSGeorge Karpenkov const auto &U = II.U; 59810ab2aceSGeorge Karpenkov memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1)); 59910ab2aceSGeorge Karpenkov assert(CurrentUnitData); 60010ab2aceSGeorge Karpenkov size_t Size = U.size(); 60110ab2aceSGeorge Karpenkov assert(Size <= MaxInputLen && "Oversized Unit"); 60210ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, U.data(), Size); 60310ab2aceSGeorge Karpenkov 60410ab2aceSGeorge Karpenkov assert(MaxMutationLen > 0); 60510ab2aceSGeorge Karpenkov 60610ab2aceSGeorge Karpenkov size_t CurrentMaxMutationLen = 60710ab2aceSGeorge Karpenkov Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen)); 60810ab2aceSGeorge Karpenkov assert(CurrentMaxMutationLen > 0); 60910ab2aceSGeorge Karpenkov 61010ab2aceSGeorge Karpenkov for (int i = 0; i < Options.MutateDepth; i++) { 61110ab2aceSGeorge Karpenkov if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 61210ab2aceSGeorge Karpenkov break; 61310ab2aceSGeorge Karpenkov size_t NewSize = 0; 61410ab2aceSGeorge Karpenkov NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen); 61510ab2aceSGeorge Karpenkov assert(NewSize > 0 && "Mutator returned empty unit"); 61610ab2aceSGeorge Karpenkov assert(NewSize <= CurrentMaxMutationLen && "Mutator return overisized unit"); 61710ab2aceSGeorge Karpenkov Size = NewSize; 61810ab2aceSGeorge Karpenkov II.NumExecutedMutations++; 61910ab2aceSGeorge Karpenkov if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II)) 62010ab2aceSGeorge Karpenkov ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size}); 62110ab2aceSGeorge Karpenkov 62210ab2aceSGeorge Karpenkov TryDetectingAMemoryLeak(CurrentUnitData, Size, 62310ab2aceSGeorge Karpenkov /*DuringInitialCorpusExecution*/ false); 62410ab2aceSGeorge Karpenkov } 62510ab2aceSGeorge Karpenkov } 62610ab2aceSGeorge Karpenkov 62710ab2aceSGeorge Karpenkov void Fuzzer::Loop() { 62810ab2aceSGeorge Karpenkov TPC.SetPrintNewPCs(Options.PrintNewCovPcs); 62910ab2aceSGeorge Karpenkov system_clock::time_point LastCorpusReload = system_clock::now(); 63010ab2aceSGeorge Karpenkov if (Options.DoCrossOver) 63110ab2aceSGeorge Karpenkov MD.SetCorpus(&Corpus); 63210ab2aceSGeorge Karpenkov while (true) { 63310ab2aceSGeorge Karpenkov auto Now = system_clock::now(); 63410ab2aceSGeorge Karpenkov if (duration_cast<seconds>(Now - LastCorpusReload).count() >= 63510ab2aceSGeorge Karpenkov Options.ReloadIntervalSec) { 63610ab2aceSGeorge Karpenkov RereadOutputCorpus(MaxInputLen); 63710ab2aceSGeorge Karpenkov LastCorpusReload = system_clock::now(); 63810ab2aceSGeorge Karpenkov } 63910ab2aceSGeorge Karpenkov if (TotalNumberOfRuns >= Options.MaxNumberOfRuns) 64010ab2aceSGeorge Karpenkov break; 64110ab2aceSGeorge Karpenkov if (TimedOut()) break; 64210ab2aceSGeorge Karpenkov 64310ab2aceSGeorge Karpenkov // Update TmpMaxMutationLen 64410ab2aceSGeorge Karpenkov if (Options.ExperimentalLenControl) { 64510ab2aceSGeorge Karpenkov if (TmpMaxMutationLen < MaxMutationLen && 64610ab2aceSGeorge Karpenkov (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 && 64710ab2aceSGeorge Karpenkov duration_cast<seconds>(Now - LastCorpusUpdateTime).count() >= 1)) { 64810ab2aceSGeorge Karpenkov LastCorpusUpdateRun = TotalNumberOfRuns; 64910ab2aceSGeorge Karpenkov LastCorpusUpdateTime = Now; 65010ab2aceSGeorge Karpenkov TmpMaxMutationLen = 65110ab2aceSGeorge Karpenkov Min(MaxMutationLen, 65210ab2aceSGeorge Karpenkov TmpMaxMutationLen + Max(size_t(4), TmpMaxMutationLen / 8)); 65310ab2aceSGeorge Karpenkov if (TmpMaxMutationLen <= MaxMutationLen) 65410ab2aceSGeorge Karpenkov Printf("#%zd\tTEMP_MAX_LEN: %zd\n", TotalNumberOfRuns, 65510ab2aceSGeorge Karpenkov TmpMaxMutationLen); 65610ab2aceSGeorge Karpenkov } 65710ab2aceSGeorge Karpenkov } else { 65810ab2aceSGeorge Karpenkov TmpMaxMutationLen = MaxMutationLen; 65910ab2aceSGeorge Karpenkov } 66010ab2aceSGeorge Karpenkov 66110ab2aceSGeorge Karpenkov // Perform several mutations and runs. 66210ab2aceSGeorge Karpenkov MutateAndTestOne(); 66310ab2aceSGeorge Karpenkov } 66410ab2aceSGeorge Karpenkov 66510ab2aceSGeorge Karpenkov PrintStats("DONE ", "\n"); 66610ab2aceSGeorge Karpenkov MD.PrintRecommendedDictionary(); 66710ab2aceSGeorge Karpenkov } 66810ab2aceSGeorge Karpenkov 66910ab2aceSGeorge Karpenkov void Fuzzer::MinimizeCrashLoop(const Unit &U) { 67010ab2aceSGeorge Karpenkov if (U.size() <= 1) return; 67110ab2aceSGeorge Karpenkov while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) { 67210ab2aceSGeorge Karpenkov MD.StartMutationSequence(); 67310ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, U.data(), U.size()); 67410ab2aceSGeorge Karpenkov for (int i = 0; i < Options.MutateDepth; i++) { 67510ab2aceSGeorge Karpenkov size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen); 67610ab2aceSGeorge Karpenkov assert(NewSize > 0 && NewSize <= MaxMutationLen); 67710ab2aceSGeorge Karpenkov ExecuteCallback(CurrentUnitData, NewSize); 67810ab2aceSGeorge Karpenkov PrintPulseAndReportSlowInput(CurrentUnitData, NewSize); 67910ab2aceSGeorge Karpenkov TryDetectingAMemoryLeak(CurrentUnitData, NewSize, 68010ab2aceSGeorge Karpenkov /*DuringInitialCorpusExecution*/ false); 68110ab2aceSGeorge Karpenkov } 68210ab2aceSGeorge Karpenkov } 68310ab2aceSGeorge Karpenkov } 68410ab2aceSGeorge Karpenkov 68510ab2aceSGeorge Karpenkov void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) { 68610ab2aceSGeorge Karpenkov if (SMR.IsServer()) { 68710ab2aceSGeorge Karpenkov SMR.WriteByteArray(Data, Size); 68810ab2aceSGeorge Karpenkov } else if (SMR.IsClient()) { 68910ab2aceSGeorge Karpenkov SMR.PostClient(); 69010ab2aceSGeorge Karpenkov SMR.WaitServer(); 69110ab2aceSGeorge Karpenkov size_t OtherSize = SMR.ReadByteArraySize(); 69210ab2aceSGeorge Karpenkov uint8_t *OtherData = SMR.GetByteArray(); 69310ab2aceSGeorge Karpenkov if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) { 69410ab2aceSGeorge Karpenkov size_t i = 0; 69510ab2aceSGeorge Karpenkov for (i = 0; i < Min(Size, OtherSize); i++) 69610ab2aceSGeorge Karpenkov if (Data[i] != OtherData[i]) 69710ab2aceSGeorge Karpenkov break; 69810ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; " 69910ab2aceSGeorge Karpenkov "offset %zd\n", GetPid(), Size, OtherSize, i); 70010ab2aceSGeorge Karpenkov DumpCurrentUnit("mismatch-"); 70110ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: equivalence-mismatch\n"); 70210ab2aceSGeorge Karpenkov PrintFinalStats(); 70310ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); 70410ab2aceSGeorge Karpenkov } 70510ab2aceSGeorge Karpenkov } 70610ab2aceSGeorge Karpenkov } 70710ab2aceSGeorge Karpenkov 70810ab2aceSGeorge Karpenkov } // namespace fuzzer 70910ab2aceSGeorge Karpenkov 71010ab2aceSGeorge Karpenkov extern "C" { 71110ab2aceSGeorge Karpenkov 71210ab2aceSGeorge Karpenkov size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { 71310ab2aceSGeorge Karpenkov assert(fuzzer::F); 71410ab2aceSGeorge Karpenkov return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize); 71510ab2aceSGeorge Karpenkov } 71610ab2aceSGeorge Karpenkov 71710ab2aceSGeorge Karpenkov // Experimental 71810ab2aceSGeorge Karpenkov void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) { 71910ab2aceSGeorge Karpenkov assert(fuzzer::F); 72010ab2aceSGeorge Karpenkov fuzzer::F->AnnounceOutput(Data, Size); 72110ab2aceSGeorge Karpenkov } 72210ab2aceSGeorge Karpenkov } // extern "C" 723