23 #if defined(__has_include)
24 #if __has_include(<sanitizer / coverage_interface.h>)
25 #include <sanitizer/coverage_interface.h>
27 #if __has_include(<sanitizer / lsan_interface.h>)
28 #include <sanitizer/lsan_interface.h>
32 #define NO_SANITIZE_MEMORY
33 #if defined(__has_feature)
34 #if __has_feature(memory_sanitizer)
35 #undef NO_SANITIZE_MEMORY
36 #define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
43 thread_local
bool Fuzzer::IsMyThread;
46 Printf(
"ERROR: %s is not defined. Exiting.\n"
47 "Did you use -fsanitize-coverage=... to build your code?\n",
52 #define CHECK_EXTERNAL_FUNCTION(fn) \
55 MissingExternalApiFunction(#fn); \
61 void Fuzzer::ResetEdgeCoverage() {
63 EF->__sanitizer_reset_coverage();
66 void Fuzzer::ResetCounters() {
68 EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
71 void Fuzzer::PrepareCounters(Fuzzer::Coverage *
C) {
73 size_t NumCounters =
EF->__sanitizer_get_number_of_counters();
74 C->CounterBitmap.resize(NumCounters);
80 bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) {
83 uint64_t NewBlockCoverage =
EF->__sanitizer_get_total_unique_coverage();
84 if (NewBlockCoverage > C->BlockCoverage) {
86 C->BlockCoverage = NewBlockCoverage;
90 EF->__sanitizer_get_total_unique_caller_callee_pairs) {
91 uint64_t NewCallerCalleeCoverage =
92 EF->__sanitizer_get_total_unique_caller_callee_pairs();
93 if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) {
95 C->CallerCalleeCoverage = NewCallerCalleeCoverage;
100 uint64_t CounterDelta =
101 EF->__sanitizer_update_counter_bitset_and_clear_counters(
102 C->CounterBitmap.data());
103 if (CounterDelta > 0) {
105 C->CounterBitmapBits += CounterDelta;
118 Printf(
"MallocFreeTracer: START\n");
125 Printf(
"MallocFreeTracer: STOP %zd %zd (%s)\n",
Mallocs.load(),
145 Printf(
"MALLOC[%zd] %p %zd\n", N, ptr, size);
146 if (TraceLevel >= 2 &&
EF)
147 EF->__sanitizer_print_stack_trace();
155 Printf(
"FREE[%zd] %p\n", N, ptr);
156 if (TraceLevel >= 2 &&
EF)
157 EF->__sanitizer_print_stack_trace();
165 Printf(
"==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n",
GetPid(),
167 Printf(
" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
168 if (
EF->__sanitizer_print_stack_trace)
169 EF->__sanitizer_print_stack_trace();
170 DumpCurrentUnit(
"oom-");
171 Printf(
"SUMMARY: libFuzzer: out-of-memory\n");
178 : CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
186 if (Options.
DetectLeaks &&
EF->__sanitizer_install_malloc_and_free_hooks)
196 MaxInputLen = MaxMutationLen = Options.
MaxLen;
197 AllocateCurrentUnitData();
199 memset(BaseSha1, 0,
sizeof(BaseSha1));
204 void Fuzzer::AllocateCurrentUnitData() {
205 if (CurrentUnitData || MaxInputLen == 0)
return;
206 CurrentUnitData =
new uint8_t[MaxInputLen];
209 void Fuzzer::SetDeathCallback() {
211 EF->__sanitizer_set_death_callback(StaticDeathCallback);
214 void Fuzzer::StaticDeathCallback() {
225 "*** NOTE: merge did not succeed due to a failure on one of the inputs.\n"
226 "*** You will need to filter out crashes from the corpus, e.g. like this:\n"
227 "*** for f in WITH_CRASHES/*; do ./fuzzer $f && cp $f NO_CRASHES; done\n"
228 "*** Future versions may have crash-resistant merge, stay tuned.\n"
234 void Fuzzer::DumpCurrentUnit(
const char *
Prefix) {
236 if (!CurrentUnitData)
return;
239 size_t UnitSize = CurrentUnitSize;
244 WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
249 void Fuzzer::DeathCallback() {
250 DumpCurrentUnit(
"crash-");
266 F->InterruptCallback();
270 Printf(
"==%lu== ERROR: libFuzzer: file size exceeded\n",
GetPid());
274 void Fuzzer::CrashCallback() {
275 Printf(
"==%lu== ERROR: libFuzzer: deadly signal\n",
GetPid());
276 if (
EF->__sanitizer_print_stack_trace)
277 EF->__sanitizer_print_stack_trace();
278 Printf(
"NOTE: libFuzzer has rudimentary signal handlers.\n"
279 " Combine libFuzzer with AddressSanitizer or similar for better "
281 Printf(
"SUMMARY: libFuzzer: deadly signal\n");
282 DumpCurrentUnit(
"crash-");
287 void Fuzzer::InterruptCallback() {
288 Printf(
"==%lu== libFuzzer: run interrupted; exiting\n",
GetPid());
294 void Fuzzer::AlarmCallback() {
304 Printf(
"AlarmCallback %zd\n", Seconds);
306 Printf(
"ALARM: working on the last Unit for %zd seconds\n", Seconds);
307 Printf(
" and the timeout value is %d (use -timeout=N to change)\n",
309 DumpCurrentUnit(
"timeout-");
310 Printf(
"==%lu== ERROR: libFuzzer: timeout after %d seconds\n",
GetPid(),
312 if (
EF->__sanitizer_print_stack_trace)
313 EF->__sanitizer_print_stack_trace();
314 Printf(
"SUMMARY: libFuzzer: timeout\n");
322 "==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
324 Printf(
" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
325 if (
EF->__sanitizer_print_memory_profile)
326 EF->__sanitizer_print_memory_profile(95);
327 DumpCurrentUnit(
"oom-");
328 Printf(
"SUMMARY: libFuzzer: out-of-memory\n");
333 void Fuzzer::PrintStats(
const char *Where,
const char *
End,
size_t Units) {
336 static bool csvHeaderPrinted =
false;
337 if (!csvHeaderPrinted) {
338 csvHeaderPrinted =
true;
339 Printf(
"runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n");
341 Printf(
"%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns,
348 Printf(
"#%zd\t%s", TotalNumberOfRuns, Where);
361 if (!Corpus.
empty()) {
366 else if (
N < (1 << 24))
373 Printf(
" units: %zd", Units);
375 Printf(
" exec/s: %zd", ExecPerSec);
389 Printf(
"stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
390 Printf(
"stat::average_exec_per_sec: %zd\n", ExecPerSec);
391 Printf(
"stat::new_units_added: %zd\n", NumberOfNewUnitsAdded);
392 Printf(
"stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds);
397 assert(this->MaxInputLen == 0);
399 this->MaxInputLen = MaxInputLen;
400 this->MaxMutationLen = MaxInputLen;
401 AllocateCurrentUnitData();
402 Printf(
"INFO: -max_len is not provided, using %zd\n", MaxInputLen);
406 assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
407 this->MaxMutationLen = MaxMutationLen;
410 void Fuzzer::CheckExitOnSrcPosOrItem() {
412 static auto *PCsSet =
new std::set<uintptr_t>;
416 if (!PCsSet->insert(PC).second)
continue;
418 if (Descr.find(Options.
ExitOnSrcPos) != std::string::npos) {
419 Printf(
"INFO: found line matching '%s', exiting.\n",
427 Printf(
"INFO: found item with checksum '%s', exiting.\n",
436 std::vector<Unit> AdditionalCorpus;
438 &EpochOfLastReadOfOutputCorpus, MaxSize,
441 Printf(
"Reload: read %zd new units.\n", AdditionalCorpus.size());
442 bool Reloaded =
false;
443 for (
auto &U : AdditionalCorpus) {
444 if (U.size() > MaxSize)
447 if (
size_t NumFeatures =
RunOne(U)) {
448 CheckExitOnSrcPosOrItem();
455 PrintStats(
"RELOAD");
459 std::random_shuffle(V->begin(), V->end(), MD.
GetRand());
461 std::stable_sort(V->begin(), V->end(), [](
const Unit &
A,
const Unit &
B) {
462 return A.size() <
B.size();
467 Printf(
"#0\tREAD units: %zd\n", InitialCorpus->size());
469 ShuffleCorpus(InitialCorpus);
475 for (
const auto &U : *InitialCorpus) {
476 if (
size_t NumFeatures =
RunOne(U)) {
477 CheckExitOnSrcPosOrItem();
485 PrintStats(
"INITED");
486 if (Corpus.
empty()) {
487 Printf(
"ERROR: no interesting inputs were found. "
488 "Is the code instrumented for coverage? Exiting.\n");
508 if (!Res && RecordMaxCoverage(&MaxCoverage))
513 duration_cast<seconds>(UnitStopTime - UnitStartTime).
count();
514 if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
515 secondsSinceProcessStartUp() >= 2)
516 PrintStats(
"pulse ");
517 if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 &&
518 TimeOfUnit >= Options.ReportSlowUnits) {
519 TimeOfLongestUnitInSeconds = TimeOfUnit;
520 Printf(
"Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
521 WriteUnitToFileWithPrefix({Data, Data + Size},
"slow-unit-");
526 size_t Fuzzer::GetCurrentUnitInFuzzingThead(
const uint8_t **Data)
const {
527 assert(InFuzzingThread());
528 *Data = CurrentUnitData;
529 return CurrentUnitSize;
532 void Fuzzer::ExecuteCallback(
const uint8_t *Data,
size_t Size) {
533 assert(InFuzzingThread());
536 uint8_t *DataCopy =
new uint8_t[Size];
537 memcpy(DataCopy, Data, Size);
538 if (CurrentUnitData && CurrentUnitData != Data)
539 memcpy(CurrentUnitData, Data, Size);
540 CurrentUnitSize = Size;
546 int Res = CB(DataCopy, Size);
556 void Fuzzer::WriteToOutputCorpus(
const Unit &U) {
557 if (Options.OnlyASCII)
559 if (Options.OutputCorpus.empty())
563 if (Options.Verbosity >= 2)
564 Printf(
"Written to %s\n", Path.c_str());
567 void Fuzzer::WriteUnitToFileWithPrefix(
const Unit &U,
const char *Prefix) {
568 if (!Options.SaveArtifacts)
570 std::string Path = Options.ArtifactPrefix + Prefix +
Hash(U);
571 if (!Options.ExactArtifactPath.empty())
572 Path = Options.ExactArtifactPath;
574 Printf(
"artifact_prefix='%s'; Test unit written to %s\n",
575 Options.ArtifactPrefix.c_str(), Path.c_str());
580 void Fuzzer::PrintStatusForNewUnit(
const Unit &U) {
581 if (!Options.PrintNEW)
583 PrintStats(
"NEW ",
"");
584 if (Options.Verbosity) {
585 Printf(
" L: %zd ", U.size());
586 MD.PrintMutationSequence();
591 void Fuzzer::ReportNewCoverage(InputInfo *II,
const Unit &U) {
592 II->NumSuccessfullMutations++;
593 MD.RecordSuccessfulMutationSequence();
594 PrintStatusForNewUnit(U);
595 WriteToOutputCorpus(U);
596 NumberOfNewUnitsAdded++;
608 size_t OldSize = Res.size();
609 for (
int Iter = 0; Iter < 10; Iter++) {
612 Corpus.ResetFeatureSet();
615 for (
auto &U : Initial) {
621 for (
auto &U : Res) {
627 char Stat[7] =
"MIN ";
628 Stat[3] =
'0' + Iter;
629 PrintStats(Stat,
"\n", Tmp.size());
631 size_t NewSize = Tmp.size();
632 assert(NewSize <= OldSize);
635 if (NewSize + 5 >= OldSize)
643 if (Corpora.size() <= 1) {
644 Printf(
"Merge requires two or more corpus dirs\n");
648 std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end());
654 for (
auto &C : ExtraCorpora)
657 if (!Initial.empty()) {
658 Printf(
"=== Minimizing the initial corpus of %zd units\n", Initial.size());
659 Initial = FindExtraUnits({}, Initial);
662 Printf(
"=== Merging extra %zd units\n", Extra.size());
663 auto Res = FindExtraUnits(Initial, Extra);
666 WriteToOutputCorpus(U);
668 Printf(
"=== Merge: written %zd units\n", Res.size());
673 void Fuzzer::TryDetectingAMemoryLeak(
const uint8_t *Data,
size_t Size,
674 bool DuringInitialCorpusExecution) {
675 if (!HasMoreMallocsThanFrees)
return;
676 if (!Options.DetectLeaks)
return;
677 if (!&(
EF->__lsan_enable) || !&(
EF->__lsan_disable) ||
678 !(
EF->__lsan_do_recoverable_leak_check))
682 EF->__lsan_disable();
683 ExecuteCallback(Data, Size);
685 if (!HasMoreMallocsThanFrees)
return;
686 if (NumberOfLeakDetectionAttempts++ > 1000) {
687 Options.DetectLeaks =
false;
688 Printf(
"INFO: libFuzzer disabled leak detection after every mutation.\n"
689 " Most likely the target function accumulates allocated\n"
690 " memory in a global state w/o actually leaking it.\n"
691 " You may try running this binary with -trace_malloc=[12]"
692 " to get a trace of mallocs and frees.\n"
693 " If LeakSanitizer is enabled in this process it will still\n"
694 " run on the process shutdown.\n");
699 if (
EF->__lsan_do_recoverable_leak_check()) {
700 if (DuringInitialCorpusExecution)
701 Printf(
"\nINFO: a leak has been found in the initial corpus.\n\n");
702 Printf(
"INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
703 CurrentUnitSize = Size;
704 DumpCurrentUnit(
"leak-");
706 _Exit(Options.ErrorExitCode);
712 assert(MaxInputSize <= MaxMutationLen);
713 if (MaxInputSize == MaxMutationLen)
return MaxMutationLen;
714 size_t Result = MaxInputSize;
715 size_t R = Rand.
Rand();
716 if ((R % (1U << 7)) == 0)
718 if ((R % (1U << 15)) == 0)
719 Result += 10 + Result / 2;
720 return Min(Result, MaxMutationLen);
723 void Fuzzer::MutateAndTestOne() {
724 MD.StartMutationSequence();
726 auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
727 const auto &U = II.U;
728 memcpy(BaseSha1, II.Sha1,
sizeof(BaseSha1));
730 size_t Size = U.size();
731 assert(Size <= MaxInputLen &&
"Oversized Unit");
732 memcpy(CurrentUnitData, U.data(), Size);
734 assert(MaxMutationLen > 0);
736 size_t CurrentMaxMutationLen =
737 Options.ExperimentalLenControl
742 for (
int i = 0;
i < Options.MutateDepth;
i++) {
743 if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
746 NewSize = MD.Mutate(CurrentUnitData, Size, CurrentMaxMutationLen);
747 assert(NewSize > 0 &&
"Mutator returned empty unit");
748 assert(NewSize <= CurrentMaxMutationLen &&
"Mutator return overisized unit");
751 StartTraceRecording();
752 II.NumExecutedMutations++;
753 if (
size_t NumFeatures = RunOne(CurrentUnitData, Size)) {
754 Corpus.AddToCorpus({CurrentUnitData, CurrentUnitData + Size}, NumFeatures,
756 ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
757 CheckExitOnSrcPosOrItem();
759 StopTraceRecording();
760 TryDetectingAMemoryLeak(CurrentUnitData, Size,
765 void Fuzzer::ResetCoverage() {
768 PrepareCounters(&MaxCoverage);
771 void Fuzzer::Loop() {
774 if (Options.DoCrossOver)
775 MD.SetCorpus(&Corpus);
778 if (duration_cast<seconds>(Now - LastCorpusReload).
count() >=
779 Options.ReloadIntervalSec) {
780 RereadOutputCorpus(MaxInputLen);
783 if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
785 if (TimedOut())
break;
790 PrintStats(
"DONE ",
"\n");
791 MD.PrintRecommendedDictionary();
794 void Fuzzer::MinimizeCrashLoop(
const Unit &U) {
795 if (U.size() <= 2)
return;
796 while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
797 MD.StartMutationSequence();
798 memcpy(CurrentUnitData, U.data(), U.size());
799 for (
int i = 0;
i < Options.MutateDepth;
i++) {
800 size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
801 assert(NewSize > 0 && NewSize <= MaxMutationLen);
802 RunOne(CurrentUnitData, NewSize);
803 TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
void PrintHexArray(const uint8_t *Data, size_t Size, const char *PrintAfter)
void SetPrintNewPCs(bool P)
int(* UserCallback)(const uint8_t *Data, size_t Size)
void InitializeTraceState()
size_t CallerCalleeCoverage
void SetMaxInputLen(size_t MaxInputLen)
#define ATTRIBUTE_NO_SANITIZE_MEMORY
bool InFuzzingThread() const
static void StaticFileSizeExceedCallback()
MutationDispatcher & GetMD()
size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize)
Applies one of the default mutations.
static MallocFreeTracer AllocTracer
uintptr_t GetPC(size_t Idx)
void ReadDirToVectorOfUnits(const char *Path, std::vector< Unit > *V, long *Epoch, size_t MaxSize, bool ExitOnError)
size_t GetNumBitsSinceLastMerge() const
void PrintMutationSequence()
Print the current sequence of mutations.
size_t RunOne(const uint8_t *Data, size_t Size)
std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC)
long GetEpoch(const std::string &Path)
static GCRegistry::Add< OcamlGC > B("ocaml","ocaml 3.10-compatible GC")
auto count(R &&Range, const E &Element) -> typename std::iterator_traits< decltype(std::begin(Range))>::difference_type
Wrapper function around std::count to count the number of times an element Element occurs in the give...
ATTRIBUTE_NO_SANITIZE_MEMORY void MallocHook(const volatile void *ptr, size_t size)
void Printf(const char *Fmt,...)
std::string Base64(const Unit &U)
Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD, FuzzingOptions Options)
void ExecuteCallback(const uint8_t *Data, size_t Size)
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize)
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
std::string DirPlusFile(const std::string &DirPath, const std::string &FileName)
std::atomic< size_t > Frees
bool UpdateValueProfileMap(ValueBitMap *MaxValueProfileMap)
static const unsigned End
static const size_t kMaxUnitSizeToPrint
size_t GetTotalPCCoverage()
void SetUseCounters(bool UC)
static size_t ComputeMutationLen(size_t MaxInputSize, size_t MaxMutationLen, Random &Rand)
static void Merge(const std::string &Input, const std::vector< std::string > Result, size_t NumNewFeatures)
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
void WriteToFile(const Unit &U, const std::string &Path)
void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size, bool DuringInitialCorpusExecution)
static void MissingExternalApiFunction(const char *FnName)
bool IsASCII(const Unit &U)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
bool UsingTracePcGuard() const
void SetMaxMutationLen(size_t MaxMutationLen)
void HandleMalloc(size_t Size)
void ShuffleAndMinimize(UnitVector *V)
void InitializePrintNewPCs()
std::vector< Unit > UnitVector
std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes])
void Start(int TraceLevel)
static void StaticAlarmCallback()
static void WarnOnUnsuccessfullMerge(bool DoWarn)
std::atomic< size_t > Mallocs
#define CHECK_EXTERNAL_FUNCTION(fn)
std::vector< uint8_t > Unit
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static void StaticInterruptCallback()
std::string Hash(const Unit &U)
void SetUseValueProfile(bool VP)
size_t CollectFeatures(Callback CB)
void RereadOutputCorpus(size_t MaxSize)
#define NO_SANITIZE_MEMORY
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")
static void StaticCrashSignalCallback()
ATTRIBUTE_NO_SANITIZE_MEMORY void FreeHook(const volatile void *ptr)
static void PrintASCII(const Word &W, const char *PrintAfter)