[libFuzzer] add -print_funcs=1 (on bey default): print newly discovered functions during fuzzing

llvm-svn: 311797
This commit is contained in:
Kostya Serebryany 2017-08-25 20:09:25 +00:00
parent 1dbb7578ff
commit 2eef816e6e
8 changed files with 69 additions and 6 deletions

View File

@ -603,6 +603,7 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
Options.SaveArtifacts =
!DoPlainRun || Flags.minimize_crash_internal_step;
Options.PrintNewCovPcs = Flags.print_pcs;
Options.PrintNewCovFuncs = Flags.print_funcs;
Options.PrintFinalStats = Flags.print_final_stats;
Options.PrintCorpusStats = Flags.print_corpus_stats;
Options.PrintCoverage = Flags.print_coverage;

View File

@ -91,6 +91,7 @@ FUZZER_FLAG_STRING(exact_artifact_path,
"and will not use checksum in the file name. Do not "
"use the same path for several parallel processes.")
FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
FUZZER_FLAG_INT(print_funcs, 1, "If 1, print out newly covered functions.")
FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
FUZZER_FLAG_INT(print_corpus_stats, 0,
"If 1, print statistics on corpus elements at exit.")

View File

@ -626,6 +626,7 @@ void Fuzzer::MutateAndTestOne() {
void Fuzzer::Loop() {
TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
TPC.SetPrintNewFuncs(Options.PrintNewCovFuncs);
system_clock::time_point LastCorpusReload = system_clock::now();
if (Options.DoCrossOver)
MD.SetCorpus(&Corpus);

View File

@ -47,6 +47,7 @@ struct FuzzingOptions {
bool SaveArtifacts = true;
bool PrintNEW = true; // Print a status line when new units are found;
bool PrintNewCovPcs = false;
bool PrintNewCovFuncs = false;
bool PrintFinalStats = false;
bool PrintCorpusStats = false;
bool PrintCoverage = false;

View File

@ -143,11 +143,18 @@ void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
}
void TracePC::UpdateObservedPCs() {
auto Observe = [&](uintptr_t PC) {
bool Inserted = ObservedPCs.insert(PC).second;
if (Inserted && DoPrintNewPCs)
auto ObservePC = [&](uintptr_t PC) {
if (ObservedPCs.insert(PC).second && DoPrintNewPCs)
PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PC + 1);
};
auto Observe = [&](const PCTableEntry &TE) {
if (TE.PCFlags & 1)
if (ObservedFuncs.insert(TE.PC).second && DoPrintNewFuncs)
PrintPC("\tNEW_FUNC: %p %F %L\n", "\tNEW_PC: %p\n", TE.PC + 1);
ObservePC(TE.PC);
};
if (NumPCsInPCTables) {
if (NumInline8bitCounters == NumPCsInPCTables) {
for (size_t i = 0; i < NumModulesWithInline8bitCounters; i++) {
@ -157,7 +164,7 @@ void TracePC::UpdateObservedPCs() {
(size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
for (size_t j = 0; j < Size; j++)
if (Beg[j])
Observe(ModulePCTable[i].Start[j].PC);
Observe(ModulePCTable[i].Start[j]);
}
} else if (NumGuards == NumPCsInPCTables) {
size_t GuardIdx = 1;
@ -168,7 +175,7 @@ void TracePC::UpdateObservedPCs() {
(size_t)(ModulePCTable[i].Stop - ModulePCTable[i].Start));
for (size_t j = 0; j < Size; j++, GuardIdx++)
if (Counters()[GuardIdx])
Observe(ModulePCTable[i].Start[j].PC);
Observe(ModulePCTable[i].Start[j]);
}
}
}
@ -177,7 +184,7 @@ void TracePC::UpdateObservedPCs() {
auto P = ClangCountersBegin();
for (size_t Idx = 0; Idx < NumClangCounters; Idx++)
if (P[Idx])
Observe((uintptr_t)Idx);
ObservePC((uintptr_t)Idx);
}
}

View File

@ -82,6 +82,7 @@ class TracePC {
void SetUseCounters(bool UC) { UseCounters = UC; }
void SetUseValueProfile(bool VP) { UseValueProfile = VP; }
void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; }
void SetPrintNewFuncs(bool P) { DoPrintNewFuncs = P; }
void UpdateObservedPCs();
template <class Callback> void CollectFeatures(Callback CB) const;
@ -133,6 +134,7 @@ private:
bool UseCounters = false;
bool UseValueProfile = false;
bool DoPrintNewPCs = false;
bool DoPrintNewFuncs = false;
struct Module {
uint32_t *Start, *Stop;
@ -158,6 +160,7 @@ private:
uintptr_t *PCs() const;
std::set<uintptr_t> ObservedPCs;
std::set<uintptr_t> ObservedFuncs;
ValueBitMap ValueProfileMap;
uintptr_t InitialStack;

View File

@ -0,0 +1,39 @@
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// Simple test for a fuzzer. The fuzzer must find the string "Hi!".
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <iostream>
extern "C" {
__attribute__((noinline))
void FunctionC(const uint8_t *Data, size_t Size) {
if (Size > 3 && Data[3] == 'Z') {
static bool PrintedOnce = false;
if (!PrintedOnce) {
std::cout << "BINGO\n";
PrintedOnce = true;
}
}
}
__attribute__((noinline))
void FunctionB(const uint8_t *Data, size_t Size) {
if (Size > 2 && Data[2] == 'Z')
FunctionC(Data, Size);
}
__attribute__((noinline))
void FunctionA(const uint8_t *Data, size_t Size) {
if (Size > 1 && Data[1] == 'U')
FunctionB(Data, Size);
}
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size > 0 && Data[0] == 'F')
FunctionA(Data, Size);
return 0;
}

View File

@ -0,0 +1,10 @@
RUN: %cpp_compiler %S/PrintFuncTest.cpp -o %t
RUN: %t -seed=1 -runs=100000 2>&1 | FileCheck %s
RUN: %t -seed=1 -runs=100000 -print_funcs=0 2>&1 | FileCheck %s --check-prefix=NO
CHECK: NEW_FUNC: {{.*}} FunctionA
CHECK: NEW_FUNC: {{.*}} FunctionB
CHECK: NEW_FUNC: {{.*}} FunctionC
CHECK: BINGO
NO-NOT: NEW_FUNC
NO: BINGO