Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

Commit 1a42a60

Browse files
committed
[libFuzzer] experimental flag -drill (another search heuristic; Mike Aizatsky's idea)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@252838 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 6c3ce45 commit 1a42a60

File tree

6 files changed

+89
-20
lines changed

6 files changed

+89
-20
lines changed

lib/Fuzzer/FuzzerDriver.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ static void WorkerThread(const std::string &Cmd, std::atomic<int> *Counter,
152152
std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
153153
if (Flags.verbosity)
154154
Printf("%s", ToRun.c_str());
155-
int ExitCode = system(ToRun.c_str());
155+
int ExitCode = ExecuteCommand(ToRun.c_str());
156156
if (ExitCode != 0)
157157
*HasErrors = true;
158158
std::lock_guard<std::mutex> Lock(Mu);
@@ -255,15 +255,19 @@ int FuzzerDriver(const std::vector<std::string> &Args,
255255
Options.ReportSlowUnits = Flags.report_slow_units;
256256
if (Flags.artifact_prefix)
257257
Options.ArtifactPrefix = Flags.artifact_prefix;
258+
std::vector<Unit> Dictionary;
258259
if (Flags.dict)
259-
if (!ParseDictionaryFile(FileToString(Flags.dict), &Options.Dictionary))
260+
if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
260261
return 1;
261-
if (Flags.verbosity > 0 && !Options.Dictionary.empty())
262-
Printf("Dictionary: %zd entries\n", Options.Dictionary.size());
262+
if (Flags.verbosity > 0 && !Dictionary.empty())
263+
Printf("Dictionary: %zd entries\n", Dictionary.size());
263264
Options.SaveArtifacts = !Flags.test_single_input;
264265

265266
Fuzzer F(USF, Options);
266267

268+
for (auto &U: Dictionary)
269+
USF.GetMD().AddWordToDictionary(U.data(), U.size());
270+
267271
// Timer
268272
if (Flags.timeout > 0)
269273
SetTimer(Flags.timeout / 2 + 1);
@@ -294,7 +298,11 @@ int FuzzerDriver(const std::vector<std::string> &Args,
294298
F.ShuffleAndMinimize();
295299
if (Flags.save_minimized_corpus)
296300
F.SaveCorpus();
297-
F.Loop();
301+
else if (Flags.drill)
302+
F.Drill();
303+
else
304+
F.Loop();
305+
298306
if (Flags.verbosity)
299307
Printf("Done %d runs in %zd second(s)\n", F.getTotalNumberOfRuns(),
300308
F.secondsSinceProcessStartUp());

lib/Fuzzer/FuzzerFlags.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,5 @@ FUZZER_FLAG_STRING(test_single_input, "Use specified file as test input.")
6767
FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, "
6868
"timeout, or slow inputs) as "
6969
"$(artifact_prefix)file")
70+
FUZZER_FLAG_INT(drill, 0, "Experimental: fuzz using a single unit as the seed "
71+
"corpus, then merge with the initial corpus")

lib/Fuzzer/FuzzerInternal.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void PrintASCII(const Unit &U, const char *PrintAfter = "");
4343
std::string Hash(const Unit &U);
4444
void SetTimer(int Seconds);
4545
void PrintFileAsBase64(const std::string &Path);
46-
void ExecuteCommand(const std::string &Command);
46+
int ExecuteCommand(const std::string &Command);
4747

4848
// Private copy of SHA1 implementation.
4949
static const int kSHA1NumBytes = 20;
@@ -94,13 +94,15 @@ class Fuzzer {
9494
std::string OutputCorpus;
9595
std::string SyncCommand;
9696
std::string ArtifactPrefix = "./";
97-
std::vector<Unit> Dictionary;
9897
bool SaveArtifacts = true;
98+
bool PrintNEW = true; // Print a status line when new units are found;
9999
};
100100
Fuzzer(UserSuppliedFuzzer &USF, FuzzingOptions Options);
101101
void AddToCorpus(const Unit &U) { Corpus.push_back(U); }
102-
size_t ChooseUnitToMutate();
102+
size_t ChooseUnitIdxToMutate();
103+
const Unit &ChooseUnitToMutate() { return Corpus[ChooseUnitIdxToMutate()]; };
103104
void Loop();
105+
void Drill();
104106
void ShuffleAndMinimize();
105107
void InitializeTraceState();
106108
size_t CorpusSize() const { return Corpus.size(); }
@@ -135,6 +137,7 @@ class Fuzzer {
135137
void WriteToOutputCorpus(const Unit &U);
136138
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
137139
void PrintStats(const char *Where, const char *End = "\n");
140+
void PrintStatusForNewUnit(const Unit &U);
138141
void PrintUnitInASCII(const Unit &U, const char *PrintAfter = "");
139142

140143
void SyncCorpus();

lib/Fuzzer/FuzzerLoop.cpp

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ extern "C" {
1818
// libFuzzer can be linked w/o the sanitizers and sanitizer-coveragte
1919
// (in which case it will complain at start-up time).
2020
__attribute__((weak)) void __sanitizer_print_stack_trace();
21+
__attribute__((weak)) void __sanitizer_reset_coverage();
2122
__attribute__((weak)) size_t __sanitizer_get_total_unique_caller_callee_pairs();
2223
__attribute__((weak)) size_t __sanitizer_get_total_unique_coverage();
2324
__attribute__((weak))
@@ -293,9 +294,9 @@ void Fuzzer::SaveCorpus() {
293294
Options.OutputCorpus.c_str());
294295
}
295296

296-
void Fuzzer::ReportNewCoverage(const Unit &U) {
297-
Corpus.push_back(U);
298-
UnitHashesAddedToCorpus.insert(Hash(U));
297+
void Fuzzer::PrintStatusForNewUnit(const Unit &U) {
298+
if (!Options.PrintNEW)
299+
return;
299300
PrintStats("NEW ", "");
300301
if (Options.Verbosity) {
301302
Printf(" L: %zd", U.size());
@@ -306,6 +307,12 @@ void Fuzzer::ReportNewCoverage(const Unit &U) {
306307
}
307308
Printf("\n");
308309
}
310+
}
311+
312+
void Fuzzer::ReportNewCoverage(const Unit &U) {
313+
Corpus.push_back(U);
314+
UnitHashesAddedToCorpus.insert(Hash(U));
315+
PrintStatusForNewUnit(U);
309316
WriteToOutputCorpus(U);
310317
if (Options.ExitOnFirst)
311318
exit(0);
@@ -374,7 +381,7 @@ void Fuzzer::MutateAndTestOne(Unit *U) {
374381
// Returns an index of random unit from the corpus to mutate.
375382
// Hypothesis: units added to the corpus last are more likely to be interesting.
376383
// This function gives more wieght to the more recent units.
377-
size_t Fuzzer::ChooseUnitToMutate() {
384+
size_t Fuzzer::ChooseUnitIdxToMutate() {
378385
size_t N = Corpus.size();
379386
size_t Total = (N + 1) * N / 2;
380387
size_t R = USF.GetRand()(Total);
@@ -391,12 +398,57 @@ size_t Fuzzer::ChooseUnitToMutate() {
391398
return IdxBeg;
392399
}
393400

394-
void Fuzzer::Loop() {
395-
for (auto &U: Options.Dictionary)
396-
USF.GetMD().AddWordToDictionary(U.data(), U.size());
401+
// Experimental search heuristic: drilling.
402+
// - Read, shuffle, execute and minimize the corpus.
403+
// - Choose one random unit.
404+
// - Reset the coverage.
405+
// - Start fuzzing as if the chosen unit was the only element of the corpus.
406+
// - When done, reset the coverage again.
407+
// - Merge the newly created corpus into the original one.
408+
void Fuzzer::Drill() {
409+
// The corpus is already read, shuffled, and minimized.
410+
assert(!Corpus.empty());
411+
Options.PrintNEW = false; // Don't print NEW status lines when drilling.
412+
413+
Unit U = ChooseUnitToMutate();
414+
415+
CHECK_WEAK_API_FUNCTION(__sanitizer_reset_coverage);
416+
__sanitizer_reset_coverage();
417+
418+
std::vector<Unit> SavedCorpus;
419+
SavedCorpus.swap(Corpus);
420+
Corpus.push_back(U);
421+
assert(Corpus.size() == 1);
422+
RunOne(U);
423+
PrintStats("DRILL ");
424+
std::string SavedOutputCorpusPath; // Don't write new units while drilling.
425+
SavedOutputCorpusPath.swap(Options.OutputCorpus);
426+
Loop();
427+
428+
__sanitizer_reset_coverage();
429+
430+
PrintStats("REINIT");
431+
SavedOutputCorpusPath.swap(Options.OutputCorpus);
432+
for (auto &U : SavedCorpus)
433+
RunOne(U);
434+
PrintStats("MERGE ");
435+
Options.PrintNEW = true;
436+
size_t NumMerged = 0;
437+
for (auto &U : Corpus) {
438+
if (RunOne(U)) {
439+
PrintStatusForNewUnit(U);
440+
NumMerged++;
441+
WriteToOutputCorpus(U);
442+
}
443+
}
444+
PrintStats("MERGED");
445+
if (NumMerged && Options.Verbosity)
446+
Printf("Drilling discovered %zd new units\n", NumMerged);
447+
}
397448

449+
void Fuzzer::Loop() {
398450
while (true) {
399-
size_t J1 = ChooseUnitToMutate();;
451+
size_t J1 = ChooseUnitIdxToMutate();;
400452
SyncCorpus();
401453
RereadOutputCorpus();
402454
if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
@@ -408,7 +460,7 @@ void Fuzzer::Loop() {
408460
CurrentUnit = Corpus[J1];
409461
// Optionally, cross with another unit.
410462
if (Options.DoCrossOver && USF.GetRand().RandBool()) {
411-
size_t J2 = ChooseUnitToMutate();
463+
size_t J2 = ChooseUnitIdxToMutate();
412464
if (!Corpus[J1].empty() && !Corpus[J2].empty()) {
413465
assert(!Corpus[J2].empty());
414466
CurrentUnit.resize(Options.MaxLen);

lib/Fuzzer/FuzzerUtil.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ int NumberOfCpuCores() {
6969
return N;
7070
}
7171

72-
void ExecuteCommand(const std::string &Command) {
73-
system(Command.c_str());
72+
int ExecuteCommand(const std::string &Command) {
73+
return system(Command.c_str());
7474
}
7575

7676
bool ToASCII(Unit &U) {

lib/Fuzzer/test/fuzzer.test

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ NullDerefTestPrefix: Test unit written to ZZZcrash-
3131

3232
#not LLVMFuzzer-FullCoverageSetTest -timeout=15 -seed=1 -mutate_depth=2 -use_full_coverage_set=1 2>&1 | FileCheck %s
3333

34-
#not LLVMFuzzer-FourIndependentBranchesTest -timeout=15 -seed=1 -use_traces=1 2>&1 | FileCheck %s
34+
RUN: rm -rf FourIndependentBranchesTestCORPUS
35+
RUN: mkdir FourIndependentBranchesTestCORPUS
36+
RUN: LLVMFuzzer-FourIndependentBranchesTest -seed=1 -runs=1000000 FourIndependentBranchesTestCORPUS
37+
RUN: not LLVMFuzzer-FourIndependentBranchesTest -runs=100000 -drill=1 -jobs=200 FourIndependentBranchesTestCORPUS 2>&1 | FileCheck %s
38+
RUN: rm -rf FourIndependentBranchesTestCORPUS
3539

3640
RUN: not LLVMFuzzer-CounterTest -use_counters=1 -max_len=6 -seed=1 -timeout=15 2>&1 | FileCheck %s
3741

0 commit comments

Comments
 (0)