diff options
author | Kostya Serebryany <kcc@google.com> | 2019-02-08 21:27:23 +0000 |
---|---|---|
committer | Kostya Serebryany <kcc@google.com> | 2019-02-08 21:27:23 +0000 |
commit | f762a11544b77bcb5cbb45e9726562018cd5c8fa (patch) | |
tree | d9a22b41759cdc51c01d54feeb26a7d1a5a23044 /compiler-rt/lib/fuzzer/FuzzerDriver.cpp | |
parent | 3bf72d7d64b8465acd4f4af1a469d68d9dc86058 (diff) | |
download | bcm5719-llvm-f762a11544b77bcb5cbb45e9726562018cd5c8fa.tar.gz bcm5719-llvm-f762a11544b77bcb5cbb45e9726562018cd5c8fa.zip |
[libFuzzer] introduce an experimental mode -fork=1, where fuzzing happens in a subprocess (still running multiple inputs per process), thus making the fuzzing more resilient to timeouts and OOMs. This is just a skeleton of the code, and some associated refactoring, not a fully working feature yet.
llvm-svn: 353570
Diffstat (limited to 'compiler-rt/lib/fuzzer/FuzzerDriver.cpp')
-rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerDriver.cpp | 68 |
1 files changed, 58 insertions, 10 deletions
diff --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp index 2bc895d008c..418bebb9388 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp +++ b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp @@ -16,6 +16,7 @@ #include "FuzzerMutate.h" #include "FuzzerRandom.h" #include "FuzzerTracePC.h" +#include "FuzzerMerge.h" #include <algorithm> #include <atomic> #include <chrono> @@ -24,6 +25,7 @@ #include <mutex> #include <string> #include <thread> +#include <fstream> // This function should be present in the libFuzzer so that the client // binary can test for its existence. @@ -304,6 +306,11 @@ static std::string GetDedupTokenFromFile(const std::string &Path) { return S.substr(Beg, End - Beg); } +static std::string TempPath(const char *Extension) { + return DirPlusFile(TmpDir(), + "libFuzzerTemp." + std::to_string(GetPid()) + Extension); +} + int CleanseCrashInput(const Vector<std::string> &Args, const FuzzingOptions &Options) { if (Inputs->size() != 1 || !Flags.exact_artifact_path) { @@ -319,10 +326,8 @@ int CleanseCrashInput(const Vector<std::string> &Args, assert(Cmd.hasArgument(InputFilePath)); Cmd.removeArgument(InputFilePath); - auto LogFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); - auto TmpFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".repro"); + auto LogFilePath = TempPath(".txt"); + auto TmpFilePath = TempPath(".repro"); Cmd.addArgument(TmpFilePath); Cmd.setOutputFile(LogFilePath); Cmd.combineOutAndErr(); @@ -382,8 +387,7 @@ int MinimizeCrashInput(const Vector<std::string> &Args, BaseCmd.addFlag("max_total_time", "600"); } - auto LogFilePath = DirPlusFile( - TmpDir(), "libFuzzerTemp." + std::to_string(GetPid()) + ".txt"); + auto LogFilePath = TempPath(".txt"); BaseCmd.setOutputFile(LogFilePath); BaseCmd.combineOutAndErr(); @@ -467,6 +471,36 @@ int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) { return 0; } +// This is just a sceleton of an experimental -fork=1 feature. +void FuzzWithFork(const FuzzingOptions &Options, + const Vector<std::string> &Args, + const Vector<std::string> &Corpora) { + auto CFPath = TempPath(".fork"); + Printf("INFO: -fork=1: doing fuzzing in a separate process in order to " + "be more resistant to crashes, timeouts, and OOMs\n"); + auto Files = + CrashResistantMerge(Args, Corpora, CFPath, nullptr, nullptr); + Printf("INFO: -fork=1: seed corpus analyzed, %zd seeds chosen, starting to " + "fuzz in separate processes\n", Files.size()); + + Command Cmd(Args); + Cmd.removeFlag("fork"); + if (Files.size() >= 2) + Cmd.addFlag("seed_inputs", + Files.back() + "," + Files[Files.size() - 2]); + Cmd.addFlag("runs", "1000000"); + Cmd.addFlag("max_total_time", "30"); + for (size_t i = 0; i < 1000; i++) { + Printf("RUN %s\n", Cmd.toString().c_str()); + int ExitCode = ExecuteCommand(Cmd); + // TODO: sniff the crash, ignore OOMs and timeouts. + if (ExitCode != 0) break; + } + + RemoveFile(CFPath); + exit(0); +} + int AnalyzeDictionary(Fuzzer *F, const Vector<Unit>& Dict, UnitVector& Corpus) { Printf("Started dictionary minimization (up to %d tests)\n", @@ -694,11 +728,25 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) { exit(0); } + if (Flags.fork) + FuzzWithFork(Options, Args, *Inputs); + if (Flags.merge) { - F->CrashResistantMerge(Args, *Inputs, - Flags.load_coverage_summary, - Flags.save_coverage_summary, - Flags.merge_control_file); + if (Inputs->size() < 2) { + Printf("INFO: Merge requires two or more corpus dirs\n"); + exit(0); + } + std::string CFPath = + Flags.merge_control_file ? Flags.merge_control_file : TempPath(".txt"); + auto Files = + CrashResistantMerge(Args, *Inputs, CFPath, Flags.load_coverage_summary, + Flags.save_coverage_summary); + for (auto &Path : Files) + F->WriteToOutputCorpus(FileToVector(Path, Options.MaxLen)); + // We are done, delete the control file if it was a temporary one. + if (!Flags.merge_control_file) + RemoveFile(CFPath); + exit(0); } |