Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit 242325a

Browse files
committed
[libFuzzer] add -merge flag to merge corpora
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@251168 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 4a000fe commit 242325a

File tree

6 files changed

+73
-0
lines changed

6 files changed

+73
-0
lines changed

docs/LibFuzzer.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ The most important flags are::
6464
max_total_time 0 If positive, indicates the maximal total time in seconds to run the fuzzer.
6565
help 0 Print help.
6666
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
67+
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.
6768
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.
6869
workers 0 Number of simultaneous worker processes to run the jobs. If zero, "min(jobs,NumberOfCpuCores()/2)" is used.
6970
sync_command 0 Execute an external command "<sync_command> <test_corpus>" to synchronize the test corpus.

lib/Fuzzer/FuzzerDriver.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ int FuzzerDriver(const std::vector<std::string> &Args,
269269
if (Flags.test_single_input)
270270
return RunOneTest(&F, Flags.test_single_input);
271271

272+
if (Flags.merge) {
273+
F.Merge(*Inputs);
274+
exit(0);
275+
}
276+
272277
unsigned Seed = Flags.seed;
273278
// Initialize Seed.
274279
if (Seed == 0)

lib/Fuzzer/FuzzerFlags.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ FUZZER_FLAG_INT(
3636
save_minimized_corpus, 0,
3737
"If 1, the minimized corpus is saved into the first input directory. "
3838
"Example: ./fuzzer -save_minimized_corpus=1 NEW_EMPTY_DIR OLD_CORPUS")
39+
FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
40+
"merged into the 1-st corpus. Only interesting units will be taken.")
3941
FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters")
4042
FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters")
4143
FUZZER_FLAG_INT(use_traces, 0, "Experimental: use instruction traces")

lib/Fuzzer/FuzzerInternal.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class Fuzzer {
104104
void InitializeTraceState();
105105
size_t CorpusSize() const { return Corpus.size(); }
106106
void ReadDir(const std::string &Path, long *Epoch) {
107+
Printf("Loading corpus: %s\n", Path.c_str());
107108
ReadDirToVectorOfUnits(Path.c_str(), &Corpus, Epoch);
108109
}
109110
void RereadOutputCorpus();
@@ -121,6 +122,9 @@ class Fuzzer {
121122

122123
void ExecuteCallback(const Unit &U);
123124

125+
// Merge Corpora[1:] into Corpora[0].
126+
void Merge(const std::vector<std::string> &Corpora);
127+
124128
private:
125129
void AlarmCallback();
126130
void MutateAndTestOne(Unit *U);

lib/Fuzzer/FuzzerLoop.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,38 @@ void Fuzzer::ReportNewCoverage(const Unit &U) {
286286
exit(0);
287287
}
288288

289+
void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
290+
if (Corpora.size() <= 1) {
291+
Printf("Merge requires two or more corpus dirs\n");
292+
return;
293+
}
294+
auto InitialCorpusDir = Corpora[0];
295+
ReadDir(InitialCorpusDir, nullptr);
296+
Printf("Merge: running the initial corpus '%s' of %d units\n",
297+
InitialCorpusDir.c_str(), Corpus.size());
298+
for (auto &U : Corpus)
299+
RunOne(U);
300+
301+
std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end());
302+
303+
size_t NumTried = 0;
304+
size_t NumMerged = 0;
305+
for (auto &C : ExtraCorpora) {
306+
Corpus.clear();
307+
ReadDir(C, nullptr);
308+
Printf("Merge: merging the extra corpus '%s' of %zd units\n", C.c_str(),
309+
Corpus.size());
310+
for (auto &U : Corpus) {
311+
NumTried++;
312+
if (RunOne(U)) {
313+
WriteToOutputCorpus(U);
314+
NumMerged++;
315+
}
316+
}
317+
}
318+
Printf("Merge: written %zd out of %zd units\n", NumMerged, NumTried);
319+
}
320+
289321
void Fuzzer::MutateAndTestOne(Unit *U) {
290322
for (int i = 0; i < Options.MutateDepth; i++) {
291323
StartTraceRecording();

lib/Fuzzer/test/merge.test

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
CHECK: BINGO
2+
3+
RUN: rm -rf %tmp/T1 %tmp/T2
4+
RUN: mkdir -p %tmp/T1 %tmp/T2
5+
RUN: echo F..... > %tmp/T1/1
6+
RUN: echo .U.... > %tmp/T1/2
7+
RUN: echo ..Z... > %tmp/T1/3
8+
9+
# T1 has 3 elements, T2 is empty.
10+
RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK1
11+
CHECK1: Merge: running the initial corpus {{.*}} of 3 units
12+
CHECK1: Merge: written 0 out of 0 units
13+
14+
RUN: echo ...Z.. > %tmp/T2/1
15+
RUN: echo ....E. > %tmp/T2/2
16+
RUN: echo .....R > %tmp/T2/3
17+
RUN: echo F..... > %tmp/T2/a
18+
RUN: echo .U.... > %tmp/T2/b
19+
RUN: echo ..Z... > %tmp/T2/c
20+
21+
# T1 has 3 elements, T2 has 6 elements, only 3 are new.
22+
RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK2
23+
CHECK2: Merge: running the initial corpus {{.*}} of 3 units
24+
CHECK2: Merge: written 3 out of 6 units
25+
26+
# Now, T1 has 6 units and T2 has no new interesting units.
27+
RUN: LLVMFuzzer-FullCoverageSetTest -merge=1 %tmp/T1 %tmp/T2 2>&1 | FileCheck %s --check-prefix=CHECK3
28+
CHECK3: Merge: running the initial corpus {{.*}} of 6 units
29+
CHECK3: Merge: written 0 out of 6 units

0 commit comments

Comments
 (0)