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