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:
13clang++ -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
18LD_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
36static const uptr kAllocatorSpace = 0x600000000000ULL;
37static const uptr kAllocatorSize = 0x10000000000ULL; // 1T.
38
39struct __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
49namespace {
50
51typedef SizeClassAllocator64<__AP64> PrimaryAllocator;
52typedef CombinedAllocator<PrimaryAllocator> Allocator;
53typedef Allocator::AllocatorCache AllocatorCache;
54
55static Allocator allocator;
56static bool global_inited;
57static THREADLOCAL AllocatorCache cache;
58static THREADLOCAL bool thread_inited;
59static pthread_key_t pkey;
60
61static void thread_dtor(void *v) {
62 if ((uptr)v != 3) {
63 pthread_setspecific(key: pkey, pointer: (void*)((uptr)v + 1));
64 return;
65 }
66 allocator.SwallowCache(cache: &cache);
67}
68
69static size_t GetRss() {
70 if (FILE *f = fopen(filename: "/proc/self/statm", modes: "r")) {
71 size_t size = 0, rss = 0;
72 fscanf(stream: f, format: "%zd %zd", &size, &rss);
73 fclose(stream: f);
74 return rss << 12; // rss is in pages.
75 }
76 return 0;
77}
78
79struct AtExit {
80 ~AtExit() {
81 allocator.PrintStats();
82 Printf("RSS: %zdM\n", GetRss() >> 20);
83 }
84};
85
86static AtExit at_exit;
87
88static void NOINLINE thread_init() {
89 if (!global_inited) {
90 global_inited = true;
91 allocator.Init(release_to_os_interval_ms: false /*may_return_null*/);
92 pthread_key_create(key: &pkey, destr_function: thread_dtor);
93 }
94 thread_inited = true;
95 pthread_setspecific(key: pkey, pointer: (void*)1);
96 cache.Init(nullptr);
97}
98} // namespace
99
100extern "C" {
101void *malloc(size_t size) {
102 if (UNLIKELY(!thread_inited))
103 thread_init();
104 void *p = allocator.Allocate(cache: &cache, size, alignment: 8);
105 SANITIZER_MALLOC_HOOK(p, size);
106 return p;
107}
108
109void free(void *p) {
110 if (UNLIKELY(!thread_inited))
111 thread_init();
112 SANITIZER_FREE_HOOK(p);
113 allocator.Deallocate(cache: &cache, p);
114}
115
116void *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(s: p, c: 0, n: size);
122 SANITIZER_MALLOC_HOOK(p, size);
123 return p;
124}
125
126void *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: &cache, p, new_size: size, alignment: 8);
133 if (p) {
134 SANITIZER_MALLOC_HOOK(p, size);
135 }
136 return p;
137}
138
139#if SANITIZER_INTERCEPT_MEMALIGN
140void *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
149int posix_memalign(void **memptr, size_t alignment, size_t size) {
150 if (UNLIKELY(!thread_inited))
151 thread_init();
152 *memptr = allocator.Allocate(cache: &cache, size, alignment);
153 SANITIZER_MALLOC_HOOK(*memptr, size);
154 return 0;
155}
156
157void *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: &cache, size, alignment: GetPageSizeCached());
163 SANITIZER_MALLOC_HOOK(p, size);
164 return p;
165}
166
167#if SANITIZER_INTERCEPT_CFREE
168void cfree(void *p) ALIAS(free);
169#endif // SANITIZER_INTERCEPT_CFREE
170#if SANITIZER_INTERCEPT_PVALLOC
171void *pvalloc(size_t size) ALIAS(valloc);
172#endif // SANITIZER_INTERCEPT_PVALLOC
173#if SANITIZER_INTERCEPT_MEMALIGN
174void *__libc_memalign(size_t alignment, size_t size) ALIAS(memalign);
175#endif // SANITIZER_INTERCEPT_MEMALIGN
176
177void malloc_usable_size() {
178}
179
180#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
181void mallinfo() {
182}
183
184void mallopt() {
185}
186#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
187} // extern "C"
188
189namespace std {
190 struct nothrow_t;
191}
192
193void *operator new(size_t size) ALIAS(malloc);
194void *operator new[](size_t size) ALIAS(malloc);
195void *operator new(size_t size, std::nothrow_t const&) ALIAS(malloc);
196void *operator new[](size_t size, std::nothrow_t const&) ALIAS(malloc);
197void operator delete(void *ptr) throw() ALIAS(free);
198void operator delete[](void *ptr) throw() ALIAS(free);
199void operator delete(void *ptr, std::nothrow_t const&) ALIAS(free);
200void operator delete[](void *ptr, std::nothrow_t const&) ALIAS(free);
201

source code of compiler-rt/lib/sanitizer_common/tests/sanitizer_allocator_testlib.cpp