1 //===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 //===----------------------------------------------------------------------===//
11 #include "FuzzerCorpus.h"
13 #include "FuzzerInternal.h"
14 #include "FuzzerMutate.h"
15 #include "FuzzerPlatform.h"
16 #include "FuzzerRandom.h"
17 #include "FuzzerTracePC.h"
24 #if defined(__has_include)
25 #if __has_include(<sanitizer / lsan_interface.h>)
26 #include <sanitizer/lsan_interface.h>
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))
39 static const size_t kMaxUnitSizeToPrint
= 256;
41 thread_local
bool Fuzzer::IsMyThread
;
43 bool RunningUserCallback
= false;
45 // Only one Fuzzer per process.
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
;
54 Printf("MallocFreeTracer: START\n");
58 // Returns true if there were more mallocs than frees.
61 Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs
.load(),
62 Frees
.load(), Mallocs
== Frees
? "same" : "DIFFERENT");
63 bool Result
= Mallocs
> Frees
;
69 std::atomic
<size_t> Mallocs
;
70 std::atomic
<size_t> Frees
;
73 std::recursive_mutex TraceMutex
;
74 bool TraceDisabled
= false;
77 static MallocFreeTracer AllocTracer
;
79 // Locks printing and avoids nested hooks triggered from mallocs/frees in
83 TraceLock() : Lock(AllocTracer
.TraceMutex
) {
84 AllocTracer
.TraceDisabled
= !AllocTracer
.TraceDisabled
;
86 ~TraceLock() { AllocTracer
.TraceDisabled
= !AllocTracer
.TraceDisabled
; }
88 bool IsDisabled() const {
89 // This is already inverted value.
90 return !AllocTracer
.TraceDisabled
;
94 std::lock_guard
<std::recursive_mutex
> Lock
;
97 ATTRIBUTE_NO_SANITIZE_MEMORY
98 void MallocHook(const volatile void *ptr
, size_t size
) {
99 size_t N
= AllocTracer
.Mallocs
++;
100 F
->HandleMalloc(size
);
101 if (int TraceLevel
= AllocTracer
.TraceLevel
) {
103 if (Lock
.IsDisabled())
105 Printf("MALLOC[%zd] %p %zd\n", N
, ptr
, size
);
106 if (TraceLevel
>= 2 && EF
)
111 ATTRIBUTE_NO_SANITIZE_MEMORY
112 void FreeHook(const volatile void *ptr
) {
113 size_t N
= AllocTracer
.Frees
++;
114 if (int TraceLevel
= AllocTracer
.TraceLevel
) {
116 if (Lock
.IsDisabled())
118 Printf("FREE[%zd] %p\n", N
, ptr
);
119 if (TraceLevel
>= 2 && EF
)
124 // Crash on a single malloc that exceeds the rss limit.
125 void Fuzzer::HandleMalloc(size_t Size
) {
126 if (!Options
.MallocLimitMb
|| (Size
>> 20) < (size_t)Options
.MallocLimitMb
)
128 Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
130 Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
132 DumpCurrentUnit("oom-");
133 Printf("SUMMARY: libFuzzer: out-of-memory\n");
135 _Exit(Options
.OOMExitCode
); // Stop right now.
138 Fuzzer::Fuzzer(UserCallback CB
, InputCorpus
&Corpus
, MutationDispatcher
&MD
,
139 const FuzzingOptions
&Options
)
140 : CB(CB
), Corpus(Corpus
), MD(MD
), Options(Options
) {
141 if (EF
->__sanitizer_set_death_callback
)
142 EF
->__sanitizer_set_death_callback(StaticDeathCallback
);
147 if (Options
.DetectLeaks
&& EF
->__sanitizer_install_malloc_and_free_hooks
)
148 EF
->__sanitizer_install_malloc_and_free_hooks(MallocHook
, FreeHook
);
149 TPC
.SetUseCounters(Options
.UseCounters
);
150 TPC
.SetUseValueProfileMask(Options
.UseValueProfile
);
152 if (Options
.Verbosity
)
153 TPC
.PrintModuleInfo();
154 if (!Options
.OutputCorpus
.empty() && Options
.ReloadIntervalSec
)
155 EpochOfLastReadOfOutputCorpus
= GetEpoch(Options
.OutputCorpus
);
156 MaxInputLen
= MaxMutationLen
= Options
.MaxLen
;
157 TmpMaxMutationLen
= 0; // Will be set once we load the corpus.
158 AllocateCurrentUnitData();
160 memset(BaseSha1
, 0, sizeof(BaseSha1
));
163 void Fuzzer::AllocateCurrentUnitData() {
164 if (CurrentUnitData
|| MaxInputLen
== 0)
166 CurrentUnitData
= new uint8_t[MaxInputLen
];
169 void Fuzzer::StaticDeathCallback() {
174 void Fuzzer::DumpCurrentUnit(const char *Prefix
) {
175 if (!CurrentUnitData
)
176 return; // Happens when running individual inputs.
177 ScopedDisableMsanInterceptorChecks S
;
178 MD
.PrintMutationSequence();
179 Printf("; base unit: %s\n", Sha1ToString(BaseSha1
).c_str());
180 size_t UnitSize
= CurrentUnitSize
;
181 if (UnitSize
<= kMaxUnitSizeToPrint
) {
182 PrintHexArray(CurrentUnitData
, UnitSize
, "\n");
183 PrintASCII(CurrentUnitData
, UnitSize
, "\n");
185 WriteUnitToFileWithPrefix({CurrentUnitData
, CurrentUnitData
+ UnitSize
},
190 void Fuzzer::DeathCallback() {
191 DumpCurrentUnit("crash-");
195 void Fuzzer::StaticAlarmCallback() {
200 void Fuzzer::StaticCrashSignalCallback() {
205 void Fuzzer::StaticExitCallback() {
210 void Fuzzer::StaticInterruptCallback() {
212 F
->InterruptCallback();
215 void Fuzzer::StaticGracefulExitCallback() {
217 F
->GracefulExitRequested
= true;
218 Printf("INFO: signal received, trying to exit gracefully\n");
221 void Fuzzer::StaticFileSizeExceedCallback() {
222 Printf("==%lu== ERROR: libFuzzer: file size exceeded\n", GetPid());
226 void Fuzzer::CrashCallback() {
227 if (EF
->__sanitizer_acquire_crash_state
&&
228 !EF
->__sanitizer_acquire_crash_state())
230 Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
232 Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
233 " Combine libFuzzer with AddressSanitizer or similar for better "
235 Printf("SUMMARY: libFuzzer: deadly signal\n");
236 DumpCurrentUnit("crash-");
238 _Exit(Options
.ErrorExitCode
); // Stop right now.
241 void Fuzzer::ExitCallback() {
242 if (!RunningUserCallback
)
243 return; // This exit did not come from the user callback
244 if (EF
->__sanitizer_acquire_crash_state
&&
245 !EF
->__sanitizer_acquire_crash_state())
247 Printf("==%lu== ERROR: libFuzzer: fuzz target exited\n", GetPid());
249 Printf("SUMMARY: libFuzzer: fuzz target exited\n");
250 DumpCurrentUnit("crash-");
252 _Exit(Options
.ErrorExitCode
);
255 void Fuzzer::MaybeExitGracefully() {
256 if (!F
->GracefulExitRequested
) return;
257 Printf("==%lu== INFO: libFuzzer: exiting as requested\n", GetPid());
258 RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
259 F
->PrintFinalStats();
263 int Fuzzer::InterruptExitCode() {
265 return F
->Options
.InterruptExitCode
;
268 void Fuzzer::InterruptCallback() {
269 Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
271 ScopedDisableMsanInterceptorChecks S
; // RmDirRecursive may call opendir().
272 RmDirRecursive(TempPath("FuzzWithFork", ".dir"));
273 // Stop right now, don't perform any at-exit actions.
274 _Exit(Options
.InterruptExitCode
);
278 void Fuzzer::AlarmCallback() {
279 assert(Options
.UnitTimeoutSec
> 0);
280 // In Windows and Fuchsia, Alarm callback is executed by a different thread.
281 // NetBSD's current behavior needs this change too.
282 #if !LIBFUZZER_WINDOWS && !LIBFUZZER_NETBSD && !LIBFUZZER_FUCHSIA
283 if (!InFuzzingThread())
286 if (!RunningUserCallback
)
287 return; // We have not started running units yet.
289 duration_cast
<seconds
>(system_clock::now() - UnitStartTime
).count();
292 if (Options
.Verbosity
>= 2)
293 Printf("AlarmCallback %zd\n", Seconds
);
294 if (Seconds
>= (size_t)Options
.UnitTimeoutSec
) {
295 if (EF
->__sanitizer_acquire_crash_state
&&
296 !EF
->__sanitizer_acquire_crash_state())
298 Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds
);
299 Printf(" and the timeout value is %d (use -timeout=N to change)\n",
300 Options
.UnitTimeoutSec
);
301 DumpCurrentUnit("timeout-");
302 Printf("==%lu== ERROR: libFuzzer: timeout after %zu seconds\n", GetPid(),
305 Printf("SUMMARY: libFuzzer: timeout\n");
307 _Exit(Options
.TimeoutExitCode
); // Stop right now.
311 void Fuzzer::RssLimitCallback() {
312 if (EF
->__sanitizer_acquire_crash_state
&&
313 !EF
->__sanitizer_acquire_crash_state())
315 Printf("==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %dMb)\n",
316 GetPid(), GetPeakRSSMb(), Options
.RssLimitMb
);
317 Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
318 PrintMemoryProfile();
319 DumpCurrentUnit("oom-");
320 Printf("SUMMARY: libFuzzer: out-of-memory\n");
322 _Exit(Options
.OOMExitCode
); // Stop right now.
325 void Fuzzer::PrintStats(const char *Where
, const char *End
, size_t Units
,
327 size_t ExecPerSec
= execPerSec();
328 if (!Options
.Verbosity
)
330 Printf("#%zd\t%s", TotalNumberOfRuns
, Where
);
331 if (size_t N
= TPC
.GetTotalPCCoverage())
332 Printf(" cov: %zd", N
);
333 if (size_t N
= Features
? Features
: Corpus
.NumFeatures())
334 Printf(" ft: %zd", N
);
335 if (!Corpus
.empty()) {
336 Printf(" corp: %zd", Corpus
.NumActiveUnits());
337 if (size_t N
= Corpus
.SizeInBytes()) {
340 else if (N
< (1 << 24))
341 Printf("/%zdKb", N
>> 10);
343 Printf("/%zdMb", N
>> 20);
345 if (size_t FF
= Corpus
.NumInputsThatTouchFocusFunction())
346 Printf(" focus: %zd", FF
);
348 if (TmpMaxMutationLen
)
349 Printf(" lim: %zd", TmpMaxMutationLen
);
351 Printf(" units: %zd", Units
);
353 Printf(" exec/s: %zd", ExecPerSec
);
354 Printf(" rss: %zdMb", GetPeakRSSMb());
358 void Fuzzer::PrintFinalStats() {
359 if (Options
.PrintFullCoverage
)
360 TPC
.PrintCoverage(/*PrintAllCounters=*/true);
361 if (Options
.PrintCoverage
)
362 TPC
.PrintCoverage(/*PrintAllCounters=*/false);
363 if (Options
.PrintCorpusStats
)
365 if (!Options
.PrintFinalStats
)
367 size_t ExecPerSec
= execPerSec();
368 Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns
);
369 Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec
);
370 Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded
);
371 Printf("stat::slowest_unit_time_sec: %ld\n", TimeOfLongestUnitInSeconds
);
372 Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb());
375 void Fuzzer::SetMaxInputLen(size_t MaxInputLen
) {
376 assert(this->MaxInputLen
== 0); // Can only reset MaxInputLen from 0 to non-0.
378 this->MaxInputLen
= MaxInputLen
;
379 this->MaxMutationLen
= MaxInputLen
;
380 AllocateCurrentUnitData();
381 Printf("INFO: -max_len is not provided; "
382 "libFuzzer will not generate inputs larger than %zd bytes\n",
386 void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen
) {
387 assert(MaxMutationLen
&& MaxMutationLen
<= MaxInputLen
);
388 this->MaxMutationLen
= MaxMutationLen
;
391 void Fuzzer::CheckExitOnSrcPosOrItem() {
392 if (!Options
.ExitOnSrcPos
.empty()) {
393 static auto *PCsSet
= new std::set
<uintptr_t>;
394 auto HandlePC
= [&](const TracePC::PCTableEntry
*TE
) {
395 if (!PCsSet
->insert(TE
->PC
).second
)
397 std::string Descr
= DescribePC("%F %L", TE
->PC
+ 1);
398 if (Descr
.find(Options
.ExitOnSrcPos
) != std::string::npos
) {
399 Printf("INFO: found line matching '%s', exiting.\n",
400 Options
.ExitOnSrcPos
.c_str());
404 TPC
.ForEachObservedPC(HandlePC
);
406 if (!Options
.ExitOnItem
.empty()) {
407 if (Corpus
.HasUnit(Options
.ExitOnItem
)) {
408 Printf("INFO: found item with checksum '%s', exiting.\n",
409 Options
.ExitOnItem
.c_str());
415 void Fuzzer::RereadOutputCorpus(size_t MaxSize
) {
416 if (Options
.OutputCorpus
.empty() || !Options
.ReloadIntervalSec
)
418 std::vector
<Unit
> AdditionalCorpus
;
419 std::vector
<std::string
> AdditionalCorpusPaths
;
420 ReadDirToVectorOfUnits(
421 Options
.OutputCorpus
.c_str(), &AdditionalCorpus
,
422 &EpochOfLastReadOfOutputCorpus
, MaxSize
,
423 /*ExitOnError*/ false,
424 (Options
.Verbosity
>= 2 ? &AdditionalCorpusPaths
: nullptr));
425 if (Options
.Verbosity
>= 2)
426 Printf("Reload: read %zd new units.\n", AdditionalCorpus
.size());
427 bool Reloaded
= false;
428 for (size_t i
= 0; i
!= AdditionalCorpus
.size(); ++i
) {
429 auto &U
= AdditionalCorpus
[i
];
430 if (U
.size() > MaxSize
)
432 if (!Corpus
.HasUnit(U
)) {
433 if (RunOne(U
.data(), U
.size())) {
434 CheckExitOnSrcPosOrItem();
436 if (Options
.Verbosity
>= 2)
437 Printf("Reloaded %s\n", AdditionalCorpusPaths
[i
].c_str());
442 PrintStats("RELOAD");
445 void Fuzzer::PrintPulseAndReportSlowInput(const uint8_t *Data
, size_t Size
) {
447 duration_cast
<seconds
>(UnitStopTime
- UnitStartTime
).count();
448 if (!(TotalNumberOfRuns
& (TotalNumberOfRuns
- 1)) &&
449 secondsSinceProcessStartUp() >= 2)
450 PrintStats("pulse ");
452 static_cast<long>(static_cast<double>(TimeOfLongestUnitInSeconds
) * 1.1);
453 if (TimeOfUnit
> Threshhold
&& TimeOfUnit
>= Options
.ReportSlowUnits
) {
454 TimeOfLongestUnitInSeconds
= TimeOfUnit
;
455 Printf("Slowest unit: %ld s:\n", TimeOfLongestUnitInSeconds
);
456 WriteUnitToFileWithPrefix({Data
, Data
+ Size
}, "slow-unit-");
460 static void WriteFeatureSetToFile(const std::string
&FeaturesDir
,
461 const std::string
&FileName
,
462 const std::vector
<uint32_t> &FeatureSet
) {
463 if (FeaturesDir
.empty() || FeatureSet
.empty()) return;
464 WriteToFile(reinterpret_cast<const uint8_t *>(FeatureSet
.data()),
465 FeatureSet
.size() * sizeof(FeatureSet
[0]),
466 DirPlusFile(FeaturesDir
, FileName
));
469 static void RenameFeatureSetFile(const std::string
&FeaturesDir
,
470 const std::string
&OldFile
,
471 const std::string
&NewFile
) {
472 if (FeaturesDir
.empty()) return;
473 RenameFile(DirPlusFile(FeaturesDir
, OldFile
),
474 DirPlusFile(FeaturesDir
, NewFile
));
477 static void WriteEdgeToMutationGraphFile(const std::string
&MutationGraphFile
,
479 const InputInfo
*BaseII
,
480 const std::string
&MS
) {
481 if (MutationGraphFile
.empty())
484 std::string Sha1
= Sha1ToString(II
->Sha1
);
486 std::string OutputString
;
489 OutputString
.append("\"");
490 OutputString
.append(Sha1
);
491 OutputString
.append("\"\n");
493 // Add a new edge if there is base input.
495 std::string BaseSha1
= Sha1ToString(BaseII
->Sha1
);
496 OutputString
.append("\"");
497 OutputString
.append(BaseSha1
);
498 OutputString
.append("\" -> \"");
499 OutputString
.append(Sha1
);
500 OutputString
.append("\" [label=\"");
501 OutputString
.append(MS
);
502 OutputString
.append("\"];\n");
505 AppendToFile(OutputString
, MutationGraphFile
);
508 bool Fuzzer::RunOne(const uint8_t *Data
, size_t Size
, bool MayDeleteFile
,
509 InputInfo
*II
, bool ForceAddToCorpus
,
510 bool *FoundUniqFeatures
) {
513 // Largest input length should be INT_MAX.
514 assert(Size
< std::numeric_limits
<uint32_t>::max());
516 if(!ExecuteCallback(Data
, Size
)) return false;
517 auto TimeOfUnit
= duration_cast
<microseconds
>(UnitStopTime
- UnitStartTime
);
519 UniqFeatureSetTmp
.clear();
520 size_t FoundUniqFeaturesOfII
= 0;
521 size_t NumUpdatesBefore
= Corpus
.NumFeatureUpdates();
522 TPC
.CollectFeatures([&](uint32_t Feature
) {
523 if (Corpus
.AddFeature(Feature
, static_cast<uint32_t>(Size
), Options
.Shrink
))
524 UniqFeatureSetTmp
.push_back(Feature
);
525 if (Options
.Entropic
)
526 Corpus
.UpdateFeatureFrequency(II
, Feature
);
527 if (Options
.ReduceInputs
&& II
&& !II
->NeverReduce
)
528 if (std::binary_search(II
->UniqFeatureSet
.begin(),
529 II
->UniqFeatureSet
.end(), Feature
))
530 FoundUniqFeaturesOfII
++;
532 if (FoundUniqFeatures
)
533 *FoundUniqFeatures
= FoundUniqFeaturesOfII
;
534 PrintPulseAndReportSlowInput(Data
, Size
);
535 size_t NumNewFeatures
= Corpus
.NumFeatureUpdates() - NumUpdatesBefore
;
536 if (NumNewFeatures
|| ForceAddToCorpus
) {
537 TPC
.UpdateObservedPCs();
539 Corpus
.AddToCorpus({Data
, Data
+ Size
}, NumNewFeatures
, MayDeleteFile
,
540 TPC
.ObservedFocusFunction(), ForceAddToCorpus
,
541 TimeOfUnit
, UniqFeatureSetTmp
, DFT
, II
);
542 WriteFeatureSetToFile(Options
.FeaturesDir
, Sha1ToString(NewII
->Sha1
),
543 NewII
->UniqFeatureSet
);
544 WriteEdgeToMutationGraphFile(Options
.MutationGraphFile
, NewII
, II
,
545 MD
.MutationSequence());
548 if (II
&& FoundUniqFeaturesOfII
&&
549 II
->DataFlowTraceForFocusFunction
.empty() &&
550 FoundUniqFeaturesOfII
== II
->UniqFeatureSet
.size() &&
551 II
->U
.size() > Size
) {
552 auto OldFeaturesFile
= Sha1ToString(II
->Sha1
);
553 Corpus
.Replace(II
, {Data
, Data
+ Size
}, TimeOfUnit
);
554 RenameFeatureSetFile(Options
.FeaturesDir
, OldFeaturesFile
,
555 Sha1ToString(II
->Sha1
));
561 void Fuzzer::TPCUpdateObservedPCs() { TPC
.UpdateObservedPCs(); }
563 size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data
) const {
564 assert(InFuzzingThread());
565 *Data
= CurrentUnitData
;
566 return CurrentUnitSize
;
569 void Fuzzer::CrashOnOverwrittenData() {
570 Printf("==%d== ERROR: libFuzzer: fuzz target overwrites its const input\n",
573 Printf("SUMMARY: libFuzzer: overwrites-const-input\n");
574 DumpCurrentUnit("crash-");
576 _Exit(Options
.ErrorExitCode
); // Stop right now.
579 // Compare two arrays, but not all bytes if the arrays are large.
580 static bool LooseMemeq(const uint8_t *A
, const uint8_t *B
, size_t Size
) {
581 const size_t Limit
= 64;
583 return !memcmp(A
, B
, Size
);
584 // Compare first and last Limit/2 bytes.
585 return !memcmp(A
, B
, Limit
/ 2) &&
586 !memcmp(A
+ Size
- Limit
/ 2, B
+ Size
- Limit
/ 2, Limit
/ 2);
589 // This method is not inlined because it would cause a test to fail where it
590 // is part of the stack unwinding. See D97975 for details.
591 ATTRIBUTE_NOINLINE
bool Fuzzer::ExecuteCallback(const uint8_t *Data
,
593 TPC
.RecordInitialStack();
595 assert(InFuzzingThread());
596 // We copy the contents of Unit into a separate heap buffer
597 // so that we reliably find buffer overflows in it.
598 uint8_t *DataCopy
= new uint8_t[Size
];
599 memcpy(DataCopy
, Data
, Size
);
600 if (EF
->__msan_unpoison
)
601 EF
->__msan_unpoison(DataCopy
, Size
);
602 if (EF
->__msan_unpoison_param
)
603 EF
->__msan_unpoison_param(2);
604 if (CurrentUnitData
&& CurrentUnitData
!= Data
)
605 memcpy(CurrentUnitData
, Data
, Size
);
606 CurrentUnitSize
= Size
;
609 ScopedEnableMsanInterceptorChecks S
;
610 AllocTracer
.Start(Options
.TraceMalloc
);
611 UnitStartTime
= system_clock::now();
613 RunningUserCallback
= true;
614 CBRes
= CB(DataCopy
, Size
);
615 RunningUserCallback
= false;
616 UnitStopTime
= system_clock::now();
617 assert(CBRes
== 0 || CBRes
== -1);
618 HasMoreMallocsThanFrees
= AllocTracer
.Stop();
620 if (!LooseMemeq(DataCopy
, Data
, Size
))
621 CrashOnOverwrittenData();
627 std::string
Fuzzer::WriteToOutputCorpus(const Unit
&U
) {
628 if (Options
.OnlyASCII
)
630 if (Options
.OutputCorpus
.empty())
632 std::string Path
= DirPlusFile(Options
.OutputCorpus
, Hash(U
));
633 WriteToFile(U
, Path
);
634 if (Options
.Verbosity
>= 2)
635 Printf("Written %zd bytes to %s\n", U
.size(), Path
.c_str());
639 void Fuzzer::WriteUnitToFileWithPrefix(const Unit
&U
, const char *Prefix
) {
640 if (!Options
.SaveArtifacts
)
642 std::string Path
= Options
.ArtifactPrefix
+ Prefix
+ Hash(U
);
643 if (!Options
.ExactArtifactPath
.empty())
644 Path
= Options
.ExactArtifactPath
; // Overrides ArtifactPrefix.
645 WriteToFile(U
, Path
);
646 Printf("artifact_prefix='%s'; Test unit written to %s\n",
647 Options
.ArtifactPrefix
.c_str(), Path
.c_str());
648 if (U
.size() <= kMaxUnitSizeToPrint
)
649 Printf("Base64: %s\n", Base64(U
).c_str());
652 void Fuzzer::PrintStatusForNewUnit(const Unit
&U
, const char *Text
) {
653 if (!Options
.PrintNEW
)
655 PrintStats(Text
, "");
656 if (Options
.Verbosity
) {
657 Printf(" L: %zd/%zd ", U
.size(), Corpus
.MaxInputSize());
658 MD
.PrintMutationSequence(Options
.Verbosity
>= 2);
663 void Fuzzer::ReportNewCoverage(InputInfo
*II
, const Unit
&U
) {
664 II
->NumSuccessfullMutations
++;
665 MD
.RecordSuccessfulMutationSequence();
666 PrintStatusForNewUnit(U
, II
->Reduced
? "REDUCE" : "NEW ");
667 WriteToOutputCorpus(U
);
668 NumberOfNewUnitsAdded
++;
669 CheckExitOnSrcPosOrItem(); // Check only after the unit is saved to corpus.
670 LastCorpusUpdateRun
= TotalNumberOfRuns
;
673 // Tries detecting a memory leak on the particular input that we have just
674 // executed before calling this function.
675 void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data
, size_t Size
,
676 bool DuringInitialCorpusExecution
) {
677 if (!HasMoreMallocsThanFrees
)
678 return; // mallocs==frees, a leak is unlikely.
679 if (!Options
.DetectLeaks
)
681 if (!DuringInitialCorpusExecution
&&
682 TotalNumberOfRuns
>= Options
.MaxNumberOfRuns
)
684 if (!&(EF
->__lsan_enable
) || !&(EF
->__lsan_disable
) ||
685 !(EF
->__lsan_do_recoverable_leak_check
))
687 // Run the target once again, but with lsan disabled so that if there is
688 // a real leak we do not report it twice.
689 EF
->__lsan_disable();
690 ExecuteCallback(Data
, Size
);
692 if (!HasMoreMallocsThanFrees
)
693 return; // a leak is unlikely.
694 if (NumberOfLeakDetectionAttempts
++ > 1000) {
695 Options
.DetectLeaks
= false;
696 Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
697 " Most likely the target function accumulates allocated\n"
698 " memory in a global state w/o actually leaking it.\n"
699 " You may try running this binary with -trace_malloc=[12]"
700 " to get a trace of mallocs and frees.\n"
701 " If LeakSanitizer is enabled in this process it will still\n"
702 " run on the process shutdown.\n");
705 // Now perform the actual lsan pass. This is expensive and we must ensure
706 // we don't call it too often.
707 if (EF
->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
708 if (DuringInitialCorpusExecution
)
709 Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
710 Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
711 CurrentUnitSize
= Size
;
712 DumpCurrentUnit("leak-");
714 _Exit(Options
.ErrorExitCode
); // not exit() to disable lsan further on.
718 void Fuzzer::MutateAndTestOne() {
719 MD
.StartMutationSequence();
721 auto &II
= Corpus
.ChooseUnitToMutate(MD
.GetRand());
722 if (Options
.DoCrossOver
) {
723 auto &CrossOverII
= Corpus
.ChooseUnitToCrossOverWith(
724 MD
.GetRand(), Options
.CrossOverUniformDist
);
725 MD
.SetCrossOverWith(&CrossOverII
.U
);
727 const auto &U
= II
.U
;
728 memcpy(BaseSha1
, II
.Sha1
, sizeof(BaseSha1
));
729 assert(CurrentUnitData
);
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 Min(MaxMutationLen
, Max(U
.size(), TmpMaxMutationLen
));
738 assert(CurrentMaxMutationLen
> 0);
740 for (int i
= 0; i
< Options
.MutateDepth
; i
++) {
741 if (TotalNumberOfRuns
>= Options
.MaxNumberOfRuns
)
743 MaybeExitGracefully();
745 if (II
.HasFocusFunction
&& !II
.DataFlowTraceForFocusFunction
.empty() &&
746 Size
<= CurrentMaxMutationLen
)
747 NewSize
= MD
.MutateWithMask(CurrentUnitData
, Size
, Size
,
748 II
.DataFlowTraceForFocusFunction
);
750 // If MutateWithMask either failed or wasn't called, call default Mutate.
752 NewSize
= MD
.Mutate(CurrentUnitData
, Size
, CurrentMaxMutationLen
);
753 assert(NewSize
> 0 && "Mutator returned empty unit");
754 assert(NewSize
<= CurrentMaxMutationLen
&& "Mutator return oversized unit");
756 II
.NumExecutedMutations
++;
757 Corpus
.IncrementNumExecutedMutations();
759 bool FoundUniqFeatures
= false;
760 bool NewCov
= RunOne(CurrentUnitData
, Size
, /*MayDeleteFile=*/true, &II
,
761 /*ForceAddToCorpus*/ false, &FoundUniqFeatures
);
762 TryDetectingAMemoryLeak(CurrentUnitData
, Size
,
763 /*DuringInitialCorpusExecution*/ false);
765 ReportNewCoverage(&II
, {CurrentUnitData
, CurrentUnitData
+ Size
});
766 break; // We will mutate this input more in the next rounds.
768 if (Options
.ReduceDepth
&& !FoundUniqFeatures
)
772 II
.NeedsEnergyUpdate
= true;
775 void Fuzzer::PurgeAllocator() {
776 if (Options
.PurgeAllocatorIntervalSec
< 0 || !EF
->__sanitizer_purge_allocator
)
778 if (duration_cast
<seconds
>(system_clock::now() -
779 LastAllocatorPurgeAttemptTime
)
780 .count() < Options
.PurgeAllocatorIntervalSec
)
783 if (Options
.RssLimitMb
<= 0 ||
784 GetPeakRSSMb() > static_cast<size_t>(Options
.RssLimitMb
) / 2)
785 EF
->__sanitizer_purge_allocator();
787 LastAllocatorPurgeAttemptTime
= system_clock::now();
790 void Fuzzer::ReadAndExecuteSeedCorpora(std::vector
<SizedFile
> &CorporaFiles
) {
791 const size_t kMaxSaneLen
= 1 << 20;
792 const size_t kMinDefaultLen
= 4096;
795 size_t TotalSize
= 0;
796 for (auto &File
: CorporaFiles
) {
797 MaxSize
= Max(File
.Size
, MaxSize
);
798 MinSize
= Min(File
.Size
, MinSize
);
799 TotalSize
+= File
.Size
;
801 if (Options
.MaxLen
== 0)
802 SetMaxInputLen(std::clamp(MaxSize
, kMinDefaultLen
, kMaxSaneLen
));
803 assert(MaxInputLen
> 0);
805 // Test the callback with empty input and never try it again.
807 ExecuteCallback(&dummy
, 0);
809 if (CorporaFiles
.empty()) {
810 Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
811 Unit
U({'\n'}); // Valid ASCII input.
812 RunOne(U
.data(), U
.size());
814 Printf("INFO: seed corpus: files: %zd min: %zdb max: %zdb total: %zdb"
816 CorporaFiles
.size(), MinSize
, MaxSize
, TotalSize
, GetPeakRSSMb());
817 if (Options
.ShuffleAtStartUp
)
818 std::shuffle(CorporaFiles
.begin(), CorporaFiles
.end(), MD
.GetRand());
820 if (Options
.PreferSmall
) {
821 std::stable_sort(CorporaFiles
.begin(), CorporaFiles
.end());
822 assert(CorporaFiles
.front().Size
<= CorporaFiles
.back().Size
);
825 // Load and execute inputs one by one.
826 for (auto &SF
: CorporaFiles
) {
827 auto U
= FileToVector(SF
.File
, MaxInputLen
, /*ExitOnError=*/false);
828 assert(U
.size() <= MaxInputLen
);
829 RunOne(U
.data(), U
.size(), /*MayDeleteFile*/ false, /*II*/ nullptr,
830 /*ForceAddToCorpus*/ Options
.KeepSeed
,
831 /*FoundUniqFeatures*/ nullptr);
832 CheckExitOnSrcPosOrItem();
833 TryDetectingAMemoryLeak(U
.data(), U
.size(),
834 /*DuringInitialCorpusExecution*/ true);
838 PrintStats("INITED");
839 if (!Options
.FocusFunction
.empty()) {
840 Printf("INFO: %zd/%zd inputs touch the focus function\n",
841 Corpus
.NumInputsThatTouchFocusFunction(), Corpus
.size());
842 if (!Options
.DataFlowTrace
.empty())
843 Printf("INFO: %zd/%zd inputs have the Data Flow Trace\n",
844 Corpus
.NumInputsWithDataFlowTrace(),
845 Corpus
.NumInputsThatTouchFocusFunction());
848 if (Corpus
.empty() && Options
.MaxNumberOfRuns
) {
849 Printf("WARNING: no interesting inputs were found so far. "
850 "Is the code instrumented for coverage?\n"
851 "This may also happen if the target rejected all inputs we tried so "
853 // The remaining logic requires that the corpus is not empty,
854 // so we add one fake input to the in-memory corpus.
855 Corpus
.AddToCorpus({'\n'}, /*NumFeatures=*/1, /*MayDeleteFile=*/true,
856 /*HasFocusFunction=*/false, /*NeverReduce=*/false,
857 /*TimeOfUnit=*/duration_cast
<microseconds
>(0s
), {0}, DFT
,
862 void Fuzzer::Loop(std::vector
<SizedFile
> &CorporaFiles
) {
863 auto FocusFunctionOrAuto
= Options
.FocusFunction
;
864 DFT
.Init(Options
.DataFlowTrace
, &FocusFunctionOrAuto
, CorporaFiles
,
866 TPC
.SetFocusFunction(FocusFunctionOrAuto
);
867 ReadAndExecuteSeedCorpora(CorporaFiles
);
868 DFT
.Clear(); // No need for DFT any more.
869 TPC
.SetPrintNewPCs(Options
.PrintNewCovPcs
);
870 TPC
.SetPrintNewFuncs(Options
.PrintNewCovFuncs
);
871 system_clock::time_point LastCorpusReload
= system_clock::now();
874 Min(MaxMutationLen
, Max(size_t(4), Corpus
.MaxInputSize()));
877 auto Now
= system_clock::now();
878 if (!Options
.StopFile
.empty() &&
879 !FileToVector(Options
.StopFile
, 1, false).empty())
881 if (duration_cast
<seconds
>(Now
- LastCorpusReload
).count() >=
882 Options
.ReloadIntervalSec
) {
883 RereadOutputCorpus(MaxInputLen
);
884 LastCorpusReload
= system_clock::now();
886 if (TotalNumberOfRuns
>= Options
.MaxNumberOfRuns
)
891 // Update TmpMaxMutationLen
892 if (Options
.LenControl
) {
893 if (TmpMaxMutationLen
< MaxMutationLen
&&
894 TotalNumberOfRuns
- LastCorpusUpdateRun
>
895 Options
.LenControl
* Log(TmpMaxMutationLen
)) {
897 Min(MaxMutationLen
, TmpMaxMutationLen
+ Log(TmpMaxMutationLen
));
898 LastCorpusUpdateRun
= TotalNumberOfRuns
;
901 TmpMaxMutationLen
= MaxMutationLen
;
904 // Perform several mutations and runs.
910 PrintStats("DONE ", "\n");
911 MD
.PrintRecommendedDictionary();
914 void Fuzzer::MinimizeCrashLoop(const Unit
&U
) {
917 while (!TimedOut() && TotalNumberOfRuns
< Options
.MaxNumberOfRuns
) {
918 MD
.StartMutationSequence();
919 memcpy(CurrentUnitData
, U
.data(), U
.size());
920 for (int i
= 0; i
< Options
.MutateDepth
; i
++) {
921 size_t NewSize
= MD
.Mutate(CurrentUnitData
, U
.size(), MaxMutationLen
);
922 assert(NewSize
> 0 && NewSize
<= MaxMutationLen
);
923 ExecuteCallback(CurrentUnitData
, NewSize
);
924 PrintPulseAndReportSlowInput(CurrentUnitData
, NewSize
);
925 TryDetectingAMemoryLeak(CurrentUnitData
, NewSize
,
926 /*DuringInitialCorpusExecution*/ false);
931 } // namespace fuzzer
935 ATTRIBUTE_INTERFACE
size_t
936 LLVMFuzzerMutate(uint8_t *Data
, size_t Size
, size_t MaxSize
) {
938 return fuzzer::F
->GetMD().DefaultMutate(Data
, Size
, MaxSize
);