Line data Source code
1 : /* This Source Code Form is subject to the terms of the Mozilla Public
2 : * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
4 :
5 : #ifndef MOZ_MEMORY
6 : # error Should not compile this file when MOZ_MEMORY is not set
7 : #endif
8 :
9 : #ifndef MOZ_REPLACE_MALLOC
10 : # error Should not compile this file when replace-malloc is disabled
11 : #endif
12 :
13 : #include "mozmemory_wrap.h"
14 :
15 : /* Declare all je_* functions */
16 : #define MALLOC_DECL(name, return_type, ...) \
17 : return_type je_ ## name(__VA_ARGS__);
18 : #include "malloc_decls.h"
19 :
20 : #include "mozilla/Likely.h"
21 : #include "mozilla/MacroArgs.h"
22 : #include <errno.h>
23 : #ifndef XP_WIN
24 : #include <unistd.h>
25 : #endif
26 :
27 : /*
28 : * Windows doesn't come with weak imports as they are possible with
29 : * LD_PRELOAD or DYLD_INSERT_LIBRARIES on Linux/OSX. On this platform,
30 : * the replacement functions are defined as variable pointers to the
31 : * function resolved with GetProcAddress() instead of weak definitions
32 : * of functions. On Android, the same needs to happen as well, because
33 : * the Android linker doesn't handle weak linking with non LD_PRELOADed
34 : * libraries, but LD_PRELOADing is not very convenient on Android, with
35 : * the zygote.
36 : */
37 : #ifdef XP_DARWIN
38 : # define MOZ_REPLACE_WEAK __attribute__((weak_import))
39 : #elif defined(XP_WIN) || defined(MOZ_WIDGET_ANDROID)
40 : # define MOZ_NO_REPLACE_FUNC_DECL
41 : #elif defined(__GNUC__)
42 : # define MOZ_REPLACE_WEAK __attribute__((weak))
43 : #endif
44 :
45 : #include "replace_malloc.h"
46 :
47 : #define MALLOC_DECL(name, return_type, ...) \
48 : je_ ## name,
49 :
50 : static const malloc_table_t malloc_table = {
51 : #include "malloc_decls.h"
52 : };
53 :
54 : static malloc_table_t replace_malloc_table;
55 :
56 : #ifdef MOZ_NO_REPLACE_FUNC_DECL
57 : # define MALLOC_DECL(name, return_type, ...) \
58 : typedef return_type (name ## _impl_t)(__VA_ARGS__); \
59 : name ## _impl_t* replace_ ## name = NULL;
60 : # define MALLOC_FUNCS (MALLOC_FUNCS_INIT | MALLOC_FUNCS_BRIDGE)
61 : # include "malloc_decls.h"
62 : #endif
63 :
64 : #ifdef XP_WIN
65 : # include <windows.h>
66 :
67 : typedef HMODULE replace_malloc_handle_t;
68 :
69 : static replace_malloc_handle_t
70 : replace_malloc_handle()
71 : {
72 : char replace_malloc_lib[1024];
73 : if (GetEnvironmentVariableA("MOZ_REPLACE_MALLOC_LIB", (LPSTR)&replace_malloc_lib,
74 : sizeof(replace_malloc_lib)) > 0) {
75 : return LoadLibraryA(replace_malloc_lib);
76 : }
77 : return NULL;
78 : }
79 :
80 : # define REPLACE_MALLOC_GET_FUNC(handle, name) \
81 : (name ## _impl_t*) GetProcAddress(handle, "replace_" # name)
82 :
83 : #elif defined(MOZ_WIDGET_ANDROID)
84 : # include <dlfcn.h>
85 : # include <stdlib.h>
86 :
87 : typedef void* replace_malloc_handle_t;
88 :
89 : static replace_malloc_handle_t
90 : replace_malloc_handle()
91 : {
92 : const char *replace_malloc_lib = getenv("MOZ_REPLACE_MALLOC_LIB");
93 : if (replace_malloc_lib && *replace_malloc_lib) {
94 : return dlopen(replace_malloc_lib, RTLD_LAZY);
95 : }
96 : return NULL;
97 : }
98 :
99 : # define REPLACE_MALLOC_GET_FUNC(handle, name) \
100 : (name ## _impl_t*) dlsym(handle, "replace_" # name)
101 :
102 : #else
103 :
104 : # include <stdbool.h>
105 :
106 : typedef bool replace_malloc_handle_t;
107 :
108 : static replace_malloc_handle_t
109 3 : replace_malloc_handle()
110 : {
111 3 : return true;
112 : }
113 :
114 : # define REPLACE_MALLOC_GET_FUNC(handle, name) \
115 : replace_ ## name
116 :
117 : #endif
118 :
119 : static void replace_malloc_init_funcs();
120 :
121 : /*
122 : * Below is the malloc implementation overriding jemalloc and calling the
123 : * replacement functions if they exist.
124 : */
125 :
126 : static int replace_malloc_initialized = 0;
127 : static void
128 3 : init()
129 : {
130 3 : replace_malloc_init_funcs();
131 : // Set this *before* calling replace_init, otherwise if replace_init calls
132 : // malloc() we'll get an infinite loop.
133 3 : replace_malloc_initialized = 1;
134 3 : if (replace_init)
135 0 : replace_init(&malloc_table);
136 3 : }
137 :
138 : /*
139 : * Malloc implementation functions are MOZ_MEMORY_API, and jemalloc
140 : * specific functions MOZ_JEMALLOC_API; see mozmemory_wrap.h
141 : */
142 : #define MACRO_CALL(a, b) a b
143 : /* Can't use macros recursively, so we need another one doing the same as above. */
144 : #define MACRO_CALL2(a, b) a b
145 :
146 : #define ARGS_HELPER(name, ...) MACRO_CALL2( \
147 : MOZ_PASTE_PREFIX_AND_ARG_COUNT(name, ##__VA_ARGS__), \
148 : (__VA_ARGS__))
149 : #define TYPED_ARGS0()
150 : #define TYPED_ARGS1(t1) t1 arg1
151 : #define TYPED_ARGS2(t1, t2) TYPED_ARGS1(t1), t2 arg2
152 : #define TYPED_ARGS3(t1, t2, t3) TYPED_ARGS2(t1, t2), t3 arg3
153 :
154 : #define ARGS0()
155 : #define ARGS1(t1) arg1
156 : #define ARGS2(t1, t2) ARGS1(t1), arg2
157 : #define ARGS3(t1, t2, t3) ARGS2(t1, t2), arg3
158 :
159 : #define GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ...) \
160 : return_type name ## _impl(ARGS_HELPER(TYPED_ARGS, ##__VA_ARGS__)) \
161 : { \
162 : if (MOZ_UNLIKELY(!replace_malloc_initialized)) \
163 : init(); \
164 : return replace_malloc_table.name(ARGS_HELPER(ARGS, ##__VA_ARGS__)); \
165 : }
166 :
167 : #define GENERIC_MALLOC_DECL(name, return_type, ...) \
168 : GENERIC_MALLOC_DECL_HELPER(name, return, return_type, ##__VA_ARGS__)
169 : #define GENERIC_MALLOC_DECL_VOID(name, ...) \
170 : GENERIC_MALLOC_DECL_HELPER(name, , void, ##__VA_ARGS__)
171 :
172 : #define MALLOC_DECL(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
173 : #define MALLOC_DECL_VOID(...) MOZ_MEMORY_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
174 : #define MALLOC_FUNCS MALLOC_FUNCS_MALLOC
175 : #include "malloc_decls.h"
176 :
177 : #define MALLOC_DECL(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL, (__VA_ARGS__))
178 : #define MALLOC_DECL_VOID(...) MOZ_JEMALLOC_API MACRO_CALL(GENERIC_MALLOC_DECL_VOID, (__VA_ARGS__))
179 : #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
180 : #include "malloc_decls.h"
181 :
182 : MFBT_API struct ReplaceMallocBridge*
183 0 : get_bridge(void)
184 : {
185 0 : if (MOZ_UNLIKELY(!replace_malloc_initialized))
186 0 : init();
187 0 : if (MOZ_LIKELY(!replace_get_bridge))
188 0 : return NULL;
189 0 : return replace_get_bridge();
190 : }
191 :
192 : /* The following comment and definitions are from jemalloc.c: */
193 : #if defined(__GLIBC__) && !defined(__UCLIBC__)
194 :
195 : /*
196 : * glibc provides the RTLD_DEEPBIND flag for dlopen which can make it possible
197 : * to inconsistently reference libc's malloc(3)-compatible functions
198 : * (https://bugzilla.mozilla.org/show_bug.cgi?id=493541).
199 : *
200 : * These definitions interpose hooks in glibc. The functions are actually
201 : * passed an extra argument for the caller return address, which will be
202 : * ignored.
203 : */
204 :
205 : typedef void (* __free_hook_type)(void *ptr);
206 : typedef void *(* __malloc_hook_type)(size_t size);
207 : typedef void *(* __realloc_hook_type)(void *ptr, size_t size);
208 : typedef void *(* __memalign_hook_type)(size_t alignment, size_t size);
209 :
210 : MOZ_MEMORY_API __free_hook_type __free_hook = free_impl;
211 : MOZ_MEMORY_API __malloc_hook_type __malloc_hook = malloc_impl;
212 : MOZ_MEMORY_API __realloc_hook_type __realloc_hook = realloc_impl;
213 : MOZ_MEMORY_API __memalign_hook_type __memalign_hook = memalign_impl;
214 :
215 : #endif
216 :
217 : /*
218 : * posix_memalign, aligned_alloc, memalign and valloc all implement some kind
219 : * of aligned memory allocation. For convenience, a replace-malloc library can
220 : * skip defining replace_posix_memalign, replace_aligned_alloc and
221 : * replace_valloc, and default implementations will be automatically derived
222 : * from replace_memalign.
223 : */
224 : static int
225 0 : default_posix_memalign(void** ptr, size_t alignment, size_t size)
226 : {
227 0 : if (size == 0) {
228 0 : *ptr = NULL;
229 0 : return 0;
230 : }
231 : /* alignment must be a power of two and a multiple of sizeof(void *) */
232 0 : if (((alignment - 1) & alignment) != 0 || (alignment % sizeof(void *)))
233 0 : return EINVAL;
234 0 : *ptr = replace_malloc_table.memalign(alignment, size);
235 0 : return *ptr ? 0 : ENOMEM;
236 : }
237 :
238 : static void*
239 0 : default_aligned_alloc(size_t alignment, size_t size)
240 : {
241 : /* size should be a multiple of alignment */
242 0 : if (size % alignment)
243 0 : return NULL;
244 0 : return replace_malloc_table.memalign(alignment, size);
245 : }
246 :
247 : // Nb: sysconf() is expensive, but valloc is obsolete and rarely used.
248 : static void*
249 0 : default_valloc(size_t size)
250 : {
251 : #ifdef XP_WIN
252 : SYSTEM_INFO si;
253 : GetSystemInfo(&si);
254 : size_t page_size = si.dwPageSize;
255 : #else
256 0 : size_t page_size = sysconf(_SC_PAGE_SIZE);
257 : #endif
258 0 : return replace_malloc_table.memalign(page_size, size);
259 : }
260 :
261 : static void
262 3 : replace_malloc_init_funcs()
263 : {
264 3 : replace_malloc_handle_t handle = replace_malloc_handle();
265 3 : if (handle) {
266 : #ifdef MOZ_NO_REPLACE_FUNC_DECL
267 : # define MALLOC_DECL(name, ...) \
268 : replace_ ## name = REPLACE_MALLOC_GET_FUNC(handle, name);
269 :
270 : # define MALLOC_FUNCS (MALLOC_FUNCS_INIT | MALLOC_FUNCS_BRIDGE)
271 : # include "malloc_decls.h"
272 : #endif
273 :
274 : #define MALLOC_DECL(name, ...) \
275 : replace_malloc_table.name = REPLACE_MALLOC_GET_FUNC(handle, name);
276 : #include "malloc_decls.h"
277 : }
278 :
279 3 : if (!replace_malloc_table.posix_memalign && replace_malloc_table.memalign)
280 0 : replace_malloc_table.posix_memalign = default_posix_memalign;
281 :
282 3 : if (!replace_malloc_table.aligned_alloc && replace_malloc_table.memalign)
283 0 : replace_malloc_table.aligned_alloc = default_aligned_alloc;
284 :
285 3 : if (!replace_malloc_table.valloc && replace_malloc_table.memalign)
286 0 : replace_malloc_table.valloc = default_valloc;
287 :
288 : #define MALLOC_DECL(name, ...) \
289 : if (!replace_malloc_table.name) { \
290 : replace_malloc_table.name = je_ ## name; \
291 : }
292 : #include "malloc_decls.h"
293 3 : }
|