From: Kostya Serebryany Date: Sat, 24 Oct 2015 01:16:40 +0000 (+0000) Subject: [libFuzzer] add -merge flag to merge corpora X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=242325ad984cdafe43ae19c5acbd9eca22851adc [libFuzzer] add -merge flag to merge corpora git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251168 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LibFuzzer.rst b/docs/LibFuzzer.rst index 85c110f272f..97ae928988b 100644 --- a/docs/LibFuzzer.rst +++ b/docs/LibFuzzer.rst @@ -64,6 +64,7 @@ The most important flags are:: max_total_time 0 If positive, indicates the maximal total time in seconds to run the fuzzer. help 0 Print help. save_minimized_corpus 0 If 1, the minimized corpus is saved into the first input directory. Example: ./fuzzer -save_minimized_corpus=1 NEW_EMPTY_DIR OLD_CORPUS + merge 0 If 1, the 2-nd, 3-rd, etc corpora will be merged into the 1-st corpus. Only interesting units will be taken. jobs 0 Number of jobs to run. If jobs >= 1 we spawn this number of jobs in separate worker processes with stdout/stderr redirected to fuzz-JOB.log. workers 0 Number of simultaneous worker processes to run the jobs. If zero, "min(jobs,NumberOfCpuCores()/2)" is used. sync_command 0 Execute an external command " " to synchronize the test corpus. diff --git a/lib/Fuzzer/FuzzerDriver.cpp b/lib/Fuzzer/FuzzerDriver.cpp index f9cb28a6e51..821d34cccc2 100644 --- a/lib/Fuzzer/FuzzerDriver.cpp +++ b/lib/Fuzzer/FuzzerDriver.cpp @@ -269,6 +269,11 @@ int FuzzerDriver(const std::vector &Args, if (Flags.test_single_input) return RunOneTest(&F, Flags.test_single_input); + if (Flags.merge) { + F.Merge(*Inputs); + exit(0); + } + unsigned Seed = Flags.seed; // Initialize Seed. if (Seed == 0) diff --git a/lib/Fuzzer/FuzzerFlags.def b/lib/Fuzzer/FuzzerFlags.def index cea28e3bf04..9cd2dedb37a 100644 --- a/lib/Fuzzer/FuzzerFlags.def +++ b/lib/Fuzzer/FuzzerFlags.def @@ -36,6 +36,8 @@ FUZZER_FLAG_INT( save_minimized_corpus, 0, "If 1, the minimized corpus is saved into the first input directory. " "Example: ./fuzzer -save_minimized_corpus=1 NEW_EMPTY_DIR OLD_CORPUS") +FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be " + "merged into the 1-st corpus. Only interesting units will be taken.") FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters") FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters") FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces") diff --git a/lib/Fuzzer/FuzzerInternal.h b/lib/Fuzzer/FuzzerInternal.h index 2dc44f98def..d6e1cb85a23 100644 --- a/lib/Fuzzer/FuzzerInternal.h +++ b/lib/Fuzzer/FuzzerInternal.h @@ -104,6 +104,7 @@ class Fuzzer { void InitializeTraceState(); size_t CorpusSize() const { return Corpus.size(); } void ReadDir(const std::string &Path, long *Epoch) { + Printf("Loading corpus: %s\n", Path.c_str()); ReadDirToVectorOfUnits(Path.c_str(), &Corpus, Epoch); } void RereadOutputCorpus(); @@ -121,6 +122,9 @@ class Fuzzer { void ExecuteCallback(const Unit &U); + // Merge Corpora[1:] into Corpora[0]. + void Merge(const std::vector &Corpora); + private: void AlarmCallback(); void MutateAndTestOne(Unit *U); diff --git a/lib/Fuzzer/FuzzerLoop.cpp b/lib/Fuzzer/FuzzerLoop.cpp index 268989f103a..4f07961e066 100644 --- a/lib/Fuzzer/FuzzerLoop.cpp +++ b/lib/Fuzzer/FuzzerLoop.cpp @@ -286,6 +286,38 @@ void Fuzzer::ReportNewCoverage(const Unit &U) { exit(0); } +void Fuzzer::Merge(const std::vector &Corpora) { + if (Corpora.size() <= 1) { + Printf("Merge requires two or more corpus dirs\n"); + return; + } + auto InitialCorpusDir = Corpora[0]; + ReadDir(InitialCorpusDir, nullptr); + Printf("Merge: running the initial corpus '%s' of %d units\n", + InitialCorpusDir.c_str(), Corpus.size()); + for (auto &U : Corpus) + RunOne(U); + + std::vector ExtraCorpora(Corpora.begin() + 1, Corpora.end()); + + size_t NumTried = 0; + size_t NumMerged = 0; + for (auto &C : ExtraCorpora) { + Corpus.clear(); + ReadDir(C, nullptr); + Printf("Merge: merging the extra corpus '%s' of %zd units\n", C.c_str(), + Corpus.size()); + for (auto &U : Corpus) { + NumTried++; + if (RunOne(U)) { + WriteToOutputCorpus(U); + NumMerged++; + } + } + } + Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried); +} + void Fuzzer::MutateAndTestOne(Unit *U) { for (int i = 0; i < Options.MutateDepth; i++) { StartTraceRecording(); diff --git a/lib/Fuzzer/test/merge.test b/lib/Fuzzer/test/merge.test new file mode 100644 index 00000000000..57ecc141bbf --- /dev/null +++ b/lib/Fuzzer/test/merge.test @@ -0,0 +1,29 @@ +CHECK: BINGO + +RUN: rm -rf %tmp/T1 %tmp/T2 +RUN: mkdir -p %tmp/T1 %tmp/T2 +RUN: echo F..... > %tmp/T1/1 +RUN: echo .U.... > %tmp/T1/2 +RUN: echo ..Z... > %tmp/T1/3 + +# T1 has 3 elements, T2 is empty. +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1 +CHECK1: Merge: running the initial corpus {{.*}} of 3 units +CHECK1: Merge: written 0 out of 0 units + +RUN: echo ...Z.. > %tmp/T2/1 +RUN: echo ....E. > %tmp/T2/2 +RUN: echo .....R > %tmp/T2/3 +RUN: echo F..... > %tmp/T2/a +RUN: echo .U.... > %tmp/T2/b +RUN: echo ..Z... > %tmp/T2/c + +# T1 has 3 elements, T2 has 6 elements, only 3 are new. +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2 +CHECK2: Merge: running the initial corpus {{.*}} of 3 units +CHECK2: Merge: written 3 out of 6 units + +# Now, T1 has 6 units and T2 has no new interesting units. +RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3 +CHECK3: Merge: running the initial corpus {{.*}} of 6 units +CHECK3: Merge: written 0 out of 6 units