110ab2aceSGeorge Karpenkov //===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
210ab2aceSGeorge Karpenkov //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
610ab2aceSGeorge Karpenkov //
710ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
810ab2aceSGeorge Karpenkov // FuzzerDriver and flag parsing.
910ab2aceSGeorge Karpenkov //===----------------------------------------------------------------------===//
1010ab2aceSGeorge Karpenkov
1104304d12SMatt Morehouse #include "FuzzerCommand.h"
1210ab2aceSGeorge Karpenkov #include "FuzzerCorpus.h"
135c08e811SKostya Serebryany #include "FuzzerFork.h"
1410ab2aceSGeorge Karpenkov #include "FuzzerIO.h"
1510ab2aceSGeorge Karpenkov #include "FuzzerInterface.h"
1610ab2aceSGeorge Karpenkov #include "FuzzerInternal.h"
175c08e811SKostya Serebryany #include "FuzzerMerge.h"
1810ab2aceSGeorge Karpenkov #include "FuzzerMutate.h"
19226866e1SDokyung Song #include "FuzzerPlatform.h"
2010ab2aceSGeorge Karpenkov #include "FuzzerRandom.h"
2110ab2aceSGeorge Karpenkov #include "FuzzerTracePC.h"
2210ab2aceSGeorge Karpenkov #include <algorithm>
2310ab2aceSGeorge Karpenkov #include <atomic>
2410ab2aceSGeorge Karpenkov #include <chrono>
2510ab2aceSGeorge Karpenkov #include <cstdlib>
2610ab2aceSGeorge Karpenkov #include <cstring>
2710ab2aceSGeorge Karpenkov #include <mutex>
2810ab2aceSGeorge Karpenkov #include <string>
2910ab2aceSGeorge Karpenkov #include <thread>
30c5d72517SMarco Vanotti #include <fstream>
3110ab2aceSGeorge Karpenkov
3210ab2aceSGeorge Karpenkov // This function should be present in the libFuzzer so that the client
3310ab2aceSGeorge Karpenkov // binary can test for its existence.
34b795c31dSJonathan Metzman #if LIBFUZZER_MSVC
__libfuzzer_is_present()35b795c31dSJonathan Metzman extern "C" void __libfuzzer_is_present() {}
36c12f1118SVitaly Buka #if defined(_M_IX86) || defined(__i386__)
37c12f1118SVitaly Buka #pragma comment(linker, "/include:___libfuzzer_is_present")
38c12f1118SVitaly Buka #else
39b795c31dSJonathan Metzman #pragma comment(linker, "/include:__libfuzzer_is_present")
40c12f1118SVitaly Buka #endif
41b795c31dSJonathan Metzman #else
__libfuzzer_is_present()4210ab2aceSGeorge Karpenkov extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
43b795c31dSJonathan Metzman #endif // LIBFUZZER_MSVC
4410ab2aceSGeorge Karpenkov
4510ab2aceSGeorge Karpenkov namespace fuzzer {
4610ab2aceSGeorge Karpenkov
4710ab2aceSGeorge Karpenkov // Program arguments.
4810ab2aceSGeorge Karpenkov struct FlagDescription {
4910ab2aceSGeorge Karpenkov const char *Name;
5010ab2aceSGeorge Karpenkov const char *Description;
5110ab2aceSGeorge Karpenkov int Default;
5210ab2aceSGeorge Karpenkov int *IntFlag;
5310ab2aceSGeorge Karpenkov const char **StrFlag;
5410ab2aceSGeorge Karpenkov unsigned int *UIntFlag;
5510ab2aceSGeorge Karpenkov };
5610ab2aceSGeorge Karpenkov
5710ab2aceSGeorge Karpenkov struct {
5810ab2aceSGeorge Karpenkov #define FUZZER_DEPRECATED_FLAG(Name)
5910ab2aceSGeorge Karpenkov #define FUZZER_FLAG_INT(Name, Default, Description) int Name;
6010ab2aceSGeorge Karpenkov #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
6110ab2aceSGeorge Karpenkov #define FUZZER_FLAG_STRING(Name, Description) const char *Name;
6210ab2aceSGeorge Karpenkov #include "FuzzerFlags.def"
6310ab2aceSGeorge Karpenkov #undef FUZZER_DEPRECATED_FLAG
6410ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_INT
6510ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_UNSIGNED
6610ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_STRING
6710ab2aceSGeorge Karpenkov } Flags;
6810ab2aceSGeorge Karpenkov
6910ab2aceSGeorge Karpenkov static const FlagDescription FlagDescriptions [] {
7010ab2aceSGeorge Karpenkov #define FUZZER_DEPRECATED_FLAG(Name) \
7110ab2aceSGeorge Karpenkov {#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
7210ab2aceSGeorge Karpenkov #define FUZZER_FLAG_INT(Name, Default, Description) \
7310ab2aceSGeorge Karpenkov {#Name, Description, Default, &Flags.Name, nullptr, nullptr},
7410ab2aceSGeorge Karpenkov #define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \
7510ab2aceSGeorge Karpenkov {#Name, Description, static_cast<int>(Default), \
7610ab2aceSGeorge Karpenkov nullptr, nullptr, &Flags.Name},
7710ab2aceSGeorge Karpenkov #define FUZZER_FLAG_STRING(Name, Description) \
7810ab2aceSGeorge Karpenkov {#Name, Description, 0, nullptr, &Flags.Name, nullptr},
7910ab2aceSGeorge Karpenkov #include "FuzzerFlags.def"
8010ab2aceSGeorge Karpenkov #undef FUZZER_DEPRECATED_FLAG
8110ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_INT
8210ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_UNSIGNED
8310ab2aceSGeorge Karpenkov #undef FUZZER_FLAG_STRING
8410ab2aceSGeorge Karpenkov };
8510ab2aceSGeorge Karpenkov
8610ab2aceSGeorge Karpenkov static const size_t kNumFlags =
8710ab2aceSGeorge Karpenkov sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
8810ab2aceSGeorge Karpenkov
897c921753SKostya Serebryany static std::vector<std::string> *Inputs;
9010ab2aceSGeorge Karpenkov static std::string *ProgName;
9110ab2aceSGeorge Karpenkov
PrintHelp()9210ab2aceSGeorge Karpenkov static void PrintHelp() {
9310ab2aceSGeorge Karpenkov Printf("Usage:\n");
9410ab2aceSGeorge Karpenkov auto Prog = ProgName->c_str();
9510ab2aceSGeorge Karpenkov Printf("\nTo run fuzzing pass 0 or more directories.\n");
9610ab2aceSGeorge Karpenkov Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
9710ab2aceSGeorge Karpenkov
9810ab2aceSGeorge Karpenkov Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n");
9910ab2aceSGeorge Karpenkov Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog);
10010ab2aceSGeorge Karpenkov
10110ab2aceSGeorge Karpenkov Printf("\nFlags: (strictly in form -flag=value)\n");
10210ab2aceSGeorge Karpenkov size_t MaxFlagLen = 0;
10310ab2aceSGeorge Karpenkov for (size_t F = 0; F < kNumFlags; F++)
10410ab2aceSGeorge Karpenkov MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
10510ab2aceSGeorge Karpenkov
10610ab2aceSGeorge Karpenkov for (size_t F = 0; F < kNumFlags; F++) {
10710ab2aceSGeorge Karpenkov const auto &D = FlagDescriptions[F];
10810ab2aceSGeorge Karpenkov if (strstr(D.Description, "internal flag") == D.Description) continue;
10910ab2aceSGeorge Karpenkov Printf(" %s", D.Name);
11010ab2aceSGeorge Karpenkov for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
11110ab2aceSGeorge Karpenkov Printf(" ");
11210ab2aceSGeorge Karpenkov Printf("\t");
11310ab2aceSGeorge Karpenkov Printf("%d\t%s\n", D.Default, D.Description);
11410ab2aceSGeorge Karpenkov }
11510ab2aceSGeorge Karpenkov Printf("\nFlags starting with '--' will be ignored and "
11610ab2aceSGeorge Karpenkov "will be passed verbatim to subprocesses.\n");
11710ab2aceSGeorge Karpenkov }
11810ab2aceSGeorge Karpenkov
FlagValue(const char * Param,const char * Name)11910ab2aceSGeorge Karpenkov static const char *FlagValue(const char *Param, const char *Name) {
12010ab2aceSGeorge Karpenkov size_t Len = strlen(Name);
12110ab2aceSGeorge Karpenkov if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
12210ab2aceSGeorge Karpenkov Param[Len + 1] == '=')
12310ab2aceSGeorge Karpenkov return &Param[Len + 2];
12410ab2aceSGeorge Karpenkov return nullptr;
12510ab2aceSGeorge Karpenkov }
12610ab2aceSGeorge Karpenkov
12710ab2aceSGeorge Karpenkov // Avoid calling stol as it triggers a bug in clang/glibc build.
MyStol(const char * Str)12810ab2aceSGeorge Karpenkov static long MyStol(const char *Str) {
12910ab2aceSGeorge Karpenkov long Res = 0;
13010ab2aceSGeorge Karpenkov long Sign = 1;
13110ab2aceSGeorge Karpenkov if (*Str == '-') {
13210ab2aceSGeorge Karpenkov Str++;
13310ab2aceSGeorge Karpenkov Sign = -1;
13410ab2aceSGeorge Karpenkov }
13510ab2aceSGeorge Karpenkov for (size_t i = 0; Str[i]; i++) {
13610ab2aceSGeorge Karpenkov char Ch = Str[i];
13710ab2aceSGeorge Karpenkov if (Ch < '0' || Ch > '9')
13810ab2aceSGeorge Karpenkov return Res;
13910ab2aceSGeorge Karpenkov Res = Res * 10 + (Ch - '0');
14010ab2aceSGeorge Karpenkov }
14110ab2aceSGeorge Karpenkov return Res * Sign;
14210ab2aceSGeorge Karpenkov }
14310ab2aceSGeorge Karpenkov
ParseOneFlag(const char * Param)14410ab2aceSGeorge Karpenkov static bool ParseOneFlag(const char *Param) {
14510ab2aceSGeorge Karpenkov if (Param[0] != '-') return false;
14610ab2aceSGeorge Karpenkov if (Param[1] == '-') {
14710ab2aceSGeorge Karpenkov static bool PrintedWarning = false;
14810ab2aceSGeorge Karpenkov if (!PrintedWarning) {
14910ab2aceSGeorge Karpenkov PrintedWarning = true;
15010ab2aceSGeorge Karpenkov Printf("INFO: libFuzzer ignores flags that start with '--'\n");
15110ab2aceSGeorge Karpenkov }
15210ab2aceSGeorge Karpenkov for (size_t F = 0; F < kNumFlags; F++)
15310ab2aceSGeorge Karpenkov if (FlagValue(Param + 1, FlagDescriptions[F].Name))
15410ab2aceSGeorge Karpenkov Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1);
15510ab2aceSGeorge Karpenkov return true;
15610ab2aceSGeorge Karpenkov }
15710ab2aceSGeorge Karpenkov for (size_t F = 0; F < kNumFlags; F++) {
15810ab2aceSGeorge Karpenkov const char *Name = FlagDescriptions[F].Name;
15910ab2aceSGeorge Karpenkov const char *Str = FlagValue(Param, Name);
16010ab2aceSGeorge Karpenkov if (Str) {
16110ab2aceSGeorge Karpenkov if (FlagDescriptions[F].IntFlag) {
1626708186cSAaron Green auto Val = MyStol(Str);
1636708186cSAaron Green *FlagDescriptions[F].IntFlag = static_cast<int>(Val);
16410ab2aceSGeorge Karpenkov if (Flags.verbosity >= 2)
16510ab2aceSGeorge Karpenkov Printf("Flag: %s %d\n", Name, Val);
16610ab2aceSGeorge Karpenkov return true;
16710ab2aceSGeorge Karpenkov } else if (FlagDescriptions[F].UIntFlag) {
1686708186cSAaron Green auto Val = std::stoul(Str);
1696708186cSAaron Green *FlagDescriptions[F].UIntFlag = static_cast<unsigned int>(Val);
17010ab2aceSGeorge Karpenkov if (Flags.verbosity >= 2)
17110ab2aceSGeorge Karpenkov Printf("Flag: %s %u\n", Name, Val);
17210ab2aceSGeorge Karpenkov return true;
17310ab2aceSGeorge Karpenkov } else if (FlagDescriptions[F].StrFlag) {
17410ab2aceSGeorge Karpenkov *FlagDescriptions[F].StrFlag = Str;
17510ab2aceSGeorge Karpenkov if (Flags.verbosity >= 2)
17610ab2aceSGeorge Karpenkov Printf("Flag: %s %s\n", Name, Str);
17710ab2aceSGeorge Karpenkov return true;
17810ab2aceSGeorge Karpenkov } else { // Deprecated flag.
17910ab2aceSGeorge Karpenkov Printf("Flag: %s: deprecated, don't use\n", Name);
18010ab2aceSGeorge Karpenkov return true;
18110ab2aceSGeorge Karpenkov }
18210ab2aceSGeorge Karpenkov }
18310ab2aceSGeorge Karpenkov }
18410ab2aceSGeorge Karpenkov Printf("\n\nWARNING: unrecognized flag '%s'; "
18510ab2aceSGeorge Karpenkov "use -help=1 to list all flags\n\n", Param);
18610ab2aceSGeorge Karpenkov return true;
18710ab2aceSGeorge Karpenkov }
18810ab2aceSGeorge Karpenkov
18910ab2aceSGeorge Karpenkov // We don't use any library to minimize dependencies.
ParseFlags(const std::vector<std::string> & Args,const ExternalFunctions * EF)1907c921753SKostya Serebryany static void ParseFlags(const std::vector<std::string> &Args,
1910784e01aSMax Moroz const ExternalFunctions *EF) {
19210ab2aceSGeorge Karpenkov for (size_t F = 0; F < kNumFlags; F++) {
19310ab2aceSGeorge Karpenkov if (FlagDescriptions[F].IntFlag)
19410ab2aceSGeorge Karpenkov *FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
19510ab2aceSGeorge Karpenkov if (FlagDescriptions[F].UIntFlag)
19610ab2aceSGeorge Karpenkov *FlagDescriptions[F].UIntFlag =
19710ab2aceSGeorge Karpenkov static_cast<unsigned int>(FlagDescriptions[F].Default);
19810ab2aceSGeorge Karpenkov if (FlagDescriptions[F].StrFlag)
19910ab2aceSGeorge Karpenkov *FlagDescriptions[F].StrFlag = nullptr;
20010ab2aceSGeorge Karpenkov }
2010784e01aSMax Moroz
2020784e01aSMax Moroz // Disable len_control by default, if LLVMFuzzerCustomMutator is used.
20315f1d5d1SMax Moroz if (EF->LLVMFuzzerCustomMutator) {
2040784e01aSMax Moroz Flags.len_control = 0;
20515f1d5d1SMax Moroz Printf("INFO: found LLVMFuzzerCustomMutator (%p). "
20615f1d5d1SMax Moroz "Disabling -len_control by default.\n", EF->LLVMFuzzerCustomMutator);
20715f1d5d1SMax Moroz }
2080784e01aSMax Moroz
2097c921753SKostya Serebryany Inputs = new std::vector<std::string>;
21010ab2aceSGeorge Karpenkov for (size_t A = 1; A < Args.size(); A++) {
21110ab2aceSGeorge Karpenkov if (ParseOneFlag(Args[A].c_str())) {
21210ab2aceSGeorge Karpenkov if (Flags.ignore_remaining_args)
21310ab2aceSGeorge Karpenkov break;
21410ab2aceSGeorge Karpenkov continue;
21510ab2aceSGeorge Karpenkov }
21610ab2aceSGeorge Karpenkov Inputs->push_back(Args[A]);
21710ab2aceSGeorge Karpenkov }
21810ab2aceSGeorge Karpenkov }
21910ab2aceSGeorge Karpenkov
22010ab2aceSGeorge Karpenkov static std::mutex Mu;
22110ab2aceSGeorge Karpenkov
PulseThread()22210ab2aceSGeorge Karpenkov static void PulseThread() {
22310ab2aceSGeorge Karpenkov while (true) {
22410ab2aceSGeorge Karpenkov SleepSeconds(600);
22510ab2aceSGeorge Karpenkov std::lock_guard<std::mutex> Lock(Mu);
22610ab2aceSGeorge Karpenkov Printf("pulse...\n");
22710ab2aceSGeorge Karpenkov }
22810ab2aceSGeorge Karpenkov }
22910ab2aceSGeorge Karpenkov
WorkerThread(const Command & BaseCmd,std::atomic<unsigned> * Counter,unsigned NumJobs,std::atomic<bool> * HasErrors)23004304d12SMatt Morehouse static void WorkerThread(const Command &BaseCmd, std::atomic<unsigned> *Counter,
23110ab2aceSGeorge Karpenkov unsigned NumJobs, std::atomic<bool> *HasErrors) {
232*d9ce33a0SThurston Dang ScopedDisableMsanInterceptorChecks S;
23310ab2aceSGeorge Karpenkov while (true) {
23410ab2aceSGeorge Karpenkov unsigned C = (*Counter)++;
23510ab2aceSGeorge Karpenkov if (C >= NumJobs) break;
23610ab2aceSGeorge Karpenkov std::string Log = "fuzz-" + std::to_string(C) + ".log";
23704304d12SMatt Morehouse Command Cmd(BaseCmd);
23804304d12SMatt Morehouse Cmd.setOutputFile(Log);
23904304d12SMatt Morehouse Cmd.combineOutAndErr();
24004304d12SMatt Morehouse if (Flags.verbosity) {
24104304d12SMatt Morehouse std::string CommandLine = Cmd.toString();
2427ac58ee3SKostya Serebryany Printf("%s\n", CommandLine.c_str());
24304304d12SMatt Morehouse }
24404304d12SMatt Morehouse int ExitCode = ExecuteCommand(Cmd);
24510ab2aceSGeorge Karpenkov if (ExitCode != 0)
24610ab2aceSGeorge Karpenkov *HasErrors = true;
24710ab2aceSGeorge Karpenkov std::lock_guard<std::mutex> Lock(Mu);
24810ab2aceSGeorge Karpenkov Printf("================== Job %u exited with exit code %d ============\n",
24910ab2aceSGeorge Karpenkov C, ExitCode);
25010ab2aceSGeorge Karpenkov fuzzer::CopyFileToErr(Log);
25110ab2aceSGeorge Karpenkov }
25210ab2aceSGeorge Karpenkov }
25310ab2aceSGeorge Karpenkov
ValidateDirectoryExists(const std::string & Path,bool CreateDirectory)254711b9806SMatt Morehouse static void ValidateDirectoryExists(const std::string &Path,
255711b9806SMatt Morehouse bool CreateDirectory) {
256711b9806SMatt Morehouse if (Path.empty()) {
257711b9806SMatt Morehouse Printf("ERROR: Provided directory path is an empty string\n");
258cb891279SMatt Morehouse exit(1);
2592392ff09SMatt Morehouse }
260711b9806SMatt Morehouse
261711b9806SMatt Morehouse if (IsDirectory(Path))
262711b9806SMatt Morehouse return;
263711b9806SMatt Morehouse
264711b9806SMatt Morehouse if (CreateDirectory) {
265711b9806SMatt Morehouse if (!MkDirRecursive(Path)) {
266711b9806SMatt Morehouse Printf("ERROR: Failed to create directory \"%s\"\n", Path.c_str());
267711b9806SMatt Morehouse exit(1);
268711b9806SMatt Morehouse }
269711b9806SMatt Morehouse return;
270711b9806SMatt Morehouse }
271711b9806SMatt Morehouse
272711b9806SMatt Morehouse Printf("ERROR: The required directory \"%s\" does not exist\n", Path.c_str());
273711b9806SMatt Morehouse exit(1);
27410670bdfSMatt Morehouse }
2752392ff09SMatt Morehouse
CloneArgsWithoutX(const std::vector<std::string> & Args,const char * X1,const char * X2)2767c921753SKostya Serebryany std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
27710ab2aceSGeorge Karpenkov const char *X1, const char *X2) {
27810ab2aceSGeorge Karpenkov std::string Cmd;
27910ab2aceSGeorge Karpenkov for (auto &S : Args) {
28010ab2aceSGeorge Karpenkov if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
28110ab2aceSGeorge Karpenkov continue;
28210ab2aceSGeorge Karpenkov Cmd += S + " ";
28310ab2aceSGeorge Karpenkov }
28410ab2aceSGeorge Karpenkov return Cmd;
28510ab2aceSGeorge Karpenkov }
28610ab2aceSGeorge Karpenkov
RunInMultipleProcesses(const std::vector<std::string> & Args,unsigned NumWorkers,unsigned NumJobs)2877c921753SKostya Serebryany static int RunInMultipleProcesses(const std::vector<std::string> &Args,
28810ab2aceSGeorge Karpenkov unsigned NumWorkers, unsigned NumJobs) {
28910ab2aceSGeorge Karpenkov std::atomic<unsigned> Counter(0);
29010ab2aceSGeorge Karpenkov std::atomic<bool> HasErrors(false);
29104304d12SMatt Morehouse Command Cmd(Args);
29204304d12SMatt Morehouse Cmd.removeFlag("jobs");
29304304d12SMatt Morehouse Cmd.removeFlag("workers");
2947c921753SKostya Serebryany std::vector<std::thread> V;
29510ab2aceSGeorge Karpenkov std::thread Pulse(PulseThread);
29610ab2aceSGeorge Karpenkov Pulse.detach();
297b2a25385SDavid CARLIER V.resize(NumWorkers);
298b2a25385SDavid CARLIER for (unsigned i = 0; i < NumWorkers; i++) {
299b2a25385SDavid CARLIER V[i] = std::thread(WorkerThread, std::ref(Cmd), &Counter, NumJobs,
300b2a25385SDavid CARLIER &HasErrors);
301b2a25385SDavid CARLIER SetThreadName(V[i], "FuzzerWorker");
302b2a25385SDavid CARLIER }
30310ab2aceSGeorge Karpenkov for (auto &T : V)
30410ab2aceSGeorge Karpenkov T.join();
30510ab2aceSGeorge Karpenkov return HasErrors ? 1 : 0;
30610ab2aceSGeorge Karpenkov }
30710ab2aceSGeorge Karpenkov
RssThread(Fuzzer * F,size_t RssLimitMb)30810ab2aceSGeorge Karpenkov static void RssThread(Fuzzer *F, size_t RssLimitMb) {
30910ab2aceSGeorge Karpenkov while (true) {
31010ab2aceSGeorge Karpenkov SleepSeconds(1);
31110ab2aceSGeorge Karpenkov size_t Peak = GetPeakRSSMb();
31210ab2aceSGeorge Karpenkov if (Peak > RssLimitMb)
31310ab2aceSGeorge Karpenkov F->RssLimitCallback();
31410ab2aceSGeorge Karpenkov }
31510ab2aceSGeorge Karpenkov }
31610ab2aceSGeorge Karpenkov
StartRssThread(Fuzzer * F,size_t RssLimitMb)31710ab2aceSGeorge Karpenkov static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
31823bee0b0SJonathan Metzman if (!RssLimitMb)
31923bee0b0SJonathan Metzman return;
32010ab2aceSGeorge Karpenkov std::thread T(RssThread, F, RssLimitMb);
32110ab2aceSGeorge Karpenkov T.detach();
32210ab2aceSGeorge Karpenkov }
32310ab2aceSGeorge Karpenkov
RunOneTest(Fuzzer * F,const char * InputFilePath,size_t MaxLen)32410ab2aceSGeorge Karpenkov int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
32510ab2aceSGeorge Karpenkov Unit U = FileToVector(InputFilePath);
32610ab2aceSGeorge Karpenkov if (MaxLen && MaxLen < U.size())
32710ab2aceSGeorge Karpenkov U.resize(MaxLen);
32810ab2aceSGeorge Karpenkov F->ExecuteCallback(U.data(), U.size());
329dc62d5ecSMax Moroz if (Flags.print_full_coverage) {
330dc62d5ecSMax Moroz // Leak detection is not needed when collecting full coverage data.
331dc62d5ecSMax Moroz F->TPCUpdateObservedPCs();
332dc62d5ecSMax Moroz } else {
33310ab2aceSGeorge Karpenkov F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
334dc62d5ecSMax Moroz }
33510ab2aceSGeorge Karpenkov return 0;
33610ab2aceSGeorge Karpenkov }
33710ab2aceSGeorge Karpenkov
AllInputsAreFiles()33810ab2aceSGeorge Karpenkov static bool AllInputsAreFiles() {
33910ab2aceSGeorge Karpenkov if (Inputs->empty()) return false;
34010ab2aceSGeorge Karpenkov for (auto &Path : *Inputs)
34110ab2aceSGeorge Karpenkov if (!IsFile(Path))
34210ab2aceSGeorge Karpenkov return false;
34310ab2aceSGeorge Karpenkov return true;
34410ab2aceSGeorge Karpenkov }
34510ab2aceSGeorge Karpenkov
GetDedupTokenFromCmdOutput(const std::string & S)34685515c7fSYuanfang Chen static std::string GetDedupTokenFromCmdOutput(const std::string &S) {
34710ab2aceSGeorge Karpenkov auto Beg = S.find("DEDUP_TOKEN:");
34810ab2aceSGeorge Karpenkov if (Beg == std::string::npos)
34910ab2aceSGeorge Karpenkov return "";
35010ab2aceSGeorge Karpenkov auto End = S.find('\n', Beg);
35110ab2aceSGeorge Karpenkov if (End == std::string::npos)
35210ab2aceSGeorge Karpenkov return "";
35310ab2aceSGeorge Karpenkov return S.substr(Beg, End - Beg);
35410ab2aceSGeorge Karpenkov }
35510ab2aceSGeorge Karpenkov
CleanseCrashInput(const std::vector<std::string> & Args,const FuzzingOptions & Options)3567c921753SKostya Serebryany int CleanseCrashInput(const std::vector<std::string> &Args,
35710ab2aceSGeorge Karpenkov const FuzzingOptions &Options) {
35810ab2aceSGeorge Karpenkov if (Inputs->size() != 1 || !Flags.exact_artifact_path) {
35910ab2aceSGeorge Karpenkov Printf("ERROR: -cleanse_crash should be given one input file and"
36010ab2aceSGeorge Karpenkov " -exact_artifact_path\n");
36110ab2aceSGeorge Karpenkov exit(1);
36210ab2aceSGeorge Karpenkov }
36310ab2aceSGeorge Karpenkov std::string InputFilePath = Inputs->at(0);
36410ab2aceSGeorge Karpenkov std::string OutputFilePath = Flags.exact_artifact_path;
36504304d12SMatt Morehouse Command Cmd(Args);
36604304d12SMatt Morehouse Cmd.removeFlag("cleanse_crash");
36710ab2aceSGeorge Karpenkov
36804304d12SMatt Morehouse assert(Cmd.hasArgument(InputFilePath));
36904304d12SMatt Morehouse Cmd.removeArgument(InputFilePath);
37010ab2aceSGeorge Karpenkov
3714f3c3bbbSYuanfang Chen auto TmpFilePath = TempPath("CleanseCrashInput", ".repro");
37204304d12SMatt Morehouse Cmd.addArgument(TmpFilePath);
37385515c7fSYuanfang Chen Cmd.setOutputFile(getDevNull());
37404304d12SMatt Morehouse Cmd.combineOutAndErr();
37510ab2aceSGeorge Karpenkov
37610ab2aceSGeorge Karpenkov std::string CurrentFilePath = InputFilePath;
37710ab2aceSGeorge Karpenkov auto U = FileToVector(CurrentFilePath);
37810ab2aceSGeorge Karpenkov size_t Size = U.size();
37910ab2aceSGeorge Karpenkov
3807c921753SKostya Serebryany const std::vector<uint8_t> ReplacementBytes = {' ', 0xff};
38110ab2aceSGeorge Karpenkov for (int NumAttempts = 0; NumAttempts < 5; NumAttempts++) {
38210ab2aceSGeorge Karpenkov bool Changed = false;
38310ab2aceSGeorge Karpenkov for (size_t Idx = 0; Idx < Size; Idx++) {
38410ab2aceSGeorge Karpenkov Printf("CLEANSE[%d]: Trying to replace byte %zd of %zd\n", NumAttempts,
38510ab2aceSGeorge Karpenkov Idx, Size);
38610ab2aceSGeorge Karpenkov uint8_t OriginalByte = U[Idx];
38710ab2aceSGeorge Karpenkov if (ReplacementBytes.end() != std::find(ReplacementBytes.begin(),
38810ab2aceSGeorge Karpenkov ReplacementBytes.end(),
38910ab2aceSGeorge Karpenkov OriginalByte))
39010ab2aceSGeorge Karpenkov continue;
39110ab2aceSGeorge Karpenkov for (auto NewByte : ReplacementBytes) {
39210ab2aceSGeorge Karpenkov U[Idx] = NewByte;
39310ab2aceSGeorge Karpenkov WriteToFile(U, TmpFilePath);
39410ab2aceSGeorge Karpenkov auto ExitCode = ExecuteCommand(Cmd);
39510ab2aceSGeorge Karpenkov RemoveFile(TmpFilePath);
39610ab2aceSGeorge Karpenkov if (!ExitCode) {
39710ab2aceSGeorge Karpenkov U[Idx] = OriginalByte;
39810ab2aceSGeorge Karpenkov } else {
39910ab2aceSGeorge Karpenkov Changed = true;
40010ab2aceSGeorge Karpenkov Printf("CLEANSE: Replaced byte %zd with 0x%x\n", Idx, NewByte);
40110ab2aceSGeorge Karpenkov WriteToFile(U, OutputFilePath);
40210ab2aceSGeorge Karpenkov break;
40310ab2aceSGeorge Karpenkov }
40410ab2aceSGeorge Karpenkov }
40510ab2aceSGeorge Karpenkov }
40610ab2aceSGeorge Karpenkov if (!Changed) break;
40710ab2aceSGeorge Karpenkov }
40810ab2aceSGeorge Karpenkov return 0;
40910ab2aceSGeorge Karpenkov }
41010ab2aceSGeorge Karpenkov
MinimizeCrashInput(const std::vector<std::string> & Args,const FuzzingOptions & Options)4117c921753SKostya Serebryany int MinimizeCrashInput(const std::vector<std::string> &Args,
41210ab2aceSGeorge Karpenkov const FuzzingOptions &Options) {
41310ab2aceSGeorge Karpenkov if (Inputs->size() != 1) {
41410ab2aceSGeorge Karpenkov Printf("ERROR: -minimize_crash should be given one input file\n");
41510ab2aceSGeorge Karpenkov exit(1);
41610ab2aceSGeorge Karpenkov }
41710ab2aceSGeorge Karpenkov std::string InputFilePath = Inputs->at(0);
41804304d12SMatt Morehouse Command BaseCmd(Args);
41904304d12SMatt Morehouse BaseCmd.removeFlag("minimize_crash");
42004304d12SMatt Morehouse BaseCmd.removeFlag("exact_artifact_path");
42104304d12SMatt Morehouse assert(BaseCmd.hasArgument(InputFilePath));
42204304d12SMatt Morehouse BaseCmd.removeArgument(InputFilePath);
42310ab2aceSGeorge Karpenkov if (Flags.runs <= 0 && Flags.max_total_time == 0) {
42410ab2aceSGeorge Karpenkov Printf("INFO: you need to specify -runs=N or "
42510ab2aceSGeorge Karpenkov "-max_total_time=N with -minimize_crash=1\n"
42610ab2aceSGeorge Karpenkov "INFO: defaulting to -max_total_time=600\n");
42704304d12SMatt Morehouse BaseCmd.addFlag("max_total_time", "600");
42810ab2aceSGeorge Karpenkov }
42910ab2aceSGeorge Karpenkov
43004304d12SMatt Morehouse BaseCmd.combineOutAndErr();
43110ab2aceSGeorge Karpenkov
43210ab2aceSGeorge Karpenkov std::string CurrentFilePath = InputFilePath;
43310ab2aceSGeorge Karpenkov while (true) {
43410ab2aceSGeorge Karpenkov Unit U = FileToVector(CurrentFilePath);
43510ab2aceSGeorge Karpenkov Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
43610ab2aceSGeorge Karpenkov CurrentFilePath.c_str(), U.size());
43710ab2aceSGeorge Karpenkov
43804304d12SMatt Morehouse Command Cmd(BaseCmd);
43904304d12SMatt Morehouse Cmd.addArgument(CurrentFilePath);
44010ab2aceSGeorge Karpenkov
44185515c7fSYuanfang Chen Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
44285515c7fSYuanfang Chen std::string CmdOutput;
4434caeb62eSYuanfang Chen bool Success = ExecuteCommand(Cmd, &CmdOutput);
44485515c7fSYuanfang Chen if (Success) {
44510ab2aceSGeorge Karpenkov Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
44610ab2aceSGeorge Karpenkov exit(1);
44710ab2aceSGeorge Karpenkov }
44810ab2aceSGeorge Karpenkov Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
44910ab2aceSGeorge Karpenkov "it further\n",
45010ab2aceSGeorge Karpenkov CurrentFilePath.c_str(), U.size());
45185515c7fSYuanfang Chen auto DedupToken1 = GetDedupTokenFromCmdOutput(CmdOutput);
45210ab2aceSGeorge Karpenkov if (!DedupToken1.empty())
45310ab2aceSGeorge Karpenkov Printf("CRASH_MIN: DedupToken1: %s\n", DedupToken1.c_str());
45410ab2aceSGeorge Karpenkov
45510ab2aceSGeorge Karpenkov std::string ArtifactPath =
45610ab2aceSGeorge Karpenkov Flags.exact_artifact_path
45710ab2aceSGeorge Karpenkov ? Flags.exact_artifact_path
45810ab2aceSGeorge Karpenkov : Options.ArtifactPrefix + "minimized-from-" + Hash(U);
45904304d12SMatt Morehouse Cmd.addFlag("minimize_crash_internal_step", "1");
46004304d12SMatt Morehouse Cmd.addFlag("exact_artifact_path", ArtifactPath);
46185515c7fSYuanfang Chen Printf("CRASH_MIN: executing: %s\n", Cmd.toString().c_str());
46285515c7fSYuanfang Chen CmdOutput.clear();
4634caeb62eSYuanfang Chen Success = ExecuteCommand(Cmd, &CmdOutput);
46485515c7fSYuanfang Chen Printf("%s", CmdOutput.c_str());
46585515c7fSYuanfang Chen if (Success) {
46610ab2aceSGeorge Karpenkov if (Flags.exact_artifact_path) {
46710ab2aceSGeorge Karpenkov CurrentFilePath = Flags.exact_artifact_path;
46810ab2aceSGeorge Karpenkov WriteToFile(U, CurrentFilePath);
46910ab2aceSGeorge Karpenkov }
47091985c2eSWu, Yingcong Printf("CRASH_MIN: failed to minimize beyond %s (%zu bytes), exiting\n",
47110ab2aceSGeorge Karpenkov CurrentFilePath.c_str(), U.size());
47210ab2aceSGeorge Karpenkov break;
47310ab2aceSGeorge Karpenkov }
47485515c7fSYuanfang Chen auto DedupToken2 = GetDedupTokenFromCmdOutput(CmdOutput);
47510ab2aceSGeorge Karpenkov if (!DedupToken2.empty())
47610ab2aceSGeorge Karpenkov Printf("CRASH_MIN: DedupToken2: %s\n", DedupToken2.c_str());
47710ab2aceSGeorge Karpenkov
47810ab2aceSGeorge Karpenkov if (DedupToken1 != DedupToken2) {
47910ab2aceSGeorge Karpenkov if (Flags.exact_artifact_path) {
48010ab2aceSGeorge Karpenkov CurrentFilePath = Flags.exact_artifact_path;
48110ab2aceSGeorge Karpenkov WriteToFile(U, CurrentFilePath);
48210ab2aceSGeorge Karpenkov }
48310ab2aceSGeorge Karpenkov Printf("CRASH_MIN: mismatch in dedup tokens"
48410ab2aceSGeorge Karpenkov " (looks like a different bug). Won't minimize further\n");
48510ab2aceSGeorge Karpenkov break;
48610ab2aceSGeorge Karpenkov }
48710ab2aceSGeorge Karpenkov
48810ab2aceSGeorge Karpenkov CurrentFilePath = ArtifactPath;
48910ab2aceSGeorge Karpenkov Printf("*********************************\n");
49010ab2aceSGeorge Karpenkov }
49110ab2aceSGeorge Karpenkov return 0;
49210ab2aceSGeorge Karpenkov }
49310ab2aceSGeorge Karpenkov
MinimizeCrashInputInternalStep(Fuzzer * F,InputCorpus * Corpus)49410ab2aceSGeorge Karpenkov int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
49510ab2aceSGeorge Karpenkov assert(Inputs->size() == 1);
49610ab2aceSGeorge Karpenkov std::string InputFilePath = Inputs->at(0);
49710ab2aceSGeorge Karpenkov Unit U = FileToVector(InputFilePath);
49810ab2aceSGeorge Karpenkov Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
49910ab2aceSGeorge Karpenkov if (U.size() < 2) {
50010ab2aceSGeorge Karpenkov Printf("INFO: The input is small enough, exiting\n");
50110ab2aceSGeorge Karpenkov exit(0);
50210ab2aceSGeorge Karpenkov }
50310ab2aceSGeorge Karpenkov F->SetMaxInputLen(U.size());
50410ab2aceSGeorge Karpenkov F->SetMaxMutationLen(U.size() - 1);
50510ab2aceSGeorge Karpenkov F->MinimizeCrashLoop(U);
50610ab2aceSGeorge Karpenkov Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
50710ab2aceSGeorge Karpenkov exit(0);
50810ab2aceSGeorge Karpenkov }
50910ab2aceSGeorge Karpenkov
Merge(Fuzzer * F,FuzzingOptions & Options,const std::vector<std::string> & Args,const std::vector<std::string> & Corpora,const char * CFPathOrNull)5107c921753SKostya Serebryany void Merge(Fuzzer *F, FuzzingOptions &Options,
5117c921753SKostya Serebryany const std::vector<std::string> &Args,
5127c921753SKostya Serebryany const std::vector<std::string> &Corpora, const char *CFPathOrNull) {
513114cfafeSKostya Serebryany if (Corpora.size() < 2) {
514114cfafeSKostya Serebryany Printf("INFO: Merge requires two or more corpus dirs\n");
515114cfafeSKostya Serebryany exit(0);
516114cfafeSKostya Serebryany }
517114cfafeSKostya Serebryany
5187c921753SKostya Serebryany std::vector<SizedFile> OldCorpus, NewCorpus;
519114cfafeSKostya Serebryany GetSizedFilesFromDir(Corpora[0], &OldCorpus);
520114cfafeSKostya Serebryany for (size_t i = 1; i < Corpora.size(); i++)
521114cfafeSKostya Serebryany GetSizedFilesFromDir(Corpora[i], &NewCorpus);
522114cfafeSKostya Serebryany std::sort(OldCorpus.begin(), OldCorpus.end());
523114cfafeSKostya Serebryany std::sort(NewCorpus.begin(), NewCorpus.end());
524114cfafeSKostya Serebryany
5254f3c3bbbSYuanfang Chen std::string CFPath = CFPathOrNull ? CFPathOrNull : TempPath("Merge", ".txt");
5267c921753SKostya Serebryany std::vector<std::string> NewFiles;
5277c921753SKostya Serebryany std::set<uint32_t> NewFeatures, NewCov;
5280fda9dcbSKostya Serebryany CrashResistantMerge(Args, OldCorpus, NewCorpus, &NewFiles, {}, &NewFeatures,
529e6597dbaSaristotelis {}, &NewCov, CFPath, true, Flags.set_cover_merge);
5300fda9dcbSKostya Serebryany for (auto &Path : NewFiles)
531114cfafeSKostya Serebryany F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen));
532114cfafeSKostya Serebryany // We are done, delete the control file if it was a temporary one.
533114cfafeSKostya Serebryany if (!Flags.merge_control_file)
534114cfafeSKostya Serebryany RemoveFile(CFPath);
535114cfafeSKostya Serebryany
536114cfafeSKostya Serebryany exit(0);
537114cfafeSKostya Serebryany }
538114cfafeSKostya Serebryany
AnalyzeDictionary(Fuzzer * F,const std::vector<Unit> & Dict,UnitVector & Corpus)5397c921753SKostya Serebryany int AnalyzeDictionary(Fuzzer *F, const std::vector<Unit> &Dict,
54010ab2aceSGeorge Karpenkov UnitVector &Corpus) {
54191985c2eSWu, Yingcong Printf("Started dictionary minimization (up to %zu tests)\n",
54210ab2aceSGeorge Karpenkov Dict.size() * Corpus.size() * 2);
54310ab2aceSGeorge Karpenkov
54410ab2aceSGeorge Karpenkov // Scores and usage count for each dictionary unit.
5457c921753SKostya Serebryany std::vector<int> Scores(Dict.size());
5467c921753SKostya Serebryany std::vector<int> Usages(Dict.size());
54710ab2aceSGeorge Karpenkov
5487c921753SKostya Serebryany std::vector<size_t> InitialFeatures;
5497c921753SKostya Serebryany std::vector<size_t> ModifiedFeatures;
55010ab2aceSGeorge Karpenkov for (auto &C : Corpus) {
55110ab2aceSGeorge Karpenkov // Get coverage for the testcase without modifications.
55210ab2aceSGeorge Karpenkov F->ExecuteCallback(C.data(), C.size());
55310ab2aceSGeorge Karpenkov InitialFeatures.clear();
554bcd78491SKostya Serebryany TPC.CollectFeatures([&](size_t Feature) {
55510ab2aceSGeorge Karpenkov InitialFeatures.push_back(Feature);
55610ab2aceSGeorge Karpenkov });
55710ab2aceSGeorge Karpenkov
55810ab2aceSGeorge Karpenkov for (size_t i = 0; i < Dict.size(); ++i) {
5597c921753SKostya Serebryany std::vector<uint8_t> Data = C;
56010ab2aceSGeorge Karpenkov auto StartPos = std::search(Data.begin(), Data.end(),
56110ab2aceSGeorge Karpenkov Dict[i].begin(), Dict[i].end());
56210ab2aceSGeorge Karpenkov // Skip dictionary unit, if the testcase does not contain it.
56310ab2aceSGeorge Karpenkov if (StartPos == Data.end())
56410ab2aceSGeorge Karpenkov continue;
56510ab2aceSGeorge Karpenkov
56610ab2aceSGeorge Karpenkov ++Usages[i];
56710ab2aceSGeorge Karpenkov while (StartPos != Data.end()) {
56810ab2aceSGeorge Karpenkov // Replace all occurrences of dictionary unit in the testcase.
56910ab2aceSGeorge Karpenkov auto EndPos = StartPos + Dict[i].size();
57010ab2aceSGeorge Karpenkov for (auto It = StartPos; It != EndPos; ++It)
57110ab2aceSGeorge Karpenkov *It ^= 0xFF;
57210ab2aceSGeorge Karpenkov
57310ab2aceSGeorge Karpenkov StartPos = std::search(EndPos, Data.end(),
57410ab2aceSGeorge Karpenkov Dict[i].begin(), Dict[i].end());
57510ab2aceSGeorge Karpenkov }
57610ab2aceSGeorge Karpenkov
57710ab2aceSGeorge Karpenkov // Get coverage for testcase with masked occurrences of dictionary unit.
57810ab2aceSGeorge Karpenkov F->ExecuteCallback(Data.data(), Data.size());
57910ab2aceSGeorge Karpenkov ModifiedFeatures.clear();
580bcd78491SKostya Serebryany TPC.CollectFeatures([&](size_t Feature) {
58110ab2aceSGeorge Karpenkov ModifiedFeatures.push_back(Feature);
58210ab2aceSGeorge Karpenkov });
58310ab2aceSGeorge Karpenkov
58410ab2aceSGeorge Karpenkov if (InitialFeatures == ModifiedFeatures)
58510ab2aceSGeorge Karpenkov --Scores[i];
58610ab2aceSGeorge Karpenkov else
58710ab2aceSGeorge Karpenkov Scores[i] += 2;
58810ab2aceSGeorge Karpenkov }
58910ab2aceSGeorge Karpenkov }
59010ab2aceSGeorge Karpenkov
59110ab2aceSGeorge Karpenkov Printf("###### Useless dictionary elements. ######\n");
59210ab2aceSGeorge Karpenkov for (size_t i = 0; i < Dict.size(); ++i) {
59310ab2aceSGeorge Karpenkov // Dictionary units with positive score are treated as useful ones.
59410ab2aceSGeorge Karpenkov if (Scores[i] > 0)
59510ab2aceSGeorge Karpenkov continue;
59610ab2aceSGeorge Karpenkov
59710ab2aceSGeorge Karpenkov Printf("\"");
59810ab2aceSGeorge Karpenkov PrintASCII(Dict[i].data(), Dict[i].size(), "\"");
59910ab2aceSGeorge Karpenkov Printf(" # Score: %d, Used: %d\n", Scores[i], Usages[i]);
60010ab2aceSGeorge Karpenkov }
60110ab2aceSGeorge Karpenkov Printf("###### End of useless dictionary elements. ######\n");
60210ab2aceSGeorge Karpenkov return 0;
60310ab2aceSGeorge Karpenkov }
60410ab2aceSGeorge Karpenkov
ParseSeedInuts(const char * seed_inputs)6057c921753SKostya Serebryany std::vector<std::string> ParseSeedInuts(const char *seed_inputs) {
606da96d921SKostya Serebryany // Parse -seed_inputs=file1,file2,... or -seed_inputs=@seed_inputs_file
6077c921753SKostya Serebryany std::vector<std::string> Files;
608da96d921SKostya Serebryany if (!seed_inputs) return Files;
609da96d921SKostya Serebryany std::string SeedInputs;
610da96d921SKostya Serebryany if (Flags.seed_inputs[0] == '@')
611da96d921SKostya Serebryany SeedInputs = FileToString(Flags.seed_inputs + 1); // File contains list.
612da96d921SKostya Serebryany else
613da96d921SKostya Serebryany SeedInputs = Flags.seed_inputs; // seed_inputs contains the list.
614da96d921SKostya Serebryany if (SeedInputs.empty()) {
615da96d921SKostya Serebryany Printf("seed_inputs is empty or @file does not exist.\n");
616da96d921SKostya Serebryany exit(1);
617da96d921SKostya Serebryany }
618da96d921SKostya Serebryany // Parse SeedInputs.
619da96d921SKostya Serebryany size_t comma_pos = 0;
620da96d921SKostya Serebryany while ((comma_pos = SeedInputs.find_last_of(',')) != std::string::npos) {
621da96d921SKostya Serebryany Files.push_back(SeedInputs.substr(comma_pos + 1));
622da96d921SKostya Serebryany SeedInputs = SeedInputs.substr(0, comma_pos);
623da96d921SKostya Serebryany }
624da96d921SKostya Serebryany Files.push_back(SeedInputs);
625da96d921SKostya Serebryany return Files;
626da96d921SKostya Serebryany }
627da96d921SKostya Serebryany
6287c921753SKostya Serebryany static std::vector<SizedFile>
ReadCorpora(const std::vector<std::string> & CorpusDirs,const std::vector<std::string> & ExtraSeedFiles)6297c921753SKostya Serebryany ReadCorpora(const std::vector<std::string> &CorpusDirs,
6307c921753SKostya Serebryany const std::vector<std::string> &ExtraSeedFiles) {
6317c921753SKostya Serebryany std::vector<SizedFile> SizedFiles;
6324c7353c5SKostya Serebryany size_t LastNumFiles = 0;
6334c7353c5SKostya Serebryany for (auto &Dir : CorpusDirs) {
6344c7353c5SKostya Serebryany GetSizedFilesFromDir(Dir, &SizedFiles);
6354c7353c5SKostya Serebryany Printf("INFO: % 8zd files found in %s\n", SizedFiles.size() - LastNumFiles,
6364c7353c5SKostya Serebryany Dir.c_str());
6374c7353c5SKostya Serebryany LastNumFiles = SizedFiles.size();
6384c7353c5SKostya Serebryany }
6394c7353c5SKostya Serebryany for (auto &File : ExtraSeedFiles)
6404c7353c5SKostya Serebryany if (auto Size = FileSize(File))
6414c7353c5SKostya Serebryany SizedFiles.push_back({File, Size});
6424c7353c5SKostya Serebryany return SizedFiles;
6434c7353c5SKostya Serebryany }
6444c7353c5SKostya Serebryany
FuzzerDriver(int * argc,char *** argv,UserCallback Callback)64510ab2aceSGeorge Karpenkov int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
64610ab2aceSGeorge Karpenkov using namespace fuzzer;
64710ab2aceSGeorge Karpenkov assert(argc && argv && "Argument pointers cannot be nullptr");
64810ab2aceSGeorge Karpenkov std::string Argv0((*argv)[0]);
64910ab2aceSGeorge Karpenkov EF = new ExternalFunctions();
65010ab2aceSGeorge Karpenkov if (EF->LLVMFuzzerInitialize)
65110ab2aceSGeorge Karpenkov EF->LLVMFuzzerInitialize(argc, argv);
652a34c65e8SMatt Morehouse if (EF->__msan_scoped_disable_interceptor_checks)
653a34c65e8SMatt Morehouse EF->__msan_scoped_disable_interceptor_checks();
6547c921753SKostya Serebryany const std::vector<std::string> Args(*argv, *argv + *argc);
65510ab2aceSGeorge Karpenkov assert(!Args.empty());
65610ab2aceSGeorge Karpenkov ProgName = new std::string(Args[0]);
65710ab2aceSGeorge Karpenkov if (Argv0 != *ProgName) {
65810ab2aceSGeorge Karpenkov Printf("ERROR: argv[0] has been modified in LLVMFuzzerInitialize\n");
65910ab2aceSGeorge Karpenkov exit(1);
66010ab2aceSGeorge Karpenkov }
6610784e01aSMax Moroz ParseFlags(Args, EF);
66210ab2aceSGeorge Karpenkov if (Flags.help) {
66310ab2aceSGeorge Karpenkov PrintHelp();
66410ab2aceSGeorge Karpenkov return 0;
66510ab2aceSGeorge Karpenkov }
66610ab2aceSGeorge Karpenkov
66710ab2aceSGeorge Karpenkov if (Flags.close_fd_mask & 2)
66810ab2aceSGeorge Karpenkov DupAndCloseStderr();
66910ab2aceSGeorge Karpenkov if (Flags.close_fd_mask & 1)
67010ab2aceSGeorge Karpenkov CloseStdout();
67110ab2aceSGeorge Karpenkov
67210ab2aceSGeorge Karpenkov if (Flags.jobs > 0 && Flags.workers == 0) {
67310ab2aceSGeorge Karpenkov Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
67410ab2aceSGeorge Karpenkov if (Flags.workers > 1)
67510ab2aceSGeorge Karpenkov Printf("Running %u workers\n", Flags.workers);
67610ab2aceSGeorge Karpenkov }
67710ab2aceSGeorge Karpenkov
67810ab2aceSGeorge Karpenkov if (Flags.workers > 0 && Flags.jobs > 0)
67910ab2aceSGeorge Karpenkov return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
68010ab2aceSGeorge Karpenkov
68110ab2aceSGeorge Karpenkov FuzzingOptions Options;
68210ab2aceSGeorge Karpenkov Options.Verbosity = Flags.verbosity;
68310ab2aceSGeorge Karpenkov Options.MaxLen = Flags.max_len;
68436c89b3cSMatt Morehouse Options.LenControl = Flags.len_control;
68562673c43SDokyung Song Options.KeepSeed = Flags.keep_seed;
68610ab2aceSGeorge Karpenkov Options.UnitTimeoutSec = Flags.timeout;
68710ab2aceSGeorge Karpenkov Options.ErrorExitCode = Flags.error_exitcode;
68810ab2aceSGeorge Karpenkov Options.TimeoutExitCode = Flags.timeout_exitcode;
689cdbb9dc9SKostya Serebryany Options.IgnoreTimeouts = Flags.ignore_timeouts;
690cdbb9dc9SKostya Serebryany Options.IgnoreOOMs = Flags.ignore_ooms;
6919982ee54SKostya Serebryany Options.IgnoreCrashes = Flags.ignore_crashes;
69210ab2aceSGeorge Karpenkov Options.MaxTotalTimeSec = Flags.max_total_time;
69310ab2aceSGeorge Karpenkov Options.DoCrossOver = Flags.cross_over;
694b53243e1SDokyung Song Options.CrossOverUniformDist = Flags.cross_over_uniform_dist;
69510ab2aceSGeorge Karpenkov Options.MutateDepth = Flags.mutate_depth;
696ad05ee05SKostya Serebryany Options.ReduceDepth = Flags.reduce_depth;
69710ab2aceSGeorge Karpenkov Options.UseCounters = Flags.use_counters;
69810ab2aceSGeorge Karpenkov Options.UseMemmem = Flags.use_memmem;
69910ab2aceSGeorge Karpenkov Options.UseCmp = Flags.use_cmp;
70010ab2aceSGeorge Karpenkov Options.UseValueProfile = Flags.use_value_profile;
70110ab2aceSGeorge Karpenkov Options.Shrink = Flags.shrink;
70210ab2aceSGeorge Karpenkov Options.ReduceInputs = Flags.reduce_inputs;
70310ab2aceSGeorge Karpenkov Options.ShuffleAtStartUp = Flags.shuffle;
70410ab2aceSGeorge Karpenkov Options.PreferSmall = Flags.prefer_small;
70510ab2aceSGeorge Karpenkov Options.ReloadIntervalSec = Flags.reload;
70610ab2aceSGeorge Karpenkov Options.OnlyASCII = Flags.only_ascii;
70710ab2aceSGeorge Karpenkov Options.DetectLeaks = Flags.detect_leaks;
7086f1c26f2SAlex Shlyapnikov Options.PurgeAllocatorIntervalSec = Flags.purge_allocator_interval;
70910ab2aceSGeorge Karpenkov Options.TraceMalloc = Flags.trace_malloc;
71010ab2aceSGeorge Karpenkov Options.RssLimitMb = Flags.rss_limit_mb;
711de9bafb1SKostya Serebryany Options.MallocLimitMb = Flags.malloc_limit_mb;
712de9bafb1SKostya Serebryany if (!Options.MallocLimitMb)
713de9bafb1SKostya Serebryany Options.MallocLimitMb = Options.RssLimitMb;
71410ab2aceSGeorge Karpenkov if (Flags.runs >= 0)
71510ab2aceSGeorge Karpenkov Options.MaxNumberOfRuns = Flags.runs;
7162392ff09SMatt Morehouse if (!Inputs->empty() && !Flags.minimize_crash_internal_step) {
7172392ff09SMatt Morehouse // Ensure output corpus assumed to be the first arbitrary argument input
7182392ff09SMatt Morehouse // is not a path to an existing file.
7192392ff09SMatt Morehouse std::string OutputCorpusDir = (*Inputs)[0];
7202392ff09SMatt Morehouse if (!IsFile(OutputCorpusDir)) {
7212392ff09SMatt Morehouse Options.OutputCorpus = OutputCorpusDir;
722711b9806SMatt Morehouse ValidateDirectoryExists(Options.OutputCorpus, Flags.create_missing_dirs);
7232392ff09SMatt Morehouse }
7242392ff09SMatt Morehouse }
72510ab2aceSGeorge Karpenkov Options.ReportSlowUnits = Flags.report_slow_units;
7262392ff09SMatt Morehouse if (Flags.artifact_prefix) {
72710ab2aceSGeorge Karpenkov Options.ArtifactPrefix = Flags.artifact_prefix;
7282392ff09SMatt Morehouse
7292392ff09SMatt Morehouse // Since the prefix could be a full path to a file name prefix, assume
7302392ff09SMatt Morehouse // that if the path ends with the platform's separator that a directory
7312392ff09SMatt Morehouse // is desired
7322392ff09SMatt Morehouse std::string ArtifactPathDir = Options.ArtifactPrefix;
7332392ff09SMatt Morehouse if (!IsSeparator(ArtifactPathDir[ArtifactPathDir.length() - 1])) {
7342392ff09SMatt Morehouse ArtifactPathDir = DirName(ArtifactPathDir);
7352392ff09SMatt Morehouse }
736711b9806SMatt Morehouse ValidateDirectoryExists(ArtifactPathDir, Flags.create_missing_dirs);
7372392ff09SMatt Morehouse }
7382392ff09SMatt Morehouse if (Flags.exact_artifact_path) {
73910ab2aceSGeorge Karpenkov Options.ExactArtifactPath = Flags.exact_artifact_path;
740711b9806SMatt Morehouse ValidateDirectoryExists(DirName(Options.ExactArtifactPath),
741711b9806SMatt Morehouse Flags.create_missing_dirs);
7422392ff09SMatt Morehouse }
7437c921753SKostya Serebryany std::vector<Unit> Dictionary;
74410ab2aceSGeorge Karpenkov if (Flags.dict)
74510ab2aceSGeorge Karpenkov if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
74610ab2aceSGeorge Karpenkov return 1;
74710ab2aceSGeorge Karpenkov if (Flags.verbosity > 0 && !Dictionary.empty())
74810ab2aceSGeorge Karpenkov Printf("Dictionary: %zd entries\n", Dictionary.size());
7494c7353c5SKostya Serebryany bool RunIndividualFiles = AllInputsAreFiles();
75010ab2aceSGeorge Karpenkov Options.SaveArtifacts =
7514c7353c5SKostya Serebryany !RunIndividualFiles || Flags.minimize_crash_internal_step;
75210ab2aceSGeorge Karpenkov Options.PrintNewCovPcs = Flags.print_pcs;
7532eef816eSKostya Serebryany Options.PrintNewCovFuncs = Flags.print_funcs;
75410ab2aceSGeorge Karpenkov Options.PrintFinalStats = Flags.print_final_stats;
75510ab2aceSGeorge Karpenkov Options.PrintCorpusStats = Flags.print_corpus_stats;
75610ab2aceSGeorge Karpenkov Options.PrintCoverage = Flags.print_coverage;
757dc62d5ecSMax Moroz Options.PrintFullCoverage = Flags.print_full_coverage;
75810ab2aceSGeorge Karpenkov if (Flags.exit_on_src_pos)
75910ab2aceSGeorge Karpenkov Options.ExitOnSrcPos = Flags.exit_on_src_pos;
76010ab2aceSGeorge Karpenkov if (Flags.exit_on_item)
76110ab2aceSGeorge Karpenkov Options.ExitOnItem = Flags.exit_on_item;
762e9c6f06cSKostya Serebryany if (Flags.focus_function)
763e9c6f06cSKostya Serebryany Options.FocusFunction = Flags.focus_function;
7641fd005f5SKostya Serebryany if (Flags.data_flow_trace)
7651fd005f5SKostya Serebryany Options.DataFlowTrace = Flags.data_flow_trace;
7662392ff09SMatt Morehouse if (Flags.features_dir) {
7674614cc3dSKostya Serebryany Options.FeaturesDir = Flags.features_dir;
768711b9806SMatt Morehouse ValidateDirectoryExists(Options.FeaturesDir, Flags.create_missing_dirs);
7692392ff09SMatt Morehouse }
7701bb1eac6SDokyung Song if (Flags.mutation_graph_file)
7711bb1eac6SDokyung Song Options.MutationGraphFile = Flags.mutation_graph_file;
772b7cc3d99SKostya Serebryany if (Flags.collect_data_flow)
773b7cc3d99SKostya Serebryany Options.CollectDataFlow = Flags.collect_data_flow;
774db88fc56SKostya Serebryany if (Flags.stop_file)
775db88fc56SKostya Serebryany Options.StopFile = Flags.stop_file;
776e2e38fcaSMatt Morehouse Options.Entropic = Flags.entropic;
777e2e38fcaSMatt Morehouse Options.EntropicFeatureFrequencyThreshold =
778e2e38fcaSMatt Morehouse (size_t)Flags.entropic_feature_frequency_threshold;
779e2e38fcaSMatt Morehouse Options.EntropicNumberOfRarestFeatures =
780e2e38fcaSMatt Morehouse (size_t)Flags.entropic_number_of_rarest_features;
7815cda4dc7SDokyung Song Options.EntropicScalePerExecTime = Flags.entropic_scale_per_exec_time;
782f3c2e0bcSMatt Morehouse if (!Options.FocusFunction.empty())
783f3c2e0bcSMatt Morehouse Options.Entropic = false; // FocusFunction overrides entropic scheduling.
784f3c2e0bcSMatt Morehouse if (Options.Entropic)
78591985c2eSWu, Yingcong Printf("INFO: Running with entropic power schedule (0x%zX, %zu).\n",
786e2e38fcaSMatt Morehouse Options.EntropicFeatureFrequencyThreshold,
787e2e38fcaSMatt Morehouse Options.EntropicNumberOfRarestFeatures);
788e2e38fcaSMatt Morehouse struct EntropicOptions Entropic;
789e2e38fcaSMatt Morehouse Entropic.Enabled = Options.Entropic;
790e2e38fcaSMatt Morehouse Entropic.FeatureFrequencyThreshold =
791e2e38fcaSMatt Morehouse Options.EntropicFeatureFrequencyThreshold;
792e2e38fcaSMatt Morehouse Entropic.NumberOfRarestFeatures = Options.EntropicNumberOfRarestFeatures;
7935cda4dc7SDokyung Song Entropic.ScalePerExecTime = Options.EntropicScalePerExecTime;
79410ab2aceSGeorge Karpenkov
79510ab2aceSGeorge Karpenkov unsigned Seed = Flags.seed;
79610ab2aceSGeorge Karpenkov // Initialize Seed.
79710ab2aceSGeorge Karpenkov if (Seed == 0)
7986708186cSAaron Green Seed = static_cast<unsigned>(
7996708186cSAaron Green std::chrono::system_clock::now().time_since_epoch().count() + GetPid());
80010ab2aceSGeorge Karpenkov if (Flags.verbosity)
80110ab2aceSGeorge Karpenkov Printf("INFO: Seed: %u\n", Seed);
80210ab2aceSGeorge Karpenkov
80367f5b05cSWu, Yingcong if (Flags.collect_data_flow && Flags.data_flow_trace && !Flags.fork &&
804e6597dbaSaristotelis !(Flags.merge || Flags.set_cover_merge)) {
8054c7353c5SKostya Serebryany if (RunIndividualFiles)
806da96d921SKostya Serebryany return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
8074c7353c5SKostya Serebryany ReadCorpora({}, *Inputs));
8084c7353c5SKostya Serebryany else
8094c7353c5SKostya Serebryany return CollectDataFlow(Flags.collect_data_flow, Flags.data_flow_trace,
8104c7353c5SKostya Serebryany ReadCorpora(*Inputs, {}));
8114c7353c5SKostya Serebryany }
812da96d921SKostya Serebryany
813c5d72517SMarco Vanotti Random Rand(Seed);
814c5d72517SMarco Vanotti auto *MD = new MutationDispatcher(Rand, Options);
815e2e38fcaSMatt Morehouse auto *Corpus = new InputCorpus(Options.OutputCorpus, Entropic);
81610ab2aceSGeorge Karpenkov auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
81710ab2aceSGeorge Karpenkov
81810ab2aceSGeorge Karpenkov for (auto &U: Dictionary)
81910ab2aceSGeorge Karpenkov if (U.size() <= Word::GetMaxSize())
82010ab2aceSGeorge Karpenkov MD->AddWordToManualDictionary(Word(U.data(), U.size()));
82110ab2aceSGeorge Karpenkov
82223bee0b0SJonathan Metzman // Threads are only supported by Chrome. Don't use them with emscripten
82323bee0b0SJonathan Metzman // for now.
82423bee0b0SJonathan Metzman #if !LIBFUZZER_EMSCRIPTEN
82510ab2aceSGeorge Karpenkov StartRssThread(F, Flags.rss_limit_mb);
82623bee0b0SJonathan Metzman #endif // LIBFUZZER_EMSCRIPTEN
82710ab2aceSGeorge Karpenkov
82810ab2aceSGeorge Karpenkov Options.HandleAbrt = Flags.handle_abrt;
8299df7ee34SIlya Leoshkevich Options.HandleAlrm = !Flags.minimize_crash;
83010ab2aceSGeorge Karpenkov Options.HandleBus = Flags.handle_bus;
83110ab2aceSGeorge Karpenkov Options.HandleFpe = Flags.handle_fpe;
83210ab2aceSGeorge Karpenkov Options.HandleIll = Flags.handle_ill;
83310ab2aceSGeorge Karpenkov Options.HandleInt = Flags.handle_int;
83410ab2aceSGeorge Karpenkov Options.HandleSegv = Flags.handle_segv;
83510ab2aceSGeorge Karpenkov Options.HandleTerm = Flags.handle_term;
83610ab2aceSGeorge Karpenkov Options.HandleXfsz = Flags.handle_xfsz;
837a2ca2dccSKostya Serebryany Options.HandleUsr1 = Flags.handle_usr1;
838a2ca2dccSKostya Serebryany Options.HandleUsr2 = Flags.handle_usr2;
839f897e82bSJoe Pletcher Options.HandleWinExcept = Flags.handle_winexcept;
840f897e82bSJoe Pletcher
84110ab2aceSGeorge Karpenkov SetSignalHandler(Options);
84210ab2aceSGeorge Karpenkov
84310ab2aceSGeorge Karpenkov std::atexit(Fuzzer::StaticExitCallback);
84410ab2aceSGeorge Karpenkov
84510ab2aceSGeorge Karpenkov if (Flags.minimize_crash)
84610ab2aceSGeorge Karpenkov return MinimizeCrashInput(Args, Options);
84710ab2aceSGeorge Karpenkov
84810ab2aceSGeorge Karpenkov if (Flags.minimize_crash_internal_step)
84910ab2aceSGeorge Karpenkov return MinimizeCrashInputInternalStep(F, Corpus);
85010ab2aceSGeorge Karpenkov
85110ab2aceSGeorge Karpenkov if (Flags.cleanse_crash)
85210ab2aceSGeorge Karpenkov return CleanseCrashInput(Args, Options);
85310ab2aceSGeorge Karpenkov
8544c7353c5SKostya Serebryany if (RunIndividualFiles) {
85510ab2aceSGeorge Karpenkov Options.SaveArtifacts = false;
85610ab2aceSGeorge Karpenkov int Runs = std::max(1, Flags.runs);
85710ab2aceSGeorge Karpenkov Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
85810ab2aceSGeorge Karpenkov Inputs->size(), Runs);
85910ab2aceSGeorge Karpenkov for (auto &Path : *Inputs) {
86010ab2aceSGeorge Karpenkov auto StartTime = system_clock::now();
86110ab2aceSGeorge Karpenkov Printf("Running: %s\n", Path.c_str());
86210ab2aceSGeorge Karpenkov for (int Iter = 0; Iter < Runs; Iter++)
86310ab2aceSGeorge Karpenkov RunOneTest(F, Path.c_str(), Options.MaxLen);
86410ab2aceSGeorge Karpenkov auto StopTime = system_clock::now();
86510ab2aceSGeorge Karpenkov auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
86691985c2eSWu, Yingcong Printf("Executed %s in %ld ms\n", Path.c_str(), (long)MS);
86710ab2aceSGeorge Karpenkov }
86810ab2aceSGeorge Karpenkov Printf("***\n"
86910ab2aceSGeorge Karpenkov "*** NOTE: fuzzing was not performed, you have only\n"
87010ab2aceSGeorge Karpenkov "*** executed the target code on a fixed set of inputs.\n"
87110ab2aceSGeorge Karpenkov "***\n");
87210ab2aceSGeorge Karpenkov F->PrintFinalStats();
87310ab2aceSGeorge Karpenkov exit(0);
87410ab2aceSGeorge Karpenkov }
87510ab2aceSGeorge Karpenkov
876a30dbbe9Sgtt1995 Options.ForkCorpusGroups = Flags.fork_corpus_groups;
877f762a115SKostya Serebryany if (Flags.fork)
87860c5ded2SKostya Serebryany FuzzWithFork(F->GetMD().GetRand(), Options, Args, *Inputs, Flags.fork);
879f762a115SKostya Serebryany
880e6597dbaSaristotelis if (Flags.merge || Flags.set_cover_merge)
881114cfafeSKostya Serebryany Merge(F, Options, Args, *Inputs, Flags.merge_control_file);
88210ab2aceSGeorge Karpenkov
88368fdef1fSKostya Serebryany if (Flags.merge_inner) {
88468fdef1fSKostya Serebryany const size_t kDefaultMaxMergeLen = 1 << 20;
88568fdef1fSKostya Serebryany if (Options.MaxLen == 0)
88668fdef1fSKostya Serebryany F->SetMaxInputLen(kDefaultMaxMergeLen);
88768fdef1fSKostya Serebryany assert(Flags.merge_control_file);
888e6597dbaSaristotelis F->CrashResistantMergeInternalStep(Flags.merge_control_file,
889e6597dbaSaristotelis !strncmp(Flags.merge_inner, "2", 1));
89068fdef1fSKostya Serebryany exit(0);
89168fdef1fSKostya Serebryany }
89210ab2aceSGeorge Karpenkov
8933a8e3c83SKostya Serebryany if (Flags.analyze_dict) {
8943a8e3c83SKostya Serebryany size_t MaxLen = INT_MAX; // Large max length.
89510ab2aceSGeorge Karpenkov UnitVector InitialCorpus;
89610ab2aceSGeorge Karpenkov for (auto &Inp : *Inputs) {
89710ab2aceSGeorge Karpenkov Printf("Loading corpus dir: %s\n", Inp.c_str());
89810ab2aceSGeorge Karpenkov ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
8993a8e3c83SKostya Serebryany MaxLen, /*ExitOnError=*/false);
90010ab2aceSGeorge Karpenkov }
90110ab2aceSGeorge Karpenkov
90210ab2aceSGeorge Karpenkov if (Dictionary.empty() || Inputs->empty()) {
90310ab2aceSGeorge Karpenkov Printf("ERROR: can't analyze dict without dict and corpus provided\n");
90410ab2aceSGeorge Karpenkov return 1;
90510ab2aceSGeorge Karpenkov }
90610ab2aceSGeorge Karpenkov if (AnalyzeDictionary(F, Dictionary, InitialCorpus)) {
90710ab2aceSGeorge Karpenkov Printf("Dictionary analysis failed\n");
90810ab2aceSGeorge Karpenkov exit(1);
90910ab2aceSGeorge Karpenkov }
910d9a8b6a7SSylvestre Ledru Printf("Dictionary analysis succeeded\n");
91110ab2aceSGeorge Karpenkov exit(0);
91210ab2aceSGeorge Karpenkov }
91310ab2aceSGeorge Karpenkov
9144c7353c5SKostya Serebryany auto CorporaFiles = ReadCorpora(*Inputs, ParseSeedInuts(Flags.seed_inputs));
9154c7353c5SKostya Serebryany F->Loop(CorporaFiles);
91610ab2aceSGeorge Karpenkov
91710ab2aceSGeorge Karpenkov if (Flags.verbosity)
91810ab2aceSGeorge Karpenkov Printf("Done %zd runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
91910ab2aceSGeorge Karpenkov F->secondsSinceProcessStartUp());
92010ab2aceSGeorge Karpenkov F->PrintFinalStats();
92110ab2aceSGeorge Karpenkov
92210ab2aceSGeorge Karpenkov exit(0); // Don't let F destroy itself.
92310ab2aceSGeorge Karpenkov }
92410ab2aceSGeorge Karpenkov
92534ddf0b2SMatt Morehouse extern "C" ATTRIBUTE_INTERFACE int
LLVMFuzzerRunDriver(int * argc,char *** argv,int (* UserCb)(const uint8_t * Data,size_t Size))92634ddf0b2SMatt Morehouse LLVMFuzzerRunDriver(int *argc, char ***argv,
92734ddf0b2SMatt Morehouse int (*UserCb)(const uint8_t *Data, size_t Size)) {
92834ddf0b2SMatt Morehouse return FuzzerDriver(argc, argv, UserCb);
92934ddf0b2SMatt Morehouse }
93034ddf0b2SMatt Morehouse
93110ab2aceSGeorge Karpenkov // Storage for global ExternalFunctions object.
93210ab2aceSGeorge Karpenkov ExternalFunctions *EF = nullptr;
93310ab2aceSGeorge Karpenkov
93410ab2aceSGeorge Karpenkov } // namespace fuzzer
935