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
) {
232 ScopedDisableMsanInterceptorChecks S
;
234 unsigned C
= (*Counter
)++;
235 if (C
>= NumJobs
) break;
236 std::string Log
= "fuzz-" + std::to_string(C
) + ".log";
237 Command
Cmd(BaseCmd
);
238 Cmd
.setOutputFile(Log
);
239 Cmd
.combineOutAndErr();
240 if (Flags
.verbosity
) {
241 std::string CommandLine
= Cmd
.toString();
242 Printf("%s\n", CommandLine
.c_str());
244 int ExitCode
= ExecuteCommand(Cmd
);
247 std::lock_guard
<std::mutex
> Lock(Mu
);
248 Printf("================== Job %u exited with exit code %d ============\n",
250 fuzzer::CopyFileToErr(Log
);
254 static void ValidateDirectoryExists(const std::string
&Path
,
255 bool CreateDirectory
) {
257 Printf("ERROR: Provided directory path is an empty string\n");
261 if (IsDirectory(Path
))
264 if (CreateDirectory
) {
265 if (!MkDirRecursive(Path
)) {
266 Printf("ERROR: Failed to create directory \"%s\"\n", Path
.c_str());
272 Printf("ERROR: The required directory \"%s\" does not exist\n", Path
.c_str());
276 std::string
CloneArgsWithoutX(const std::vector
<std::string
> &Args
,
277 const char *X1
, const char *X2
) {
279 for (auto &S
: Args
) {
280 if (FlagValue(S
.c_str(), X1
) || FlagValue(S
.c_str(), X2
))
287 static int RunInMultipleProcesses(const std::vector
<std::string
> &Args
,
288 unsigned NumWorkers
, unsigned NumJobs
) {
289 std::atomic
<unsigned> Counter(0);
290 std::atomic
<bool> HasErrors(false);
292 Cmd
.removeFlag("jobs");
293 Cmd
.removeFlag("workers");
294 std::vector
<std::thread
> V
;
295 std::thread
Pulse(PulseThread
);
297 V
.resize(NumWorkers
);
298 for (unsigned i
= 0; i
< NumWorkers
; i
++) {
299 V
[i
] = std::thread(WorkerThread
, std::ref(Cmd
), &Counter
, NumJobs
,
301 SetThreadName(V
[i
], "FuzzerWorker");
305 return HasErrors
? 1 : 0;
308 static void RssThread(Fuzzer
*F
, size_t RssLimitMb
) {
311 size_t Peak
= GetPeakRSSMb();
312 if (Peak
> RssLimitMb
)
313 F
->RssLimitCallback();
317 static void StartRssThread(Fuzzer
*F
, size_t RssLimitMb
) {
320 std::thread
T(RssThread
, F
, RssLimitMb
);
324 int RunOneTest(Fuzzer
*F
, const char *InputFilePath
, size_t MaxLen
) {
325 Unit U
= FileToVector(InputFilePath
);
326 if (MaxLen
&& MaxLen
< U
.size())
328 F
->ExecuteCallback(U
.data(), U
.size());
329 if (Flags
.print_full_coverage
) {
330 // Leak detection is not needed when collecting full coverage data.
331 F
->TPCUpdateObservedPCs();
333 F
->TryDetectingAMemoryLeak(U
.data(), U
.size(), true);
338 static bool AllInputsAreFiles() {
339 if (Inputs
->empty()) return false;
340 for (auto &Path
: *Inputs
)
346 static std::string
GetDedupTokenFromCmdOutput(const std::string
&S
) {
347 auto Beg
= S
.find("DEDUP_TOKEN:");
348 if (Beg
== std::string::npos
)
350 auto End
= S
.find('\n', Beg
);
351 if (End
== std::string::npos
)
353 return S
.substr(Beg
, End
- Beg
);
356 int CleanseCrashInput(const std::vector
<std::string
> &Args
,
357 const FuzzingOptions
&Options
) {
358 if (Inputs
->size() != 1 || !Flags
.exact_artifact_path
) {
359 Printf("ERROR: -cleanse_crash should be given one input file and"
360 " -exact_artifact_path\n");
363 std::string InputFilePath
= Inputs
->at(0);
364 std::string OutputFilePath
= Flags
.exact_artifact_path
;
366 Cmd
.removeFlag("cleanse_crash");
368 assert(Cmd
.hasArgument(InputFilePath
));
369 Cmd
.removeArgument(InputFilePath
);
371 auto TmpFilePath
= TempPath("CleanseCrashInput", ".repro");
372 Cmd
.addArgument(TmpFilePath
);
373 Cmd
.setOutputFile(getDevNull());
374 Cmd
.combineOutAndErr();
376 std::string CurrentFilePath
= InputFilePath
;
377 auto U
= FileToVector(CurrentFilePath
);
378 size_t Size
= U
.size();
380 const std::vector
<uint8_t> ReplacementBytes
= {' ', 0xff};
381 for (int NumAttempts
= 0; NumAttempts
< 5; NumAttempts
++) {
382 bool Changed
= false;
383 for (size_t Idx
= 0; Idx
< Size
; Idx
++) {
384 Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts
,
386 uint8_t OriginalByte
= U
[Idx
];
387 if (ReplacementBytes
.end() != std::find(ReplacementBytes
.begin(),
388 ReplacementBytes
.end(),
391 for (auto NewByte
: ReplacementBytes
) {
393 WriteToFile(U
, TmpFilePath
);
394 auto ExitCode
= ExecuteCommand(Cmd
);
395 RemoveFile(TmpFilePath
);
397 U
[Idx
] = OriginalByte
;
400 Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx
, NewByte
);
401 WriteToFile(U
, OutputFilePath
);
411 int MinimizeCrashInput(const std::vector
<std::string
> &Args
,
412 const FuzzingOptions
&Options
) {
413 if (Inputs
->size() != 1) {
414 Printf("ERROR: -minimize_crash should be given one input file\n");
417 std::string InputFilePath
= Inputs
->at(0);
418 Command
BaseCmd(Args
);
419 BaseCmd
.removeFlag("minimize_crash");
420 BaseCmd
.removeFlag("exact_artifact_path");
421 assert(BaseCmd
.hasArgument(InputFilePath
));
422 BaseCmd
.removeArgument(InputFilePath
);
423 if (Flags
.runs
<= 0 && Flags
.max_total_time
== 0) {
424 Printf("INFO: you need to specify -runs=N or "
425 "-max_total_time=N with -minimize_crash=1\n"
426 "INFO: defaulting to -max_total_time=600\n");
427 BaseCmd
.addFlag("max_total_time", "600");
430 BaseCmd
.combineOutAndErr();
432 std::string CurrentFilePath
= InputFilePath
;
434 Unit U
= FileToVector(CurrentFilePath
);
435 Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
436 CurrentFilePath
.c_str(), U
.size());
438 Command
Cmd(BaseCmd
);
439 Cmd
.addArgument(CurrentFilePath
);
441 Printf("CRASH_MIN: executing: %s\n", Cmd
.toString().c_str());
442 std::string CmdOutput
;
443 bool Success
= ExecuteCommand(Cmd
, &CmdOutput
);
445 Printf("ERROR: the input %s did not crash\n", CurrentFilePath
.c_str());
448 Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
450 CurrentFilePath
.c_str(), U
.size());
451 auto DedupToken1
= GetDedupTokenFromCmdOutput(CmdOutput
);
452 if (!DedupToken1
.empty())
453 Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1
.c_str());
455 std::string ArtifactPath
=
456 Flags
.exact_artifact_path
457 ? Flags
.exact_artifact_path
458 : Options
.ArtifactPrefix
+ "minimized-from-" + Hash(U
);
459 Cmd
.addFlag("minimize_crash_internal_step", "1");
460 Cmd
.addFlag("exact_artifact_path", ArtifactPath
);
461 Printf("CRASH_MIN: executing: %s\n", Cmd
.toString().c_str());
463 Success
= ExecuteCommand(Cmd
, &CmdOutput
);
464 Printf("%s", CmdOutput
.c_str());
466 if (Flags
.exact_artifact_path
) {
467 CurrentFilePath
= Flags
.exact_artifact_path
;
468 WriteToFile(U
, CurrentFilePath
);
470 Printf("CRASH_MIN: failed to minimize beyond %s (%zu bytes), exiting\n",
471 CurrentFilePath
.c_str(), U
.size());
474 auto DedupToken2
= GetDedupTokenFromCmdOutput(CmdOutput
);
475 if (!DedupToken2
.empty())
476 Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2
.c_str());
478 if (DedupToken1
!= DedupToken2
) {
479 if (Flags
.exact_artifact_path
) {
480 CurrentFilePath
= Flags
.exact_artifact_path
;
481 WriteToFile(U
, CurrentFilePath
);
483 Printf("CRASH_MIN: mismatch in dedup tokens"
484 " (looks like a different bug). Won't minimize further\n");
488 CurrentFilePath
= ArtifactPath
;
489 Printf("*********************************\n");
494 int MinimizeCrashInputInternalStep(Fuzzer
*F
, InputCorpus
*Corpus
) {
495 assert(Inputs
->size() == 1);
496 std::string InputFilePath
= Inputs
->at(0);
497 Unit U
= FileToVector(InputFilePath
);
498 Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U
.size());
500 Printf("INFO: The input is small enough, exiting\n");
503 F
->SetMaxInputLen(U
.size());
504 F
->SetMaxMutationLen(U
.size() - 1);
505 F
->MinimizeCrashLoop(U
);
506 Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
510 void Merge(Fuzzer
*F
, FuzzingOptions
&Options
,
511 const std::vector
<std::string
> &Args
,
512 const std::vector
<std::string
> &Corpora
, const char *CFPathOrNull
) {
513 if (Corpora
.size() < 2) {
514 Printf("INFO: Merge requires two or more corpus dirs\n");
518 std::vector
<SizedFile
> OldCorpus
, NewCorpus
;
519 GetSizedFilesFromDir(Corpora
[0], &OldCorpus
);
520 for (size_t i
= 1; i
< Corpora
.size(); i
++)
521 GetSizedFilesFromDir(Corpora
[i
], &NewCorpus
);
522 std::sort(OldCorpus
.begin(), OldCorpus
.end());
523 std::sort(NewCorpus
.begin(), NewCorpus
.end());
525 std::string CFPath
= CFPathOrNull
? CFPathOrNull
: TempPath("Merge", ".txt");
526 std::vector
<std::string
> NewFiles
;
527 std::set
<uint32_t> NewFeatures
, NewCov
;
528 CrashResistantMerge(Args
, OldCorpus
, NewCorpus
, &NewFiles
, {}, &NewFeatures
,
529 {}, &NewCov
, CFPath
, true, Flags
.set_cover_merge
);
530 for (auto &Path
: NewFiles
)
531 F
->WriteToOutputCorpus(FileToVector(Path
, Options
.MaxLen
));
532 // We are done, delete the control file if it was a temporary one.
533 if (!Flags
.merge_control_file
)
539 int AnalyzeDictionary(Fuzzer
*F
, const std::vector
<Unit
> &Dict
,
540 UnitVector
&Corpus
) {
541 Printf("Started dictionary minimization (up to %zu tests)\n",
542 Dict
.size() * Corpus
.size() * 2);
544 // Scores and usage count for each dictionary unit.
545 std::vector
<int> Scores(Dict
.size());
546 std::vector
<int> Usages(Dict
.size());
548 std::vector
<size_t> InitialFeatures
;
549 std::vector
<size_t> ModifiedFeatures
;
550 for (auto &C
: Corpus
) {
551 // Get coverage for the testcase without modifications.
552 F
->ExecuteCallback(C
.data(), C
.size());
553 InitialFeatures
.clear();
554 TPC
.CollectFeatures([&](size_t Feature
) {
555 InitialFeatures
.push_back(Feature
);
558 for (size_t i
= 0; i
< Dict
.size(); ++i
) {
559 std::vector
<uint8_t> Data
= C
;
560 auto StartPos
= std::search(Data
.begin(), Data
.end(),
561 Dict
[i
].begin(), Dict
[i
].end());
562 // Skip dictionary unit, if the testcase does not contain it.
563 if (StartPos
== Data
.end())
567 while (StartPos
!= Data
.end()) {
568 // Replace all occurrences of dictionary unit in the testcase.
569 auto EndPos
= StartPos
+ Dict
[i
].size();
570 for (auto It
= StartPos
; It
!= EndPos
; ++It
)
573 StartPos
= std::search(EndPos
, Data
.end(),
574 Dict
[i
].begin(), Dict
[i
].end());
577 // Get coverage for testcase with masked occurrences of dictionary unit.
578 F
->ExecuteCallback(Data
.data(), Data
.size());
579 ModifiedFeatures
.clear();
580 TPC
.CollectFeatures([&](size_t Feature
) {
581 ModifiedFeatures
.push_back(Feature
);
584 if (InitialFeatures
== ModifiedFeatures
)
591 Printf("###### Useless dictionary elements. ######\n");
592 for (size_t i
= 0; i
< Dict
.size(); ++i
) {
593 // Dictionary units with positive score are treated as useful ones.
598 PrintASCII(Dict
[i
].data(), Dict
[i
].size(), "\"");
599 Printf(" # Score: %d, Used: %d\n", Scores
[i
], Usages
[i
]);
601 Printf("###### End of useless dictionary elements. ######\n");
605 std::vector
<std::string
> ParseSeedInuts(const char *seed_inputs
) {
606 // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file
607 std::vector
<std::string
> Files
;
608 if (!seed_inputs
) return Files
;
609 std::string SeedInputs
;
610 if (Flags
.seed_inputs
[0] == '@')
611 SeedInputs
= FileToString(Flags
.seed_inputs
+ 1); // File contains list.
613 SeedInputs
= Flags
.seed_inputs
; // seed_inputs contains the list.
614 if (SeedInputs
.empty()) {
615 Printf("seed_inputs is empty or @file does not exist.\n");
619 size_t comma_pos
= 0;
620 while ((comma_pos
= SeedInputs
.find_last_of(',')) != std::string::npos
) {
621 Files
.push_back(SeedInputs
.substr(comma_pos
+ 1));
622 SeedInputs
= SeedInputs
.substr(0, comma_pos
);
624 Files
.push_back(SeedInputs
);
628 static std::vector
<SizedFile
>
629 ReadCorpora(const std::vector
<std::string
> &CorpusDirs
,
630 const std::vector
<std::string
> &ExtraSeedFiles
) {
631 std::vector
<SizedFile
> SizedFiles
;
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
,
637 LastNumFiles
= SizedFiles
.size();
639 for (auto &File
: ExtraSeedFiles
)
640 if (auto Size
= FileSize(File
))
641 SizedFiles
.push_back({File
, Size
});
645 int FuzzerDriver(int *argc
, char ***argv
, UserCallback Callback
) {
646 using namespace fuzzer
;
647 assert(argc
&& argv
&& "Argument pointers cannot be nullptr");
648 std::string
Argv0((*argv
)[0]);
649 EF
= new ExternalFunctions();
650 if (EF
->LLVMFuzzerInitialize
)
651 EF
->LLVMFuzzerInitialize(argc
, argv
);
652 if (EF
->__msan_scoped_disable_interceptor_checks
)
653 EF
->__msan_scoped_disable_interceptor_checks();
654 const std::vector
<std::string
> Args(*argv
, *argv
+ *argc
);
655 assert(!Args
.empty());
656 ProgName
= new std::string(Args
[0]);
657 if (Argv0
!= *ProgName
) {
658 Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
661 ParseFlags(Args
, EF
);
667 if (Flags
.close_fd_mask
& 2)
669 if (Flags
.close_fd_mask
& 1)
672 if (Flags
.jobs
> 0 && Flags
.workers
== 0) {
673 Flags
.workers
= std::min(NumberOfCpuCores() / 2, Flags
.jobs
);
674 if (Flags
.workers
> 1)
675 Printf("Running %u workers\n", Flags
.workers
);
678 if (Flags
.workers
> 0 && Flags
.jobs
> 0)
679 return RunInMultipleProcesses(Args
, Flags
.workers
, Flags
.jobs
);
681 FuzzingOptions Options
;
682 Options
.Verbosity
= Flags
.verbosity
;
683 Options
.MaxLen
= Flags
.max_len
;
684 Options
.LenControl
= Flags
.len_control
;
685 Options
.KeepSeed
= Flags
.keep_seed
;
686 Options
.UnitTimeoutSec
= Flags
.timeout
;
687 Options
.ErrorExitCode
= Flags
.error_exitcode
;
688 Options
.TimeoutExitCode
= Flags
.timeout_exitcode
;
689 Options
.IgnoreTimeouts
= Flags
.ignore_timeouts
;
690 Options
.IgnoreOOMs
= Flags
.ignore_ooms
;
691 Options
.IgnoreCrashes
= Flags
.ignore_crashes
;
692 Options
.MaxTotalTimeSec
= Flags
.max_total_time
;
693 Options
.DoCrossOver
= Flags
.cross_over
;
694 Options
.CrossOverUniformDist
= Flags
.cross_over_uniform_dist
;
695 Options
.MutateDepth
= Flags
.mutate_depth
;
696 Options
.ReduceDepth
= Flags
.reduce_depth
;
697 Options
.UseCounters
= Flags
.use_counters
;
698 Options
.UseMemmem
= Flags
.use_memmem
;
699 Options
.UseCmp
= Flags
.use_cmp
;
700 Options
.UseValueProfile
= Flags
.use_value_profile
;
701 Options
.Shrink
= Flags
.shrink
;
702 Options
.ReduceInputs
= Flags
.reduce_inputs
;
703 Options
.ShuffleAtStartUp
= Flags
.shuffle
;
704 Options
.PreferSmall
= Flags
.prefer_small
;
705 Options
.ReloadIntervalSec
= Flags
.reload
;
706 Options
.OnlyASCII
= Flags
.only_ascii
;
707 Options
.DetectLeaks
= Flags
.detect_leaks
;
708 Options
.PurgeAllocatorIntervalSec
= Flags
.purge_allocator_interval
;
709 Options
.TraceMalloc
= Flags
.trace_malloc
;
710 Options
.RssLimitMb
= Flags
.rss_limit_mb
;
711 Options
.MallocLimitMb
= Flags
.malloc_limit_mb
;
712 if (!Options
.MallocLimitMb
)
713 Options
.MallocLimitMb
= Options
.RssLimitMb
;
715 Options
.MaxNumberOfRuns
= Flags
.runs
;
716 if (!Inputs
->empty() && !Flags
.minimize_crash_internal_step
) {
717 // Ensure output corpus assumed to be the first arbitrary argument input
718 // is not a path to an existing file.
719 std::string OutputCorpusDir
= (*Inputs
)[0];
720 if (!IsFile(OutputCorpusDir
)) {
721 Options
.OutputCorpus
= OutputCorpusDir
;
722 ValidateDirectoryExists(Options
.OutputCorpus
, Flags
.create_missing_dirs
);
725 Options
.ReportSlowUnits
= Flags
.report_slow_units
;
726 if (Flags
.artifact_prefix
) {
727 Options
.ArtifactPrefix
= Flags
.artifact_prefix
;
729 // Since the prefix could be a full path to a file name prefix, assume
730 // that if the path ends with the platform's separator that a directory
732 std::string ArtifactPathDir
= Options
.ArtifactPrefix
;
733 if (!IsSeparator(ArtifactPathDir
[ArtifactPathDir
.length() - 1])) {
734 ArtifactPathDir
= DirName(ArtifactPathDir
);
736 ValidateDirectoryExists(ArtifactPathDir
, Flags
.create_missing_dirs
);
738 if (Flags
.exact_artifact_path
) {
739 Options
.ExactArtifactPath
= Flags
.exact_artifact_path
;
740 ValidateDirectoryExists(DirName(Options
.ExactArtifactPath
),
741 Flags
.create_missing_dirs
);
743 std::vector
<Unit
> Dictionary
;
745 if (!ParseDictionaryFile(FileToString(Flags
.dict
), &Dictionary
))
747 if (Flags
.verbosity
> 0 && !Dictionary
.empty())
748 Printf("Dictionary: %zd entries\n", Dictionary
.size());
749 bool RunIndividualFiles
= AllInputsAreFiles();
750 Options
.SaveArtifacts
=
751 !RunIndividualFiles
|| Flags
.minimize_crash_internal_step
;
752 Options
.PrintNewCovPcs
= Flags
.print_pcs
;
753 Options
.PrintNewCovFuncs
= Flags
.print_funcs
;
754 Options
.PrintFinalStats
= Flags
.print_final_stats
;
755 Options
.PrintCorpusStats
= Flags
.print_corpus_stats
;
756 Options
.PrintCoverage
= Flags
.print_coverage
;
757 Options
.PrintFullCoverage
= Flags
.print_full_coverage
;
758 if (Flags
.exit_on_src_pos
)
759 Options
.ExitOnSrcPos
= Flags
.exit_on_src_pos
;
760 if (Flags
.exit_on_item
)
761 Options
.ExitOnItem
= Flags
.exit_on_item
;
762 if (Flags
.focus_function
)
763 Options
.FocusFunction
= Flags
.focus_function
;
764 if (Flags
.data_flow_trace
)
765 Options
.DataFlowTrace
= Flags
.data_flow_trace
;
766 if (Flags
.features_dir
) {
767 Options
.FeaturesDir
= Flags
.features_dir
;
768 ValidateDirectoryExists(Options
.FeaturesDir
, Flags
.create_missing_dirs
);
770 if (Flags
.mutation_graph_file
)
771 Options
.MutationGraphFile
= Flags
.mutation_graph_file
;
772 if (Flags
.collect_data_flow
)
773 Options
.CollectDataFlow
= Flags
.collect_data_flow
;
775 Options
.StopFile
= Flags
.stop_file
;
776 Options
.Entropic
= Flags
.entropic
;
777 Options
.EntropicFeatureFrequencyThreshold
=
778 (size_t)Flags
.entropic_feature_frequency_threshold
;
779 Options
.EntropicNumberOfRarestFeatures
=
780 (size_t)Flags
.entropic_number_of_rarest_features
;
781 Options
.EntropicScalePerExecTime
= Flags
.entropic_scale_per_exec_time
;
782 if (!Options
.FocusFunction
.empty())
783 Options
.Entropic
= false; // FocusFunction overrides entropic scheduling.
784 if (Options
.Entropic
)
785 Printf("INFO: Running with entropic power schedule (0x%zX, %zu).\n",
786 Options
.EntropicFeatureFrequencyThreshold
,
787 Options
.EntropicNumberOfRarestFeatures
);
788 struct EntropicOptions Entropic
;
789 Entropic
.Enabled
= Options
.Entropic
;
790 Entropic
.FeatureFrequencyThreshold
=
791 Options
.EntropicFeatureFrequencyThreshold
;
792 Entropic
.NumberOfRarestFeatures
= Options
.EntropicNumberOfRarestFeatures
;
793 Entropic
.ScalePerExecTime
= Options
.EntropicScalePerExecTime
;
795 unsigned Seed
= Flags
.seed
;
798 Seed
= static_cast<unsigned>(
799 std::chrono::system_clock::now().time_since_epoch().count() + GetPid());
801 Printf("INFO: Seed: %u\n", Seed
);
803 if (Flags
.collect_data_flow
&& Flags
.data_flow_trace
&& !Flags
.fork
&&
804 !(Flags
.merge
|| Flags
.set_cover_merge
)) {
805 if (RunIndividualFiles
)
806 return CollectDataFlow(Flags
.collect_data_flow
, Flags
.data_flow_trace
,
807 ReadCorpora({}, *Inputs
));
809 return CollectDataFlow(Flags
.collect_data_flow
, Flags
.data_flow_trace
,
810 ReadCorpora(*Inputs
, {}));
814 auto *MD
= new MutationDispatcher(Rand
, Options
);
815 auto *Corpus
= new InputCorpus(Options
.OutputCorpus
, Entropic
);
816 auto *F
= new Fuzzer(Callback
, *Corpus
, *MD
, Options
);
818 for (auto &U
: Dictionary
)
819 if (U
.size() <= Word::GetMaxSize())
820 MD
->AddWordToManualDictionary(Word(U
.data(), U
.size()));
822 // Threads are only supported by Chrome. Don't use them with emscripten
824 #if !LIBFUZZER_EMSCRIPTEN
825 StartRssThread(F
, Flags
.rss_limit_mb
);
826 #endif // LIBFUZZER_EMSCRIPTEN
828 Options
.HandleAbrt
= Flags
.handle_abrt
;
829 Options
.HandleAlrm
= !Flags
.minimize_crash
;
830 Options
.HandleBus
= Flags
.handle_bus
;
831 Options
.HandleFpe
= Flags
.handle_fpe
;
832 Options
.HandleIll
= Flags
.handle_ill
;
833 Options
.HandleInt
= Flags
.handle_int
;
834 Options
.HandleSegv
= Flags
.handle_segv
;
835 Options
.HandleTerm
= Flags
.handle_term
;
836 Options
.HandleXfsz
= Flags
.handle_xfsz
;
837 Options
.HandleUsr1
= Flags
.handle_usr1
;
838 Options
.HandleUsr2
= Flags
.handle_usr2
;
839 Options
.HandleWinExcept
= Flags
.handle_winexcept
;
841 SetSignalHandler(Options
);
843 std::atexit(Fuzzer::StaticExitCallback
);
845 if (Flags
.minimize_crash
)
846 return MinimizeCrashInput(Args
, Options
);
848 if (Flags
.minimize_crash_internal_step
)
849 return MinimizeCrashInputInternalStep(F
, Corpus
);
851 if (Flags
.cleanse_crash
)
852 return CleanseCrashInput(Args
, Options
);
854 if (RunIndividualFiles
) {
855 Options
.SaveArtifacts
= false;
856 int Runs
= std::max(1, Flags
.runs
);
857 Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName
->c_str(),
858 Inputs
->size(), Runs
);
859 for (auto &Path
: *Inputs
) {
860 auto StartTime
= system_clock::now();
861 Printf("Running: %s\n", Path
.c_str());
862 for (int Iter
= 0; Iter
< Runs
; Iter
++)
863 RunOneTest(F
, Path
.c_str(), Options
.MaxLen
);
864 auto StopTime
= system_clock::now();
865 auto MS
= duration_cast
<milliseconds
>(StopTime
- StartTime
).count();
866 Printf("Executed %s in %ld ms\n", Path
.c_str(), (long)MS
);
869 "*** NOTE: fuzzing was not performed, you have only\n"
870 "*** executed the target code on a fixed set of inputs.\n"
872 F
->PrintFinalStats();
876 Options
.ForkCorpusGroups
= Flags
.fork_corpus_groups
;
878 FuzzWithFork(F
->GetMD().GetRand(), Options
, Args
, *Inputs
, Flags
.fork
);
880 if (Flags
.merge
|| Flags
.set_cover_merge
)
881 Merge(F
, Options
, Args
, *Inputs
, Flags
.merge_control_file
);
883 if (Flags
.merge_inner
) {
884 const size_t kDefaultMaxMergeLen
= 1 << 20;
885 if (Options
.MaxLen
== 0)
886 F
->SetMaxInputLen(kDefaultMaxMergeLen
);
887 assert(Flags
.merge_control_file
);
888 F
->CrashResistantMergeInternalStep(Flags
.merge_control_file
,
889 !strncmp(Flags
.merge_inner
, "2", 1));
893 if (Flags
.analyze_dict
) {
894 size_t MaxLen
= INT_MAX
; // Large max length.
895 UnitVector InitialCorpus
;
896 for (auto &Inp
: *Inputs
) {
897 Printf("Loading corpus dir: %s\n", Inp
.c_str());
898 ReadDirToVectorOfUnits(Inp
.c_str(), &InitialCorpus
, nullptr,
899 MaxLen
, /*ExitOnError=*/false);
902 if (Dictionary
.empty() || Inputs
->empty()) {
903 Printf("ERROR: can't analyze dict without dict and corpus provided\n");
906 if (AnalyzeDictionary(F
, Dictionary
, InitialCorpus
)) {
907 Printf("Dictionary analysis failed\n");
910 Printf("Dictionary analysis succeeded\n");
914 auto CorporaFiles
= ReadCorpora(*Inputs
, ParseSeedInuts(Flags
.seed_inputs
));
915 F
->Loop(CorporaFiles
);
918 Printf("Done %zd runs in %zd second(s)\n", F
->getTotalNumberOfRuns(),
919 F
->secondsSinceProcessStartUp());
920 F
->PrintFinalStats();
922 exit(0); // Don't let F destroy itself.
925 extern "C" ATTRIBUTE_INTERFACE
int
926 LLVMFuzzerRunDriver(int *argc
, char ***argv
,
927 int (*UserCb
)(const uint8_t *Data
, size_t Size
)) {
928 return FuzzerDriver(argc
, argv
, UserCb
);
931 // Storage for global ExternalFunctions object.
932 ExternalFunctions
*EF
= nullptr;
934 } // namespace fuzzer