1 //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 // Fuzzer's main loop.
10 //===----------------------------------------------------------------------===//
11 
12 #include "FuzzerCorpus.h"
13 #include "FuzzerIO.h"
14 #include "FuzzerInternal.h"
15 #include "FuzzerMutate.h"
16 #include "FuzzerRandom.h"
17 #include "FuzzerShmem.h"
18 #include "FuzzerTracePC.h"
19 #include <algorithm>
20 #include <cstring>
21 #include <memory>
22 #include <mutex>
23 #include <set>
24 
25 #if defined(__has_include)
26 #if __has_include(<sanitizer / lsan_interface.h>)
27 #include <sanitizer/lsan_interface.h>
28 #endif
29 #endif
30 
31 #define NO_SANITIZE_MEMORY
32 #if defined(__has_feature)
33 #if __has_feature(memory_sanitizer)
34 #undef NO_SANITIZE_MEMORY
35 #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
36 #endif
37 #endif
38 
39 namespace fuzzer {
40 static const size_t kMaxUnitSizeToPrint = 256;
41 
42 thread_local bool Fuzzer::IsMyThread;
43 
44 SharedMemoryRegion SMR;
45 
46 // Only one Fuzzer per process.
47 static Fuzzer *F;
48 
49 // Leak detection is expensive, so we first check if there were more mallocs
50 // than frees (using the sanitizer malloc hooks) and only then try to call lsan.
51 struct MallocFreeTracer {
52   void Start(int TraceLevel) {
53     this->TraceLevel = TraceLevel;
54     if (TraceLevel)
55       Printf("MallocFreeTracer: START\n");
56     Mallocs = 0;
57     Frees = 0;
58   }
59   // Returns true if there were more mallocs than frees.
60   bool Stop() {
61     if (TraceLevel)
62       Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
63              Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
64     bool Result = Mallocs > Frees;
65     Mallocs = 0;
66     Frees = 0;
67     TraceLevel = 0;
68     return Result;
69   }
70   std::atomic<size_t> Mallocs;
71   std::atomic<size_t> Frees;
72   int TraceLevel = 0;
73 };
74 
75 static MallocFreeTracer AllocTracer;
76 
77 static thread_local bool IsMallocFreeHookDisabled;
78 static std::mutex MallocFreeStackMutex;
79 
80 struct MallocFreeHookDisabler {
81   MallocFreeHookDisabler() { IsMallocFreeHookDisabled = true; }
82   ~MallocFreeHookDisabler() { IsMallocFreeHookDisabled = false; }
83 };
84 
85 ATTRIBUTE_NO_SANITIZE_MEMORY
86 void MallocHook(const volatile void *ptr, size_t size) {
87   // Avoid nested hooks for mallocs/frees in sanitizer.
88   if (IsMallocFreeHookDisabled)
89     return;
90   MallocFreeHookDisabler Disable;
91   size_t N = AllocTracer.Mallocs++;
92   F->HandleMalloc(size);
93   if (int TraceLevel = AllocTracer.TraceLevel) {
94     std::lock_guard<std::mutex> Lock(MallocFreeStackMutex);
95     Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
96     if (TraceLevel >= 2 && EF)
97       EF->__sanitizer_print_stack_trace();
98   }
99 }
100 
101 ATTRIBUTE_NO_SANITIZE_MEMORY
102 void FreeHook(const volatile void *ptr) {
103   // Avoid nested hooks for mallocs/frees in sanitizer.
104   if (IsMallocFreeHookDisabled)
105     return;
106   MallocFreeHookDisabler Disable;
107   size_t N = AllocTracer.Frees++;
108   if (int TraceLevel = AllocTracer.TraceLevel) {
109     std::lock_guard<std::mutex> Lock(MallocFreeStackMutex);
110     Printf("FREE[%zd]   %p\n", N, ptr);
111     if (TraceLevel >= 2 && EF)
112       EF->__sanitizer_print_stack_trace();
113   }
114 }
115 
116 // Crash on a single malloc that exceeds the rss limit.
117 void Fuzzer::HandleMalloc(size_t Size) {
118   if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb)
119     return;
120   Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
121          Size);
122   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
123   if (EF->__sanitizer_print_stack_trace)
124     EF->__sanitizer_print_stack_trace();
125   DumpCurrentUnit("oom-");
126   Printf("SUMMARY: libFuzzer: out-of-memory\n");
127   PrintFinalStats();
128   _Exit(Options.ErrorExitCode); // Stop right now.
129 }
130 
131 Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
132                FuzzingOptions Options)
133     : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
134   if (EF->__sanitizer_set_death_callback)
135     EF->__sanitizer_set_death_callback(StaticDeathCallback);
136   assert(!F);
137   F = this;
138   TPC.ResetMaps();
139   IsMyThread = true;
140   if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
141     EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
142   TPC.SetUseCounters(Options.UseCounters);
143   TPC.SetUseValueProfile(Options.UseValueProfile);
144   TPC.SetUseClangCoverage(Options.UseClangCoverage);
145 
146   if (Options.Verbosity)
147     TPC.PrintModuleInfo();
148   if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
149     EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
150   MaxInputLen = MaxMutationLen = Options.MaxLen;
151   TmpMaxMutationLen = Max(size_t(4), Corpus.MaxInputSize());
152   AllocateCurrentUnitData();
153   CurrentUnitSize = 0;
154   memset(BaseSha1, 0, sizeof(BaseSha1));
155 }
156 
157 Fuzzer::~Fuzzer() {}
158 
159 void Fuzzer::AllocateCurrentUnitData() {
160   if (CurrentUnitData || MaxInputLen == 0)
161     return;
162   CurrentUnitData = new uint8_t[MaxInputLen];
163 }
164 
165 void Fuzzer::StaticDeathCallback() {
166   assert(F);
167   F->DeathCallback();
168 }
169 
170 void Fuzzer::DumpCurrentUnit(const char *Prefix) {
171   if (!CurrentUnitData)
172     return; // Happens when running individual inputs.
173   MD.PrintMutationSequence();
174   Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
175   size_t UnitSize = CurrentUnitSize;
176   if (UnitSize <= kMaxUnitSizeToPrint) {
177     PrintHexArray(CurrentUnitData, UnitSize, "\n");
178     PrintASCII(CurrentUnitData, UnitSize, "\n");
179   }
180   WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
181                             Prefix);
182 }
183 
184 NO_SANITIZE_MEMORY
185 void Fuzzer::DeathCallback() {
186   DumpCurrentUnit("crash-");
187   PrintFinalStats();
188 }
189 
190 void Fuzzer::StaticAlarmCallback() {
191   assert(F);
192   F->AlarmCallback();
193 }
194 
195 void Fuzzer::StaticCrashSignalCallback() {
196   assert(F);
197   F->CrashCallback();
198 }
199 
200 void Fuzzer::StaticExitCallback() {
201   assert(F);
202   F->ExitCallback();
203 }
204 
205 void Fuzzer::StaticInterruptCallback() {
206   assert(F);
207   F->InterruptCallback();
208 }
209 
210 void Fuzzer::StaticFileSizeExceedCallback() {
211   Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
212   exit(1);
213 }
214 
215 void Fuzzer::CrashCallback() {
216   Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
217   if (EF->__sanitizer_print_stack_trace)
218     EF->__sanitizer_print_stack_trace();
219   Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
220          "      Combine libFuzzer with AddressSanitizer or similar for better "
221          "crash reports.\n");
222   Printf("SUMMARY: libFuzzer: deadly signal\n");
223   DumpCurrentUnit("crash-");
224   PrintFinalStats();
225   _Exit(Options.ErrorExitCode); // Stop right now.
226 }
227 
228 void Fuzzer::ExitCallback() {
229   if (!RunningCB)
230     return; // This exit did not come from the user callback
231   Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
232   if (EF->__sanitizer_print_stack_trace)
233     EF->__sanitizer_print_stack_trace();
234   Printf("SUMMARY: libFuzzer: fuzz target exited\n");
235   DumpCurrentUnit("crash-");
236   PrintFinalStats();
237   _Exit(Options.ErrorExitCode);
238 }
239 
240 void Fuzzer::InterruptCallback() {
241   Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
242   PrintFinalStats();
243   _Exit(0); // Stop right now, don't perform any at-exit actions.
244 }
245 
246 NO_SANITIZE_MEMORY
247 void Fuzzer::AlarmCallback() {
248   assert(Options.UnitTimeoutSec > 0);
249   // In Windows Alarm callback is executed by a different thread.
250 #if !LIBFUZZER_WINDOWS
251   if (!InFuzzingThread())
252     return;
253 #endif
254   if (!RunningCB)
255     return; // We have not started running units yet.
256   size_t Seconds =
257       duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
258   if (Seconds == 0)
259     return;
260   if (Options.Verbosity >= 2)
261     Printf("AlarmCallback %zd\n", Seconds);
262   if (Seconds >= (size_t)Options.UnitTimeoutSec) {
263     Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
264     Printf("       and the timeout value is %d (use -timeout=N to change)\n",
265            Options.UnitTimeoutSec);
266     DumpCurrentUnit("timeout-");
267     Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
268            Seconds);
269     if (EF->__sanitizer_print_stack_trace)
270       EF->__sanitizer_print_stack_trace();
271     Printf("SUMMARY: libFuzzer: timeout\n");
272     PrintFinalStats();
273     _Exit(Options.TimeoutExitCode); // Stop right now.
274   }
275 }
276 
277 void Fuzzer::RssLimitCallback() {
278   Printf(
279       "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
280       GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
281   Printf("   To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
282   if (EF->__sanitizer_print_memory_profile)
283     EF->__sanitizer_print_memory_profile(95, 8);
284   DumpCurrentUnit("oom-");
285   Printf("SUMMARY: libFuzzer: out-of-memory\n");
286   PrintFinalStats();
287   _Exit(Options.ErrorExitCode); // Stop right now.
288 }
289 
290 void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
291   size_t ExecPerSec = execPerSec();
292   if (!Options.Verbosity)
293     return;
294   Printf("#%zd\t%s", TotalNumberOfRuns, Where);
295   if (size_t N = TPC.GetTotalPCCoverage())
296     Printf(" cov: %zd", N);
297   if (size_t N = Corpus.NumFeatures())
298     Printf(" ft: %zd", N);
299   if (!Corpus.empty()) {
300     Printf(" corp: %zd", Corpus.NumActiveUnits());
301     if (size_t N = Corpus.SizeInBytes()) {
302       if (N < (1 << 14))
303         Printf("/%zdb", N);
304       else if (N < (1 << 24))
305         Printf("/%zdKb", N >> 10);
306       else
307         Printf("/%zdMb", N >> 20);
308     }
309   }
310   if (Units)
311     Printf(" units: %zd", Units);
312 
313   Printf(" exec/s: %zd", ExecPerSec);
314   Printf(" rss: %zdMb", GetPeakRSSMb());
315   Printf("%s", End);
316 }
317 
318 void Fuzzer::PrintFinalStats() {
319   if (Options.PrintCoverage)
320     TPC.PrintCoverage();
321   if (Options.DumpCoverage)
322     TPC.DumpCoverage();
323   if (Options.PrintCorpusStats)
324     Corpus.PrintStats();
325   if (!Options.PrintFinalStats)
326     return;
327   size_t ExecPerSec = execPerSec();
328   Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
329   Printf("stat::average_exec_per_sec:     %zd\n", ExecPerSec);
330   Printf("stat::new_units_added:          %zd\n", NumberOfNewUnitsAdded);
331   Printf("stat::slowest_unit_time_sec:    %zd\n", TimeOfLongestUnitInSeconds);
332   Printf("stat::peak_rss_mb:              %zd\n", GetPeakRSSMb());
333 }
334 
335 void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
336   assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
337   assert(MaxInputLen);
338   this->MaxInputLen = MaxInputLen;
339   this->MaxMutationLen = MaxInputLen;
340   AllocateCurrentUnitData();
341   Printf("INFO: -max_len is not provided; "
342          "libFuzzer will not generate inputs larger than %zd bytes\n",
343          MaxInputLen);
344 }
345 
346 void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
347   assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
348   this->MaxMutationLen = MaxMutationLen;
349 }
350 
351 void Fuzzer::CheckExitOnSrcPosOrItem() {
352   if (!Options.ExitOnSrcPos.empty()) {
353     static auto *PCsSet = new Set<uintptr_t>;
354     auto HandlePC = [&](uintptr_t PC) {
355       if (!PCsSet->insert(PC).second)
356         return;
357       std::string Descr = DescribePC("%F %L", PC + 1);
358       if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
359         Printf("INFO: found line matching '%s', exiting.\n",
360                Options.ExitOnSrcPos.c_str());
361         _Exit(0);
362       }
363     };
364     TPC.ForEachObservedPC(HandlePC);
365   }
366   if (!Options.ExitOnItem.empty()) {
367     if (Corpus.HasUnit(Options.ExitOnItem)) {
368       Printf("INFO: found item with checksum '%s', exiting.\n",
369              Options.ExitOnItem.c_str());
370       _Exit(0);
371     }
372   }
373 }
374 
375 void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
376   if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec)
377     return;
378   Vector<Unit> AdditionalCorpus;
379   ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
380                          &EpochOfLastReadOfOutputCorpus, MaxSize,
381                          /*ExitOnError*/ false);
382   if (Options.Verbosity >= 2)
383     Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
384   bool Reloaded = false;
385   for (auto &U : AdditionalCorpus) {
386     if (U.size() > MaxSize)
387       U.resize(MaxSize);
388     if (!Corpus.HasUnit(U)) {
389       if (RunOne(U.data(), U.size())) {
390         CheckExitOnSrcPosOrItem();
391         Reloaded = true;
392       }
393     }
394   }
395   if (Reloaded)
396     PrintStats("RELOAD");
397 }
398 
399 void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data, size_t Size) {
400   auto TimeOfUnit =
401       duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
402   if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
403       secondsSinceProcessStartUp() >= 2)
404     PrintStats("pulse ");
405   if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 &&
406       TimeOfUnit >= Options.ReportSlowUnits) {
407     TimeOfLongestUnitInSeconds = TimeOfUnit;
408     Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
409     WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
410   }
411 }
412 
413 bool Fuzzer::RunOne(const uint8_t *Data, size_t Size, bool MayDeleteFile,
414                     InputInfo *II) {
415   if (!Size)
416     return false;
417 
418   ExecuteCallback(Data, Size);
419 
420   UniqFeatureSetTmp.clear();
421   size_t FoundUniqFeaturesOfII = 0;
422   size_t NumUpdatesBefore = Corpus.NumFeatureUpdates();
423   TPC.CollectFeatures([&](size_t Feature) {
424     Corpus.UpdateFeatureFrequency(Feature);
425     if (Corpus.AddFeature(Feature, Size, Options.Shrink))
426       UniqFeatureSetTmp.push_back(Feature);
427     if (Options.ReduceInputs && II)
428       if (std::binary_search(II->UniqFeatureSet.begin(),
429                              II->UniqFeatureSet.end(), Feature))
430         FoundUniqFeaturesOfII++;
431   });
432   PrintPulseAndReportSlowInput(Data, Size);
433   size_t NumNewFeatures = Corpus.NumFeatureUpdates() - NumUpdatesBefore;
434   if (NumNewFeatures) {
435     TPC.UpdateObservedPCs();
436     Corpus.AddToCorpus({Data, Data + Size}, NumNewFeatures, MayDeleteFile,
437                        UniqFeatureSetTmp);
438     return true;
439   }
440   if (II && FoundUniqFeaturesOfII &&
441       FoundUniqFeaturesOfII == II->UniqFeatureSet.size() &&
442       II->U.size() > Size) {
443     Corpus.Replace(II, {Data, Data + Size});
444     return true;
445   }
446   return false;
447 }
448 
449 size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
450   assert(InFuzzingThread());
451   *Data = CurrentUnitData;
452   return CurrentUnitSize;
453 }
454 
455 void Fuzzer::CrashOnOverwrittenData() {
456   Printf("==%d== ERROR: libFuzzer: fuzz target overwrites it's const input\n",
457          GetPid());
458   DumpCurrentUnit("crash-");
459   Printf("SUMMARY: libFuzzer: out-of-memory\n");
460   _Exit(Options.ErrorExitCode); // Stop right now.
461 }
462 
463 // Compare two arrays, but not all bytes if the arrays are large.
464 static bool LooseMemeq(const uint8_t *A, const uint8_t *B, size_t Size) {
465   const size_t Limit = 64;
466   if (Size <= 64)
467     return !memcmp(A, B, Size);
468   // Compare first and last Limit/2 bytes.
469   return !memcmp(A, B, Limit / 2) &&
470          !memcmp(A + Size - Limit / 2, B + Size - Limit / 2, Limit / 2);
471 }
472 
473 void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
474   TPC.RecordInitialStack();
475   TotalNumberOfRuns++;
476   assert(InFuzzingThread());
477   if (SMR.IsClient())
478     SMR.WriteByteArray(Data, Size);
479   // We copy the contents of Unit into a separate heap buffer
480   // so that we reliably find buffer overflows in it.
481   uint8_t *DataCopy = new uint8_t[Size];
482   memcpy(DataCopy, Data, Size);
483   if (CurrentUnitData && CurrentUnitData != Data)
484     memcpy(CurrentUnitData, Data, Size);
485   CurrentUnitSize = Size;
486   AllocTracer.Start(Options.TraceMalloc);
487   UnitStartTime = system_clock::now();
488   TPC.ResetMaps();
489   RunningCB = true;
490   int Res = CB(DataCopy, Size);
491   RunningCB = false;
492   UnitStopTime = system_clock::now();
493   (void)Res;
494   assert(Res == 0);
495   HasMoreMallocsThanFrees = AllocTracer.Stop();
496   if (!LooseMemeq(DataCopy, Data, Size))
497     CrashOnOverwrittenData();
498   CurrentUnitSize = 0;
499   delete[] DataCopy;
500 }
501 
502 void Fuzzer::WriteToOutputCorpus(const Unit &U) {
503   if (Options.OnlyASCII)
504     assert(IsASCII(U));
505   if (Options.OutputCorpus.empty())
506     return;
507   std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
508   WriteToFile(U, Path);
509   if (Options.Verbosity >= 2)
510     Printf("Written %zd bytes to %s\n", U.size(), Path.c_str());
511 }
512 
513 void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
514   if (!Options.SaveArtifacts)
515     return;
516   std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
517   if (!Options.ExactArtifactPath.empty())
518     Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
519   WriteToFile(U, Path);
520   Printf("artifact_prefix='%s'; Test unit written to %s\n",
521          Options.ArtifactPrefix.c_str(), Path.c_str());
522   if (U.size() <= kMaxUnitSizeToPrint)
523     Printf("Base64: %s\n", Base64(U).c_str());
524 }
525 
526 void Fuzzer::PrintStatusForNewUnit(const Unit &U, const char *Text) {
527   if (!Options.PrintNEW)
528     return;
529   PrintStats(Text, "");
530   if (Options.Verbosity) {
531     Printf(" L: %zd/%zd ", U.size(), Corpus.MaxInputSize());
532     MD.PrintMutationSequence();
533     Printf("\n");
534   }
535 }
536 
537 void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
538   II->NumSuccessfullMutations++;
539   MD.RecordSuccessfulMutationSequence();
540   PrintStatusForNewUnit(U, II->Reduced ? "REDUCE" : "NEW   ");
541   WriteToOutputCorpus(U);
542   NumberOfNewUnitsAdded++;
543   CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
544   LastCorpusUpdateRun = TotalNumberOfRuns;
545   LastCorpusUpdateTime = system_clock::now();
546 }
547 
548 // Tries detecting a memory leak on the particular input that we have just
549 // executed before calling this function.
550 void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
551                                      bool DuringInitialCorpusExecution) {
552   if (!HasMoreMallocsThanFrees)
553     return; // mallocs==frees, a leak is unlikely.
554   if (!Options.DetectLeaks)
555     return;
556   if (!DuringInitialCorpusExecution &&
557       TotalNumberOfRuns >= Options.MaxNumberOfRuns)
558     return;
559   if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
560       !(EF->__lsan_do_recoverable_leak_check))
561     return; // No lsan.
562   // Run the target once again, but with lsan disabled so that if there is
563   // a real leak we do not report it twice.
564   EF->__lsan_disable();
565   ExecuteCallback(Data, Size);
566   EF->__lsan_enable();
567   if (!HasMoreMallocsThanFrees)
568     return; // a leak is unlikely.
569   if (NumberOfLeakDetectionAttempts++ > 1000) {
570     Options.DetectLeaks = false;
571     Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
572            "      Most likely the target function accumulates allocated\n"
573            "      memory in a global state w/o actually leaking it.\n"
574            "      You may try running this binary with -trace_malloc=[12]"
575            "      to get a trace of mallocs and frees.\n"
576            "      If LeakSanitizer is enabled in this process it will still\n"
577            "      run on the process shutdown.\n");
578     return;
579   }
580   // Now perform the actual lsan pass. This is expensive and we must ensure
581   // we don't call it too often.
582   if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
583     if (DuringInitialCorpusExecution)
584       Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
585     Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
586     CurrentUnitSize = Size;
587     DumpCurrentUnit("leak-");
588     PrintFinalStats();
589     _Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
590   }
591 }
592 
593 void Fuzzer::MutateAndTestOne() {
594   MD.StartMutationSequence();
595 
596   auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
597   if (Options.UseFeatureFrequency)
598     Corpus.UpdateFeatureFrequencyScore(&II);
599   const auto &U = II.U;
600   memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
601   assert(CurrentUnitData);
602   size_t Size = U.size();
603   assert(Size <= MaxInputLen && "Oversized Unit");
604   memcpy(CurrentUnitData, U.data(), Size);
605 
606   assert(MaxMutationLen > 0);
607 
608   size_t CurrentMaxMutationLen =
609       Min(MaxMutationLen, Max(U.size(), TmpMaxMutationLen));
610   assert(CurrentMaxMutationLen > 0);
611 
612   for (int i = 0; i < Options.MutateDepth; i++) {
613     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
614       break;
615     size_t NewSize = 0;
616     NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
617     assert(NewSize > 0 && "Mutator returned empty unit");
618     assert(NewSize <= CurrentMaxMutationLen && "Mutator return oversized unit");
619     Size = NewSize;
620     II.NumExecutedMutations++;
621     if (RunOne(CurrentUnitData, Size, /*MayDeleteFile=*/true, &II))
622       ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
623 
624     TryDetectingAMemoryLeak(CurrentUnitData, Size,
625                             /*DuringInitialCorpusExecution*/ false);
626   }
627 }
628 
629 void Fuzzer::PurgeAllocator() {
630   if (Options.PurgeAllocatorIntervalSec < 0 || !EF->__sanitizer_purge_allocator)
631     return;
632   if (duration_cast<seconds>(system_clock::now() -
633                              LastAllocatorPurgeAttemptTime)
634           .count() < Options.PurgeAllocatorIntervalSec)
635     return;
636 
637   if (Options.RssLimitMb <= 0 ||
638       GetPeakRSSMb() > static_cast<size_t>(Options.RssLimitMb) / 2)
639     EF->__sanitizer_purge_allocator();
640 
641   LastAllocatorPurgeAttemptTime = system_clock::now();
642 }
643 
644 void Fuzzer::ReadAndExecuteSeedCorpora(const Vector<std::string> &CorpusDirs) {
645   const size_t kMaxSaneLen = 1 << 20;
646   const size_t kMinDefaultLen = 4096;
647   Vector<SizedFile> SizedFiles;
648   size_t MaxSize = 0;
649   size_t MinSize = -1;
650   size_t TotalSize = 0;
651   size_t LastNumFiles = 0;
652   for (auto &Dir : CorpusDirs) {
653     GetSizedFilesFromDir(Dir, &SizedFiles);
654     Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
655            Dir.c_str());
656     LastNumFiles = SizedFiles.size();
657   }
658   for (auto &File : SizedFiles) {
659     MaxSize = Max(File.Size, MaxSize);
660     MinSize = Min(File.Size, MinSize);
661     TotalSize += File.Size;
662   }
663   if (Options.MaxLen == 0)
664     SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxSize), kMaxSaneLen));
665   assert(MaxInputLen > 0);
666 
667   // Test the callback with empty input and never try it again.
668   uint8_t dummy = 0;
669   ExecuteCallback(&dummy, 0);
670 
671   if (SizedFiles.empty()) {
672     Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
673     Unit U({'\n'}); // Valid ASCII input.
674     RunOne(U.data(), U.size());
675   } else {
676     Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
677            " rss: %zdMb\n",
678            SizedFiles.size(), MinSize, MaxSize, TotalSize, GetPeakRSSMb());
679     if (Options.ShuffleAtStartUp)
680       std::shuffle(SizedFiles.begin(), SizedFiles.end(), MD.GetRand());
681 
682     if (Options.PreferSmall) {
683       std::stable_sort(SizedFiles.begin(), SizedFiles.end());
684       assert(SizedFiles.front().Size <= SizedFiles.back().Size);
685     }
686 
687     // Load and execute inputs one by one.
688     for (auto &SF : SizedFiles) {
689       auto U = FileToVector(SF.File, MaxInputLen, /*ExitOnError=*/false);
690       assert(U.size() <= MaxInputLen);
691       RunOne(U.data(), U.size());
692       CheckExitOnSrcPosOrItem();
693       TryDetectingAMemoryLeak(U.data(), U.size(),
694                               /*DuringInitialCorpusExecution*/ true);
695     }
696   }
697 
698   PrintStats("INITED");
699   if (Corpus.empty()) {
700     Printf("ERROR: no interesting inputs were found. "
701            "Is the code instrumented for coverage? Exiting.\n");
702     exit(1);
703   }
704 }
705 
706 void Fuzzer::Loop(const Vector<std::string> &CorpusDirs) {
707   ReadAndExecuteSeedCorpora(CorpusDirs);
708   TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
709   TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
710   system_clock::time_point LastCorpusReload = system_clock::now();
711   if (Options.DoCrossOver)
712     MD.SetCorpus(&Corpus);
713   while (true) {
714     auto Now = system_clock::now();
715     if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
716         Options.ReloadIntervalSec) {
717       RereadOutputCorpus(MaxInputLen);
718       LastCorpusReload = system_clock::now();
719     }
720     if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
721       break;
722     if (TimedOut())
723       break;
724 
725     // Update TmpMaxMutationLen
726     if (Options.ExperimentalLenControl) {
727       if (TmpMaxMutationLen < MaxMutationLen &&
728           (TotalNumberOfRuns - LastCorpusUpdateRun > 1000 &&
729            duration_cast<seconds>(Now - LastCorpusUpdateTime).count() >= 1)) {
730         LastCorpusUpdateRun = TotalNumberOfRuns;
731         LastCorpusUpdateTime = Now;
732         TmpMaxMutationLen =
733             Min(MaxMutationLen,
734                 TmpMaxMutationLen + Max(size_t(4), TmpMaxMutationLen / 8));
735         if (TmpMaxMutationLen <= MaxMutationLen)
736           Printf("#%zd\tTEMP_MAX_LEN: %zd\n", TotalNumberOfRuns,
737                  TmpMaxMutationLen);
738       }
739     } else {
740       TmpMaxMutationLen = MaxMutationLen;
741     }
742 
743     // Perform several mutations and runs.
744     MutateAndTestOne();
745 
746     PurgeAllocator();
747   }
748 
749   PrintStats("DONE  ", "\n");
750   MD.PrintRecommendedDictionary();
751 }
752 
753 void Fuzzer::MinimizeCrashLoop(const Unit &U) {
754   if (U.size() <= 1)
755     return;
756   while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
757     MD.StartMutationSequence();
758     memcpy(CurrentUnitData, U.data(), U.size());
759     for (int i = 0; i < Options.MutateDepth; i++) {
760       size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
761       assert(NewSize > 0 && NewSize <= MaxMutationLen);
762       ExecuteCallback(CurrentUnitData, NewSize);
763       PrintPulseAndReportSlowInput(CurrentUnitData, NewSize);
764       TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
765                               /*DuringInitialCorpusExecution*/ false);
766     }
767   }
768 }
769 
770 void Fuzzer::AnnounceOutput(const uint8_t *Data, size_t Size) {
771   if (SMR.IsServer()) {
772     SMR.WriteByteArray(Data, Size);
773   } else if (SMR.IsClient()) {
774     SMR.PostClient();
775     SMR.WaitServer();
776     size_t OtherSize = SMR.ReadByteArraySize();
777     uint8_t *OtherData = SMR.GetByteArray();
778     if (Size != OtherSize || memcmp(Data, OtherData, Size) != 0) {
779       size_t i = 0;
780       for (i = 0; i < Min(Size, OtherSize); i++)
781         if (Data[i] != OtherData[i])
782           break;
783       Printf("==%lu== ERROR: libFuzzer: equivalence-mismatch. Sizes: %zd %zd; "
784              "offset %zd\n",
785              GetPid(), Size, OtherSize, i);
786       DumpCurrentUnit("mismatch-");
787       Printf("SUMMARY: libFuzzer: equivalence-mismatch\n");
788       PrintFinalStats();
789       _Exit(Options.ErrorExitCode);
790     }
791   }
792 }
793 
794 } // namespace fuzzer
795 
796 extern "C" {
797 
798 size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
799   assert(fuzzer::F);
800   return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
801 }
802 
803 // Experimental
804 void LLVMFuzzerAnnounceOutput(const uint8_t *Data, size_t Size) {
805   assert(fuzzer::F);
806   fuzzer::F->AnnounceOutput(Data, Size);
807 }
808 } // extern "C"
809