[compiler-rt] 3580a45 - [GWP-ASan] Move random-related code in the allocator (redo)

Kostya Kortchinsky via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 22 13:56:42 PDT 2020


Author: Kostya Kortchinsky
Date: 2020-10-22T13:56:24-07:00
New Revision: 3580a45014e90a9895cc2dec28ab2e7f78c47470

URL: https://github.com/llvm/llvm-project/commit/3580a45014e90a9895cc2dec28ab2e7f78c47470
DIFF: https://github.com/llvm/llvm-project/commit/3580a45014e90a9895cc2dec28ab2e7f78c47470.diff

LOG: [GWP-ASan] Move random-related code in the allocator (redo)

This is a redo of D89908, which triggered some `-Werror=conversion`
errors with GCC due to assignments to the 31-bit variable.

This CL adds to the original one a 31-bit mask variable that is used
at every assignment to silence the warning.

Differential Revision: https://reviews.llvm.org/D89984

Added: 
    

Modified: 
    compiler-rt/lib/gwp_asan/CMakeLists.txt
    compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
    compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
    compiler-rt/lib/gwp_asan/options.inc
    compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp

Removed: 
    compiler-rt/lib/gwp_asan/random.cpp
    compiler-rt/lib/gwp_asan/random.h


################################################################################
diff  --git a/compiler-rt/lib/gwp_asan/CMakeLists.txt b/compiler-rt/lib/gwp_asan/CMakeLists.txt
index 60efc8a39e62e..6bfb3cab13ef0 100644
--- a/compiler-rt/lib/gwp_asan/CMakeLists.txt
+++ b/compiler-rt/lib/gwp_asan/CMakeLists.txt
@@ -10,7 +10,6 @@ set(GWP_ASAN_SOURCES
   platform_specific/mutex_posix.cpp
   platform_specific/utilities_posix.cpp
   guarded_pool_allocator.cpp
-  random.cpp
   stack_trace_compressor.cpp
   utilities.cpp
 )
@@ -23,7 +22,6 @@ set(GWP_ASAN_HEADERS
   mutex.h
   options.h
   options.inc
-  random.h
   stack_trace_compressor.h
   utilities.h
 )

diff  --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
index b2602e4caa596..17e6f76727f91 100644
--- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
+++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.cpp
@@ -10,7 +10,6 @@
 
 #include "gwp_asan/optional/segv_handler.h"
 #include "gwp_asan/options.h"
-#include "gwp_asan/random.h"
 #include "gwp_asan/utilities.h"
 
 // RHEL creates the PRIu64 format macro (for printing uint64_t's) only when this
@@ -38,15 +37,6 @@ namespace {
 // referenced by users outside this translation unit, in order to avoid
 // init-order-fiasco.
 GuardedPoolAllocator *SingletonPtr = nullptr;
-
-class ScopedBoolean {
-public:
-  ScopedBoolean(bool &B) : Bool(B) { Bool = true; }
-  ~ScopedBoolean() { Bool = false; }
-
-private:
-  bool &Bool;
-};
 } // anonymous namespace
 
 // Gets the singleton implementation of this class. Thread-compatible until
