1 //===-- sanitizer_allocator_testlib.cpp -----------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // Malloc replacement library based on CombinedAllocator. 9 // The primary purpose of this file is an end-to-end integration test 10 // for CombinedAllocator. 11 //===----------------------------------------------------------------------===// 12 /* Usage: 13 clang++ -std=c++11 -fno-exceptions -g -fPIC -I. -I../include -Isanitizer \ 14 sanitizer_common/tests/sanitizer_allocator_testlib.cpp \ 15 $(\ls sanitizer_common/sanitizer_*.cpp | grep -v sanitizer_common_nolibc.cpp) \ 16 sanitizer_common/sanitizer_linux_x86_64.S \ 17 -shared -lpthread -o testmalloc.so 18 LD_PRELOAD=`pwd`/testmalloc.so /your/app 19 */ 20 #include "sanitizer_common/sanitizer_allocator.h" 21 #include "sanitizer_common/sanitizer_common.h" 22 #include <stddef.h> 23 #include <stdio.h> 24 #include <unistd.h> 25 #include <string.h> 26 #include <pthread.h> 27 28 #ifndef SANITIZER_MALLOC_HOOK 29 # define SANITIZER_MALLOC_HOOK(p, s) 30 #endif 31 32 #ifndef SANITIZER_FREE_HOOK 33 # define SANITIZER_FREE_HOOK(p) 34 #endif 35 36 static const uptr kAllocatorSpace = 0x600000000000ULL; 37 static const uptr kAllocatorSize = 0x10000000000ULL; // 1T. 38 39 struct __AP64 { 40 static const uptr kSpaceBeg = ~(uptr)0; 41 static const uptr kSpaceSize = kAllocatorSize; 42 static const uptr kMetadataSize = 0; 43 typedef CompactSizeClassMap SizeClassMap; 44 typedef NoOpMapUnmapCallback MapUnmapCallback; 45 static const uptr kFlags = 46 SizeClassAllocator64FlagMasks::kRandomShuffleChunks; 47 }; 48 49 namespace { 50 51 typedef SizeClassAllocator64<__AP64> PrimaryAllocator; 52 typedef CombinedAllocator<PrimaryAllocator> Allocator; 53 typedef Allocator::AllocatorCache AllocatorCache; 54 55 static Allocator allocator; 56 static bool global_inited; 57 static THREADLOCAL AllocatorCache cache; 58 static THREADLOCAL bool thread_inited; 59 static pthread_key_t pkey; 60 61 static void thread_dtor(void *v) { 62 if ((uptr)v != 3) { 63 pthread_setspecific(pkey, (void*)((uptr)v + 1)); 64 return; 65 } 66 allocator.SwallowCache(&cache); 67 } 68 69 static size_t GetRss() { 70 if (FILE *f = fopen("/proc/self/statm", "r")) { 71 size_t size = 0, rss = 0; 72 fscanf(f, "%zd %zd", &size, &rss); 73 fclose(f); 74 return rss << 12; // rss is in pages. 75 } 76 return 0; 77 } 78 79 struct AtExit { 80 ~AtExit() { 81 allocator.PrintStats(); 82 Printf("RSS: %zdM\n", GetRss() >> 20); 83 } 84 }; 85 86 static AtExit at_exit; 87 88 static void NOINLINE thread_init() { 89 if (!global_inited) { 90 global_inited = true; 91 allocator.Init(false /*may_return_null*/); 92 pthread_key_create(&pkey, thread_dtor); 93 } 94 thread_inited = true; 95 pthread_setspecific(pkey, (void*)1); 96 cache.Init(nullptr); 97 } 98 } // namespace 99 100 extern "C" { 101 void *malloc(size_t size) { 102 if (UNLIKELY(!thread_inited)) 103 thread_init(); 104 void *p = allocator.Allocate(&cache, size, 8); 105 SANITIZER_MALLOC_HOOK(p, size); 106 return p; 107 } 108 109 void free(void *p) { 110 if (UNLIKELY(!thread_inited)) 111 thread_init(); 112 SANITIZER_FREE_HOOK(p); 113 allocator.Deallocate(&cache, p); 114 } 115 116 void *calloc(size_t nmemb, size_t size) { 117 if (UNLIKELY(!thread_inited)) 118 thread_init(); 119 size *= nmemb; 120 void *p = allocator.Allocate(&cache, size, 8, false); 121 memset(p, 0, size); 122 SANITIZER_MALLOC_HOOK(p, size); 123 return p; 124 } 125 126 void *realloc(void *p, size_t size) { 127 if (UNLIKELY(!thread_inited)) 128 thread_init(); 129 if (p) { 130 SANITIZER_FREE_HOOK(p); 131 } 132 p = allocator.Reallocate(&cache, p, size, 8); 133 if (p) { 134 SANITIZER_MALLOC_HOOK(p, size); 135 } 136 return p; 137 } 138 139 #if SANITIZER_INTERCEPT_MEMALIGN 140 void *memalign(size_t alignment, size_t size) { 141 if (UNLIKELY(!thread_inited)) 142 thread_init(); 143 void *p = allocator.Allocate(&cache, size, alignment); 144 SANITIZER_MALLOC_HOOK(p, size); 145 return p; 146 } 147 #endif // SANITIZER_INTERCEPT_MEMALIGN 148 149 int posix_memalign(void **memptr, size_t alignment, size_t size) { 150 if (UNLIKELY(!thread_inited)) 151 thread_init(); 152 *memptr = allocator.Allocate(&cache, size, alignment); 153 SANITIZER_MALLOC_HOOK(*memptr, size); 154 return 0; 155 } 156 157 void *valloc(size_t size) { 158 if (UNLIKELY(!thread_inited)) 159 thread_init(); 160 if (size == 0) 161 size = GetPageSizeCached(); 162 void *p = allocator.Allocate(&cache, size, GetPageSizeCached()); 163 SANITIZER_MALLOC_HOOK(p, size); 164 return p; 165 } 166 167 #if SANITIZER_INTERCEPT_CFREE 168 void cfree(void *p) ALIAS("free"); 169 #endif // SANITIZER_INTERCEPT_CFREE 170 #if SANITIZER_INTERCEPT_PVALLOC 171 void *pvalloc(size_t size) ALIAS("valloc"); 172 #endif // SANITIZER_INTERCEPT_PVALLOC 173 #if SANITIZER_INTERCEPT_MEMALIGN 174 void *__libc_memalign(size_t alignment, size_t size) ALIAS("memalign"); 175 #endif // SANITIZER_INTERCEPT_MEMALIGN 176 177 void malloc_usable_size() { 178 } 179 180 #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO 181 void mallinfo() { 182 } 183 184 void mallopt() { 185 } 186 #endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO 187 } // extern "C" 188 189 namespace std { 190 struct nothrow_t; 191 } 192 193 void *operator new(size_t size) ALIAS("malloc"); 194 void *operator new[](size_t size) ALIAS("malloc"); 195 void *operator new(size_t size, std::nothrow_t const&) ALIAS("malloc"); 196 void *operator new[](size_t size, std::nothrow_t const&) ALIAS("malloc"); 197 void operator delete(void *ptr) throw() ALIAS("free"); 198 void operator delete[](void *ptr) throw() ALIAS("free"); 199 void operator delete(void *ptr, std::nothrow_t const&) ALIAS("free"); 200 void operator delete[](void *ptr, std::nothrow_t const&) ALIAS("free"); 201