1 //===-- sanitizer_allocator.cc --------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is shared between AddressSanitizer and ThreadSanitizer
10 // This allocator is used inside run-times.
11 //===----------------------------------------------------------------------===//
12 #include "sanitizer_allocator.h"
13 #include "sanitizer_allocator_internal.h"
14 #include "sanitizer_common.h"
15 #include "sanitizer_flags.h"
17 namespace __sanitizer
{
19 // ThreadSanitizer for Go uses libc malloc/free.
20 #if defined(SANITIZER_GO) || defined(SANITIZER_USE_MALLOC)
21 # if SANITIZER_LINUX && !SANITIZER_ANDROID
22 extern "C" void *__libc_malloc(uptr size
);
23 extern "C" void __libc_free(void *ptr
);
24 # define LIBC_MALLOC __libc_malloc
25 # define LIBC_FREE __libc_free
28 # define LIBC_MALLOC malloc
29 # define LIBC_FREE free
32 static void *RawInternalAlloc(uptr size
, InternalAllocatorCache
*cache
) {
34 return LIBC_MALLOC(size
);
37 static void RawInternalFree(void *ptr
, InternalAllocatorCache
*cache
) {
42 InternalAllocator
*internal_allocator() {
48 static ALIGNED(64) char internal_alloc_placeholder
[sizeof(InternalAllocator
)];
49 static atomic_uint8_t internal_allocator_initialized
;
50 static StaticSpinMutex internal_alloc_init_mu
;
52 static InternalAllocatorCache internal_allocator_cache
;
53 static StaticSpinMutex internal_allocator_cache_mu
;
55 InternalAllocator
*internal_allocator() {
56 InternalAllocator
*internal_allocator_instance
=
57 reinterpret_cast<InternalAllocator
*>(&internal_alloc_placeholder
);
58 if (atomic_load(&internal_allocator_initialized
, memory_order_acquire
) == 0) {
59 SpinMutexLock
l(&internal_alloc_init_mu
);
60 if (atomic_load(&internal_allocator_initialized
, memory_order_relaxed
) ==
62 internal_allocator_instance
->Init();
63 atomic_store(&internal_allocator_initialized
, 1, memory_order_release
);
66 return internal_allocator_instance
;
69 static void *RawInternalAlloc(uptr size
, InternalAllocatorCache
*cache
) {
71 SpinMutexLock
l(&internal_allocator_cache_mu
);
72 return internal_allocator()->Allocate(&internal_allocator_cache
, size
, 8,
75 return internal_allocator()->Allocate(cache
, size
, 8, false);
78 static void RawInternalFree(void *ptr
, InternalAllocatorCache
*cache
) {
80 SpinMutexLock
l(&internal_allocator_cache_mu
);
81 return internal_allocator()->Deallocate(&internal_allocator_cache
, ptr
);
83 internal_allocator()->Deallocate(cache
, ptr
);
86 #endif // SANITIZER_GO
88 const u64 kBlockMagic
= 0x6A6CB03ABCEBC041ull
;
90 void *InternalAlloc(uptr size
, InternalAllocatorCache
*cache
) {
91 if (size
+ sizeof(u64
) < size
)
93 void *p
= RawInternalAlloc(size
+ sizeof(u64
), cache
);
96 ((u64
*)p
)[0] = kBlockMagic
;
97 return (char*)p
+ sizeof(u64
);
100 void InternalFree(void *addr
, InternalAllocatorCache
*cache
) {
103 addr
= (char*)addr
- sizeof(u64
);
104 CHECK_EQ(kBlockMagic
, ((u64
*)addr
)[0]);
106 RawInternalFree(addr
, cache
);
110 static LowLevelAllocateCallback low_level_alloc_callback
;
112 void *LowLevelAllocator::Allocate(uptr size
) {
113 // Align allocation size.
114 size
= RoundUpTo(size
, 8);
115 if (allocated_end_
- allocated_current_
< (sptr
)size
) {
116 uptr size_to_allocate
= Max(size
, GetPageSizeCached());
118 (char*)MmapOrDie(size_to_allocate
, __func__
);
119 allocated_end_
= allocated_current_
+ size_to_allocate
;
120 if (low_level_alloc_callback
) {
121 low_level_alloc_callback((uptr
)allocated_current_
,
125 CHECK(allocated_end_
- allocated_current_
>= (sptr
)size
);
126 void *res
= allocated_current_
;
127 allocated_current_
+= size
;
131 void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback
) {
132 low_level_alloc_callback
= callback
;
135 bool CallocShouldReturnNullDueToOverflow(uptr size
, uptr n
) {
136 if (!size
) return false;
137 uptr max
= (uptr
)-1L;
138 return (max
/ size
) < n
;
141 void *AllocatorReturnNull() {
142 if (common_flags()->allocator_may_return_null
)
144 Report("%s's allocator is terminating the process instead of returning 0\n",
146 Report("If you don't like this behavior set allocator_may_return_null=1\n");
151 } // namespace __sanitizer