[compiler-rt] d56ef85 - [scudo] Use require_constant_initialization

Vitaly Buka via llvm-commits llvm-commits at lists.llvm.org
Sat May 1 01:46:57 PDT 2021


Author: Vitaly Buka
Date: 2021-05-01T01:46:47-07:00
New Revision: d56ef8523c71b2a9b1629265be276b3871509e7b

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

LOG: [scudo] Use require_constant_initialization

Attribute guaranties safe static initialization of globals.

Reviewed By: hctim

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

Added: 
    

Modified: 
    compiler-rt/lib/scudo/standalone/combined.h
    compiler-rt/lib/scudo/standalone/internal_defs.h
    compiler-rt/lib/scudo/standalone/list.h
    compiler-rt/lib/scudo/standalone/local_cache.h
    compiler-rt/lib/scudo/standalone/mutex.h
    compiler-rt/lib/scudo/standalone/options.h
    compiler-rt/lib/scudo/standalone/primary32.h
    compiler-rt/lib/scudo/standalone/primary64.h
    compiler-rt/lib/scudo/standalone/quarantine.h
    compiler-rt/lib/scudo/standalone/secondary.h
    compiler-rt/lib/scudo/standalone/stack_depot.h
    compiler-rt/lib/scudo/standalone/stats.h
    compiler-rt/lib/scudo/standalone/tsd.h
    compiler-rt/lib/scudo/standalone/tsd_exclusive.h
    compiler-rt/lib/scudo/standalone/wrappers_c.cpp
    compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp

Removed: 
    


