diff options
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerDriver.cpp | 3 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerFlags.def | 3 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerInternal.h | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerLoop.cpp | 5 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerOptions.h | 1 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerTracePC.cpp | 39 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerTracePC.h | 3 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerUtil.h | 2 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp | 4 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp | 14 | ||||
| -rw-r--r-- | compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp | 4 | ||||
| -rw-r--r-- | compiler-rt/test/fuzzer/large.test | 4 | 
12 files changed, 82 insertions, 1 deletions
diff --git a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp b/compiler-rt/lib/fuzzer/FuzzerDriver.cpp index 6528d4d9240..acebd3a7b1e 100644 --- a/compiler-rt/lib/fuzzer/FuzzerDriver.cpp +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerFlags.def b/compiler-rt/lib/fuzzer/FuzzerFlags.def index 1bbf982c51c..198e4dd91e6 100644 --- a/compiler-rt/lib/fuzzer/FuzzerFlags.def +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerInternal.h b/compiler-rt/lib/fuzzer/FuzzerInternal.h index 9950445bc18..9e3e4bb948c 100644 --- a/compiler-rt/lib/fuzzer/FuzzerInternal.h +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerLoop.cpp b/compiler-rt/lib/fuzzer/FuzzerLoop.cpp index 0247b574df8..959d5a23559 100644 --- a/compiler-rt/lib/fuzzer/FuzzerLoop.cpp +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerOptions.h b/compiler-rt/lib/fuzzer/FuzzerOptions.h index ef89754fa0f..3f8e959f490 100644 --- a/compiler-rt/lib/fuzzer/FuzzerOptions.h +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp b/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp index 12ed9f842a4..34a07b87a6d 100644 --- a/compiler-rt/lib/fuzzer/FuzzerTracePC.cpp +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerTracePC.h b/compiler-rt/lib/fuzzer/FuzzerTracePC.h index 2ab75b8286b..49514b92e76 100644 --- a/compiler-rt/lib/fuzzer/FuzzerTracePC.h +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerUtil.h b/compiler-rt/lib/fuzzer/FuzzerUtil.h index 85c5571d684..0a127911df3 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtil.h +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp index bef4192353a..7b5c8f647ae 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtilFuchsia.cpp +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp index 68948d5ae21..56b10ffa668 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtilPosix.cpp +++ b/compiler-rt/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/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp b/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp index 524f63cf1a7..75b43f7a183 100644 --- a/compiler-rt/lib/fuzzer/FuzzerUtilWindows.cpp +++ b/compiler-rt/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; diff --git a/compiler-rt/test/fuzzer/large.test b/compiler-rt/test/fuzzer/large.test index a83e20cd9ff..a2e0ac036ea 100644 --- a/compiler-rt/test/fuzzer/large.test +++ b/compiler-rt/test/fuzzer/large.test @@ -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  | 

