Revert "[GWP-ASan] Move random-related code in the allocator"

This reverts commit 9903b0586cfb76ef2401c342501e61e1bd3daa0f.

Causes build failures (on GCC 10.2) with the following error:

In file included from /home/nikic/llvm-project/compiler-rt/lib/scudo/standalone/combined.h:29,
                 from /home/nikic/llvm-project/compiler-rt/lib/scudo/standalone/allocator_config.h:12,
                 from /home/nikic/llvm-project/compiler-rt/lib/scudo/standalone/wrappers_cpp.cpp:14:
/home/nikic/llvm-project/compiler-rt/lib/scudo/standalone/../../gwp_asan/guarded_pool_allocator.h: In member function ‘bool gwp_asan::GuardedPoolAllocator::shouldSample()’:
/home/nikic/llvm-project/compiler-rt/lib/scudo/standalone/../../gwp_asan/guarded_pool_allocator.h:82:69: error: conversion from ‘uint32_t’ {aka ‘unsigned int’} to ‘unsigned int:31’ may change value [-Werror=conversion]
   82 |           (getRandomUnsigned32() % (AdjustedSampleRatePlusOne - 1)) + 1;
      |           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~

GitOrigin-RevId: 04e42f62548d4c0367664188a938b609435718e2
diff --git a/guarded_pool_allocator.cpp b/guarded_pool_allocator.cpp
index 93fe5c2..b2602e4 100644
--- a/guarded_pool_allocator.cpp
+++ b/guarded_pool_allocator.cpp
@@ -10,6 +10,7 @@
 
 #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
@@ -37,6 +38,15 @@
 // 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
@@ -54,7 +64,7 @@
     return;
 
   Check(Opts.SampleRate >= 0, "GWP-ASan Error: SampleRate is < 0.");
-  Check(Opts.SampleRate < (1 << 30), "GWP-ASan Error: SampleRate is >= 2^30.");
+  Check(Opts.SampleRate <= INT32_MAX, "GWP-ASan Error: SampleRate is > 2^31.");
   Check(Opts.MaxSimultaneousAllocations >= 0,
         "GWP-ASan Error: MaxSimultaneousAllocations is < 0.");
 
@@ -145,15 +155,13 @@
 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) {
-    ThreadLocals.NextSampleCounter = AdjustedSampleRatePlusOne - 1;
+  if (State.GuardedPagePoolEnd == 0)
     return nullptr;
-  }
 
   // Protect against recursivity.
   if (ThreadLocals.RecursiveGuard)
     return nullptr;
-  ScopedRecursiveGuard SRG;
+  ScopedBoolean SB(ThreadLocals.RecursiveGuard);
 
   if (Size == 0 || Size > State.maximumAllocationSize())
     return nullptr;
@@ -233,7 +241,7 @@
     // Ensure that the unwinder is not called if the recursive flag is set,
     // otherwise non-reentrant unwinders may deadlock.
     if (!ThreadLocals.RecursiveGuard) {
-      ScopedRecursiveGuard SRG;
+      ScopedBoolean B(ThreadLocals.RecursiveGuard);
       Meta->DeallocationTrace.RecordBacktrace(Backtrace);
     }
   }
@@ -278,15 +286,6 @@
   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/guarded_pool_allocator.h b/guarded_pool_allocator.h
index cf31437..12049e1 100644
--- a/guarded_pool_allocator.h
+++ b/guarded_pool_allocator.h
@@ -13,6 +13,7 @@
 #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>
@@ -194,40 +195,17 @@
   // the same cache line for performance reasons. These are the most touched
   // variables in GWP-ASan.
   struct alignas(8) 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;
+    constexpr ThreadLocalPackedVariables() {}
     // Thread-local decrementing counter that indicates that a given allocation
     // should be sampled when it reaches zero.
-    uint32_t NextSampleCounter : 31;
+    uint32_t NextSampleCounter = 0;
     // 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 : 1;
+    bool RecursiveGuard = false;
   };
-  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/options.inc b/options.inc
index c81e1f4..6cdddfb 100644
--- a/options.inc
+++ b/options.inc
@@ -29,7 +29,7 @@
 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^30 - 1) are supported.")
+                "up to (2^31 - 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/platform_specific/guarded_pool_allocator_posix.cpp b/platform_specific/guarded_pool_allocator_posix.cpp
index c2cd244..a8767a4 100644
--- a/platform_specific/guarded_pool_allocator_posix.cpp
+++ b/platform_specific/guarded_pool_allocator_posix.cpp
@@ -16,7 +16,6 @@
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/types.h>
-#include <time.h>
 #include <unistd.h>
 
 #ifdef ANDROID
@@ -34,11 +33,6 @@
 }
 
 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/random.cpp b/random.cpp
new file mode 100644
index 0000000..927709a
--- /dev/null
+++ b/random.cpp
@@ -0,0 +1,29 @@
+//===-- 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/random.h b/random.h
new file mode 100644
index 0000000..953b989
--- /dev/null
+++ b/random.h
@@ -0,0 +1,23 @@
+//===-- 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_