################################################################################
diff  --git a/compiler-rt/lib/scudo/standalone/combined.h b/compiler-rt/lib/scudo/standalone/combined.h
index 33ae6c42eca9c..146408a26bf39 100644
--- a/compiler-rt/lib/scudo/standalone/combined.h
+++ b/compiler-rt/lib/scudo/standalone/combined.h
@@ -944,8 +944,8 @@ class Allocator {
   static const sptr MemTagAllocationTraceIndex = -2;
   static const sptr MemTagAllocationTidIndex = -1;
 
-  u32 Cookie;
-  u32 QuarantineMaxChunkSize;
+  u32 Cookie = 0;
+  u32 QuarantineMaxChunkSize = 0;
 
   GlobalStats Stats;
   PrimaryT Primary;
@@ -977,7 +977,7 @@ class Allocator {
 #endif
     Entry Entries[NumEntries];
   };
-  AllocationRingBuffer RingBuffer;
+  AllocationRingBuffer RingBuffer = {};
 
   // The following might get optimized out by the compiler.
   NOINLINE void performSanityChecks() {

diff  --git a/compiler-rt/lib/scudo/standalone/internal_defs.h b/compiler-rt/lib/scudo/standalone/internal_defs.h
index e12a5804bacb5..bbf7631be189e 100644
--- a/compiler-rt/lib/scudo/standalone/internal_defs.h
+++ b/compiler-rt/lib/scudo/standalone/internal_defs.h
@@ -48,6 +48,34 @@
 #define USED __attribute__((used))
 #define NOEXCEPT noexcept
 
+// This check is only available on Clang. This is essentially an alias of
+// C++20's 'constinit' specifier which will take care of this when (if?) we can
+// ask all libc's that use Scudo to compile us with C++20. Dynamic
+// initialization is bad; Scudo is designed to be lazy-initializated on the
+// first call to malloc/free (and friends), and this generally happens in the
+// loader somewhere in libdl's init. After the loader is done, control is
+// transferred to libc's initialization, and the dynamic initializers are run.
+// If there's a dynamic initializer for Scudo, then it will clobber the
+// already-initialized Scudo, and re-initialize all its members back to default
+// values, causing various explosions. Unfortunately, marking
+// scudo::Allocator<>'s constructor as 'constexpr' isn't sufficient to prevent
+// dynamic initialization, as default initialization is fine under 'constexpr'
+// (but not 'constinit'). Clang at -O0, and gcc at all opt levels will emit a
+// dynamic initializer for any constant-initialized variables if there is a mix
+// of default-initialized and constant-initialized variables.
+//
+// If you're looking at this because your build failed, you probably introduced
+// a new member to scudo::Allocator<> (possibly transiently) that didn't have an
+// initializer. The fix is easy - just add one.
+#if defined(__has_attribute)
+#if __has_attribute(require_constant_initialization)
+#define SCUDO_REQUIRE_CONSTANT_INITIALIZATION                                  \
+  __attribute__((__require_constant_initialization__))
+#else
+#define SCUDO_REQUIRE_CONSTANT_INITIALIZATION
+#endif
+#endif
+
 namespace scudo {
 
 typedef unsigned long uptr;

diff  --git a/compiler-rt/lib/scudo/standalone/list.h b/compiler-rt/lib/scudo/standalone/list.h
index c3b898a328ca3..1ac93c2f65d7f 100644
--- a/compiler-rt/lib/scudo/standalone/list.h
+++ b/compiler-rt/lib/scudo/standalone/list.h
@@ -57,9 +57,9 @@ template <class T> struct IntrusiveList {
   void checkConsistency() const;
 
 protected:
-  uptr Size;
-  T *First;
-  T *Last;
+  uptr Size = 0;
+  T *First = nullptr;
+  T *Last = nullptr;
 };
 
 template <class T> void IntrusiveList<T>::checkConsistency() const {

diff  --git a/compiler-rt/lib/scudo/standalone/local_cache.h b/compiler-rt/lib/scudo/standalone/local_cache.h
index 509221f4d6198..43cbc68ead3fc 100644
--- a/compiler-rt/lib/scudo/standalone/local_cache.h
+++ b/compiler-rt/lib/scudo/standalone/local_cache.h
@@ -138,9 +138,9 @@ template <class SizeClassAllocator> struct SizeClassAllocatorLocalCache {
     uptr ClassSize;
     CompactPtrT Chunks[2 * TransferBatch::MaxNumCached];
   };
-  PerClass PerClassArray[NumClasses];
+  PerClass PerClassArray[NumClasses] = {};
   LocalStats Stats;
-  SizeClassAllocator *Allocator;
+  SizeClassAllocator *Allocator = nullptr;
 
   ALWAYS_INLINE void initCacheMaybe(PerClass *C) {
     if (LIKELY(C->MaxCount))

diff  --git a/compiler-rt/lib/scudo/standalone/mutex.h b/compiler-rt/lib/scudo/standalone/mutex.h
index d6e6a5b33aaee..a654d35c5a78c 100644
--- a/compiler-rt/lib/scudo/standalone/mutex.h
+++ b/compiler-rt/lib/scudo/standalone/mutex.h
@@ -48,9 +48,9 @@ class HybridMutex {
   static constexpr u8 NumberOfYields = 8U;
 
 #if SCUDO_LINUX
-  atomic_u32 M;
+  atomic_u32 M = {};
 #elif SCUDO_FUCHSIA
-  sync_mutex_t M;
+  sync_mutex_t M = {};
 #endif
 
   void lockSlow();

diff  --git a/compiler-rt/lib/scudo/standalone/options.h b/compiler-rt/lib/scudo/standalone/options.h
index d0277aaa6877c..4e67865133346 100644
--- a/compiler-rt/lib/scudo/standalone/options.h
+++ b/compiler-rt/lib/scudo/standalone/options.h
@@ -44,9 +44,8 @@ template <typename Config> bool useMemoryTagging(Options Options) {
 }
 
 struct AtomicOptions {
-  atomic_u32 Val;
+  atomic_u32 Val = {};
 
-public:
   Options load() const { return Options{atomic_load_relaxed(&Val)}; }
 
   void clear(OptionBit Opt) {

diff  --git a/compiler-rt/lib/scudo/standalone/primary32.h b/compiler-rt/lib/scudo/standalone/primary32.h
index 5b62c15b22b4a..33d81754fb587 100644
--- a/compiler-rt/lib/scudo/standalone/primary32.h
+++ b/compiler-rt/lib/scudo/standalone/primary32.h
@@ -489,17 +489,17 @@ template <typename Config> class SizeClassAllocator32 {
     return TotalReleasedBytes;
   }
 
-  SizeClassInfo SizeClassInfoArray[NumClasses];
+  SizeClassInfo SizeClassInfoArray[NumClasses] = {};
 
   // Track the regions in use, 0 is unused, otherwise store ClassId + 1.
-  ByteMap PossibleRegions;
-  atomic_s32 ReleaseToOsIntervalMs;
+  ByteMap PossibleRegions = {};
+  atomic_s32 ReleaseToOsIntervalMs = {};
   // Unless several threads request regions simultaneously from 
diff erent size
   // classes, the stash rarely contains more than 1 entry.
   static constexpr uptr MaxStashedRegions = 4;
   HybridMutex RegionsStashMutex;
-  uptr NumberOfStashedRegions;
-  uptr RegionsStash[MaxStashedRegions];
+  uptr NumberOfStashedRegions = 0;
+  uptr RegionsStash[MaxStashedRegions] = {};
 };
 
 } // namespace scudo

diff  --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h
index b1a3ebf82b8f9..94375fceee1df 100644
--- a/compiler-rt/lib/scudo/standalone/primary64.h
+++ b/compiler-rt/lib/scudo/standalone/primary64.h
@@ -285,24 +285,24 @@ template <typename Config> class SizeClassAllocator64 {
   struct UnpaddedRegionInfo {
     HybridMutex Mutex;
     SinglyLinkedList<TransferBatch> FreeList;
-    uptr RegionBeg;
-    RegionStats Stats;
-    u32 RandState;
-    uptr MappedUser;    // Bytes mapped for user memory.
-    uptr AllocatedUser; // Bytes allocated for user memory.
-    MapPlatformData Data;
-    ReleaseToOsInfo ReleaseInfo;
-    bool Exhausted;
+    uptr RegionBeg = 0;
+    RegionStats Stats = {};
+    u32 RandState = 0;
+    uptr MappedUser = 0;    // Bytes mapped for user memory.
+    uptr AllocatedUser = 0; // Bytes allocated for user memory.
+    MapPlatformData Data = {};
+    ReleaseToOsInfo ReleaseInfo = {};
+    bool Exhausted = false;
   };
   struct RegionInfo : UnpaddedRegionInfo {
     char Padding[SCUDO_CACHE_LINE_SIZE -
-                 (sizeof(UnpaddedRegionInfo) % SCUDO_CACHE_LINE_SIZE)];
+                 (sizeof(UnpaddedRegionInfo) % SCUDO_CACHE_LINE_SIZE)] = {};
   };
   static_assert(sizeof(RegionInfo) % SCUDO_CACHE_LINE_SIZE == 0, "");
 
-  uptr PrimaryBase;
-  MapPlatformData Data;
-  atomic_s32 ReleaseToOsIntervalMs;
+  uptr PrimaryBase = 0;
+  MapPlatformData Data = {};
+  atomic_s32 ReleaseToOsIntervalMs = {};
   alignas(SCUDO_CACHE_LINE_SIZE) RegionInfo RegionInfoArray[NumClasses];
 
   RegionInfo *getRegionInfo(uptr ClassId) {

diff  --git a/compiler-rt/lib/scudo/standalone/quarantine.h b/compiler-rt/lib/scudo/standalone/quarantine.h
index 27aa4bfec91af..8d4b38e21fc00 100644
--- a/compiler-rt/lib/scudo/standalone/quarantine.h
+++ b/compiler-rt/lib/scudo/standalone/quarantine.h
@@ -161,7 +161,7 @@ template <typename Callback> class QuarantineCache {
 
 private:
   SinglyLinkedList<QuarantineBatch> List;
-  atomic_uptr Size;
+  atomic_uptr Size = {};
 
   void addToSize(uptr add) { atomic_store_relaxed(&Size, getSize() + add); }
   void subFromSize(uptr sub) { atomic_store_relaxed(&Size, getSize() - sub); }
@@ -246,9 +246,9 @@ template <typename Callback, typename Node> class GlobalQuarantine {
   alignas(SCUDO_CACHE_LINE_SIZE) HybridMutex CacheMutex;
   CacheT Cache;
   alignas(SCUDO_CACHE_LINE_SIZE) HybridMutex RecycleMutex;
-  atomic_uptr MinSize;
-  atomic_uptr MaxSize;
-  alignas(SCUDO_CACHE_LINE_SIZE) atomic_uptr MaxCacheSize;
+  atomic_uptr MinSize = {};
+  atomic_uptr MaxSize = {};
+  alignas(SCUDO_CACHE_LINE_SIZE) atomic_uptr MaxCacheSize = {};
 
   void NOINLINE recycle(uptr MinSize, Callback Cb) {
     CacheT Tmp;

diff  --git a/compiler-rt/lib/scudo/standalone/secondary.h b/compiler-rt/lib/scudo/standalone/secondary.h
index 03ac68cc02ddb..540f6b63c36f9 100644
--- a/compiler-rt/lib/scudo/standalone/secondary.h
+++ b/compiler-rt/lib/scudo/standalone/secondary.h
@@ -377,16 +377,16 @@ template <typename Config> class MapAllocatorCache {
   }
 
   HybridMutex Mutex;
-  u32 EntriesCount;
-  u32 QuarantinePos;
-  atomic_u32 MaxEntriesCount;
-  atomic_uptr MaxEntrySize;
-  u64 OldestTime;
-  u32 IsFullEvents;
-  atomic_s32 ReleaseToOsIntervalMs;
-
-  CachedBlock Entries[Config::SecondaryCacheEntriesArraySize];
-  CachedBlock Quarantine[Config::SecondaryCacheQuarantineSize];
+  u32 EntriesCount = 0;
+  u32 QuarantinePos = 0;
+  atomic_u32 MaxEntriesCount = {};
+  atomic_uptr MaxEntrySize = {};
+  u64 OldestTime = 0;
+  u32 IsFullEvents = 0;
+  atomic_s32 ReleaseToOsIntervalMs = {};
+
+  CachedBlock Entries[Config::SecondaryCacheEntriesArraySize] = {};
+  CachedBlock Quarantine[Config::SecondaryCacheQuarantineSize] = {};
 };
 
 template <typename Config> class MapAllocator {
@@ -451,11 +451,11 @@ template <typename Config> class MapAllocator {
 
   HybridMutex Mutex;
   DoublyLinkedList<LargeBlock::Header> InUseBlocks;
-  uptr AllocatedBytes;
-  uptr FreedBytes;
-  uptr LargestSize;
-  u32 NumberOfAllocs;
-  u32 NumberOfFrees;
+  uptr AllocatedBytes = 0;
+  uptr FreedBytes = 0;
+  uptr LargestSize = 0;
+  u32 NumberOfAllocs = 0;
+  u32 NumberOfFrees = 0;
   LocalStats Stats;
 };
 

diff  --git a/compiler-rt/lib/scudo/standalone/stack_depot.h b/compiler-rt/lib/scudo/standalone/stack_depot.h
index 7968f7efff7c5..458198fcb7aa5 100644
--- a/compiler-rt/lib/scudo/standalone/stack_depot.h
+++ b/compiler-rt/lib/scudo/standalone/stack_depot.h
@@ -40,7 +40,7 @@ class MurMur2HashBuilder {
 
 class StackDepot {
   HybridMutex RingEndMu;
-  u32 RingEnd;
+  u32 RingEnd = 0;
 
   // This data structure stores a stack trace for each allocation and
   // deallocation when stack trace recording is enabled, that may be looked up
@@ -70,7 +70,7 @@ class StackDepot {
 #endif
   static const uptr TabSize = 1 << TabBits;
   static const uptr TabMask = TabSize - 1;
-  atomic_u32 Tab[TabSize];
+  atomic_u32 Tab[TabSize] = {};
 
 #ifdef SCUDO_FUZZ
   static const uptr RingBits = 4;
@@ -79,7 +79,7 @@ class StackDepot {
 #endif
   static const uptr RingSize = 1 << RingBits;
   static const uptr RingMask = RingSize - 1;
-  atomic_u64 Ring[RingSize];
+  atomic_u64 Ring[RingSize] = {};
 
 public:
   // Insert hash of the stack trace [Begin, End) into the stack depot, and

diff  --git a/compiler-rt/lib/scudo/standalone/stats.h b/compiler-rt/lib/scudo/standalone/stats.h
index d76b904949ea2..b64a992636180 100644
--- a/compiler-rt/lib/scudo/standalone/stats.h
+++ b/compiler-rt/lib/scudo/standalone/stats.h
@@ -46,11 +46,11 @@ class LocalStats {
 
   uptr get(StatType I) const { return atomic_load_relaxed(&StatsArray[I]); }
 
-  LocalStats *Next;
-  LocalStats *Prev;
+  LocalStats *Next = nullptr;
+  LocalStats *Prev = nullptr;
 
 private:
-  atomic_uptr StatsArray[StatCount];
+  atomic_uptr StatsArray[StatCount] = {};
 };
 
 // Global stats, used for aggregation and querying.

diff  --git a/compiler-rt/lib/scudo/standalone/tsd.h b/compiler-rt/lib/scudo/standalone/tsd.h
index b3701c63f8a9b..a6e669b66e65f 100644
--- a/compiler-rt/lib/scudo/standalone/tsd.h
+++ b/compiler-rt/lib/scudo/standalone/tsd.h
@@ -26,7 +26,7 @@ namespace scudo {
 template <class Allocator> struct alignas(SCUDO_CACHE_LINE_SIZE) TSD {
   typename Allocator::CacheT Cache;
   typename Allocator::QuarantineCacheT QuarantineCache;
-  u8 DestructorIterations;
+  u8 DestructorIterations = 0;
 
   void initLinkerInitialized(Allocator *Instance) {
     Instance->initCache(&Cache);
@@ -59,7 +59,7 @@ template <class Allocator> struct alignas(SCUDO_CACHE_LINE_SIZE) TSD {
 
 private:
   HybridMutex Mutex;
-  atomic_uptr Precedence;
+  atomic_uptr Precedence = {};
 };
 
 } // namespace scudo

diff  --git a/compiler-rt/lib/scudo/standalone/tsd_exclusive.h b/compiler-rt/lib/scudo/standalone/tsd_exclusive.h
index 04850405959b2..a907ed4684a51 100644
--- a/compiler-rt/lib/scudo/standalone/tsd_exclusive.h
+++ b/compiler-rt/lib/scudo/standalone/tsd_exclusive.h
@@ -108,9 +108,9 @@ template <class Allocator> struct TSDRegistryExT {
     Instance->callPostInitCallback();
   }
 
-  pthread_key_t PThreadKey;
-  bool Initialized;
-  atomic_u8 Disabled;
+  pthread_key_t PThreadKey = {};
+  bool Initialized = false;
+  atomic_u8 Disabled = {};
   TSD<Allocator> FallbackTSD;
   HybridMutex Mutex;
   static thread_local ThreadState State;

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
index 098cc089a1cab..81c7dd60ee334 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c.cpp
@@ -26,6 +26,7 @@ extern "C" void SCUDO_PREFIX(malloc_postinit)();
 // Export the static allocator so that the C++ wrappers can access it.
 // Technically we could have a completely separated heap for C & C++ but in
 // reality the amount of cross pollination between the two is staggering.
+SCUDO_REQUIRE_CONSTANT_INITIALIZATION
 scudo::Allocator<scudo::Config, SCUDO_PREFIX(malloc_postinit)> SCUDO_ALLOCATOR;
 
 #include "wrappers_c.inc"

diff  --git a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
index 75ef22a16e179..18c3bf2c0edfa 100644
--- a/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
+++ b/compiler-rt/lib/scudo/standalone/wrappers_c_bionic.cpp
@@ -23,6 +23,7 @@
 #define SCUDO_ALLOCATOR Allocator
 
 extern "C" void SCUDO_PREFIX(malloc_postinit)();
+SCUDO_REQUIRE_CONSTANT_INITIALIZATION
 static scudo::Allocator<scudo::AndroidConfig, SCUDO_PREFIX(malloc_postinit)>
     SCUDO_ALLOCATOR;
 
@@ -36,6 +37,7 @@ static scudo::Allocator<scudo::AndroidConfig, SCUDO_PREFIX(malloc_postinit)>
 #define SCUDO_ALLOCATOR SvelteAllocator
 
 extern "C" void SCUDO_PREFIX(malloc_postinit)();
+SCUDO_REQUIRE_CONSTANT_INITIALIZATION
 static scudo::Allocator<scudo::AndroidSvelteConfig,
                         SCUDO_PREFIX(malloc_postinit)>
     SCUDO_ALLOCATOR;


        


More information about the llvm-commits mailing list