[libFuzzer] add -exit_on_src_pos to test libFuzzer itself, add a test script for RE2 that uses this flag

llvm-svn: 282458
This commit is contained in:
Kostya Serebryany 2016-09-27 00:10:20 +00:00
parent bde62d78e9
commit 5ff481fd9e
12 changed files with 55 additions and 13 deletions

View File

@ -79,6 +79,7 @@ void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
void PrintASCII(const Unit &U, const char *PrintAfter = "");
void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC);
std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC);
std::string Hash(const Unit &U);
void SetTimer(int Seconds);
void SetSigSegvHandler();

View File

@ -428,6 +428,8 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.PrintCorpusStats = Flags.print_corpus_stats;
Options.PrintCoverage = Flags.print_coverage;
Options.PruneCorpus = Flags.prune_corpus;
if (Flags.exit_on_src_pos)
Options.ExitOnSrcPos = Flags.exit_on_src_pos;
unsigned Seed = Flags.seed;
// Initialize Seed.

View File

@ -94,6 +94,9 @@ FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
"reaching this limit of RSS memory usage.")
FUZZER_FLAG_INT(prune_corpus, 1, "Prune corpus items without new coverage when "
"loading corpus.")
FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
" from the given source location. Example: -exit_on_src_pos=foo.cc:123. "
"Used primarily for testing libFuzzer itself.")
FUZZER_DEPRECATED_FLAG(exit_on_first)
FUZZER_DEPRECATED_FLAG(save_minimized_corpus)

View File

@ -116,6 +116,7 @@ private:
void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
bool DuringInitialCorpusExecution);
void AddToCorpusAndMaybeRerun(const Unit &U);
void CheckExitOnSrcPos();
bool UpdateMaxCoverage();

View File

@ -374,7 +374,24 @@ void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
this->MaxMutationLen = MaxMutationLen;
}
void Fuzzer::CheckExitOnSrcPos() {
if (!Options.ExitOnSrcPos.empty()) {
uintptr_t *PCIDs;
if (size_t NumNewPCIDs = TPC.GetNewPCIDs(&PCIDs)) {
for (size_t i = 0; i < NumNewPCIDs; i++) {
std::string Descr = DescribePC("%L", TPC.GetPCbyPCID(PCIDs[i]));
if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
Printf("INFO: found line matching '%s', exiting.\n",
Options.ExitOnSrcPos.c_str());
_Exit(0);
}
}
}
}
}
void Fuzzer::AddToCorpusAndMaybeRerun(const Unit &U) {
CheckExitOnSrcPos();
Corpus.AddToCorpus(U);
if (TPC.GetTotalPCCoverage()) {
TPC.ResetMaps();

View File

@ -40,6 +40,7 @@ struct FuzzingOptions {
std::string OutputCorpus;
std::string ArtifactPrefix = "./";
std::string ExactArtifactPath;
std::string ExitOnSrcPos;
bool SaveArtifacts = true;
bool PrintNEW = true; // Print a status line when new units are found;
bool OutputCSV = false;

View File

@ -70,7 +70,7 @@ void TracePC::ResetGuards() {
void TracePC::FinalizeTrace() {
if (TotalPCCoverage) {
for (size_t Idx = 1, N = Min(kNumCounters, NumGuards); Idx < N;
for (size_t Idx = 1, N = Min(kNumCounters, NumGuards + 1); Idx < N;
Idx++) {
uint8_t Counter = Counters[Idx];
if (!Counter) continue;
@ -96,7 +96,7 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
void TracePC::PrintCoverage() {
Printf("COVERAGE:\n");
for (size_t i = 0; i < Min(NumGuards, kNumPCs); i++) {
for (size_t i = 0; i < Min(NumGuards + 1, kNumPCs); i++) {
if (PCs[i])
PrintPC("COVERED: %p %F %L\n", "COVERED: %p\n", PCs[i]);
}

View File

@ -40,7 +40,6 @@ class TracePC {
return Min(kMaxNewPCIDs, NumNewPCIDs);
}
void ResetNewPCIDs() { NumNewPCIDs = 0; }
uintptr_t GetPCbyPCID(uintptr_t PCID) { return PCs[PCID]; }
void ResetMaps() {
@ -64,7 +63,7 @@ private:
bool UseValueProfile = false;
size_t TotalPCCoverage = 0;
static const size_t kMaxNewPCIDs = 64;
static const size_t kMaxNewPCIDs = 1024;
uintptr_t NewPCIDs[kMaxNewPCIDs];
size_t NumNewPCIDs = 0;
void AddNewPCID(uintptr_t PCID) {

View File

@ -290,16 +290,20 @@ size_t GetPeakRSSMb() {
return 0;
}
std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
if (!EF->__sanitizer_symbolize_pc) return "<can not symbolize>";
char PcDescr[1024];
EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
SymbolizedFMT, PcDescr, sizeof(PcDescr));
PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case.
return PcDescr;
}
void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
if (EF->__sanitizer_symbolize_pc) {
char PcDescr[1024];
EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
SymbolizedFMT, PcDescr, sizeof(PcDescr));
PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case.
Printf("%s", PcDescr);
} else {
if (EF->__sanitizer_symbolize_pc)
Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());
else
Printf(FallbackFMT, PC);
}
}
} // namespace fuzzer

View File

@ -0,0 +1,10 @@
#!/bin/bash
set -x
SCRIPT_DIR=$(dirname $0)
EXECUTABLE_NAME_BASE=$(basename $SCRIPT_DIR)
CORPUS=CORPUS-$EXECUTABLE_NAME_BASE
JOBS=8
rm -rf $CORPUS
mkdir $CORPUS
[ -e $EXECUTABLE_NAME_BASE ] && ./$EXECUTABLE_NAME_BASE -exit_on_src_pos=re2/dfa.cc:474 -exit_on_src_pos=re2/dfa.cc:474 -runs=1000000 -jobs=$JOBS $CORPUS
grep "INFO: found line matching 're2/dfa.cc:474', exiting." fuzz-0.log

View File

@ -21,7 +21,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
int Z = Ids[(unsigned char)'Z'];
if (F >= 0 && U > F && Z > U) {
Sink++;
// printf("IDS: %d %d %d\n", F, U, Z);
// fprintf(stderr, "IDS: %d %d %d\n", F, U, Z);
}
return 0;
}

View File

@ -53,3 +53,7 @@ RUN: not LLVMFuzzer-DSOTest 2>&1 | FileCheck %s --check-prefix=DSO
DSO: INFO: Loaded 3 modules
DSO: BINGO
RUN: LLVMFuzzer-SimpleTest-TracePC -exit_on_src_pos=SimpleTest.cpp:17 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
RUN: LLVMFuzzer-MinimizeCorpusTest-TracePC -exit_on_src_pos=MinimizeCorpusTest.cpp:23 2>&1 | FileCheck %s --check-prefix=EXIT_ON_SRC_POS
EXIT_ON_SRC_POS: INFO: found line matching '{{.*}}', exiting.