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 
thread_dtor(void * v)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 
GetRss()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 {
~AtExit__anon306212140111::AtExit80   ~AtExit() {
81     allocator.PrintStats();
82     Printf("RSS: %zdM\n", GetRss() >> 20);
83   }
84 };
85 
86 static AtExit at_exit;
87 
thread_init()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" {
malloc(size_t size)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 
free(void * p)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 
calloc(size_t nmemb,size_t size)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 
realloc(void * p,size_t size)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
memalign(size_t alignment,size_t size)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 
posix_memalign(void ** memptr,size_t alignment,size_t size)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 
valloc(size_t size)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 
malloc_usable_size()177 void malloc_usable_size() {
178 }
179 
180 #if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
mallinfo()181 void mallinfo() {
182 }
183 
mallopt()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