110ab2aceSGeorge Karpenkov //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // Fuzzer's main loop.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1010ab2aceSGeorge Karpenkov
1110ab2aceSGeorge Karpenkov #include "FuzzerCorpus.h"
1210ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1310ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
1410ab2aceSGeorge Karpenkov #include "FuzzerMutate.h"
15750369e2SDokyung Song #include "FuzzerPlatform.h"
1610ab2aceSGeorge Karpenkov #include "FuzzerRandom.h"
1710ab2aceSGeorge Karpenkov #include "FuzzerTracePC.h"
1810ab2aceSGeorge Karpenkov #include <algorithm>
1910ab2aceSGeorge Karpenkov #include <cstring>
2010ab2aceSGeorge Karpenkov #include <memory>
217dbc1d84SVitaly Buka #include <mutex>
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
4343a22969SMatt Morehouse bool RunningUserCallback = false;
4443a22969SMatt Morehouse
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 {
Startfuzzer::MallocFreeTracer5110ab2aceSGeorge 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.
Stopfuzzer::MallocFreeTracer5910ab2aceSGeorge 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;
727d22324bSVitaly Buka
737d22324bSVitaly Buka std::recursive_mutex TraceMutex;
747d22324bSVitaly Buka bool TraceDisabled = false;
7510ab2aceSGeorge Karpenkov };
7610ab2aceSGeorge Karpenkov
7710ab2aceSGeorge Karpenkov static MallocFreeTracer AllocTracer;
7810ab2aceSGeorge Karpenkov
797d22324bSVitaly Buka // Locks printing and avoids nested hooks triggered from mallocs/frees in
807d22324bSVitaly Buka // sanitizer.
817d22324bSVitaly Buka class TraceLock {
827d22324bSVitaly Buka public:
TraceLock()837d22324bSVitaly Buka TraceLock() : Lock(AllocTracer.TraceMutex) {
847d22324bSVitaly Buka AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled;
857d22324bSVitaly Buka }
~TraceLock()867d22324bSVitaly Buka ~TraceLock() { AllocTracer.TraceDisabled = !AllocTracer.TraceDisabled; }
877d22324bSVitaly Buka
IsDisabled() const887d22324bSVitaly Buka bool IsDisabled() const {
897d22324bSVitaly Buka // This is already inverted value.
907d22324bSVitaly Buka return !AllocTracer.TraceDisabled;
917d22324bSVitaly Buka }
927d22324bSVitaly Buka
937d22324bSVitaly Buka private:
947d22324bSVitaly Buka std::lock_guard<std::recursive_mutex> Lock;
957d22324bSVitaly Buka };
967dbc1d84SVitaly Buka
9710ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY
MallocHook(const volatile void * ptr,size_t size)9810ab2aceSGeorge Karpenkov void MallocHook(const volatile void *ptr, size_t size) {
9910ab2aceSGeorge Karpenkov size_t N = AllocTracer.Mallocs++;
10010ab2aceSGeorge Karpenkov F->HandleMalloc(size);
10110ab2aceSGeorge Karpenkov if (int TraceLevel = AllocTracer.TraceLevel) {
1027d22324bSVitaly Buka TraceLock Lock;
1037d22324bSVitaly Buka if (Lock.IsDisabled())
1047d22324bSVitaly Buka return;
10510ab2aceSGeorge Karpenkov Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
10610ab2aceSGeorge Karpenkov if (TraceLevel >= 2 && EF)
10714cf71a3SMatt Morehouse PrintStackTrace();
10810ab2aceSGeorge Karpenkov }
10910ab2aceSGeorge Karpenkov }
11010ab2aceSGeorge Karpenkov
11110ab2aceSGeorge Karpenkov ATTRIBUTE_NO_SANITIZE_MEMORY
FreeHook(const volatile void * ptr)11210ab2aceSGeorge Karpenkov void FreeHook(const volatile void *ptr) {
11310ab2aceSGeorge Karpenkov size_t N = AllocTracer.Frees++;
11410ab2aceSGeorge Karpenkov if (int TraceLevel = AllocTracer.TraceLevel) {
1157d22324bSVitaly Buka TraceLock Lock;
1167d22324bSVitaly Buka if (Lock.IsDisabled())
1177d22324bSVitaly Buka return;
11810ab2aceSGeorge Karpenkov Printf("FREE[%zd] %p\n", N, ptr);
11910ab2aceSGeorge Karpenkov if (TraceLevel >= 2 && EF)
12014cf71a3SMatt Morehouse PrintStackTrace();
12110ab2aceSGeorge Karpenkov }
12210ab2aceSGeorge Karpenkov }
12310ab2aceSGeorge Karpenkov
12410ab2aceSGeorge Karpenkov // Crash on a single malloc that exceeds the rss limit.
HandleMalloc(size_t Size)12510ab2aceSGeorge Karpenkov void Fuzzer::HandleMalloc(size_t Size) {
126de9bafb1SKostya Serebryany if (!Options.MallocLimitMb || (Size >> 20) < (size_t)Options.MallocLimitMb)
12710ab2aceSGeorge Karpenkov return;
12810ab2aceSGeorge Karpenkov Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
12910ab2aceSGeorge Karpenkov Size);
13010ab2aceSGeorge Karpenkov Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
13114cf71a3SMatt Morehouse PrintStackTrace();
13210ab2aceSGeorge Karpenkov DumpCurrentUnit("oom-");
13310ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: out-of-memory\n");
13410ab2aceSGeorge Karpenkov PrintFinalStats();
1350fda9dcbSKostya Serebryany _Exit(Options.OOMExitCode); // Stop right now.
13610ab2aceSGeorge Karpenkov }
13710ab2aceSGeorge Karpenkov
Fuzzer(UserCallback CB,InputCorpus & Corpus,MutationDispatcher & MD,FuzzingOptions Options)13810ab2aceSGeorge Karpenkov Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
13910ab2aceSGeorge Karpenkov FuzzingOptions Options)
14010ab2aceSGeorge Karpenkov : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
14110ab2aceSGeorge Karpenkov if (EF->__sanitizer_set_death_callback)
14210ab2aceSGeorge Karpenkov EF->__sanitizer_set_death_callback(StaticDeathCallback);
14310ab2aceSGeorge Karpenkov assert(!F);
14410ab2aceSGeorge Karpenkov F = this;
14510ab2aceSGeorge Karpenkov TPC.ResetMaps();
14610ab2aceSGeorge Karpenkov IsMyThread = true;
14710ab2aceSGeorge Karpenkov if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
14810ab2aceSGeorge Karpenkov EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
14910ab2aceSGeorge Karpenkov TPC.SetUseCounters(Options.UseCounters);
15051ddb883SKostya Serebryany TPC.SetUseValueProfileMask(Options.UseValueProfile);
15110ab2aceSGeorge Karpenkov
15210ab2aceSGeorge Karpenkov if (Options.Verbosity)
15310ab2aceSGeorge Karpenkov TPC.PrintModuleInfo();
15410ab2aceSGeorge Karpenkov if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
15510ab2aceSGeorge Karpenkov EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
15610ab2aceSGeorge Karpenkov MaxInputLen = MaxMutationLen = Options.MaxLen;
157b6ca1e72SKostya Serebryany TmpMaxMutationLen = 0; // Will be set once we load the corpus.
15810ab2aceSGeorge Karpenkov AllocateCurrentUnitData();
15910ab2aceSGeorge Karpenkov CurrentUnitSize = 0;
16010ab2aceSGeorge Karpenkov memset(BaseSha1, 0, sizeof(BaseSha1));
16110ab2aceSGeorge Karpenkov }
16210ab2aceSGeorge Karpenkov
~Fuzzer()16310ab2aceSGeorge Karpenkov Fuzzer::~Fuzzer() {}
16410ab2aceSGeorge Karpenkov
AllocateCurrentUnitData()16510ab2aceSGeorge Karpenkov void Fuzzer::AllocateCurrentUnitData() {
1665ded0701SAlex Shlyapnikov if (CurrentUnitData || MaxInputLen == 0)
1675ded0701SAlex Shlyapnikov return;
16810ab2aceSGeorge Karpenkov CurrentUnitData = new uint8_t[MaxInputLen];
16910ab2aceSGeorge Karpenkov }
17010ab2aceSGeorge Karpenkov
StaticDeathCallback()17110ab2aceSGeorge Karpenkov void Fuzzer::StaticDeathCallback() {
17210ab2aceSGeorge Karpenkov assert(F);
17310ab2aceSGeorge Karpenkov F->DeathCallback();
17410ab2aceSGeorge Karpenkov }
17510ab2aceSGeorge Karpenkov
DumpCurrentUnit(const char * Prefix)17610ab2aceSGeorge Karpenkov void Fuzzer::DumpCurrentUnit(const char *Prefix) {
1775ded0701SAlex Shlyapnikov if (!CurrentUnitData)
1785ded0701SAlex Shlyapnikov return; // Happens when running individual inputs.
179a34c65e8SMatt Morehouse ScopedDisableMsanInterceptorChecks S;
180c5d72517SMarco Vanotti MD.PrintMutationSequence();
18110ab2aceSGeorge Karpenkov Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
18210ab2aceSGeorge Karpenkov size_t UnitSize = CurrentUnitSize;
18310ab2aceSGeorge Karpenkov if (UnitSize <= kMaxUnitSizeToPrint) {
18410ab2aceSGeorge Karpenkov PrintHexArray(CurrentUnitData, UnitSize, "\n");
18510ab2aceSGeorge Karpenkov PrintASCII(CurrentUnitData, UnitSize, "\n");
18610ab2aceSGeorge Karpenkov }
18710ab2aceSGeorge Karpenkov WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
18810ab2aceSGeorge Karpenkov Prefix);
18910ab2aceSGeorge Karpenkov }
19010ab2aceSGeorge Karpenkov
19110ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY
DeathCallback()19210ab2aceSGeorge Karpenkov void Fuzzer::DeathCallback() {
19310ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-");
19410ab2aceSGeorge Karpenkov PrintFinalStats();
19510ab2aceSGeorge Karpenkov }
19610ab2aceSGeorge Karpenkov
StaticAlarmCallback()19710ab2aceSGeorge Karpenkov void Fuzzer::StaticAlarmCallback() {
19810ab2aceSGeorge Karpenkov assert(F);
19910ab2aceSGeorge Karpenkov F->AlarmCallback();
20010ab2aceSGeorge Karpenkov }
20110ab2aceSGeorge Karpenkov
StaticCrashSignalCallback()20210ab2aceSGeorge Karpenkov void Fuzzer::StaticCrashSignalCallback() {
20310ab2aceSGeorge Karpenkov assert(F);
20410ab2aceSGeorge Karpenkov F->CrashCallback();
20510ab2aceSGeorge Karpenkov }
20610ab2aceSGeorge Karpenkov
StaticExitCallback()20710ab2aceSGeorge Karpenkov void Fuzzer::StaticExitCallback() {
20810ab2aceSGeorge Karpenkov assert(F);
20910ab2aceSGeorge Karpenkov F->ExitCallback();
21010ab2aceSGeorge Karpenkov }
21110ab2aceSGeorge Karpenkov
StaticInterruptCallback()21210ab2aceSGeorge Karpenkov void Fuzzer::StaticInterruptCallback() {
21310ab2aceSGeorge Karpenkov assert(F);
21410ab2aceSGeorge Karpenkov F->InterruptCallback();
21510ab2aceSGeorge Karpenkov }
21610ab2aceSGeorge Karpenkov
StaticGracefulExitCallback()217a2ca2dccSKostya Serebryany void Fuzzer::StaticGracefulExitCallback() {
218a2ca2dccSKostya Serebryany assert(F);
219a2ca2dccSKostya Serebryany F->GracefulExitRequested = true;
220a2ca2dccSKostya Serebryany Printf("INFO: signal received, trying to exit gracefully\n");
221a2ca2dccSKostya Serebryany }
222a2ca2dccSKostya Serebryany
StaticFileSizeExceedCallback()22310ab2aceSGeorge Karpenkov void Fuzzer::StaticFileSizeExceedCallback() {
22410ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
22510ab2aceSGeorge Karpenkov exit(1);
22610ab2aceSGeorge Karpenkov }
22710ab2aceSGeorge Karpenkov
CrashCallback()22810ab2aceSGeorge Karpenkov void Fuzzer::CrashCallback() {
22915df273eSJulian Lettner if (EF->__sanitizer_acquire_crash_state &&
23015df273eSJulian Lettner !EF->__sanitizer_acquire_crash_state())
23115df273eSJulian Lettner return;
23210ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
23314cf71a3SMatt Morehouse PrintStackTrace();
23410ab2aceSGeorge Karpenkov Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
23510ab2aceSGeorge Karpenkov " Combine libFuzzer with AddressSanitizer or similar for better "
23610ab2aceSGeorge Karpenkov "crash reports.\n");
23710ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: deadly signal\n");
23810ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-");
23910ab2aceSGeorge Karpenkov PrintFinalStats();
24010ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now.
24110ab2aceSGeorge Karpenkov }
24210ab2aceSGeorge Karpenkov
ExitCallback()24310ab2aceSGeorge Karpenkov void Fuzzer::ExitCallback() {
24443a22969SMatt Morehouse if (!RunningUserCallback)
24510ab2aceSGeorge Karpenkov return; // This exit did not come from the user callback
24652fd1690SMatt Morehouse if (EF->__sanitizer_acquire_crash_state &&
24752fd1690SMatt Morehouse !EF->__sanitizer_acquire_crash_state())
24852fd1690SMatt Morehouse return;
24910ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
25014cf71a3SMatt Morehouse PrintStackTrace();
25110ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: fuzz target exited\n");
25210ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-");
25310ab2aceSGeorge Karpenkov PrintFinalStats();
25410ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode);
25510ab2aceSGeorge Karpenkov }
25610ab2aceSGeorge Karpenkov
MaybeExitGracefully()257a2ca2dccSKostya Serebryany void Fuzzer::MaybeExitGracefully() {
258f762a115SKostya Serebryany if (!F->GracefulExitRequested) return;
259a2ca2dccSKostya Serebryany Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
2604f3c3bbbSYuanfang Chen RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
261f762a115SKostya Serebryany F->PrintFinalStats();
262a2ca2dccSKostya Serebryany _Exit(0);
263a2ca2dccSKostya Serebryany }
264a2ca2dccSKostya Serebryany
InterruptCallback()26510ab2aceSGeorge Karpenkov void Fuzzer::InterruptCallback() {
26610ab2aceSGeorge Karpenkov Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
26710ab2aceSGeorge Karpenkov PrintFinalStats();
2681b76063aSMatt Morehouse ScopedDisableMsanInterceptorChecks S; // RmDirRecursive may call opendir().
2694f3c3bbbSYuanfang Chen RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
2700fda9dcbSKostya Serebryany // Stop right now, don't perform any at-exit actions.
2710fda9dcbSKostya Serebryany _Exit(Options.InterruptExitCode);
27210ab2aceSGeorge Karpenkov }
27310ab2aceSGeorge Karpenkov
27410ab2aceSGeorge Karpenkov NO_SANITIZE_MEMORY
AlarmCallback()27510ab2aceSGeorge Karpenkov void Fuzzer::AlarmCallback() {
27610ab2aceSGeorge Karpenkov assert(Options.UnitTimeoutSec > 0);
277e7bfce78SJake Ehrlich // In Windows and Fuchsia, Alarm callback is executed by a different thread.
2782e61186cSKamil Rytarowski // NetBSD's current behavior needs this change too.
279e7bfce78SJake Ehrlich #if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD && !LIBFUZZER_FUCHSIA
2805ded0701SAlex Shlyapnikov if (!InFuzzingThread())
2815ded0701SAlex Shlyapnikov return;
28210ab2aceSGeorge Karpenkov #endif
28343a22969SMatt Morehouse if (!RunningUserCallback)
28410ab2aceSGeorge Karpenkov return; // We have not started running units yet.
28510ab2aceSGeorge Karpenkov size_t Seconds =
28610ab2aceSGeorge Karpenkov duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
28710ab2aceSGeorge Karpenkov if (Seconds == 0)
28810ab2aceSGeorge Karpenkov return;
28910ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2)
29010ab2aceSGeorge Karpenkov Printf("AlarmCallback %zd\n", Seconds);
29110ab2aceSGeorge Karpenkov if (Seconds >= (size_t)Options.UnitTimeoutSec) {
29252fd1690SMatt Morehouse if (EF->__sanitizer_acquire_crash_state &&
29352fd1690SMatt Morehouse !EF->__sanitizer_acquire_crash_state())
29452fd1690SMatt Morehouse return;
29510ab2aceSGeorge Karpenkov Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
29610ab2aceSGeorge Karpenkov Printf(" and the timeout value is %d (use -timeout=N to change)\n",
29710ab2aceSGeorge Karpenkov Options.UnitTimeoutSec);
29810ab2aceSGeorge Karpenkov DumpCurrentUnit("timeout-");
29910ab2aceSGeorge Karpenkov Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
30010ab2aceSGeorge Karpenkov Seconds);
30114cf71a3SMatt Morehouse PrintStackTrace();
30210ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: timeout\n");
30310ab2aceSGeorge Karpenkov PrintFinalStats();
30410ab2aceSGeorge Karpenkov _Exit(Options.TimeoutExitCode); // Stop right now.
30510ab2aceSGeorge Karpenkov }
30610ab2aceSGeorge Karpenkov }
30710ab2aceSGeorge Karpenkov
RssLimitCallback()30810ab2aceSGeorge Karpenkov void Fuzzer::RssLimitCallback() {
30952fd1690SMatt Morehouse if (EF->__sanitizer_acquire_crash_state &&
31052fd1690SMatt Morehouse !EF->__sanitizer_acquire_crash_state())
31152fd1690SMatt Morehouse return;
31210ab2aceSGeorge Karpenkov Printf(
31310ab2aceSGeorge Karpenkov "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
31410ab2aceSGeorge Karpenkov GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
31510ab2aceSGeorge Karpenkov Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
31614cf71a3SMatt Morehouse PrintMemoryProfile();
31710ab2aceSGeorge Karpenkov DumpCurrentUnit("oom-");
31810ab2aceSGeorge Karpenkov Printf("SUMMARY: libFuzzer: out-of-memory\n");
31910ab2aceSGeorge Karpenkov PrintFinalStats();
3200fda9dcbSKostya Serebryany _Exit(Options.OOMExitCode); // Stop right now.
32110ab2aceSGeorge Karpenkov }
32210ab2aceSGeorge Karpenkov
PrintStats(const char * Where,const char * End,size_t Units,size_t Features)32374cec618SMax Moroz void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units,
32474cec618SMax Moroz size_t Features) {
32510ab2aceSGeorge Karpenkov size_t ExecPerSec = execPerSec();
32610ab2aceSGeorge Karpenkov if (!Options.Verbosity)
32710ab2aceSGeorge Karpenkov return;
32810ab2aceSGeorge Karpenkov Printf("#%zd\t%s", TotalNumberOfRuns, Where);
32910ab2aceSGeorge Karpenkov if (size_t N = TPC.GetTotalPCCoverage())
33010ab2aceSGeorge Karpenkov Printf(" cov: %zd", N);
33174cec618SMax Moroz if (size_t N = Features ? Features : Corpus.NumFeatures())
33210ab2aceSGeorge Karpenkov Printf(" ft: %zd", N);
33310ab2aceSGeorge Karpenkov if (!Corpus.empty()) {
33410ab2aceSGeorge Karpenkov Printf(" corp: %zd", Corpus.NumActiveUnits());
33510ab2aceSGeorge Karpenkov if (size_t N = Corpus.SizeInBytes()) {
33610ab2aceSGeorge Karpenkov if (N < (1 << 14))
33710ab2aceSGeorge Karpenkov Printf("/%zdb", N);
33810ab2aceSGeorge Karpenkov else if (N < (1 << 24))
33910ab2aceSGeorge Karpenkov Printf("/%zdKb", N >> 10);
34010ab2aceSGeorge Karpenkov else
34110ab2aceSGeorge Karpenkov Printf("/%zdMb", N >> 20);
34210ab2aceSGeorge Karpenkov }
343e9c6f06cSKostya Serebryany if (size_t FF = Corpus.NumInputsThatTouchFocusFunction())
344e9c6f06cSKostya Serebryany Printf(" focus: %zd", FF);
34510ab2aceSGeorge Karpenkov }
346ddf352b9SMatt Morehouse if (TmpMaxMutationLen)
347ddf352b9SMatt Morehouse Printf(" lim: %zd", TmpMaxMutationLen);
34810ab2aceSGeorge Karpenkov if (Units)
34910ab2aceSGeorge Karpenkov Printf(" units: %zd", Units);
35010ab2aceSGeorge Karpenkov
35110ab2aceSGeorge Karpenkov Printf(" exec/s: %zd", ExecPerSec);
35210ab2aceSGeorge Karpenkov Printf(" rss: %zdMb", GetPeakRSSMb());
35310ab2aceSGeorge Karpenkov Printf("%s", End);
35410ab2aceSGeorge Karpenkov }
35510ab2aceSGeorge Karpenkov
PrintFinalStats()35610ab2aceSGeorge Karpenkov void Fuzzer::PrintFinalStats() {
357dc62d5ecSMax Moroz if (Options.PrintFullCoverage)
358dc62d5ecSMax Moroz TPC.PrintCoverage(/*PrintAllCounters=*/true);
35910ab2aceSGeorge Karpenkov if (Options.PrintCoverage)
360dc62d5ecSMax Moroz TPC.PrintCoverage(/*PrintAllCounters=*/false);
36110ab2aceSGeorge Karpenkov if (Options.PrintCorpusStats)
36210ab2aceSGeorge Karpenkov Corpus.PrintStats();
3635ded0701SAlex Shlyapnikov if (!Options.PrintFinalStats)
3645ded0701SAlex Shlyapnikov return;
36510ab2aceSGeorge Karpenkov size_t ExecPerSec = execPerSec();
36610ab2aceSGeorge Karpenkov Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
36710ab2aceSGeorge Karpenkov Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec);
36810ab2aceSGeorge Karpenkov Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded);
36910ab2aceSGeorge Karpenkov Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds);
37010ab2aceSGeorge Karpenkov Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb());
37110ab2aceSGeorge Karpenkov }
37210ab2aceSGeorge Karpenkov
SetMaxInputLen(size_t MaxInputLen)37310ab2aceSGeorge Karpenkov void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
37410ab2aceSGeorge Karpenkov assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
37510ab2aceSGeorge Karpenkov assert(MaxInputLen);
37610ab2aceSGeorge Karpenkov this->MaxInputLen = MaxInputLen;
37710ab2aceSGeorge Karpenkov this->MaxMutationLen = MaxInputLen;
37810ab2aceSGeorge Karpenkov AllocateCurrentUnitData();
37910ab2aceSGeorge Karpenkov Printf("INFO: -max_len is not provided; "
38010ab2aceSGeorge Karpenkov "libFuzzer will not generate inputs larger than %zd bytes\n",
38110ab2aceSGeorge Karpenkov MaxInputLen);
38210ab2aceSGeorge Karpenkov }
38310ab2aceSGeorge Karpenkov
SetMaxMutationLen(size_t MaxMutationLen)38410ab2aceSGeorge Karpenkov void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
38510ab2aceSGeorge Karpenkov assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
38610ab2aceSGeorge Karpenkov this->MaxMutationLen = MaxMutationLen;
38710ab2aceSGeorge Karpenkov }
38810ab2aceSGeorge Karpenkov
CheckExitOnSrcPosOrItem()38910ab2aceSGeorge Karpenkov void Fuzzer::CheckExitOnSrcPosOrItem() {
39010ab2aceSGeorge Karpenkov if (!Options.ExitOnSrcPos.empty()) {
3917c921753SKostya Serebryany static auto *PCsSet = new std::set<uintptr_t>;
39296f81bc6SKostya Serebryany auto HandlePC = [&](const TracePC::PCTableEntry *TE) {
39396f81bc6SKostya Serebryany if (!PCsSet->insert(TE->PC).second)
3945ded0701SAlex Shlyapnikov return;
39596f81bc6SKostya Serebryany std::string Descr = DescribePC("%F %L", TE->PC + 1);
39610ab2aceSGeorge Karpenkov if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
39710ab2aceSGeorge Karpenkov Printf("INFO: found line matching '%s', exiting.\n",
39810ab2aceSGeorge Karpenkov Options.ExitOnSrcPos.c_str());
39910ab2aceSGeorge Karpenkov _Exit(0);
40010ab2aceSGeorge Karpenkov }
40110ab2aceSGeorge Karpenkov };
40210ab2aceSGeorge Karpenkov TPC.ForEachObservedPC(HandlePC);
40310ab2aceSGeorge Karpenkov }
40410ab2aceSGeorge Karpenkov if (!Options.ExitOnItem.empty()) {
40510ab2aceSGeorge Karpenkov if (Corpus.HasUnit(Options.ExitOnItem)) {
40610ab2aceSGeorge Karpenkov Printf("INFO: found item with checksum '%s', exiting.\n",
40710ab2aceSGeorge Karpenkov Options.ExitOnItem.c_str());
40810ab2aceSGeorge Karpenkov _Exit(0);
40910ab2aceSGeorge Karpenkov }
41010ab2aceSGeorge Karpenkov }
41110ab2aceSGeorge Karpenkov }
41210ab2aceSGeorge Karpenkov
RereadOutputCorpus(size_t MaxSize)41310ab2aceSGeorge Karpenkov void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
4145ded0701SAlex Shlyapnikov if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
4155ded0701SAlex Shlyapnikov return;
4167c921753SKostya Serebryany std::vector<Unit> AdditionalCorpus;
4177c921753SKostya Serebryany std::vector<std::string> AdditionalCorpusPaths;
418827ccc93SAlexey Vishnyakov ReadDirToVectorOfUnits(
419827ccc93SAlexey Vishnyakov Options.OutputCorpus.c_str(), &AdditionalCorpus,
42010ab2aceSGeorge Karpenkov &EpochOfLastReadOfOutputCorpus, MaxSize,
421827ccc93SAlexey Vishnyakov /*ExitOnError*/ false,
422827ccc93SAlexey Vishnyakov (Options.Verbosity >= 2 ? &AdditionalCorpusPaths : nullptr));
42310ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2)
42410ab2aceSGeorge Karpenkov Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
42510ab2aceSGeorge Karpenkov bool Reloaded = false;
426827ccc93SAlexey Vishnyakov for (size_t i = 0; i != AdditionalCorpus.size(); ++i) {
427827ccc93SAlexey Vishnyakov auto &U = AdditionalCorpus[i];
42810ab2aceSGeorge Karpenkov if (U.size() > MaxSize)
42910ab2aceSGeorge Karpenkov U.resize(MaxSize);
43010ab2aceSGeorge Karpenkov if (!Corpus.HasUnit(U)) {
43110ab2aceSGeorge Karpenkov if (RunOne(U.data(), U.size())) {
43210ab2aceSGeorge Karpenkov CheckExitOnSrcPosOrItem();
43310ab2aceSGeorge Karpenkov Reloaded = true;
434827ccc93SAlexey Vishnyakov if (Options.Verbosity >= 2)
435827ccc93SAlexey Vishnyakov Printf("Reloaded %s\n", AdditionalCorpusPaths[i].c_str());
43610ab2aceSGeorge Karpenkov }
43710ab2aceSGeorge Karpenkov }
43810ab2aceSGeorge Karpenkov }
43910ab2aceSGeorge Karpenkov if (Reloaded)
44010ab2aceSGeorge Karpenkov PrintStats("RELOAD");
44110ab2aceSGeorge Karpenkov }
44210ab2aceSGeorge Karpenkov
PrintPulseAndReportSlowInput(const uint8_t * Data,size_t Size)44310ab2aceSGeorge Karpenkov void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
44410ab2aceSGeorge Karpenkov auto TimeOfUnit =
44510ab2aceSGeorge Karpenkov duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
44610ab2aceSGeorge Karpenkov if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
44710ab2aceSGeorge Karpenkov secondsSinceProcessStartUp() >= 2)
44810ab2aceSGeorge Karpenkov PrintStats("pulse ");
4496708186cSAaron Green auto Threshhold =
4506708186cSAaron Green static_cast<long>(static_cast<double>(TimeOfLongestUnitInSeconds) * 1.1);
4516708186cSAaron Green if (TimeOfUnit > Threshhold && TimeOfUnit >= Options.ReportSlowUnits) {
45210ab2aceSGeorge Karpenkov TimeOfLongestUnitInSeconds = TimeOfUnit;
45310ab2aceSGeorge Karpenkov Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
45410ab2aceSGeorge Karpenkov WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
45510ab2aceSGeorge Karpenkov }
45610ab2aceSGeorge Karpenkov }
45710ab2aceSGeorge Karpenkov
WriteFeatureSetToFile(const std::string & FeaturesDir,const std::string & FileName,const std::vector<uint32_t> & FeatureSet)4584614cc3dSKostya Serebryany static void WriteFeatureSetToFile(const std::string &FeaturesDir,
4595e67abd9SKostya Serebryany const std::string &FileName,
4607c921753SKostya Serebryany const std::vector<uint32_t> &FeatureSet) {
4614614cc3dSKostya Serebryany if (FeaturesDir.empty() || FeatureSet.empty()) return;
4624614cc3dSKostya Serebryany WriteToFile(reinterpret_cast<const uint8_t *>(FeatureSet.data()),
4634614cc3dSKostya Serebryany FeatureSet.size() * sizeof(FeatureSet[0]),
4645e67abd9SKostya Serebryany DirPlusFile(FeaturesDir, FileName));
4654614cc3dSKostya Serebryany }
4664614cc3dSKostya Serebryany
RenameFeatureSetFile(const std::string & FeaturesDir,const std::string & OldFile,const std::string & NewFile)4674614cc3dSKostya Serebryany static void RenameFeatureSetFile(const std::string &FeaturesDir,
4684614cc3dSKostya Serebryany const std::string &OldFile,
4694614cc3dSKostya Serebryany const std::string &NewFile) {
4704614cc3dSKostya Serebryany if (FeaturesDir.empty()) return;
4714614cc3dSKostya Serebryany RenameFile(DirPlusFile(FeaturesDir, OldFile),
4724614cc3dSKostya Serebryany DirPlusFile(FeaturesDir, NewFile));
4734614cc3dSKostya Serebryany }
4744614cc3dSKostya Serebryany
WriteEdgeToMutationGraphFile(const std::string & MutationGraphFile,const InputInfo * II,const InputInfo * BaseII,const std::string & MS)4751bb1eac6SDokyung Song static void WriteEdgeToMutationGraphFile(const std::string &MutationGraphFile,
4761bb1eac6SDokyung Song const InputInfo *II,
4771bb1eac6SDokyung Song const InputInfo *BaseII,
4781bb1eac6SDokyung Song const std::string &MS) {
4791bb1eac6SDokyung Song if (MutationGraphFile.empty())
4801bb1eac6SDokyung Song return;
4811bb1eac6SDokyung Song
4821bb1eac6SDokyung Song std::string Sha1 = Sha1ToString(II->Sha1);
4831bb1eac6SDokyung Song
4841bb1eac6SDokyung Song std::string OutputString;
4851bb1eac6SDokyung Song
4861bb1eac6SDokyung Song // Add a new vertex.
4871bb1eac6SDokyung Song OutputString.append("\"");
4881bb1eac6SDokyung Song OutputString.append(Sha1);
4891bb1eac6SDokyung Song OutputString.append("\"\n");
4901bb1eac6SDokyung Song
4911bb1eac6SDokyung Song // Add a new edge if there is base input.
4921bb1eac6SDokyung Song if (BaseII) {
4931bb1eac6SDokyung Song std::string BaseSha1 = Sha1ToString(BaseII->Sha1);
4941bb1eac6SDokyung Song OutputString.append("\"");
4951bb1eac6SDokyung Song OutputString.append(BaseSha1);
4961bb1eac6SDokyung Song OutputString.append("\" -> \"");
4971bb1eac6SDokyung Song OutputString.append(Sha1);
4981bb1eac6SDokyung Song OutputString.append("\" [label=\"");
4991bb1eac6SDokyung Song OutputString.append(MS);
5001bb1eac6SDokyung Song OutputString.append("\"];\n");
5011bb1eac6SDokyung Song }
5021bb1eac6SDokyung Song
5031bb1eac6SDokyung Song AppendToFile(OutputString, MutationGraphFile);
5041bb1eac6SDokyung Song }
5051bb1eac6SDokyung Song
RunOne(const uint8_t * Data,size_t Size,bool MayDeleteFile,InputInfo * II,bool ForceAddToCorpus,bool * FoundUniqFeatures)50610ab2aceSGeorge Karpenkov bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
50762673c43SDokyung Song InputInfo *II, bool ForceAddToCorpus,
50862673c43SDokyung Song bool *FoundUniqFeatures) {
5095ded0701SAlex Shlyapnikov if (!Size)
5105ded0701SAlex Shlyapnikov return false;
5116708186cSAaron Green // Largest input length should be INT_MAX.
5126708186cSAaron Green assert(Size < std::numeric_limits<uint32_t>::max());
51310ab2aceSGeorge Karpenkov
514*92fb3101SKostya Serebryany if(!ExecuteCallback(Data, Size)) return false;
5155cda4dc7SDokyung Song auto TimeOfUnit = duration_cast<microseconds>(UnitStopTime - UnitStartTime);
51610ab2aceSGeorge Karpenkov
51710ab2aceSGeorge Karpenkov UniqFeatureSetTmp.clear();
51810ab2aceSGeorge Karpenkov size_t FoundUniqFeaturesOfII = 0;
51910ab2aceSGeorge Karpenkov size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
5206708186cSAaron Green TPC.CollectFeatures([&](uint32_t Feature) {
5216708186cSAaron Green if (Corpus.AddFeature(Feature, static_cast<uint32_t>(Size), Options.Shrink))
52210ab2aceSGeorge Karpenkov UniqFeatureSetTmp.push_back(Feature);
523e2e38fcaSMatt Morehouse if (Options.Entropic)
524e2e38fcaSMatt Morehouse Corpus.UpdateFeatureFrequency(II, Feature);
52562673c43SDokyung Song if (Options.ReduceInputs && II && !II->NeverReduce)
52610ab2aceSGeorge Karpenkov if (std::binary_search(II->UniqFeatureSet.begin(),
52710ab2aceSGeorge Karpenkov II->UniqFeatureSet.end(), Feature))
52810ab2aceSGeorge Karpenkov FoundUniqFeaturesOfII++;
52910ab2aceSGeorge Karpenkov });
530ad05ee05SKostya Serebryany if (FoundUniqFeatures)
531ad05ee05SKostya Serebryany *FoundUniqFeatures = FoundUniqFeaturesOfII;
53210ab2aceSGeorge Karpenkov PrintPulseAndReportSlowInput(Data, Size);
53310ab2aceSGeorge Karpenkov size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
53462673c43SDokyung Song if (NumNewFeatures || ForceAddToCorpus) {
53510ab2aceSGeorge Karpenkov TPC.UpdateObservedPCs();
53662673c43SDokyung Song auto NewII =
53762673c43SDokyung Song Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
53862673c43SDokyung Song TPC.ObservedFocusFunction(), ForceAddToCorpus,
5395cda4dc7SDokyung Song TimeOfUnit, UniqFeatureSetTmp, DFT, II);
5405e67abd9SKostya Serebryany WriteFeatureSetToFile(Options.FeaturesDir, Sha1ToString(NewII->Sha1),
5414614cc3dSKostya Serebryany NewII->UniqFeatureSet);
5421bb1eac6SDokyung Song WriteEdgeToMutationGraphFile(Options.MutationGraphFile, NewII, II,
543c5d72517SMarco Vanotti MD.MutationSequence());
54410ab2aceSGeorge Karpenkov return true;
54510ab2aceSGeorge Karpenkov }
54610ab2aceSGeorge Karpenkov if (II && FoundUniqFeaturesOfII &&
54767af9923SKostya Serebryany II->DataFlowTraceForFocusFunction.empty() &&
54810ab2aceSGeorge Karpenkov FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
54910ab2aceSGeorge Karpenkov II->U.size() > Size) {
5504614cc3dSKostya Serebryany auto OldFeaturesFile = Sha1ToString(II->Sha1);
5519e7b7303SPZ Read Corpus.Replace(II, {Data, Data + Size}, TimeOfUnit);
5524614cc3dSKostya Serebryany RenameFeatureSetFile(Options.FeaturesDir, OldFeaturesFile,
5534614cc3dSKostya Serebryany Sha1ToString(II->Sha1));
55410ab2aceSGeorge Karpenkov return true;
55510ab2aceSGeorge Karpenkov }
55610ab2aceSGeorge Karpenkov return false;
55710ab2aceSGeorge Karpenkov }
55810ab2aceSGeorge Karpenkov
TPCUpdateObservedPCs()559dc62d5ecSMax Moroz void Fuzzer::TPCUpdateObservedPCs() { TPC.UpdateObservedPCs(); }
560dc62d5ecSMax Moroz
GetCurrentUnitInFuzzingThead(const uint8_t ** Data) const56110ab2aceSGeorge Karpenkov size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
56210ab2aceSGeorge Karpenkov assert(InFuzzingThread());
56310ab2aceSGeorge Karpenkov *Data = CurrentUnitData;
56410ab2aceSGeorge Karpenkov return CurrentUnitSize;
56510ab2aceSGeorge Karpenkov }
56610ab2aceSGeorge Karpenkov
CrashOnOverwrittenData()56710ab2aceSGeorge Karpenkov void Fuzzer::CrashOnOverwrittenData() {
568da3cf616SMitch Phillips Printf("==%d== ERROR: libFuzzer: fuzz target overwrites its const input\n",
56910ab2aceSGeorge Karpenkov GetPid());
570d1e222e5SMitch Phillips PrintStackTrace();
571d1e222e5SMitch Phillips Printf("SUMMARY: libFuzzer: overwrites-const-input\n");
57210ab2aceSGeorge Karpenkov DumpCurrentUnit("crash-");
573d1e222e5SMitch Phillips PrintFinalStats();
57410ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // Stop right now.
57510ab2aceSGeorge Karpenkov }
57610ab2aceSGeorge Karpenkov
57710ab2aceSGeorge Karpenkov // Compare two arrays, but not all bytes if the arrays are large.
LooseMemeq(const uint8_t * A,const uint8_t * B,size_t Size)57810ab2aceSGeorge Karpenkov static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
57910ab2aceSGeorge Karpenkov const size_t Limit = 64;
58010ab2aceSGeorge Karpenkov if (Size <= 64)
58110ab2aceSGeorge Karpenkov return !memcmp(A, B, Size);
58210ab2aceSGeorge Karpenkov // Compare first and last Limit/2 bytes.
58310ab2aceSGeorge Karpenkov return !memcmp(A, B, Limit / 2) &&
58410ab2aceSGeorge Karpenkov !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
58510ab2aceSGeorge Karpenkov }
58610ab2aceSGeorge Karpenkov
5875908c7caSJonas Paulsson // This method is not inlined because it would cause a test to fail where it
5885908c7caSJonas Paulsson // is part of the stack unwinding. See D97975 for details.
ExecuteCallback(const uint8_t * Data,size_t Size)589*92fb3101SKostya Serebryany ATTRIBUTE_NOINLINE bool Fuzzer::ExecuteCallback(const uint8_t *Data,
5904b82f614SMatt Morehouse size_t Size) {
59110ab2aceSGeorge Karpenkov TPC.RecordInitialStack();
59210ab2aceSGeorge Karpenkov TotalNumberOfRuns++;
59310ab2aceSGeorge Karpenkov assert(InFuzzingThread());
59410ab2aceSGeorge Karpenkov // We copy the contents of Unit into a separate heap buffer
59510ab2aceSGeorge Karpenkov // so that we reliably find buffer overflows in it.
59610ab2aceSGeorge Karpenkov uint8_t *DataCopy = new uint8_t[Size];
59710ab2aceSGeorge Karpenkov memcpy(DataCopy, Data, Size);
598a34c65e8SMatt Morehouse if (EF->__msan_unpoison)
599a34c65e8SMatt Morehouse EF->__msan_unpoison(DataCopy, Size);
6003478494cSMatt Morehouse if (EF->__msan_unpoison_param)
6013478494cSMatt Morehouse EF->__msan_unpoison_param(2);
60210ab2aceSGeorge Karpenkov if (CurrentUnitData && CurrentUnitData != Data)
60310ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, Data, Size);
60410ab2aceSGeorge Karpenkov CurrentUnitSize = Size;
605*92fb3101SKostya Serebryany int CBRes = 0;
606a34c65e8SMatt Morehouse {
607a34c65e8SMatt Morehouse ScopedEnableMsanInterceptorChecks S;
60810ab2aceSGeorge Karpenkov AllocTracer.Start(Options.TraceMalloc);
60910ab2aceSGeorge Karpenkov UnitStartTime = system_clock::now();
61010ab2aceSGeorge Karpenkov TPC.ResetMaps();
61143a22969SMatt Morehouse RunningUserCallback = true;
612*92fb3101SKostya Serebryany CBRes = CB(DataCopy, Size);
61343a22969SMatt Morehouse RunningUserCallback = false;
61410ab2aceSGeorge Karpenkov UnitStopTime = system_clock::now();
615*92fb3101SKostya Serebryany assert(CBRes == 0 || CBRes == -1);
61610ab2aceSGeorge Karpenkov HasMoreMallocsThanFrees = AllocTracer.Stop();
617a34c65e8SMatt Morehouse }
61810ab2aceSGeorge Karpenkov if (!LooseMemeq(DataCopy, Data, Size))
61910ab2aceSGeorge Karpenkov CrashOnOverwrittenData();
62010ab2aceSGeorge Karpenkov CurrentUnitSize = 0;
62110ab2aceSGeorge Karpenkov delete[] DataCopy;
622*92fb3101SKostya Serebryany return CBRes == 0;
62310ab2aceSGeorge Karpenkov }
62410ab2aceSGeorge Karpenkov
WriteToOutputCorpus(const Unit & U)62563f48717SKostya Serebryany std::string Fuzzer::WriteToOutputCorpus(const Unit &U) {
62610ab2aceSGeorge Karpenkov if (Options.OnlyASCII)
62710ab2aceSGeorge Karpenkov assert(IsASCII(U));
62810ab2aceSGeorge Karpenkov if (Options.OutputCorpus.empty())
62963f48717SKostya Serebryany return "";
63010ab2aceSGeorge Karpenkov std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
63110ab2aceSGeorge Karpenkov WriteToFile(U, Path);
63210ab2aceSGeorge Karpenkov if (Options.Verbosity >= 2)
63310ab2aceSGeorge Karpenkov Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
63463f48717SKostya Serebryany return Path;
63510ab2aceSGeorge Karpenkov }
63610ab2aceSGeorge Karpenkov
WriteUnitToFileWithPrefix(const Unit & U,const char * Prefix)63710ab2aceSGeorge Karpenkov void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
63810ab2aceSGeorge Karpenkov if (!Options.SaveArtifacts)
63910ab2aceSGeorge Karpenkov return;
64010ab2aceSGeorge Karpenkov std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
64110ab2aceSGeorge Karpenkov if (!Options.ExactArtifactPath.empty())
64210ab2aceSGeorge Karpenkov Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
64310ab2aceSGeorge Karpenkov WriteToFile(U, Path);
64410ab2aceSGeorge Karpenkov Printf("artifact_prefix='%s'; Test unit written to %s\n",
64510ab2aceSGeorge Karpenkov Options.ArtifactPrefix.c_str(), Path.c_str());
64610ab2aceSGeorge Karpenkov if (U.size() <= kMaxUnitSizeToPrint)
64710ab2aceSGeorge Karpenkov Printf("Base64: %s\n", Base64(U).c_str());
64810ab2aceSGeorge Karpenkov }
64910ab2aceSGeorge Karpenkov
PrintStatusForNewUnit(const Unit & U,const char * Text)65010ab2aceSGeorge Karpenkov void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
65110ab2aceSGeorge Karpenkov if (!Options.PrintNEW)
65210ab2aceSGeorge Karpenkov return;
65310ab2aceSGeorge Karpenkov PrintStats(Text, "");
65410ab2aceSGeorge Karpenkov if (Options.Verbosity) {
65510ab2aceSGeorge Karpenkov Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
656c5d72517SMarco Vanotti MD.PrintMutationSequence(Options.Verbosity >= 2);
65710ab2aceSGeorge Karpenkov Printf("\n");
65810ab2aceSGeorge Karpenkov }
65910ab2aceSGeorge Karpenkov }
66010ab2aceSGeorge Karpenkov
ReportNewCoverage(InputInfo * II,const Unit & U)66110ab2aceSGeorge Karpenkov void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
66210ab2aceSGeorge Karpenkov II->NumSuccessfullMutations++;
66310ab2aceSGeorge Karpenkov MD.RecordSuccessfulMutationSequence();
6645ded0701SAlex Shlyapnikov PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW ");
66510ab2aceSGeorge Karpenkov WriteToOutputCorpus(U);
66610ab2aceSGeorge Karpenkov NumberOfNewUnitsAdded++;
66710ab2aceSGeorge Karpenkov CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
66810ab2aceSGeorge Karpenkov LastCorpusUpdateRun = TotalNumberOfRuns;
66910ab2aceSGeorge Karpenkov }
67010ab2aceSGeorge Karpenkov
67110ab2aceSGeorge Karpenkov // Tries detecting a memory leak on the particular input that we have just
67210ab2aceSGeorge Karpenkov // executed before calling this function.
TryDetectingAMemoryLeak(const uint8_t * Data,size_t Size,bool DuringInitialCorpusExecution)67310ab2aceSGeorge Karpenkov void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
67410ab2aceSGeorge Karpenkov bool DuringInitialCorpusExecution) {
6755ded0701SAlex Shlyapnikov if (!HasMoreMallocsThanFrees)
6765ded0701SAlex Shlyapnikov return; // mallocs==frees, a leak is unlikely.
6775ded0701SAlex Shlyapnikov if (!Options.DetectLeaks)
6785ded0701SAlex Shlyapnikov return;
6793f26dac4SMax Moroz if (!DuringInitialCorpusExecution &&
6805ded0701SAlex Shlyapnikov TotalNumberOfRuns >= Options.MaxNumberOfRuns)
6815ded0701SAlex Shlyapnikov return;
68210ab2aceSGeorge Karpenkov if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
68310ab2aceSGeorge Karpenkov !(EF->__lsan_do_recoverable_leak_check))
68410ab2aceSGeorge Karpenkov return; // No lsan.
68510ab2aceSGeorge Karpenkov // Run the target once again, but with lsan disabled so that if there is
68610ab2aceSGeorge Karpenkov // a real leak we do not report it twice.
68710ab2aceSGeorge Karpenkov EF->__lsan_disable();
68810ab2aceSGeorge Karpenkov ExecuteCallback(Data, Size);
68910ab2aceSGeorge Karpenkov EF->__lsan_enable();
6905ded0701SAlex Shlyapnikov if (!HasMoreMallocsThanFrees)
6915ded0701SAlex Shlyapnikov return; // a leak is unlikely.
69210ab2aceSGeorge Karpenkov if (NumberOfLeakDetectionAttempts++ > 1000) {
69310ab2aceSGeorge Karpenkov Options.DetectLeaks = false;
69410ab2aceSGeorge Karpenkov Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
69510ab2aceSGeorge Karpenkov " Most likely the target function accumulates allocated\n"
69610ab2aceSGeorge Karpenkov " memory in a global state w/o actually leaking it.\n"
69710ab2aceSGeorge Karpenkov " You may try running this binary with -trace_malloc=[12]"
69810ab2aceSGeorge Karpenkov " to get a trace of mallocs and frees.\n"
69910ab2aceSGeorge Karpenkov " If LeakSanitizer is enabled in this process it will still\n"
70010ab2aceSGeorge Karpenkov " run on the process shutdown.\n");
70110ab2aceSGeorge Karpenkov return;
70210ab2aceSGeorge Karpenkov }
70310ab2aceSGeorge Karpenkov // Now perform the actual lsan pass. This is expensive and we must ensure
70410ab2aceSGeorge Karpenkov // we don't call it too often.
70510ab2aceSGeorge Karpenkov if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
70610ab2aceSGeorge Karpenkov if (DuringInitialCorpusExecution)
70710ab2aceSGeorge Karpenkov Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
70810ab2aceSGeorge Karpenkov Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
70910ab2aceSGeorge Karpenkov CurrentUnitSize = Size;
71010ab2aceSGeorge Karpenkov DumpCurrentUnit("leak-");
71110ab2aceSGeorge Karpenkov PrintFinalStats();
71210ab2aceSGeorge Karpenkov _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
71310ab2aceSGeorge Karpenkov }
71410ab2aceSGeorge Karpenkov }
71510ab2aceSGeorge Karpenkov
MutateAndTestOne()71610ab2aceSGeorge Karpenkov void Fuzzer::MutateAndTestOne() {
71710ab2aceSGeorge Karpenkov MD.StartMutationSequence();
71810ab2aceSGeorge Karpenkov
71910ab2aceSGeorge Karpenkov auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
720b53243e1SDokyung Song if (Options.DoCrossOver) {
721b53243e1SDokyung Song auto &CrossOverII = Corpus.ChooseUnitToCrossOverWith(
722b53243e1SDokyung Song MD.GetRand(), Options.CrossOverUniformDist);
723b53243e1SDokyung Song MD.SetCrossOverWith(&CrossOverII.U);
724b53243e1SDokyung Song }
72510ab2aceSGeorge Karpenkov const auto &U = II.U;
72610ab2aceSGeorge Karpenkov memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
72710ab2aceSGeorge Karpenkov assert(CurrentUnitData);
72810ab2aceSGeorge Karpenkov size_t Size = U.size();
72910ab2aceSGeorge Karpenkov assert(Size <= MaxInputLen && "Oversized Unit");
73010ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, U.data(), Size);
73110ab2aceSGeorge Karpenkov
73210ab2aceSGeorge Karpenkov assert(MaxMutationLen > 0);
73310ab2aceSGeorge Karpenkov
73410ab2aceSGeorge Karpenkov size_t CurrentMaxMutationLen =
73510ab2aceSGeorge Karpenkov Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
73610ab2aceSGeorge Karpenkov assert(CurrentMaxMutationLen > 0);
73710ab2aceSGeorge Karpenkov
73810ab2aceSGeorge Karpenkov for (int i = 0; i < Options.MutateDepth; i++) {
73910ab2aceSGeorge Karpenkov if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
74010ab2aceSGeorge Karpenkov break;
741a2ca2dccSKostya Serebryany MaybeExitGracefully();
74210ab2aceSGeorge Karpenkov size_t NewSize = 0;
7436b87e0c1SKostya Serebryany if (II.HasFocusFunction && !II.DataFlowTraceForFocusFunction.empty() &&
7446b87e0c1SKostya Serebryany Size <= CurrentMaxMutationLen)
7456b87e0c1SKostya Serebryany NewSize = MD.MutateWithMask(CurrentUnitData, Size, Size,
7466b87e0c1SKostya Serebryany II.DataFlowTraceForFocusFunction);
7479d5e7ee2SMax Moroz
7489d5e7ee2SMax Moroz // If MutateWithMask either failed or wasn't called, call default Mutate.
7499d5e7ee2SMax Moroz if (!NewSize)
75010ab2aceSGeorge Karpenkov NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
75110ab2aceSGeorge Karpenkov assert(NewSize > 0 && "Mutator returned empty unit");
7526f1c26f2SAlex Shlyapnikov assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
75310ab2aceSGeorge Karpenkov Size = NewSize;
75410ab2aceSGeorge Karpenkov II.NumExecutedMutations++;
755e2e38fcaSMatt Morehouse Corpus.IncrementNumExecutedMutations();
75610ab2aceSGeorge Karpenkov
757ad05ee05SKostya Serebryany bool FoundUniqFeatures = false;
758ad05ee05SKostya Serebryany bool NewCov = RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II,
75962673c43SDokyung Song /*ForceAddToCorpus*/ false, &FoundUniqFeatures);
76010ab2aceSGeorge Karpenkov TryDetectingAMemoryLeak(CurrentUnitData, Size,
76110ab2aceSGeorge Karpenkov /*DuringInitialCorpusExecution*/ false);
762ad05ee05SKostya Serebryany if (NewCov) {
763947838c9SMatt Morehouse ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
764ad05ee05SKostya Serebryany break; // We will mutate this input more in the next rounds.
765ad05ee05SKostya Serebryany }
766ad05ee05SKostya Serebryany if (Options.ReduceDepth && !FoundUniqFeatures)
767ad05ee05SKostya Serebryany break;
76810ab2aceSGeorge Karpenkov }
769e2e38fcaSMatt Morehouse
770e2e38fcaSMatt Morehouse II.NeedsEnergyUpdate = true;
77110ab2aceSGeorge Karpenkov }
77210ab2aceSGeorge Karpenkov
PurgeAllocator()7736f1c26f2SAlex Shlyapnikov void Fuzzer::PurgeAllocator() {
7745ded0701SAlex Shlyapnikov if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
7756f1c26f2SAlex Shlyapnikov return;
7766f1c26f2SAlex Shlyapnikov if (duration_cast<seconds>(system_clock::now() -
7775ded0701SAlex Shlyapnikov LastAllocatorPurgeAttemptTime)
7785ded0701SAlex Shlyapnikov .count() < Options.PurgeAllocatorIntervalSec)
7796f1c26f2SAlex Shlyapnikov return;
7806f1c26f2SAlex Shlyapnikov
7816f1c26f2SAlex Shlyapnikov if (Options.RssLimitMb <= 0 ||
7825ded0701SAlex Shlyapnikov GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
7836f1c26f2SAlex Shlyapnikov EF->__sanitizer_purge_allocator();
7846f1c26f2SAlex Shlyapnikov
7856f1c26f2SAlex Shlyapnikov LastAllocatorPurgeAttemptTime = system_clock::now();
7866f1c26f2SAlex Shlyapnikov }
7876f1c26f2SAlex Shlyapnikov
ReadAndExecuteSeedCorpora(std::vector<SizedFile> & CorporaFiles)7887c921753SKostya Serebryany void Fuzzer::ReadAndExecuteSeedCorpora(std::vector<SizedFile> &CorporaFiles) {
7893a8e3c83SKostya Serebryany const size_t kMaxSaneLen = 1 << 20;
7903a8e3c83SKostya Serebryany const size_t kMinDefaultLen = 4096;
7914faeb87eSKostya Serebryany size_t MaxSize = 0;
7924faeb87eSKostya Serebryany size_t MinSize = -1;
7934faeb87eSKostya Serebryany size_t TotalSize = 0;
7944c7353c5SKostya Serebryany for (auto &File : CorporaFiles) {
79593679be0SKostya Serebryany MaxSize = Max(File.Size, MaxSize);
79693679be0SKostya Serebryany MinSize = Min(File.Size, MinSize);
79793679be0SKostya Serebryany TotalSize += File.Size;
7984faeb87eSKostya Serebryany }
7994faeb87eSKostya Serebryany if (Options.MaxLen == 0)
8004faeb87eSKostya Serebryany SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
8014faeb87eSKostya Serebryany assert(MaxInputLen > 0);
8024faeb87eSKostya Serebryany
80351823d3aSKostya Serebryany // Test the callback with empty input and never try it again.
80451823d3aSKostya Serebryany uint8_t dummy = 0;
80551823d3aSKostya Serebryany ExecuteCallback(&dummy, 0);
80651823d3aSKostya Serebryany
8074c7353c5SKostya Serebryany if (CorporaFiles.empty()) {
8084faeb87eSKostya Serebryany Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
8094faeb87eSKostya Serebryany Unit U({'\n'}); // Valid ASCII input.
8104faeb87eSKostya Serebryany RunOne(U.data(), U.size());
8114faeb87eSKostya Serebryany } else {
8124faeb87eSKostya Serebryany Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
8134faeb87eSKostya Serebryany " rss: %zdMb\n",
8144c7353c5SKostya Serebryany CorporaFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
8154faeb87eSKostya Serebryany if (Options.ShuffleAtStartUp)
8164c7353c5SKostya Serebryany std::shuffle(CorporaFiles.begin(), CorporaFiles.end(), MD.GetRand());
8174faeb87eSKostya Serebryany
81893679be0SKostya Serebryany if (Options.PreferSmall) {
8194c7353c5SKostya Serebryany std::stable_sort(CorporaFiles.begin(), CorporaFiles.end());
8204c7353c5SKostya Serebryany assert(CorporaFiles.front().Size <= CorporaFiles.back().Size);
82193679be0SKostya Serebryany }
8224faeb87eSKostya Serebryany
8234faeb87eSKostya Serebryany // Load and execute inputs one by one.
8244c7353c5SKostya Serebryany for (auto &SF : CorporaFiles) {
825082e9a75SKostya Serebryany auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
8264faeb87eSKostya Serebryany assert(U.size() <= MaxInputLen);
82762673c43SDokyung Song RunOne(U.data(), U.size(), /*MayDeleteFile*/ false, /*II*/ nullptr,
82862673c43SDokyung Song /*ForceAddToCorpus*/ Options.KeepSeed,
82962673c43SDokyung Song /*FoundUniqFeatures*/ nullptr);
8304faeb87eSKostya Serebryany CheckExitOnSrcPosOrItem();
8314faeb87eSKostya Serebryany TryDetectingAMemoryLeak(U.data(), U.size(),
8324faeb87eSKostya Serebryany /*DuringInitialCorpusExecution*/ true);
8334faeb87eSKostya Serebryany }
8343a8e3c83SKostya Serebryany }
8353a8e3c83SKostya Serebryany
8364faeb87eSKostya Serebryany PrintStats("INITED");
83707647571SMax Moroz if (!Options.FocusFunction.empty()) {
838e9c6f06cSKostya Serebryany Printf("INFO: %zd/%zd inputs touch the focus function\n",
839e9c6f06cSKostya Serebryany Corpus.NumInputsThatTouchFocusFunction(), Corpus.size());
84067af9923SKostya Serebryany if (!Options.DataFlowTrace.empty())
84167af9923SKostya Serebryany Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n",
84207647571SMax Moroz Corpus.NumInputsWithDataFlowTrace(),
84307647571SMax Moroz Corpus.NumInputsThatTouchFocusFunction());
84407647571SMax Moroz }
845e9c6f06cSKostya Serebryany
846fe97441cSMax Moroz if (Corpus.empty() && Options.MaxNumberOfRuns) {
847*92fb3101SKostya Serebryany Printf("WARNING: no interesting inputs were found so far. "
848*92fb3101SKostya Serebryany "Is the code instrumented for coverage?\n"
849*92fb3101SKostya Serebryany "This may also happen if the target rejected all inputs we tried so "
850*92fb3101SKostya Serebryany "far\n");
851*92fb3101SKostya Serebryany // The remaining logic requires that the corpus is not empty,
852*92fb3101SKostya Serebryany // so we add one fake input to the in-memory corpus.
853*92fb3101SKostya Serebryany Corpus.AddToCorpus({'\n'}, /*NumFeatures=*/1, /*MayDeleteFile=*/true,
854*92fb3101SKostya Serebryany /*HasFocusFunction=*/false, /*NeverReduce=*/false,
855*92fb3101SKostya Serebryany /*TimeOfUnit=*/duration_cast<microseconds>(0s), {0}, DFT,
856*92fb3101SKostya Serebryany /*BaseII*/ nullptr);
8573a8e3c83SKostya Serebryany }
8583a8e3c83SKostya Serebryany }
8593a8e3c83SKostya Serebryany
Loop(std::vector<SizedFile> & CorporaFiles)8607c921753SKostya Serebryany void Fuzzer::Loop(std::vector<SizedFile> &CorporaFiles) {
861060f4b48SKostya Serebryany auto FocusFunctionOrAuto = Options.FocusFunction;
862060f4b48SKostya Serebryany DFT.Init(Options.DataFlowTrace, &FocusFunctionOrAuto, CorporaFiles,
863060f4b48SKostya Serebryany MD.GetRand());
864060f4b48SKostya Serebryany TPC.SetFocusFunction(FocusFunctionOrAuto);
8654c7353c5SKostya Serebryany ReadAndExecuteSeedCorpora(CorporaFiles);
86667af9923SKostya Serebryany DFT.Clear(); // No need for DFT any more.
86710ab2aceSGeorge Karpenkov TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
8682eef816eSKostya Serebryany TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
86910ab2aceSGeorge Karpenkov system_clock::time_point LastCorpusReload = system_clock::now();
870b6ca1e72SKostya Serebryany
871b6ca1e72SKostya Serebryany TmpMaxMutationLen =
872b6ca1e72SKostya Serebryany Min(MaxMutationLen, Max(size_t(4), Corpus.MaxInputSize()));
873b6ca1e72SKostya Serebryany
87410ab2aceSGeorge Karpenkov while (true) {
87510ab2aceSGeorge Karpenkov auto Now = system_clock::now();
876db88fc56SKostya Serebryany if (!Options.StopFile.empty() &&
877db88fc56SKostya Serebryany !FileToVector(Options.StopFile, 1, false).empty())
878db88fc56SKostya Serebryany break;
87910ab2aceSGeorge Karpenkov if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
88010ab2aceSGeorge Karpenkov Options.ReloadIntervalSec) {
88110ab2aceSGeorge Karpenkov RereadOutputCorpus(MaxInputLen);
88210ab2aceSGeorge Karpenkov LastCorpusReload = system_clock::now();
88310ab2aceSGeorge Karpenkov }
88410ab2aceSGeorge Karpenkov if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
88510ab2aceSGeorge Karpenkov break;
8865ded0701SAlex Shlyapnikov if (TimedOut())
8875ded0701SAlex Shlyapnikov break;
88810ab2aceSGeorge Karpenkov
88910ab2aceSGeorge Karpenkov // Update TmpMaxMutationLen
89036c89b3cSMatt Morehouse if (Options.LenControl) {
89110ab2aceSGeorge Karpenkov if (TmpMaxMutationLen < MaxMutationLen &&
892e9ed2327SKostya Serebryany TotalNumberOfRuns - LastCorpusUpdateRun >
89336c89b3cSMatt Morehouse Options.LenControl * Log(TmpMaxMutationLen)) {
89410ab2aceSGeorge Karpenkov TmpMaxMutationLen =
895e9ed2327SKostya Serebryany Min(MaxMutationLen, TmpMaxMutationLen + Log(TmpMaxMutationLen));
896e9ed2327SKostya Serebryany LastCorpusUpdateRun = TotalNumberOfRuns;
89710ab2aceSGeorge Karpenkov }
89810ab2aceSGeorge Karpenkov } else {
89910ab2aceSGeorge Karpenkov TmpMaxMutationLen = MaxMutationLen;
90010ab2aceSGeorge Karpenkov }
90110ab2aceSGeorge Karpenkov
90210ab2aceSGeorge Karpenkov // Perform several mutations and runs.
90310ab2aceSGeorge Karpenkov MutateAndTestOne();
9046f1c26f2SAlex Shlyapnikov
9056f1c26f2SAlex Shlyapnikov PurgeAllocator();
90610ab2aceSGeorge Karpenkov }
90710ab2aceSGeorge Karpenkov
90810ab2aceSGeorge Karpenkov PrintStats("DONE ", "\n");
909c5d72517SMarco Vanotti MD.PrintRecommendedDictionary();
91010ab2aceSGeorge Karpenkov }
91110ab2aceSGeorge Karpenkov
MinimizeCrashLoop(const Unit & U)91210ab2aceSGeorge Karpenkov void Fuzzer::MinimizeCrashLoop(const Unit &U) {
9135ded0701SAlex Shlyapnikov if (U.size() <= 1)
9145ded0701SAlex Shlyapnikov return;
91510ab2aceSGeorge Karpenkov while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
91610ab2aceSGeorge Karpenkov MD.StartMutationSequence();
91710ab2aceSGeorge Karpenkov memcpy(CurrentUnitData, U.data(), U.size());
91810ab2aceSGeorge Karpenkov for (int i = 0; i < Options.MutateDepth; i++) {
91910ab2aceSGeorge Karpenkov size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
92010ab2aceSGeorge Karpenkov assert(NewSize > 0 && NewSize <= MaxMutationLen);
92110ab2aceSGeorge Karpenkov ExecuteCallback(CurrentUnitData, NewSize);
92210ab2aceSGeorge Karpenkov PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
92310ab2aceSGeorge Karpenkov TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
92410ab2aceSGeorge Karpenkov /*DuringInitialCorpusExecution*/ false);
92510ab2aceSGeorge Karpenkov }
92610ab2aceSGeorge Karpenkov }
92710ab2aceSGeorge Karpenkov }
92810ab2aceSGeorge Karpenkov
92910ab2aceSGeorge Karpenkov } // namespace fuzzer
93010ab2aceSGeorge Karpenkov
93110ab2aceSGeorge Karpenkov extern "C" {
93210ab2aceSGeorge Karpenkov
933b795c31dSJonathan Metzman ATTRIBUTE_INTERFACE size_t
LLVMFuzzerMutate(uint8_t * Data,size_t Size,size_t MaxSize)934eac2b47bSPetr Hosek LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
93510ab2aceSGeorge Karpenkov assert(fuzzer::F);
93610ab2aceSGeorge Karpenkov return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
93710ab2aceSGeorge Karpenkov }
93810ab2aceSGeorge Karpenkov
93910ab2aceSGeorge Karpenkov } // extern "C"
940