44 #define FUZZER_DEPRECATED_FLAG(Name)
45 #define FUZZER_FLAG_INT(Name, Default, Description) int Name;
46 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
47 #define FUZZER_FLAG_STRING(Name, Description) const char *Name;
48 #include "FuzzerFlags.def"
49 #undef FUZZER_DEPRECATED_FLAG
50 #undef FUZZER_FLAG_INT
51 #undef FUZZER_FLAG_UNSIGNED
52 #undef FUZZER_FLAG_STRING
55 static const FlagDescription FlagDescriptions [] {
56 #define FUZZER_DEPRECATED_FLAG(Name) \
57 {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
58 #define FUZZER_FLAG_INT(Name, Default, Description) \
59 {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
60 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \
61 {#Name, Description, static_cast<int>(Default), \
62 nullptr, nullptr, &Flags.Name},
63 #define FUZZER_FLAG_STRING(Name, Description) \
64 {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
65 #include "FuzzerFlags.def"
66 #undef FUZZER_DEPRECATED_FLAG
67 #undef FUZZER_FLAG_INT
68 #undef FUZZER_FLAG_UNSIGNED
69 #undef FUZZER_FLAG_STRING
72 static const size_t kNumFlags =
73 sizeof(FlagDescriptions) /
sizeof(FlagDescriptions[0]);
75 static std::vector<std::string> *Inputs;
76 static std::string *ProgName;
78 static void PrintHelp() {
80 auto Prog = ProgName->c_str();
81 Printf(
"\nTo run fuzzing pass 0 or more directories.\n");
82 Printf(
"%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
84 Printf(
"\nTo run individual tests without fuzzing pass 1 or more files:\n");
85 Printf(
"%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog);
87 Printf(
"\nFlags: (strictly in form -flag=value)\n");
88 size_t MaxFlagLen = 0;
89 for (
size_t F = 0;
F < kNumFlags;
F++)
90 MaxFlagLen = std::max(strlen(FlagDescriptions[
F].
Name), MaxFlagLen);
92 for (
size_t F = 0;
F < kNumFlags;
F++) {
93 const auto &
D = FlagDescriptions[
F];
94 if (strstr(
D.Description,
"internal flag") ==
D.Description)
continue;
96 for (
size_t i = 0, n = MaxFlagLen - strlen(
D.Name);
i < n;
i++)
99 Printf(
"%d\t%s\n",
D.Default,
D.Description);
101 Printf(
"\nFlags starting with '--' will be ignored and "
102 "will be passed verbatim to subprocesses.\n");
105 static const char *FlagValue(
const char *Param,
const char *Name) {
106 size_t Len = strlen(Name);
107 if (Param[0] ==
'-' && strstr(Param + 1, Name) == Param + 1 &&
108 Param[Len + 1] ==
'=')
109 return &Param[Len + 2];
114 static long MyStol(
const char *Str) {
121 for (
size_t i = 0; Str[
i];
i++) {
123 if (Ch < '0' || Ch >
'9')
125 Res = Res * 10 + (Ch -
'0');
130 static bool ParseOneFlag(
const char *Param) {
131 if (Param[0] !=
'-')
return false;
132 if (Param[1] ==
'-') {
133 static bool PrintedWarning =
false;
134 if (!PrintedWarning) {
135 PrintedWarning =
true;
136 Printf(
"INFO: libFuzzer ignores flags that start with '--'\n");
138 for (
size_t F = 0;
F < kNumFlags;
F++)
139 if (FlagValue(Param + 1, FlagDescriptions[
F].Name))
140 Printf(
"WARNING: did you mean '%s' (single dash)?\n", Param + 1);
143 for (
size_t F = 0;
F < kNumFlags;
F++) {
144 const char *Name = FlagDescriptions[
F].Name;
145 const char *Str = FlagValue(Param, Name);
147 if (FlagDescriptions[
F].IntFlag) {
148 int Val = MyStol(Str);
149 *FlagDescriptions[
F].IntFlag = Val;
150 if (
Flags.verbosity >= 2)
151 Printf(
"Flag: %s %d\n", Name, Val);;
153 }
else if (FlagDescriptions[
F].UIntFlag) {
154 unsigned int Val = std::stoul(Str);
155 *FlagDescriptions[
F].UIntFlag = Val;
156 if (
Flags.verbosity >= 2)
157 Printf(
"Flag: %s %u\n", Name, Val);
159 }
else if (FlagDescriptions[
F].StrFlag) {
160 *FlagDescriptions[
F].StrFlag = Str;
161 if (
Flags.verbosity >= 2)
162 Printf(
"Flag: %s %s\n", Name, Str);
165 Printf(
"Flag: %s: deprecated, don't use\n", Name);
170 Printf(
"\n\nWARNING: unrecognized flag '%s'; "
171 "use -help=1 to list all flags\n\n", Param);
176 static void ParseFlags(
const std::vector<std::string> &
Args) {
177 for (
size_t F = 0;
F < kNumFlags;
F++) {
178 if (FlagDescriptions[
F].IntFlag)
179 *FlagDescriptions[
F].IntFlag = FlagDescriptions[
F].Default;
180 if (FlagDescriptions[
F].UIntFlag)
181 *FlagDescriptions[
F].UIntFlag =
182 static_cast<unsigned int>(FlagDescriptions[
F].Default);
183 if (FlagDescriptions[
F].StrFlag)
184 *FlagDescriptions[
F].StrFlag =
nullptr;
186 Inputs =
new std::vector<std::string>;
187 for (
size_t A = 1;
A < Args.size();
A++) {
188 if (ParseOneFlag(Args[
A].
c_str()))
continue;
189 Inputs->push_back(Args[
A]);
193 static std::mutex Mu;
195 static void PulseThread() {
198 std::lock_guard<std::mutex>
Lock(Mu);
203 static void WorkerThread(
const std::string &Cmd, std::atomic<unsigned> *
Counter,
204 unsigned NumJobs, std::atomic<bool> *HasErrors) {
206 unsigned C = (*Counter)++;
207 if (C >= NumJobs)
break;
209 std::string ToRun = Cmd +
" > " + Log +
" 2>&1\n";
211 Printf(
"%s", ToRun.c_str());
215 std::lock_guard<std::mutex>
Lock(Mu);
216 Printf(
"================== Job %u exited with exit code %d ============\n",
223 const char *X1,
const char *X2) {
225 for (
auto &S : Args) {
226 if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
233 static int RunInMultipleProcesses(
const std::vector<std::string> &Args,
234 unsigned NumWorkers,
unsigned NumJobs) {
235 std::atomic<unsigned>
Counter(0);
236 std::atomic<bool> HasErrors(
false);
238 std::vector<std::thread> V;
241 for (
unsigned i = 0;
i < NumWorkers;
i++)
242 V.push_back(
std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
245 return HasErrors ? 1 : 0;
248 static void RssThread(Fuzzer *
F,
size_t RssLimitMb) {
252 if (Peak > RssLimitMb)
253 F->RssLimitCallback();
257 static void StartRssThread(Fuzzer *F,
size_t RssLimitMb) {
258 if (!RssLimitMb)
return;
263 int RunOneTest(Fuzzer *F,
const char *InputFilePath,
size_t MaxLen) {
265 if (MaxLen && MaxLen < U.size())
267 F->RunOne(U.data(), U.size());
268 F->TryDetectingAMemoryLeak(U.data(), U.size(),
true);
272 static bool AllInputsAreFiles() {
273 if (Inputs->empty())
return false;
274 for (
auto &Path : *Inputs)
280 int MinimizeCrashInput(
const std::vector<std::string> &Args) {
281 if (Inputs->size() != 1) {
282 Printf(
"ERROR: -minimize_crash should be given one input file\n");
285 std::string InputFilePath = Inputs->at(0);
286 std::string BaseCmd =
288 auto InputPos = BaseCmd.find(
" " + InputFilePath +
" ");
289 assert(InputPos != std::string::npos);
290 BaseCmd.erase(InputPos, InputFilePath.size() + 1);
291 if (
Flags.runs <= 0 &&
Flags.max_total_time == 0) {
292 Printf(
"INFO: you need to specify -runs=N or "
293 "-max_total_time=N with -minimize_crash=1\n"
294 "INFO: defaulting to -max_total_time=600\n");
295 BaseCmd +=
" -max_total_time=600";
299 std::string CurrentFilePath = InputFilePath;
303 Printf(
"CRASH_MIN: '%s' is small enough\n", CurrentFilePath.c_str());
306 Printf(
"CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
307 CurrentFilePath.c_str(), U.size());
309 auto Cmd = BaseCmd +
" " + CurrentFilePath;
311 Printf(
"CRASH_MIN: executing: %s\n", Cmd.c_str());
314 Printf(
"ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
317 Printf(
"CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
319 CurrentFilePath.c_str(), U.size());
321 std::string ArtifactPath =
"minimized-from-" +
Hash(U);
322 Cmd +=
" -minimize_crash_internal_step=1 -exact_artifact_path=" +
324 Printf(
"CRASH_MIN: executing: %s\n", Cmd.c_str());
327 if (
Flags.exact_artifact_path) {
328 CurrentFilePath =
Flags.exact_artifact_path;
331 Printf(
"CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
332 CurrentFilePath.c_str(), U.size());
335 CurrentFilePath = ArtifactPath;
336 Printf(
"\n\n\n\n\n\n*********************************\n");
341 int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
342 assert(Inputs->size() == 1);
343 std::string InputFilePath = Inputs->at(0);
346 Printf(
"INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
347 Corpus->AddToCorpus(U, 0);
348 F->SetMaxInputLen(U.size());
349 F->SetMaxMutationLen(U.size() - 1);
350 F->MinimizeCrashLoop(U);
351 Printf(
"INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
357 using namespace fuzzer;
358 assert(argc && argv &&
"Argument pointers cannot be nullptr");
360 if (
EF->LLVMFuzzerInitialize)
361 EF->LLVMFuzzerInitialize(argc, argv);
362 const std::vector<std::string>
Args(*argv, *argv + *argc);
364 ProgName =
new std::string(Args[0]);
371 if (
Flags.minimize_crash)
372 return MinimizeCrashInput(Args);
374 if (
Flags.close_fd_mask & 2)
376 if (
Flags.close_fd_mask & 1)
381 if (
Flags.workers > 1)
386 return RunInMultipleProcesses(Args,
Flags.workers,
Flags.jobs);
388 const size_t kMaxSaneLen = 1 << 20;
389 const size_t kMinDefaultLen = 64;
392 Options.MaxLen =
Flags.max_len;
393 Options.ExperimentalLenControl =
Flags.experimental_len_control;
394 if (
Flags.experimental_len_control &&
Flags.max_len == 64)
395 Options.MaxLen = 1 << 20;
396 Options.UnitTimeoutSec =
Flags.timeout;
397 Options.ErrorExitCode =
Flags.error_exitcode;
398 Options.TimeoutExitCode =
Flags.timeout_exitcode;
399 Options.MaxTotalTimeSec =
Flags.max_total_time;
400 Options.DoCrossOver =
Flags.cross_over;
401 Options.MutateDepth =
Flags.mutate_depth;
402 Options.UseCounters =
Flags.use_counters;
403 Options.UseIndirCalls =
Flags.use_indir_calls;
404 Options.UseMemcmp =
Flags.use_memcmp;
405 Options.UseMemmem =
Flags.use_memmem;
406 Options.UseCmp =
Flags.use_cmp;
407 Options.UseValueProfile =
Flags.use_value_profile;
408 Options.Shrink =
Flags.shrink;
409 Options.ShuffleAtStartUp =
Flags.shuffle;
410 Options.PreferSmall =
Flags.prefer_small;
411 Options.ReloadIntervalSec =
Flags.reload;
412 Options.OnlyASCII =
Flags.only_ascii;
413 Options.OutputCSV =
Flags.output_csv;
414 Options.DetectLeaks =
Flags.detect_leaks;
415 Options.TraceMalloc =
Flags.trace_malloc;
416 Options.RssLimitMb =
Flags.rss_limit_mb;
418 Options.MaxNumberOfRuns =
Flags.runs;
419 if (!Inputs->empty() && !
Flags.minimize_crash_internal_step)
420 Options.OutputCorpus = (*Inputs)[0];
421 Options.ReportSlowUnits =
Flags.report_slow_units;
422 if (
Flags.artifact_prefix)
423 Options.ArtifactPrefix =
Flags.artifact_prefix;
424 if (
Flags.exact_artifact_path)
425 Options.ExactArtifactPath =
Flags.exact_artifact_path;
432 bool DoPlainRun = AllInputsAreFiles();
433 Options.SaveArtifacts =
434 !DoPlainRun ||
Flags.minimize_crash_internal_step;
435 Options.PrintNewCovPcs =
Flags.print_pcs;
436 Options.PrintFinalStats =
Flags.print_final_stats;
437 Options.PrintCorpusStats =
Flags.print_corpus_stats;
438 Options.PrintCoverage =
Flags.print_coverage;
439 Options.DumpCoverage =
Flags.dump_coverage;
440 if (
Flags.exit_on_src_pos)
441 Options.ExitOnSrcPos =
Flags.exit_on_src_pos;
442 if (
Flags.exit_on_item)
443 Options.ExitOnItem =
Flags.exit_on_item;
455 auto *Corpus =
new InputCorpus(Options.OutputCorpus);
456 auto *F =
new Fuzzer(Callback, *Corpus, *MD, Options);
460 MD->AddWordToManualDictionary(
Word(U.data(), U.size()));
462 StartRssThread(F,
Flags.rss_limit_mb);
464 Options.HandleAbrt =
Flags.handle_abrt;
465 Options.HandleBus =
Flags.handle_bus;
466 Options.HandleFpe =
Flags.handle_fpe;
467 Options.HandleIll =
Flags.handle_ill;
468 Options.HandleInt =
Flags.handle_int;
469 Options.HandleSegv =
Flags.handle_segv;
470 Options.HandleTerm =
Flags.handle_term;
471 Options.HandleXfsz =
Flags.handle_xfsz;
474 if (
Flags.minimize_crash_internal_step)
475 return MinimizeCrashInputInternalStep(F, Corpus);
478 Options.SaveArtifacts =
false;
479 int Runs = std::max(1,
Flags.runs);
480 Printf(
"%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
481 Inputs->size(), Runs);
482 for (
auto &Path : *Inputs) {
484 Printf(
"Running: %s\n", Path.c_str());
485 for (
int Iter = 0; Iter < Runs; Iter++)
486 RunOneTest(F, Path.c_str(), Options.MaxLen);
488 auto MS = duration_cast<milliseconds>(StopTime - StartTime).
count();
489 Printf(
"Executed %s in %zd ms\n", Path.c_str(), (long)MS);
492 "*** NOTE: fuzzing was not performed, you have only\n"
493 "*** executed the target code on a fixed set of inputs.\n"
495 F->PrintFinalStats();
500 if (Options.MaxLen == 0)
501 F->SetMaxInputLen(kMaxSaneLen);
503 if (
Flags.merge_control_file)
504 F->CrashResistantMergeInternalStep(
Flags.merge_control_file);
506 F->CrashResistantMerge(Args, *Inputs);
513 size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen;
516 for (
auto &Inp : *Inputs) {
517 Printf(
"Loading corpus dir: %s\n", Inp.c_str());
519 TemporaryMaxLen,
false);
522 if (Options.MaxLen == 0) {
524 for (
auto &U : InitialCorpus)
525 MaxLen = std::max(U.size(), MaxLen);
526 F->SetMaxInputLen(
std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen));
529 if (InitialCorpus.empty()) {
530 InitialCorpus.push_back(
Unit({
'\n'}));
531 if (Options.Verbosity)
532 Printf(
"INFO: A corpus is not provided, starting from an empty corpus\n");
534 F->ShuffleAndMinimize(&InitialCorpus);
535 InitialCorpus.clear();
539 Printf(
"Done %d runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
540 F->secondsSinceProcessStartUp());
541 F->PrintFinalStats();
static cl::opt< unsigned long long > Seed("rng-seed", cl::value_desc("seed"), cl::desc("Seed for the random number generator"), cl::init(0))
int(* UserCallback)(const uint8_t *Data, size_t Size)
void SleepSeconds(int Seconds)
bool IsFile(const std::string &Path)
struct fuzzer::@269 Flags
std::string FileToString(const std::string &Path)
static GCRegistry::Add< StatepointGC > D("statepoint-example","an example strategy for statepoint")
void ReadDirToVectorOfUnits(const char *Path, std::vector< Unit > *V, long *Epoch, size_t MaxSize, bool ExitOnError)
__attribute__((used)) void __libfuzzer_is_present()
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback)
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...
Maximum length of the test input libFuzzer tries to guess a good value based on the corpus and reports it always prefer smaller inputs during the corpus shuffle When libFuzzer itself reports a bug this exit code will be used If indicates the maximal total time in seconds to run the fuzzer minimizes the provided crash input Use with etc Experimental Use value profile to guide fuzzing Number of simultaneous worker processes to run the jobs If min(jobs, NumberOfCpuCores()/2)\" is used.") FUZZER_FLAG_INT(reload
void Printf(const char *Fmt,...)
bool ParseDictionaryFile(const std::string &Text, std::vector< Unit > *Units)
static sys::TimePoint< std::chrono::seconds > now(bool Deterministic)
void SetSignalHandler(const FuzzingOptions &Options)
static size_t GetMaxSize()
void CopyFileToErr(const std::string &Path)
SmallVectorImpl< T >::const_pointer c_str(SmallVectorImpl< T > &str)
void WriteToFile(const Unit &U, const std::string &Path)
Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
bool UsingTracePcGuard() const
std::vector< Unit > UnitVector
const std::string to_string(const T &Value)
std::vector< uint8_t > Unit
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
std::string Hash(const Unit &U)
unsigned NumberOfCpuCores()
int ExecuteCommand(const std::string &Command)
static GCRegistry::Add< ErlangGC > A("erlang","erlang-compatible garbage collector")
std::string CloneArgsWithoutX(const std::vector< std::string > &Args, const char *X1, const char *X2)