xref: /openbsd-src/gnu/llvm/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- sanitizer_allocator.cpp -------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // This file is shared between AddressSanitizer and ThreadSanitizer
103cab2bb3Spatrick // run-time libraries.
113cab2bb3Spatrick // This allocator is used inside run-times.
123cab2bb3Spatrick //===----------------------------------------------------------------------===//
133cab2bb3Spatrick 
143cab2bb3Spatrick #include "sanitizer_allocator.h"
153cab2bb3Spatrick 
163cab2bb3Spatrick #include "sanitizer_allocator_checks.h"
173cab2bb3Spatrick #include "sanitizer_allocator_internal.h"
183cab2bb3Spatrick #include "sanitizer_atomic.h"
193cab2bb3Spatrick #include "sanitizer_common.h"
20*810390e3Srobert #include "sanitizer_platform.h"
213cab2bb3Spatrick 
223cab2bb3Spatrick namespace __sanitizer {
233cab2bb3Spatrick 
243cab2bb3Spatrick // Default allocator names.
253cab2bb3Spatrick const char *PrimaryAllocatorName = "SizeClassAllocator";
263cab2bb3Spatrick const char *SecondaryAllocatorName = "LargeMmapAllocator";
273cab2bb3Spatrick 
283cab2bb3Spatrick static ALIGNED(64) char internal_alloc_placeholder[sizeof(InternalAllocator)];
293cab2bb3Spatrick static atomic_uint8_t internal_allocator_initialized;
303cab2bb3Spatrick static StaticSpinMutex internal_alloc_init_mu;
313cab2bb3Spatrick 
323cab2bb3Spatrick static InternalAllocatorCache internal_allocator_cache;
333cab2bb3Spatrick static StaticSpinMutex internal_allocator_cache_mu;
343cab2bb3Spatrick 
internal_allocator()353cab2bb3Spatrick InternalAllocator *internal_allocator() {
363cab2bb3Spatrick   InternalAllocator *internal_allocator_instance =
373cab2bb3Spatrick       reinterpret_cast<InternalAllocator *>(&internal_alloc_placeholder);
383cab2bb3Spatrick   if (atomic_load(&internal_allocator_initialized, memory_order_acquire) == 0) {
393cab2bb3Spatrick     SpinMutexLock l(&internal_alloc_init_mu);
403cab2bb3Spatrick     if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) ==
413cab2bb3Spatrick         0) {
423cab2bb3Spatrick       internal_allocator_instance->Init(kReleaseToOSIntervalNever);
433cab2bb3Spatrick       atomic_store(&internal_allocator_initialized, 1, memory_order_release);
443cab2bb3Spatrick     }
453cab2bb3Spatrick   }
463cab2bb3Spatrick   return internal_allocator_instance;
473cab2bb3Spatrick }
483cab2bb3Spatrick 
RawInternalAlloc(uptr size,InternalAllocatorCache * cache,uptr alignment)493cab2bb3Spatrick static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache,
503cab2bb3Spatrick                               uptr alignment) {
513cab2bb3Spatrick   if (alignment == 0) alignment = 8;
523cab2bb3Spatrick   if (cache == 0) {
533cab2bb3Spatrick     SpinMutexLock l(&internal_allocator_cache_mu);
543cab2bb3Spatrick     return internal_allocator()->Allocate(&internal_allocator_cache, size,
553cab2bb3Spatrick                                           alignment);
563cab2bb3Spatrick   }
573cab2bb3Spatrick   return internal_allocator()->Allocate(cache, size, alignment);
583cab2bb3Spatrick }
593cab2bb3Spatrick 
RawInternalRealloc(void * ptr,uptr size,InternalAllocatorCache * cache)603cab2bb3Spatrick static void *RawInternalRealloc(void *ptr, uptr size,
613cab2bb3Spatrick                                 InternalAllocatorCache *cache) {
623cab2bb3Spatrick   uptr alignment = 8;
633cab2bb3Spatrick   if (cache == 0) {
643cab2bb3Spatrick     SpinMutexLock l(&internal_allocator_cache_mu);
653cab2bb3Spatrick     return internal_allocator()->Reallocate(&internal_allocator_cache, ptr,
663cab2bb3Spatrick                                             size, alignment);
673cab2bb3Spatrick   }
683cab2bb3Spatrick   return internal_allocator()->Reallocate(cache, ptr, size, alignment);
693cab2bb3Spatrick }
703cab2bb3Spatrick 
RawInternalFree(void * ptr,InternalAllocatorCache * cache)713cab2bb3Spatrick static void RawInternalFree(void *ptr, InternalAllocatorCache *cache) {
723cab2bb3Spatrick   if (!cache) {
733cab2bb3Spatrick     SpinMutexLock l(&internal_allocator_cache_mu);
743cab2bb3Spatrick     return internal_allocator()->Deallocate(&internal_allocator_cache, ptr);
753cab2bb3Spatrick   }
763cab2bb3Spatrick   internal_allocator()->Deallocate(cache, ptr);
773cab2bb3Spatrick }
783cab2bb3Spatrick 
ReportInternalAllocatorOutOfMemory(uptr requested_size)793cab2bb3Spatrick static void NORETURN ReportInternalAllocatorOutOfMemory(uptr requested_size) {
803cab2bb3Spatrick   SetAllocatorOutOfMemory();
813cab2bb3Spatrick   Report("FATAL: %s: internal allocator is out of memory trying to allocate "
823cab2bb3Spatrick          "0x%zx bytes\n", SanitizerToolName, requested_size);
833cab2bb3Spatrick   Die();
843cab2bb3Spatrick }
853cab2bb3Spatrick 
InternalAlloc(uptr size,InternalAllocatorCache * cache,uptr alignment)863cab2bb3Spatrick void *InternalAlloc(uptr size, InternalAllocatorCache *cache, uptr alignment) {
87d89ec533Spatrick   void *p = RawInternalAlloc(size, cache, alignment);
883cab2bb3Spatrick   if (UNLIKELY(!p))
89d89ec533Spatrick     ReportInternalAllocatorOutOfMemory(size);
90d89ec533Spatrick   return p;
913cab2bb3Spatrick }
923cab2bb3Spatrick 
InternalRealloc(void * addr,uptr size,InternalAllocatorCache * cache)933cab2bb3Spatrick void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {
943cab2bb3Spatrick   void *p = RawInternalRealloc(addr, size, cache);
953cab2bb3Spatrick   if (UNLIKELY(!p))
963cab2bb3Spatrick     ReportInternalAllocatorOutOfMemory(size);
97d89ec533Spatrick   return p;
983cab2bb3Spatrick }
993cab2bb3Spatrick 
InternalReallocArray(void * addr,uptr count,uptr size,InternalAllocatorCache * cache)1003cab2bb3Spatrick void *InternalReallocArray(void *addr, uptr count, uptr size,
1013cab2bb3Spatrick                            InternalAllocatorCache *cache) {
1023cab2bb3Spatrick   if (UNLIKELY(CheckForCallocOverflow(count, size))) {
1033cab2bb3Spatrick     Report(
1043cab2bb3Spatrick         "FATAL: %s: reallocarray parameters overflow: count * size (%zd * %zd) "
1053cab2bb3Spatrick         "cannot be represented in type size_t\n",
1063cab2bb3Spatrick         SanitizerToolName, count, size);
1073cab2bb3Spatrick     Die();
1083cab2bb3Spatrick   }
1093cab2bb3Spatrick   return InternalRealloc(addr, count * size, cache);
1103cab2bb3Spatrick }
1113cab2bb3Spatrick 
InternalCalloc(uptr count,uptr size,InternalAllocatorCache * cache)1123cab2bb3Spatrick void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
1133cab2bb3Spatrick   if (UNLIKELY(CheckForCallocOverflow(count, size))) {
1143cab2bb3Spatrick     Report("FATAL: %s: calloc parameters overflow: count * size (%zd * %zd) "
1153cab2bb3Spatrick            "cannot be represented in type size_t\n", SanitizerToolName, count,
1163cab2bb3Spatrick            size);
1173cab2bb3Spatrick     Die();
1183cab2bb3Spatrick   }
1193cab2bb3Spatrick   void *p = InternalAlloc(count * size, cache);
1203cab2bb3Spatrick   if (LIKELY(p))
1213cab2bb3Spatrick     internal_memset(p, 0, count * size);
1223cab2bb3Spatrick   return p;
1233cab2bb3Spatrick }
1243cab2bb3Spatrick 
InternalFree(void * addr,InternalAllocatorCache * cache)1253cab2bb3Spatrick void InternalFree(void *addr, InternalAllocatorCache *cache) {
1263cab2bb3Spatrick   RawInternalFree(addr, cache);
1273cab2bb3Spatrick }
1283cab2bb3Spatrick 
InternalAllocatorLock()129*810390e3Srobert void InternalAllocatorLock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
130*810390e3Srobert   internal_allocator_cache_mu.Lock();
131*810390e3Srobert   internal_allocator()->ForceLock();
132*810390e3Srobert }
133*810390e3Srobert 
InternalAllocatorUnlock()134*810390e3Srobert void InternalAllocatorUnlock() SANITIZER_NO_THREAD_SAFETY_ANALYSIS {
135*810390e3Srobert   internal_allocator()->ForceUnlock();
136*810390e3Srobert   internal_allocator_cache_mu.Unlock();
137*810390e3Srobert }
138*810390e3Srobert 
1393cab2bb3Spatrick // LowLevelAllocator
1403cab2bb3Spatrick constexpr uptr kLowLevelAllocatorDefaultAlignment = 8;
1413cab2bb3Spatrick static uptr low_level_alloc_min_alignment = kLowLevelAllocatorDefaultAlignment;
1423cab2bb3Spatrick static LowLevelAllocateCallback low_level_alloc_callback;
1433cab2bb3Spatrick 
Allocate(uptr size)1443cab2bb3Spatrick void *LowLevelAllocator::Allocate(uptr size) {
1453cab2bb3Spatrick   // Align allocation size.
1463cab2bb3Spatrick   size = RoundUpTo(size, low_level_alloc_min_alignment);
1473cab2bb3Spatrick   if (allocated_end_ - allocated_current_ < (sptr)size) {
1483cab2bb3Spatrick     uptr size_to_allocate = RoundUpTo(size, GetPageSizeCached());
1493cab2bb3Spatrick     allocated_current_ =
1503cab2bb3Spatrick         (char*)MmapOrDie(size_to_allocate, __func__);
1513cab2bb3Spatrick     allocated_end_ = allocated_current_ + size_to_allocate;
1523cab2bb3Spatrick     if (low_level_alloc_callback) {
1533cab2bb3Spatrick       low_level_alloc_callback((uptr)allocated_current_,
1543cab2bb3Spatrick                                size_to_allocate);
1553cab2bb3Spatrick     }
1563cab2bb3Spatrick   }
1573cab2bb3Spatrick   CHECK(allocated_end_ - allocated_current_ >= (sptr)size);
1583cab2bb3Spatrick   void *res = allocated_current_;
1593cab2bb3Spatrick   allocated_current_ += size;
1603cab2bb3Spatrick   return res;
1613cab2bb3Spatrick }
1623cab2bb3Spatrick 
SetLowLevelAllocateMinAlignment(uptr alignment)1633cab2bb3Spatrick void SetLowLevelAllocateMinAlignment(uptr alignment) {
1643cab2bb3Spatrick   CHECK(IsPowerOfTwo(alignment));
1653cab2bb3Spatrick   low_level_alloc_min_alignment = Max(alignment, low_level_alloc_min_alignment);
1663cab2bb3Spatrick }
1673cab2bb3Spatrick 
SetLowLevelAllocateCallback(LowLevelAllocateCallback callback)1683cab2bb3Spatrick void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
1693cab2bb3Spatrick   low_level_alloc_callback = callback;
1703cab2bb3Spatrick }
1713cab2bb3Spatrick 
1723cab2bb3Spatrick // Allocator's OOM and other errors handling support.
1733cab2bb3Spatrick 
1743cab2bb3Spatrick static atomic_uint8_t allocator_out_of_memory = {0};
1753cab2bb3Spatrick static atomic_uint8_t allocator_may_return_null = {0};
1763cab2bb3Spatrick 
IsAllocatorOutOfMemory()1773cab2bb3Spatrick bool IsAllocatorOutOfMemory() {
1783cab2bb3Spatrick   return atomic_load_relaxed(&allocator_out_of_memory);
1793cab2bb3Spatrick }
1803cab2bb3Spatrick 
SetAllocatorOutOfMemory()1813cab2bb3Spatrick void SetAllocatorOutOfMemory() {
1823cab2bb3Spatrick   atomic_store_relaxed(&allocator_out_of_memory, 1);
1833cab2bb3Spatrick }
1843cab2bb3Spatrick 
AllocatorMayReturnNull()1853cab2bb3Spatrick bool AllocatorMayReturnNull() {
1863cab2bb3Spatrick   return atomic_load(&allocator_may_return_null, memory_order_relaxed);
1873cab2bb3Spatrick }
1883cab2bb3Spatrick 
SetAllocatorMayReturnNull(bool may_return_null)1893cab2bb3Spatrick void SetAllocatorMayReturnNull(bool may_return_null) {
1903cab2bb3Spatrick   atomic_store(&allocator_may_return_null, may_return_null,
1913cab2bb3Spatrick                memory_order_relaxed);
1923cab2bb3Spatrick }
1933cab2bb3Spatrick 
PrintHintAllocatorCannotReturnNull()1943cab2bb3Spatrick void PrintHintAllocatorCannotReturnNull() {
1953cab2bb3Spatrick   Report("HINT: if you don't care about these errors you may set "
1963cab2bb3Spatrick          "allocator_may_return_null=1\n");
1973cab2bb3Spatrick }
1983cab2bb3Spatrick 
199*810390e3Srobert static atomic_uint8_t rss_limit_exceeded;
200*810390e3Srobert 
IsRssLimitExceeded()201*810390e3Srobert bool IsRssLimitExceeded() {
202*810390e3Srobert   return atomic_load(&rss_limit_exceeded, memory_order_relaxed);
203*810390e3Srobert }
204*810390e3Srobert 
SetRssLimitExceeded(bool limit_exceeded)205*810390e3Srobert void SetRssLimitExceeded(bool limit_exceeded) {
206*810390e3Srobert   atomic_store(&rss_limit_exceeded, limit_exceeded, memory_order_relaxed);
207*810390e3Srobert }
208*810390e3Srobert 
2093cab2bb3Spatrick } // namespace __sanitizer
210