1 //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
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 //===----------------------------------------------------------------------===//
8 // FuzzerDriver and flag parsing.
9 //===----------------------------------------------------------------------===//
11 #include "FuzzerCommand.h"
12 #include "FuzzerCorpus.h"
13 #include "FuzzerFork.h"
15 #include "FuzzerInterface.h"
16 #include "FuzzerInternal.h"
17 #include "FuzzerMerge.h"
18 #include "FuzzerMutate.h"
19 #include "FuzzerPlatform.h"
20 #include "FuzzerRandom.h"
21 #include "FuzzerTracePC.h"
32 // This function should be present in the libFuzzer so that the client
33 // binary can test for its existence.
35 extern "C" void __libfuzzer_is_present() {}
36 #if defined(_M_IX86) || defined(__i386__)
37 #pragma comment(linker, "/include:___libfuzzer_is_present")
39 #pragma comment(linker, "/include:__libfuzzer_is_present")
42 extern "C" __attribute__((used
)) void __libfuzzer_is_present() {}
43 #endif // LIBFUZZER_MSVC
48 struct FlagDescription
{
50 const char *Description
;
54 unsigned int *UIntFlag
;
58 #define FUZZER_DEPRECATED_FLAG(Name)
59 #define FUZZER_FLAG_INT(Name, Default, Description) int Name;
60 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
61 #define FUZZER_FLAG_STRING(Name, Description) const char *Name;
62 #include "FuzzerFlags.def"
63 #undef FUZZER_DEPRECATED_FLAG
64 #undef FUZZER_FLAG_INT
65 #undef FUZZER_FLAG_UNSIGNED
66 #undef FUZZER_FLAG_STRING
69 static const FlagDescription FlagDescriptions
[] {
70 #define FUZZER_DEPRECATED_FLAG(Name) \
71 {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
72 #define FUZZER_FLAG_INT(Name, Default, Description) \
73 {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
74 #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \
75 {#Name, Description, static_cast<int>(Default), \
76 nullptr, nullptr, &Flags.Name},
77 #define FUZZER_FLAG_STRING(Name, Description) \
78 {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
79 #include "FuzzerFlags.def"
80 #undef FUZZER_DEPRECATED_FLAG
81 #undef FUZZER_FLAG_INT
82 #undef FUZZER_FLAG_UNSIGNED
83 #undef FUZZER_FLAG_STRING
86 static const size_t kNumFlags
=
87 sizeof(FlagDescriptions
) / sizeof(FlagDescriptions
[0]);
89 static std::vector
<std::string
> *Inputs
;
90 static std::string
*ProgName
;
92 static void PrintHelp() {
94 auto Prog
= ProgName
->c_str();
95 Printf("\nTo run fuzzing pass 0 or more directories.\n");
96 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog
);
98 Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n");
99 Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog
);
101 Printf("\nFlags: (strictly in form -flag=value)\n");
102 size_t MaxFlagLen
= 0;
103 for (size_t F
= 0; F
< kNumFlags
; F
++)
104 MaxFlagLen
= std::max(strlen(FlagDescriptions
[F
].Name
), MaxFlagLen
);
106 for (size_t F
= 0; F
< kNumFlags
; F
++) {
107 const auto &D
= FlagDescriptions
[F
];
108 if (strstr(D
.Description
, "internal flag") == D
.Description
) continue;
109 Printf(" %s", D
.Name
);
110 for (size_t i
= 0, n
= MaxFlagLen
- strlen(D
.Name
); i
< n
; i
++)
113 Printf("%d\t%s\n", D
.Default
, D
.Description
);
115 Printf("\nFlags starting with '--' will be ignored and "
116 "will be passed verbatim to subprocesses.\n");
119 static const char *FlagValue(const char *Param
, const char *Name
) {
120 size_t Len
= strlen(Name
);
121 if (Param
[0] == '-' && strstr(Param
+ 1, Name
) == Param
+ 1 &&
122 Param
[Len
+ 1] == '=')
123 return &Param
[Len
+ 2];
127 // Avoid calling stol as it triggers a bug in clang/glibc build.
128 static long MyStol(const char *Str
) {
135 for (size_t i
= 0; Str
[i
]; i
++) {
137 if (Ch
< '0' || Ch
> '9')
139 Res
= Res
* 10 + (Ch
- '0');
144 static bool ParseOneFlag(const char *Param
) {
145 if (Param
[0] != '-') return false;
146 if (Param
[1] == '-') {
147 static bool PrintedWarning
= false;
148 if (!PrintedWarning
) {
149 PrintedWarning
= true;
150 Printf("INFO: libFuzzer ignores flags that start with '--'\n");
152 for (size_t F
= 0; F
< kNumFlags
; F
++)
153 if (FlagValue(Param
+ 1, FlagDescriptions
[F
].Name
))
154 Printf("WARNING: did you mean '%s' (single dash)?\n", Param
+ 1);
157 for (size_t F
= 0; F
< kNumFlags
; F
++) {
158 const char *Name
= FlagDescriptions
[F
].Name
;
159 const char *Str
= FlagValue(Param
, Name
);
161 if (FlagDescriptions
[F
].IntFlag
) {
162 auto Val
= MyStol(Str
);
163 *FlagDescriptions
[F
].IntFlag
= static_cast<int>(Val
);
164 if (Flags
.verbosity
>= 2)
165 Printf("Flag: %s %d\n", Name
, Val
);
167 } else if (FlagDescriptions
[F
].UIntFlag
) {
168 auto Val
= std::stoul(Str
);
169 *FlagDescriptions
[F
].UIntFlag
= static_cast<unsigned int>(Val
);
170 if (Flags
.verbosity
>= 2)
171 Printf("Flag: %s %u\n", Name
, Val
);
173 } else if (FlagDescriptions
[F
].StrFlag
) {
174 *FlagDescriptions
[F
].StrFlag
= Str
;
175 if (Flags
.verbosity
>= 2)
176 Printf("Flag: %s %s\n", Name
, Str
);
178 } else { // Deprecated flag.
179 Printf("Flag: %s: deprecated, don't use\n", Name
);
184 Printf("\n\nWARNING: unrecognized flag '%s'; "
185 "use -help=1 to list all flags\n\n", Param
);
189 // We don't use any library to minimize dependencies.
190 static void ParseFlags(const std::vector
<std::string
> &Args
,
191 const ExternalFunctions
*EF
) {
192 for (size_t F
= 0; F
< kNumFlags
; F
++) {
193 if (FlagDescriptions
[F
].IntFlag
)
194 *FlagDescriptions
[F
].IntFlag
= FlagDescriptions
[F
].Default
;
195 if (FlagDescriptions
[F
].UIntFlag
)
196 *FlagDescriptions
[F
].UIntFlag
=
197 static_cast<unsigned int>(FlagDescriptions
[F
].Default
);
198 if (FlagDescriptions
[F
].StrFlag
)
199 *FlagDescriptions
[F
].StrFlag
= nullptr;
202 // Disable len_control by default, if LLVMFuzzerCustomMutator is used.
203 if (EF
->LLVMFuzzerCustomMutator
) {
204 Flags
.len_control
= 0;
205 Printf("INFO: found LLVMFuzzerCustomMutator (%p). "
206 "Disabling -len_control by default.\n", EF
->LLVMFuzzerCustomMutator
);
209 Inputs
= new std::vector
<std::string
>;
210 for (size_t A
= 1; A
< Args
.size(); A
++) {
211 if (ParseOneFlag(Args
[A
].c_str())) {
212 if (Flags
.ignore_remaining_args
)
216 Inputs
->push_back(Args
[A
]);
220 static std::mutex Mu
;
222 static void PulseThread() {
225 std::lock_guard
<std::mutex
> Lock(Mu
);
226 Printf("pulse...\n");
230 static void WorkerThread(const Command
&BaseCmd
, std::atomic
<unsigned> *Counter
,
231 unsigned NumJobs
, std::atomic
<bool> *HasErrors
) {
233 unsigned C
= (*Counter
)++;
234 if (C
>= NumJobs
) break;
235 std::string Log
= "fuzz-" + std::to_string(C
) + ".log";
236 Command
Cmd(BaseCmd
);
237 Cmd
.setOutputFile(Log
);
238 Cmd
.combineOutAndErr();
239 if (Flags
.verbosity
) {
240 std::string CommandLine
= Cmd
.toString();
241 Printf("%s\n", CommandLine
.c_str());
243 int ExitCode
= ExecuteCommand(Cmd
);
246 std::lock_guard
<std::mutex
> Lock(Mu
);
247 Printf("================== Job %u exited with exit code %d ============\n",
249 fuzzer::CopyFileToErr(Log
);
253 static void ValidateDirectoryExists(const std::string
&Path
,
254 bool CreateDirectory
) {
256 Printf("ERROR: Provided directory path is an empty string\n");
260 if (IsDirectory(Path
))
263 if (CreateDirectory
) {
264 if (!MkDirRecursive(Path
)) {
265 Printf("ERROR: Failed to create directory \"%s\"\n", Path
.c_str());
271 Printf("ERROR: The required directory \"%s\" does not exist\n", Path
.c_str());
275 std::string
CloneArgsWithoutX(const std::vector
<std::string
> &Args
,
276 const char *X1
, const char *X2
) {
278 for (auto &S
: Args
) {
279 if (FlagValue(S
.c_str(), X1
) || FlagValue(S
.c_str(), X2
))
286 static int RunInMultipleProcesses(const std::vector
<std::string
> &Args
,
287 unsigned NumWorkers
, unsigned NumJobs
) {
288 std::atomic
<unsigned> Counter(0);
289 std::atomic
<bool> HasErrors(false);
291 Cmd
.removeFlag("jobs");
292 Cmd
.removeFlag("workers");
293 std::vector
<std::thread
> V
;
294 std::thread
Pulse(PulseThread
);
296 V
.resize(NumWorkers
);
297 for (unsigned i
= 0; i
< NumWorkers
; i
++) {
298 V
[i
] = std::thread(WorkerThread
, std::ref(Cmd
), &Counter
, NumJobs
,
300 SetThreadName(V
[i
], "FuzzerWorker");
304 return HasErrors
? 1 : 0;
307 static void RssThread(Fuzzer
*F
, size_t RssLimitMb
) {
310 size_t Peak
= GetPeakRSSMb();
311 if (Peak
> RssLimitMb
)
312 F
->RssLimitCallback();
316 static void StartRssThread(Fuzzer
*F
, size_t RssLimitMb
) {
319 std::thread
T(RssThread
, F
, RssLimitMb
);
323 int RunOneTest(Fuzzer
*F
, const char *InputFilePath
, size_t MaxLen
) {
324 Unit U
= FileToVector(InputFilePath
);
325 if (MaxLen
&& MaxLen
< U
.size())
327 F
->ExecuteCallback(U
.data(), U
.size());
328 if (Flags
.print_full_coverage
) {
329 // Leak detection is not needed when collecting full coverage data.
330 F
->TPCUpdateObservedPCs();
332 F
->TryDetectingAMemoryLeak(U
.data(), U
.size(), true);
337 static bool AllInputsAreFiles() {
338 if (Inputs
->empty()) return false;
339 for (auto &Path
: *Inputs
)
345 static std::string
GetDedupTokenFromCmdOutput(const std::string
&S
) {
346 auto Beg
= S
.find("DEDUP_TOKEN:");
347 if (Beg
== std::string::npos
)
349 auto End
= S
.find('\n', Beg
);
350 if (End
== std::string::npos
)
352 return S
.substr(Beg
, End
- Beg
);
355 int CleanseCrashInput(const std::vector
<std::string
> &Args
,
356 const FuzzingOptions
&Options
) {
357 if (Inputs
->size() != 1 || !Flags
.exact_artifact_path
) {
358 Printf("ERROR: -cleanse_crash should be given one input file and"
359 " -exact_artifact_path\n");
362 std::string InputFilePath
= Inputs
->at(0);
363 std::string OutputFilePath
= Flags
.exact_artifact_path
;
365 Cmd
.removeFlag("cleanse_crash");
367 assert(Cmd
.hasArgument(InputFilePath
));
368 Cmd
.removeArgument(InputFilePath
);
370 auto TmpFilePath
= TempPath("CleanseCrashInput", ".repro");
371 Cmd
.addArgument(TmpFilePath
);
372 Cmd
.setOutputFile(getDevNull());
373 Cmd
.combineOutAndErr();
375 std::string CurrentFilePath
= InputFilePath
;
376 auto U
= FileToVector(CurrentFilePath
);
377 size_t Size
= U
.size();
379 const std::vector
<uint8_t> ReplacementBytes
= {' ', 0xff};
380 for (int NumAttempts
= 0; NumAttempts
< 5; NumAttempts
++) {
381 bool Changed
= false;
382 for (size_t Idx
= 0; Idx
< Size
; Idx
++) {
383 Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts
,
385 uint8_t OriginalByte
= U
[Idx
];
386 if (ReplacementBytes
.end() != std::find(ReplacementBytes
.begin(),
387 ReplacementBytes
.end(),
390 for (auto NewByte
: ReplacementBytes
) {
392 WriteToFile(U
, TmpFilePath
);
393 auto ExitCode
= ExecuteCommand(Cmd
);
394 RemoveFile(TmpFilePath
);
396 U
[Idx
] = OriginalByte
;
399 Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx
, NewByte
);
400 WriteToFile(U
, OutputFilePath
);
410 int MinimizeCrashInput(const std::vector
<std::string
> &Args
,
411 const FuzzingOptions
&Options
) {
412 if (Inputs
->size() != 1) {
413 Printf("ERROR: -minimize_crash should be given one input file\n");
416 std::string InputFilePath
= Inputs
->at(0);
417 Command
BaseCmd(Args
);
418 BaseCmd
.removeFlag("minimize_crash");
419 BaseCmd
.removeFlag("exact_artifact_path");
420 assert(BaseCmd
.hasArgument(InputFilePath
));
421 BaseCmd
.removeArgument(InputFilePath
);
422 if (Flags
.runs
<= 0 && Flags
.max_total_time
== 0) {
423 Printf("INFO: you need to specify -runs=N or "
424 "-max_total_time=N with -minimize_crash=1\n"
425 "INFO: defaulting to -max_total_time=600\n");
426 BaseCmd
.addFlag("max_total_time", "600");
429 BaseCmd
.combineOutAndErr();
431 std::string CurrentFilePath
= InputFilePath
;
433 Unit U
= FileToVector(CurrentFilePath
);
434 Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
435 CurrentFilePath
.c_str(), U
.size());
437 Command
Cmd(BaseCmd
);
438 Cmd
.addArgument(CurrentFilePath
);
440 Printf("CRASH_MIN: executing: %s\n", Cmd
.toString().c_str());
441 std::string CmdOutput
;
442 bool Success
= ExecuteCommand(Cmd
, &CmdOutput
);
444 Printf("ERROR: the input %s did not crash\n", CurrentFilePath
.c_str());
447 Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
449 CurrentFilePath
.c_str(), U
.size());
450 auto DedupToken1
= GetDedupTokenFromCmdOutput(CmdOutput
);
451 if (!DedupToken1
.empty())
452 Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1
.c_str());
454 std::string ArtifactPath
=
455 Flags
.exact_artifact_path
456 ? Flags
.exact_artifact_path
457 : Options
.ArtifactPrefix
+ "minimized-from-" + Hash(U
);
458 Cmd
.addFlag("minimize_crash_internal_step", "1");
459 Cmd
.addFlag("exact_artifact_path", ArtifactPath
);
460 Printf("CRASH_MIN: executing: %s\n", Cmd
.toString().c_str());
462 Success
= ExecuteCommand(Cmd
, &CmdOutput
);
463 Printf("%s", CmdOutput
.c_str());
465 if (Flags
.exact_artifact_path
) {
466 CurrentFilePath
= Flags
.exact_artifact_path
;
467 WriteToFile(U
, CurrentFilePath
);
469 Printf("CRASH_MIN: failed to minimize beyond %s (%zu bytes), exiting\n",
470 CurrentFilePath
.c_str(), U
.size());
473 auto DedupToken2
= GetDedupTokenFromCmdOutput(CmdOutput
);
474 if (!DedupToken2
.empty())
475 Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2
.c_str());
477 if (DedupToken1
!= DedupToken2
) {
478 if (Flags
.exact_artifact_path
) {
479 CurrentFilePath
= Flags
.exact_artifact_path
;
480 WriteToFile(U
, CurrentFilePath
);
482 Printf("CRASH_MIN: mismatch in dedup tokens"
483 " (looks like a different bug). Won't minimize further\n");
487 CurrentFilePath
= ArtifactPath
;
488 Printf("*********************************\n");
493 int MinimizeCrashInputInternalStep(Fuzzer
*F
, InputCorpus
*Corpus
) {
494 assert(Inputs
->size() == 1);
495 std::string InputFilePath
= Inputs
->at(0);
496 Unit U
= FileToVector(InputFilePath
);
497 Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U
.size());
499 Printf("INFO: The input is small enough, exiting\n");
502 F
->SetMaxInputLen(U
.size());
503 F
->SetMaxMutationLen(U
.size() - 1);
504 F
->MinimizeCrashLoop(U
);
505 Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
509 void Merge(Fuzzer
*F
, FuzzingOptions
&Options
,
510 const std::vector
<std::string
> &Args
,
511 const std::vector
<std::string
> &Corpora
, const char *CFPathOrNull
) {
512 if (Corpora
.size() < 2) {
513 Printf("INFO: Merge requires two or more corpus dirs\n");
517 std::vector
<SizedFile
> OldCorpus
, NewCorpus
;
518 GetSizedFilesFromDir(Corpora
[0], &OldCorpus
);
519 for (size_t i
= 1; i
< Corpora
.size(); i
++)
520 GetSizedFilesFromDir(Corpora
[i
], &NewCorpus
);
521 std::sort(OldCorpus
.begin(), OldCorpus
.end());
522 std::sort(NewCorpus
.begin(), NewCorpus
.end());
524 std::string CFPath
= CFPathOrNull
? CFPathOrNull
: TempPath("Merge", ".txt");
525 std::vector
<std::string
> NewFiles
;
526 std::set
<uint32_t> NewFeatures
, NewCov
;
527 CrashResistantMerge(Args
, OldCorpus
, NewCorpus
, &NewFiles
, {}, &NewFeatures
,
528 {}, &NewCov
, CFPath
, true, Flags
.set_cover_merge
);
529 for (auto &Path
: NewFiles
)
530 F
->WriteToOutputCorpus(FileToVector(Path
, Options
.MaxLen
));
531 // We are done, delete the control file if it was a temporary one.
532 if (!Flags
.merge_control_file
)
538 int AnalyzeDictionary(Fuzzer
*F
, const std::vector
<Unit
> &Dict
,
539 UnitVector
&Corpus
) {
540 Printf("Started dictionary minimization (up to %zu tests)\n",
541 Dict
.size() * Corpus
.size() * 2);
543 // Scores and usage count for each dictionary unit.
544 std::vector
<int> Scores(Dict
.size());
545 std::vector
<int> Usages(Dict
.size());
547 std::vector
<size_t> InitialFeatures
;
548 std::vector
<size_t> ModifiedFeatures
;
549 for (auto &C
: Corpus
) {
550 // Get coverage for the testcase without modifications.
551 F
->ExecuteCallback(C
.data(), C
.size());
552 InitialFeatures
.clear();
553 TPC
.CollectFeatures([&](size_t Feature
) {
554 InitialFeatures
.push_back(Feature
);
557 for (size_t i
= 0; i
< Dict
.size(); ++i
) {
558 std::vector
<uint8_t> Data
= C
;
559 auto StartPos
= std::search(Data
.begin(), Data
.end(),
560 Dict
[i
].begin(), Dict
[i
].end());
561 // Skip dictionary unit, if the testcase does not contain it.
562 if (StartPos
== Data
.end())
566 while (StartPos
!= Data
.end()) {
567 // Replace all occurrences of dictionary unit in the testcase.
568 auto EndPos
= StartPos
+ Dict
[i
].size();
569 for (auto It
= StartPos
; It
!= EndPos
; ++It
)
572 StartPos
= std::search(EndPos
, Data
.end(),
573 Dict
[i
].begin(), Dict
[i
].end());
576 // Get coverage for testcase with masked occurrences of dictionary unit.
577 F
->ExecuteCallback(Data
.data(), Data
.size());
578 ModifiedFeatures
.clear();
579 TPC
.CollectFeatures([&](size_t Feature
) {
580 ModifiedFeatures
.push_back(Feature
);
583 if (InitialFeatures
== ModifiedFeatures
)
590 Printf("###### Useless dictionary elements. ######\n");
591 for (size_t i
= 0; i
< Dict
.size(); ++i
) {
592 // Dictionary units with positive score are treated as useful ones.
597 PrintASCII(Dict
[i
].data(), Dict
[i
].size(), "\"");
598 Printf(" # Score: %d, Used: %d\n", Scores
[i
], Usages
[i
]);
600 Printf("###### End of useless dictionary elements. ######\n");
604 std::vector
<std::string
> ParseSeedInuts(const char *seed_inputs
) {
605 // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file
606 std::vector
<std::string
> Files
;
607 if (!seed_inputs
) return Files
;
608 std::string SeedInputs
;
609 if (Flags
.seed_inputs
[0] == '@')
610 SeedInputs
= FileToString(Flags
.seed_inputs
+ 1); // File contains list.
612 SeedInputs
= Flags
.seed_inputs
; // seed_inputs contains the list.
613 if (SeedInputs
.empty()) {
614 Printf("seed_inputs is empty or @file does not exist.\n");
618 size_t comma_pos
= 0;
619 while ((comma_pos
= SeedInputs
.find_last_of(',')) != std::string::npos
) {
620 Files
.push_back(SeedInputs
.substr(comma_pos
+ 1));
621 SeedInputs
= SeedInputs
.substr(0, comma_pos
);
623 Files
.push_back(SeedInputs
);
627 static std::vector
<SizedFile
>
628 ReadCorpora(const std::vector
<std::string
> &CorpusDirs
,
629 const std::vector
<std::string
> &ExtraSeedFiles
) {
630 std::vector
<SizedFile
> SizedFiles
;
631 size_t LastNumFiles
= 0;
632 for (auto &Dir
: CorpusDirs
) {
633 GetSizedFilesFromDir(Dir
, &SizedFiles
);
634 Printf("INFO: % 8zd files found in %s\n", SizedFiles
.size() - LastNumFiles
,
636 LastNumFiles
= SizedFiles
.size();
638 for (auto &File
: ExtraSeedFiles
)
639 if (auto Size
= FileSize(File
))
640 SizedFiles
.push_back({File
, Size
});
644 int FuzzerDriver(int *argc
, char ***argv
, UserCallback Callback
) {
645 using namespace fuzzer
;
646 assert(argc
&& argv
&& "Argument pointers cannot be nullptr");
647 std::string
Argv0((*argv
)[0]);
648 EF
= new ExternalFunctions();
649 if (EF
->LLVMFuzzerInitialize
)
650 EF
->LLVMFuzzerInitialize(argc
, argv
);
651 if (EF
->__msan_scoped_disable_interceptor_checks
)
652 EF
->__msan_scoped_disable_interceptor_checks();
653 const std::vector
<std::string
> Args(*argv
, *argv
+ *argc
);
654 assert(!Args
.empty());
655 ProgName
= new std::string(Args
[0]);
656 if (Argv0
!= *ProgName
) {
657 Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
660 ParseFlags(Args
, EF
);
666 if (Flags
.close_fd_mask
& 2)
668 if (Flags
.close_fd_mask
& 1)
671 if (Flags
.jobs
> 0 && Flags
.workers
== 0) {
672 Flags
.workers
= std::min(NumberOfCpuCores() / 2, Flags
.jobs
);
673 if (Flags
.workers
> 1)
674 Printf("Running %u workers\n", Flags
.workers
);
677 if (Flags
.workers
> 0 && Flags
.jobs
> 0)
678 return RunInMultipleProcesses(Args
, Flags
.workers
, Flags
.jobs
);
680 FuzzingOptions Options
;
681 Options
.Verbosity
= Flags
.verbosity
;
682 Options
.MaxLen
= Flags
.max_len
;
683 Options
.LenControl
= Flags
.len_control
;
684 Options
.KeepSeed
= Flags
.keep_seed
;
685 Options
.UnitTimeoutSec
= Flags
.timeout
;
686 Options
.ErrorExitCode
= Flags
.error_exitcode
;
687 Options
.TimeoutExitCode
= Flags
.timeout_exitcode
;
688 Options
.IgnoreTimeouts
= Flags
.ignore_timeouts
;
689 Options
.IgnoreOOMs
= Flags
.ignore_ooms
;
690 Options
.IgnoreCrashes
= Flags
.ignore_crashes
;
691 Options
.MaxTotalTimeSec
= Flags
.max_total_time
;
692 Options
.DoCrossOver
= Flags
.cross_over
;
693 Options
.CrossOverUniformDist
= Flags
.cross_over_uniform_dist
;
694 Options
.MutateDepth
= Flags
.mutate_depth
;
695 Options
.ReduceDepth
= Flags
.reduce_depth
;
696 Options
.UseCounters
= Flags
.use_counters
;
697 Options
.UseMemmem
= Flags
.use_memmem
;
698 Options
.UseCmp
= Flags
.use_cmp
;
699 Options
.UseValueProfile
= Flags
.use_value_profile
;
700 Options
.Shrink
= Flags
.shrink
;
701 Options
.ReduceInputs
= Flags
.reduce_inputs
;
702 Options
.ShuffleAtStartUp
= Flags
.shuffle
;
703 Options
.PreferSmall
= Flags
.prefer_small
;
704 Options
.ReloadIntervalSec
= Flags
.reload
;
705 Options
.OnlyASCII
= Flags
.only_ascii
;
706 Options
.DetectLeaks
= Flags
.detect_leaks
;
707 Options
.PurgeAllocatorIntervalSec
= Flags
.purge_allocator_interval
;
708 Options
.TraceMalloc
= Flags
.trace_malloc
;
709 Options
.RssLimitMb
= Flags
.rss_limit_mb
;
710 Options
.MallocLimitMb
= Flags
.malloc_limit_mb
;
711 if (!Options
.MallocLimitMb
)
712 Options
.MallocLimitMb
= Options
.RssLimitMb
;
714 Options
.MaxNumberOfRuns
= Flags
.runs
;
715 if (!Inputs
->empty() && !Flags
.minimize_crash_internal_step
) {
716 // Ensure output corpus assumed to be the first arbitrary argument input
717 // is not a path to an existing file.
718 std::string OutputCorpusDir
= (*Inputs
)[0];
719 if (!IsFile(OutputCorpusDir
)) {
720 Options
.OutputCorpus
= OutputCorpusDir
;
721 ValidateDirectoryExists(Options
.OutputCorpus
, Flags
.create_missing_dirs
);
724 Options
.ReportSlowUnits
= Flags
.report_slow_units
;
725 if (Flags
.artifact_prefix
) {
726 Options
.ArtifactPrefix
= Flags
.artifact_prefix
;
728 // Since the prefix could be a full path to a file name prefix, assume
729 // that if the path ends with the platform's separator that a directory
731 std::string ArtifactPathDir
= Options
.ArtifactPrefix
;
732 if (!IsSeparator(ArtifactPathDir
[ArtifactPathDir
.length() - 1])) {
733 ArtifactPathDir
= DirName(ArtifactPathDir
);
735 ValidateDirectoryExists(ArtifactPathDir
, Flags
.create_missing_dirs
);
737 if (Flags
.exact_artifact_path
) {
738 Options
.ExactArtifactPath
= Flags
.exact_artifact_path
;
739 ValidateDirectoryExists(DirName(Options
.ExactArtifactPath
),
740 Flags
.create_missing_dirs
);
742 std::vector
<Unit
> Dictionary
;
744 if (!ParseDictionaryFile(FileToString(Flags
.dict
), &Dictionary
))
746 if (Flags
.verbosity
> 0 && !Dictionary
.empty())
747 Printf("Dictionary: %zd entries\n", Dictionary
.size());
748 bool RunIndividualFiles
= AllInputsAreFiles();
749 Options
.SaveArtifacts
=
750 !RunIndividualFiles
|| Flags
.minimize_crash_internal_step
;
751 Options
.PrintNewCovPcs
= Flags
.print_pcs
;
752 Options
.PrintNewCovFuncs
= Flags
.print_funcs
;
753 Options
.PrintFinalStats
= Flags
.print_final_stats
;
754 Options
.PrintCorpusStats
= Flags
.print_corpus_stats
;
755 Options
.PrintCoverage
= Flags
.print_coverage
;
756 Options
.PrintFullCoverage
= Flags
.print_full_coverage
;
757 if (Flags
.exit_on_src_pos
)
758 Options
.ExitOnSrcPos
= Flags
.exit_on_src_pos
;
759 if (Flags
.exit_on_item
)
760 Options
.ExitOnItem
= Flags
.exit_on_item
;
761 if (Flags
.focus_function
)
762 Options
.FocusFunction
= Flags
.focus_function
;
763 if (Flags
.data_flow_trace
)
764 Options
.DataFlowTrace
= Flags
.data_flow_trace
;
765 if (Flags
.features_dir
) {
766 Options
.FeaturesDir
= Flags
.features_dir
;
767 ValidateDirectoryExists(Options
.FeaturesDir
, Flags
.create_missing_dirs
);
769 if (Flags
.mutation_graph_file
)
770 Options
.MutationGraphFile
= Flags
.mutation_graph_file
;
771 if (Flags
.collect_data_flow
)
772 Options
.CollectDataFlow
= Flags
.collect_data_flow
;
774 Options
.StopFile
= Flags
.stop_file
;
775 Options
.Entropic
= Flags
.entropic
;
776 Options
.EntropicFeatureFrequencyThreshold
=
777 (size_t)Flags
.entropic_feature_frequency_threshold
;
778 Options
.EntropicNumberOfRarestFeatures
=
779 (size_t)Flags
.entropic_number_of_rarest_features
;
780 Options
.EntropicScalePerExecTime
= Flags
.entropic_scale_per_exec_time
;
781 if (!Options
.FocusFunction
.empty())
782 Options
.Entropic
= false; // FocusFunction overrides entropic scheduling.
783 if (Options
.Entropic
)
784 Printf("INFO: Running with entropic power schedule (0x%zX, %zu).\n",
785 Options
.EntropicFeatureFrequencyThreshold
,
786 Options
.EntropicNumberOfRarestFeatures
);
787 struct EntropicOptions Entropic
;
788 Entropic
.Enabled
= Options
.Entropic
;
789 Entropic
.FeatureFrequencyThreshold
=
790 Options
.EntropicFeatureFrequencyThreshold
;
791 Entropic
.NumberOfRarestFeatures
= Options
.EntropicNumberOfRarestFeatures
;
792 Entropic
.ScalePerExecTime
= Options
.EntropicScalePerExecTime
;
794 unsigned Seed
= Flags
.seed
;
797 Seed
= static_cast<unsigned>(
798 std::chrono::system_clock::now().time_since_epoch().count() + GetPid());
800 Printf("INFO: Seed: %u\n", Seed
);
802 if (Flags
.collect_data_flow
&& Flags
.data_flow_trace
&& !Flags
.fork
&&
803 !(Flags
.merge
|| Flags
.set_cover_merge
)) {
804 if (RunIndividualFiles
)
805 return CollectDataFlow(Flags
.collect_data_flow
, Flags
.data_flow_trace
,
806 ReadCorpora({}, *Inputs
));
808 return CollectDataFlow(Flags
.collect_data_flow
, Flags
.data_flow_trace
,
809 ReadCorpora(*Inputs
, {}));
813 auto *MD
= new MutationDispatcher(Rand
, Options
);
814 auto *Corpus
= new InputCorpus(Options
.OutputCorpus
, Entropic
);
815 auto *F
= new Fuzzer(Callback
, *Corpus
, *MD
, Options
);
817 for (auto &U
: Dictionary
)
818 if (U
.size() <= Word::GetMaxSize())
819 MD
->AddWordToManualDictionary(Word(U
.data(), U
.size()));
821 // Threads are only supported by Chrome. Don't use them with emscripten
823 #if !LIBFUZZER_EMSCRIPTEN
824 StartRssThread(F
, Flags
.rss_limit_mb
);
825 #endif // LIBFUZZER_EMSCRIPTEN
827 Options
.HandleAbrt
= Flags
.handle_abrt
;
828 Options
.HandleAlrm
= !Flags
.minimize_crash
;
829 Options
.HandleBus
= Flags
.handle_bus
;
830 Options
.HandleFpe
= Flags
.handle_fpe
;
831 Options
.HandleIll
= Flags
.handle_ill
;
832 Options
.HandleInt
= Flags
.handle_int
;
833 Options
.HandleSegv
= Flags
.handle_segv
;
834 Options
.HandleTerm
= Flags
.handle_term
;
835 Options
.HandleXfsz
= Flags
.handle_xfsz
;
836 Options
.HandleUsr1
= Flags
.handle_usr1
;
837 Options
.HandleUsr2
= Flags
.handle_usr2
;
838 Options
.HandleWinExcept
= Flags
.handle_winexcept
;
840 SetSignalHandler(Options
);
842 std::atexit(Fuzzer::StaticExitCallback
);
844 if (Flags
.minimize_crash
)
845 return MinimizeCrashInput(Args
, Options
);
847 if (Flags
.minimize_crash_internal_step
)
848 return MinimizeCrashInputInternalStep(F
, Corpus
);
850 if (Flags
.cleanse_crash
)
851 return CleanseCrashInput(Args
, Options
);
853 if (RunIndividualFiles
) {
854 Options
.SaveArtifacts
= false;
855 int Runs
= std::max(1, Flags
.runs
);
856 Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName
->c_str(),
857 Inputs
->size(), Runs
);
858 for (auto &Path
: *Inputs
) {
859 auto StartTime
= system_clock::now();
860 Printf("Running: %s\n", Path
.c_str());
861 for (int Iter
= 0; Iter
< Runs
; Iter
++)
862 RunOneTest(F
, Path
.c_str(), Options
.MaxLen
);
863 auto StopTime
= system_clock::now();
864 auto MS
= duration_cast
<milliseconds
>(StopTime
- StartTime
).count();
865 Printf("Executed %s in %ld ms\n", Path
.c_str(), (long)MS
);
868 "*** NOTE: fuzzing was not performed, you have only\n"
869 "*** executed the target code on a fixed set of inputs.\n"
871 F
->PrintFinalStats();
875 Options
.ForkCorpusGroups
= Flags
.fork_corpus_groups
;
877 FuzzWithFork(F
->GetMD().GetRand(), Options
, Args
, *Inputs
, Flags
.fork
);
879 if (Flags
.merge
|| Flags
.set_cover_merge
)
880 Merge(F
, Options
, Args
, *Inputs
, Flags
.merge_control_file
);
882 if (Flags
.merge_inner
) {
883 const size_t kDefaultMaxMergeLen
= 1 << 20;
884 if (Options
.MaxLen
== 0)
885 F
->SetMaxInputLen(kDefaultMaxMergeLen
);
886 assert(Flags
.merge_control_file
);
887 F
->CrashResistantMergeInternalStep(Flags
.merge_control_file
,
888 !strncmp(Flags
.merge_inner
, "2", 1));
892 if (Flags
.analyze_dict
) {
893 size_t MaxLen
= INT_MAX
; // Large max length.
894 UnitVector InitialCorpus
;
895 for (auto &Inp
: *Inputs
) {
896 Printf("Loading corpus dir: %s\n", Inp
.c_str());
897 ReadDirToVectorOfUnits(Inp
.c_str(), &InitialCorpus
, nullptr,
898 MaxLen
, /*ExitOnError=*/false);
901 if (Dictionary
.empty() || Inputs
->empty()) {
902 Printf("ERROR: can't analyze dict without dict and corpus provided\n");
905 if (AnalyzeDictionary(F
, Dictionary
, InitialCorpus
)) {
906 Printf("Dictionary analysis failed\n");
909 Printf("Dictionary analysis succeeded\n");
913 auto CorporaFiles
= ReadCorpora(*Inputs
, ParseSeedInuts(Flags
.seed_inputs
));
914 F
->Loop(CorporaFiles
);
917 Printf("Done %zd runs in %zd second(s)\n", F
->getTotalNumberOfRuns(),
918 F
->secondsSinceProcessStartUp());
919 F
->PrintFinalStats();
921 exit(0); // Don't let F destroy itself.
924 extern "C" ATTRIBUTE_INTERFACE
int
925 LLVMFuzzerRunDriver(int *argc
, char ***argv
,
926 int (*UserCb
)(const uint8_t *Data
, size_t Size
)) {
927 return FuzzerDriver(argc
, argv
, UserCb
);
930 // Storage for global ExternalFunctions object.
931 ExternalFunctions
*EF
= nullptr;
933 } // namespace fuzzer