@@ -64,7 +54,7 @@ void GuardedPoolAllocator::init(const options::Options &Opts) {
     return;
 
   Check(Opts.SampleRate >= 0, "GWP-ASan Error: SampleRate is < 0.");
-  Check(Opts.SampleRate <= INT32_MAX, "GWP-ASan Error: SampleRate is > 2^31.");
+  Check(Opts.SampleRate < (1 << 30), "GWP-ASan Error: SampleRate is >= 2^30.");
   Check(Opts.MaxSimultaneousAllocations >= 0,
         "GWP-ASan Error: MaxSimultaneousAllocations is < 0.");
 
@@ -102,7 +92,8 @@ void GuardedPoolAllocator::init(const options::Options &Opts) {
 
   initPRNG();
   ThreadLocals.NextSampleCounter =
-      (getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1;
+      ((getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1) &
+      ThreadLocalPackedVariables::NextSampleCounterMask;
 
   State.GuardedPagePool = reinterpret_cast<uintptr_t>(GuardedPoolMemory);
   State.GuardedPagePoolEnd =
@@ -155,13 +146,17 @@ static uintptr_t getPageAddr(uintptr_t Ptr, uintptr_t PageSize) {
 void *GuardedPoolAllocator::allocate(size_t Size) {
   // GuardedPagePoolEnd == 0 when GWP-ASan is disabled. If we are disabled, fall
   // back to the supporting allocator.
-  if (State.GuardedPagePoolEnd == 0)
+  if (State.GuardedPagePoolEnd == 0) {
+    ThreadLocals.NextSampleCounter =
+        (AdjustedSampleRatePlusOne - 1) &
+        ThreadLocalPackedVariables::NextSampleCounterMask;
     return nullptr;
+  }
 
   // Protect against recursivity.
   if (ThreadLocals.RecursiveGuard)
     return nullptr;
-  ScopedBoolean SB(ThreadLocals.RecursiveGuard);
+  ScopedRecursiveGuard SRG;
 
   if (Size == 0 || Size > State.maximumAllocationSize())
     return nullptr;
@@ -241,7 +236,7 @@ void GuardedPoolAllocator::deallocate(void *Ptr) {
     // Ensure that the unwinder is not called if the recursive flag is set,
     // otherwise non-reentrant unwinders may deadlock.
     if (!ThreadLocals.RecursiveGuard) {
-      ScopedBoolean B(ThreadLocals.RecursiveGuard);
+      ScopedRecursiveGuard SRG;
       Meta->DeallocationTrace.RecordBacktrace(Backtrace);
     }
   }
@@ -286,6 +281,15 @@ void GuardedPoolAllocator::freeSlot(size_t SlotIndex) {
   FreeSlots[FreeSlotsLength++] = SlotIndex;
 }
 
+uint32_t GuardedPoolAllocator::getRandomUnsigned32() {
+  uint32_t RandomState = ThreadLocals.RandomState;
+  RandomState ^= RandomState << 13;
+  RandomState ^= RandomState >> 17;
+  RandomState ^= RandomState << 5;
+  ThreadLocals.RandomState = RandomState;
+  return RandomState;
+}
+
 GWP_ASAN_TLS_INITIAL_EXEC
 GuardedPoolAllocator::ThreadLocalPackedVariables
     GuardedPoolAllocator::ThreadLocals;

diff  --git a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
index 12049e1ab9d13..801f33e3f9ed6 100644
--- a/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
+++ b/compiler-rt/lib/gwp_asan/guarded_pool_allocator.h
@@ -13,7 +13,6 @@
 #include "gwp_asan/definitions.h"
 #include "gwp_asan/mutex.h"
 #include "gwp_asan/options.h"
-#include "gwp_asan/random.h"
 #include "gwp_asan/stack_trace_compressor.h"
 
 #include <stddef.h>
@@ -80,7 +79,8 @@ class GuardedPoolAllocator {
     // UINT32_MAX.
     if (GWP_ASAN_UNLIKELY(ThreadLocals.NextSampleCounter == 0))
       ThreadLocals.NextSampleCounter =
-          (getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1;
+          ((getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1) &
+          ThreadLocalPackedVariables::NextSampleCounterMask;
 
     return GWP_ASAN_UNLIKELY(--ThreadLocals.NextSampleCounter == 0);
   }
@@ -195,17 +195,42 @@ class GuardedPoolAllocator {
   // the same cache line for performance reasons. These are the most touched
   // variables in GWP-ASan.
   struct alignas(8) ThreadLocalPackedVariables {
-    constexpr ThreadLocalPackedVariables() {}
+    constexpr ThreadLocalPackedVariables()
+        : RandomState(0xff82eb50), NextSampleCounter(0), RecursiveGuard(false) {
+    }
+    // Initialised to a magic constant so that an uninitialised GWP-ASan won't
+    // regenerate its sample counter for as long as possible. The xorshift32()
+    // algorithm used below results in getRandomUnsigned32(0xff82eb50) ==
+    // 0xfffffea4.
+    uint32_t RandomState;
     // Thread-local decrementing counter that indicates that a given allocation
     // should be sampled when it reaches zero.
-    uint32_t NextSampleCounter = 0;
+    uint32_t NextSampleCounter : 31;
+    // The mask is needed to silence conversion errors.
+    static const uint32_t NextSampleCounterMask = (1U << 31) - 1;
     // Guard against recursivity. Unwinders often contain complex behaviour that
     // may not be safe for the allocator (i.e. the unwinder calls dlopen(),
     // which calls malloc()). When recursive behaviour is detected, we will
     // automatically fall back to the supporting allocator to supply the
     // allocation.
-    bool RecursiveGuard = false;
+    bool RecursiveGuard : 1;
   };
+  static_assert(sizeof(ThreadLocalPackedVariables) == sizeof(uint64_t),
+                "thread local data does not fit in a uint64_t");
+
+  class ScopedRecursiveGuard {
+  public:
+    ScopedRecursiveGuard() { ThreadLocals.RecursiveGuard = true; }
+    ~ScopedRecursiveGuard() { ThreadLocals.RecursiveGuard = false; }
+  };
+
+  // Initialise the PRNG, platform-specific.
+  void initPRNG();
+
+  // xorshift (32-bit output), extremely fast PRNG that uses arithmetic
+  // operations only. Seeded using platform-specific mechanisms by initPRNG().
+  uint32_t getRandomUnsigned32();
+
   static GWP_ASAN_TLS_INITIAL_EXEC ThreadLocalPackedVariables ThreadLocals;
 };
 } // namespace gwp_asan

diff  --git a/compiler-rt/lib/gwp_asan/options.inc b/compiler-rt/lib/gwp_asan/options.inc
index 6cdddfbad84d8..c81e1f47c7224 100644
--- a/compiler-rt/lib/gwp_asan/options.inc
+++ b/compiler-rt/lib/gwp_asan/options.inc
@@ -29,7 +29,7 @@ GWP_ASAN_OPTION(int, MaxSimultaneousAllocations, 16,
 GWP_ASAN_OPTION(int, SampleRate, 5000,
                 "The probability (1 / SampleRate) that an allocation is "
                 "selected for GWP-ASan sampling. Default is 5000. Sample rates "
-                "up to (2^31 - 1) are supported.")
+                "up to (2^30 - 1) are supported.")
 
 // Developer note - This option is not actually processed by GWP-ASan itself. It
 // is included here so that a user can specify whether they want signal handlers

diff  --git a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp
index a8767a4cb8089..c2cd24454fa25 100644
--- a/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp
+++ b/compiler-rt/lib/gwp_asan/platform_specific/guarded_pool_allocator_posix.cpp
@@ -16,6 +16,7 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/types.h>
+#include <time.h>
 #include <unistd.h>
 
 #ifdef ANDROID
@@ -33,6 +34,11 @@ void MaybeSetMappingName(void *Mapping, size_t Size, const char *Name) {
 }
 
 namespace gwp_asan {
+
+void GuardedPoolAllocator::initPRNG() {
+  ThreadLocals.RandomState = time(nullptr) + getThreadID();
+}
+
 void *GuardedPoolAllocator::mapMemory(size_t Size, const char *Name) const {
   void *Ptr =
       mmap(nullptr, Size, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);

diff  --git a/compiler-rt/lib/gwp_asan/random.cpp b/compiler-rt/lib/gwp_asan/random.cpp
deleted file mode 100644
index 927709abc42b0..0000000000000
--- a/compiler-rt/lib/gwp_asan/random.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-//===-- random.cpp ----------------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "gwp_asan/random.h"
-#include "gwp_asan/common.h"
-
-#include <time.h>
-
-// Initialised to a magic constant so that an uninitialised GWP-ASan won't
-// regenerate its sample counter for as long as possible. The xorshift32()
-// algorithm used below results in getRandomUnsigned32(0xff82eb50) ==
-// 0xfffffea4.
-GWP_ASAN_TLS_INITIAL_EXEC uint32_t RandomState = 0xff82eb50;
-
-namespace gwp_asan {
-void initPRNG() { RandomState = time(nullptr) + getThreadID(); }
-
-uint32_t getRandomUnsigned32() {
-  RandomState ^= RandomState << 13;
-  RandomState ^= RandomState >> 17;
-  RandomState ^= RandomState << 5;
-  return RandomState;
-}
-} // namespace gwp_asan

diff  --git a/compiler-rt/lib/gwp_asan/random.h b/compiler-rt/lib/gwp_asan/random.h
deleted file mode 100644
index 953b98909e958..0000000000000
--- a/compiler-rt/lib/gwp_asan/random.h
+++ /dev/null
@@ -1,23 +0,0 @@
-//===-- random.h ------------------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef GWP_ASAN_RANDOM_H_
-#define GWP_ASAN_RANDOM_H_
-
-#include <stdint.h>
-
-namespace gwp_asan {
-// Initialise the PRNG, using time and thread ID as the seed.
-void initPRNG();
-
-// xorshift (32-bit output), extremely fast PRNG that uses arithmetic operations
-// only. Seeded using walltime.
-uint32_t getRandomUnsigned32();
-} // namespace gwp_asan
-
-#endif // GWP_ASAN_RANDOM_H_


        


More information about the llvm-commits mailing list