[libFuzzer] experimental performance optimization -lazy_counters, off by default. Posix-only for now, tested on Linux
llvm-svn: 352700
This commit is contained in:
parent
49c4c68919
commit
8da9479e40
@ -658,7 +658,10 @@ int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
||||
Options.HandleXfsz = Flags.handle_xfsz;
|
||||
Options.HandleUsr1 = Flags.handle_usr1;
|
||||
Options.HandleUsr2 = Flags.handle_usr2;
|
||||
Options.LazyCounters = Flags.lazy_counters;
|
||||
SetSignalHandler(Options);
|
||||
if (Options.LazyCounters)
|
||||
TPC.ProtectLazyCounters();
|
||||
|
||||
std::atexit(Fuzzer::StaticExitCallback);
|
||||
|
||||
|
||||
@ -117,6 +117,9 @@ FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
|
||||
FUZZER_FLAG_INT(handle_xfsz, 1, "If 1, try to intercept SIGXFSZ.")
|
||||
FUZZER_FLAG_INT(handle_usr1, 1, "If 1, try to intercept SIGUSR1.")
|
||||
FUZZER_FLAG_INT(handle_usr2, 1, "If 1, try to intercept SIGUSR2.")
|
||||
FUZZER_FLAG_INT(lazy_counters, 0, "If 1, a performance optimization is"
|
||||
"enabled for the 8bit inline counters. "
|
||||
"Requires that libFuzzer successfully installs its SEGV handler")
|
||||
FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
|
||||
"if 2, close stderr; if 3, close both. "
|
||||
"Be careful, this will also close e.g. stderr of asan.")
|
||||
|
||||
@ -59,6 +59,7 @@ public:
|
||||
size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
|
||||
|
||||
static void StaticAlarmCallback();
|
||||
static void StaticSegvSignalCallback(void *Addr);
|
||||
static void StaticCrashSignalCallback();
|
||||
static void StaticExitCallback();
|
||||
static void StaticInterruptCallback();
|
||||
|
||||
@ -205,6 +205,11 @@ void Fuzzer::StaticCrashSignalCallback() {
|
||||
F->CrashCallback();
|
||||
}
|
||||
|
||||
void Fuzzer::StaticSegvSignalCallback(void *Addr) {
|
||||
if (TPC.UnprotectLazyCounters(Addr)) return;
|
||||
StaticCrashSignalCallback();
|
||||
}
|
||||
|
||||
void Fuzzer::StaticExitCallback() {
|
||||
assert(F);
|
||||
F->ExitCallback();
|
||||
|
||||
@ -67,6 +67,7 @@ struct FuzzingOptions {
|
||||
bool HandleXfsz = false;
|
||||
bool HandleUsr1 = false;
|
||||
bool HandleUsr2 = false;
|
||||
bool LazyCounters = false;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
@ -67,6 +67,45 @@ void TracePC::HandleInline8bitCountersInit(uint8_t *Start, uint8_t *Stop) {
|
||||
NumInline8bitCounters += M.Size();
|
||||
}
|
||||
|
||||
// Mark all full page counter regions as PROT_NONE and set Enabled=false.
|
||||
// The first time the instrumented code hits such a protected/disabled
|
||||
// counter region we should catch a SEGV and call UnprotectLazyCounters,
|
||||
// which will mark the page as PROT_READ|PROT_WRITE and set Enabled=true.
|
||||
//
|
||||
// Whenever other functions iterate over the counters they should ignore
|
||||
// regions with Enabled=false.
|
||||
void TracePC::ProtectLazyCounters() {
|
||||
size_t NumPagesProtected = 0;
|
||||
IterateCounterRegions([&](Module::Region &R) {
|
||||
if (!R.OneFullPage) return;
|
||||
if (Mprotect(R.Start, R.Stop - R.Start, false)) {
|
||||
R.Enabled = false;
|
||||
NumPagesProtected++;
|
||||
}
|
||||
});
|
||||
if (NumPagesProtected)
|
||||
Printf("INFO: %zd pages of counters where protected;"
|
||||
" libFuzzer's SEGV handler must be installed\n",
|
||||
NumPagesProtected);
|
||||
}
|
||||
|
||||
bool TracePC::UnprotectLazyCounters(void *CounterPtr) {
|
||||
// Printf("UnprotectLazyCounters: %p\n", CounterPtr);
|
||||
if (!CounterPtr)
|
||||
return false;
|
||||
bool Done = false;
|
||||
uint8_t *Addr = reinterpret_cast<uint8_t *>(CounterPtr);
|
||||
IterateCounterRegions([&](Module::Region &R) {
|
||||
if (!R.OneFullPage || R.Enabled || Done) return;
|
||||
if (Addr >= R.Start && Addr < R.Stop)
|
||||
if (Mprotect(R.Start, R.Stop - R.Start, true)) {
|
||||
R.Enabled = true;
|
||||
Done = true;
|
||||
}
|
||||
});
|
||||
return Done;
|
||||
}
|
||||
|
||||
void TracePC::HandlePCsInit(const uintptr_t *Start, const uintptr_t *Stop) {
|
||||
const PCTableEntry *B = reinterpret_cast<const PCTableEntry *>(Start);
|
||||
const PCTableEntry *E = reinterpret_cast<const PCTableEntry *>(Stop);
|
||||
|
||||
@ -119,6 +119,9 @@ class TracePC {
|
||||
void SetFocusFunction(const std::string &FuncName);
|
||||
bool ObservedFocusFunction();
|
||||
|
||||
void ProtectLazyCounters();
|
||||
bool UnprotectLazyCounters(void *CounterPtr);
|
||||
|
||||
private:
|
||||
bool UseCounters = false;
|
||||
uint32_t UseValueProfileMask = false;
|
||||
|
||||
@ -52,6 +52,8 @@ void SetSignalHandler(const FuzzingOptions& Options);
|
||||
|
||||
void SleepSeconds(int Seconds);
|
||||
|
||||
bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite);
|
||||
|
||||
unsigned long GetPid();
|
||||
|
||||
size_t GetPeakRSSMb();
|
||||
|
||||
@ -287,6 +287,10 @@ void CrashHandler(zx_handle_t *Event) {
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
|
||||
return false; // UNIMPLEMENTED
|
||||
}
|
||||
|
||||
// Platform specific functions.
|
||||
void SetSignalHandler(const FuzzingOptions &Options) {
|
||||
// Set up alarm handler if needed.
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include <iomanip>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
@ -31,6 +32,11 @@ static void AlarmHandler(int, siginfo_t *, void *) {
|
||||
Fuzzer::StaticAlarmCallback();
|
||||
}
|
||||
|
||||
static void SegvHandler(int, siginfo_t *si, void *) {
|
||||
assert(si->si_signo == SIGSEGV);
|
||||
Fuzzer::StaticSegvSignalCallback(si->si_addr);
|
||||
}
|
||||
|
||||
static void CrashHandler(int, siginfo_t *, void *) {
|
||||
Fuzzer::StaticCrashSignalCallback();
|
||||
}
|
||||
@ -64,6 +70,7 @@ static void SetSigaction(int signum,
|
||||
}
|
||||
|
||||
sigact = {};
|
||||
sigact.sa_flags = SA_SIGINFO;
|
||||
sigact.sa_sigaction = callback;
|
||||
if (sigaction(signum, &sigact, 0)) {
|
||||
Printf("libFuzzer: sigaction failed with %d\n", errno);
|
||||
@ -82,6 +89,11 @@ void SetTimer(int Seconds) {
|
||||
SetSigaction(SIGALRM, AlarmHandler);
|
||||
}
|
||||
|
||||
bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
|
||||
return 0 == mprotect(Ptr, Size,
|
||||
AllowReadWrite ? (PROT_READ | PROT_WRITE) : PROT_NONE);
|
||||
}
|
||||
|
||||
void SetSignalHandler(const FuzzingOptions& Options) {
|
||||
if (Options.UnitTimeoutSec > 0)
|
||||
SetTimer(Options.UnitTimeoutSec / 2 + 1);
|
||||
@ -90,7 +102,7 @@ void SetSignalHandler(const FuzzingOptions& Options) {
|
||||
if (Options.HandleTerm)
|
||||
SetSigaction(SIGTERM, InterruptHandler);
|
||||
if (Options.HandleSegv)
|
||||
SetSigaction(SIGSEGV, CrashHandler);
|
||||
SetSigaction(SIGSEGV, SegvHandler);
|
||||
if (Options.HandleBus)
|
||||
SetSigaction(SIGBUS, CrashHandler);
|
||||
if (Options.HandleAbrt)
|
||||
|
||||
@ -111,6 +111,10 @@ static TimerQ Timer;
|
||||
|
||||
static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
|
||||
|
||||
bool Mprotect(void *Ptr, size_t Size, bool AllowReadWrite) {
|
||||
return false; // UNIMPLEMENTED
|
||||
}
|
||||
|
||||
void SetSignalHandler(const FuzzingOptions& Options) {
|
||||
HandlerOpt = &Options;
|
||||
|
||||
|
||||
@ -1,2 +1,6 @@
|
||||
REQUIRES: linux
|
||||
RUN: %cpp_compiler %S/LargeTest.cpp -o %t-LargeTest
|
||||
RUN: %run %t-LargeTest -runs=10000
|
||||
RUN: ASAN_OPTIONS=handle_segv=0 %run %t-LargeTest -runs=10000 -lazy_counters=1 2>&1 | FileCheck %s
|
||||
|
||||
CHECK: pages of counters where protected; libFuzzer's SEGV handler must be installed
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user