summaryrefslogtreecommitdiff
path: root/lib/fuzzer
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2019-01-31 00:09:43 +0000
committerKostya Serebryany <kcc@google.com>2019-01-31 00:09:43 +0000
commit11c441a4215bedd053fb1816b3b3094f53ccefbd (patch)
tree87e43a13b0a7b2c5bec4fec0f3149547de704c44 /lib/fuzzer
parent3ba2b09f35cfb78b54ff1753c613023e84845d96 (diff)
downloadcompiler-rt-11c441a4215bedd053fb1816b3b3094f53ccefbd.tar.gz
[libFuzzer] experimental performance optimization -lazy_counters, off by default. Posix-only for now, tested on Linux
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@352700 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/fuzzer')
-rw-r--r--lib/fuzzer/FuzzerDriver.cpp3
-rw-r--r--lib/fuzzer/FuzzerFlags.def3
-rw-r--r--lib/fuzzer/FuzzerInternal.h1
-rw-r--r--lib/fuzzer/FuzzerLoop.cpp5
-rw-r--r--lib/fuzzer/FuzzerOptions.h1
-rw-r--r--lib/fuzzer/FuzzerTracePC.cpp39
-rw-r--r--lib/fuzzer/FuzzerTracePC.h3
-rw-r--r--lib/fuzzer/FuzzerUtil.h2
-rw-r--r--lib/fuzzer/FuzzerUtilFuchsia.cpp4
-rw-r--r--lib/fuzzer/FuzzerUtilPosix.cpp14
-rw-r--r--lib/fuzzer/FuzzerUtilWindows.cpp4
11 files changed, 78 insertions, 1 deletions
diff --git a/lib/fuzzer/FuzzerDriver.cpp b/lib/fuzzer/FuzzerDriver.cpp
index 6528d4d92..acebd3a7b 100644
--- a/lib/fuzzer/FuzzerDriver.cpp
+++ b/lib/fuzzer/FuzzerDriver.cpp
@@ -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);
diff --git a/lib/fuzzer/FuzzerFlags.def b/lib/fuzzer/FuzzerFlags.def
index 1bbf982c5..198e4dd91 100644
--- a/lib/fuzzer/FuzzerFlags.def
+++ b/lib/fuzzer/FuzzerFlags.def
@@ -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.")
diff --git a/lib/fuzzer/FuzzerInternal.h b/lib/fuzzer/FuzzerInternal.h
index 9950445bc..9e3e4bb94 100644
--- a/lib/fuzzer/FuzzerInternal.h
+++ b/lib/fuzzer/FuzzerInternal.h
@@ -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();
diff --git a/lib/fuzzer/FuzzerLoop.cpp b/lib/fuzzer/FuzzerLoop.cpp
index 0247b574d..959d5a235 100644
--- a/lib/fuzzer/FuzzerLoop.cpp
+++ b/lib/fuzzer/FuzzerLoop.cpp
@@ -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();
diff --git a/lib/fuzzer/FuzzerOptions.h b/lib/fuzzer/FuzzerOptions.h
index ef89754fa..3f8e959f4 100644
--- a/lib/fuzzer/FuzzerOptions.h
+++ b/lib/fuzzer/FuzzerOptions.h
@@ -67,6 +67,7 @@ struct FuzzingOptions {
bool HandleXfsz = false;
bool HandleUsr1 = false;
bool HandleUsr2 = false;
+ bool LazyCounters = false;
};
} // namespace fuzzer
diff --git a/lib/fuzzer/FuzzerTracePC.cpp b/lib/fuzzer/FuzzerTracePC.cpp
index 12ed9f842..34a07b87a 100644
--- a/lib/fuzzer/FuzzerTracePC.cpp
+++ b/lib/fuzzer/FuzzerTracePC.cpp
@@ -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);
diff --git a/lib/fuzzer/FuzzerTracePC.h b/lib/fuzzer/FuzzerTracePC.h
index 2ab75b828..49514b92e 100644
--- a/lib/fuzzer/FuzzerTracePC.h
+++ b/lib/fuzzer/FuzzerTracePC.h
@@ -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;
diff --git a/lib/fuzzer/FuzzerUtil.h b/lib/fuzzer/FuzzerUtil.h
index 85c5571d6..0a127911d 100644
--- a/lib/fuzzer/FuzzerUtil.h
+++ b/lib/fuzzer/FuzzerUtil.h
@@ -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();
diff --git a/lib/fuzzer/FuzzerUtilFuchsia.cpp b/lib/fuzzer/FuzzerUtilFuchsia.cpp
index bef419235..7b5c8f647 100644
--- a/lib/fuzzer/FuzzerUtilFuchsia.cpp
+++ b/lib/fuzzer/FuzzerUtilFuchsia.cpp
@@ -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.
diff --git a/lib/fuzzer/FuzzerUtilPosix.cpp b/lib/fuzzer/FuzzerUtilPosix.cpp
index 68948d5ae..56b10ffa6 100644
--- a/lib/fuzzer/FuzzerUtilPosix.cpp
+++ b/lib/fuzzer/FuzzerUtilPosix.cpp
@@ -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)
diff --git a/lib/fuzzer/FuzzerUtilWindows.cpp b/lib/fuzzer/FuzzerUtilWindows.cpp
index 524f63cf1..75b43f7a1 100644
--- a/lib/fuzzer/FuzzerUtilWindows.cpp
+++ b/lib/fuzzer/FuzzerUtilWindows.cpp
@@ -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;