blob: 07b668f08056832c9acdc914703a98b98290d879 [file] [log] [blame]
Christopher Ferrisdb478a62018-02-07 18:42:14 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <errno.h>
30#include <malloc.h>
31#include <stdint.h>
Christopher Ferris6c619a02019-03-01 17:59:51 -080032#include <stdio.h>
Christopher Ferrisdb478a62018-02-07 18:42:14 -080033#include <string.h>
34#include <sys/param.h>
35#include <unistd.h>
36
37#include <private/bionic_malloc_dispatch.h>
38
39// ------------------------------------------------------------------------
40// Global Data
41// ------------------------------------------------------------------------
42const MallocDispatch* g_dispatch;
43// ------------------------------------------------------------------------
44
45// ------------------------------------------------------------------------
46// Use C style prototypes for all exported functions. This makes it easy
47// to do dlsym lookups during libc initialization when hooks are enabled.
48// ------------------------------------------------------------------------
49__BEGIN_DECLS
50
51bool hooks_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child,
52 const char* options);
53void hooks_finalize();
54void hooks_get_malloc_leak_info(
55 uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory,
56 size_t* backtrace_size);
57ssize_t hooks_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
58void hooks_free_malloc_leak_info(uint8_t* info);
59size_t hooks_malloc_usable_size(void* pointer);
60void* hooks_malloc(size_t size);
Christopher Ferris6c619a02019-03-01 17:59:51 -080061int hooks_malloc_info(int options, FILE* fp);
Christopher Ferrisdb478a62018-02-07 18:42:14 -080062void hooks_free(void* pointer);
63void* hooks_memalign(size_t alignment, size_t bytes);
64void* hooks_aligned_alloc(size_t alignment, size_t bytes);
65void* hooks_realloc(void* pointer, size_t bytes);
66void* hooks_calloc(size_t nmemb, size_t bytes);
67struct mallinfo hooks_mallinfo();
68int hooks_mallopt(int param, int value);
69int hooks_posix_memalign(void** memptr, size_t alignment, size_t size);
70int hooks_iterate(uintptr_t base, size_t size,
71 void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
72void hooks_malloc_disable();
73void hooks_malloc_enable();
Florian Mayer2d6030b2018-06-05 18:26:53 +010074bool hooks_write_malloc_leak_info(FILE*);
Christopher Ferrisdb478a62018-02-07 18:42:14 -080075
76#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
77void* hooks_pvalloc(size_t bytes);
78void* hooks_valloc(size_t size);
79#endif
80
81static void* default_malloc_hook(size_t bytes, const void*) {
82 return g_dispatch->malloc(bytes);
83}
84
85static void* default_realloc_hook(void* pointer, size_t bytes, const void*) {
86 return g_dispatch->realloc(pointer, bytes);
87}
88
89static void default_free_hook(void* pointer, const void*) {
90 g_dispatch->free(pointer);
91}
92
93static void* default_memalign_hook(size_t alignment, size_t bytes, const void*) {
94 return g_dispatch->memalign(alignment, bytes);
95}
96
97__END_DECLS
98// ------------------------------------------------------------------------
99
100bool hooks_initialize(const MallocDispatch* malloc_dispatch, int*, const char*) {
101 g_dispatch = malloc_dispatch;
102 __malloc_hook = default_malloc_hook;
103 __realloc_hook = default_realloc_hook;
104 __free_hook = default_free_hook;
105 __memalign_hook = default_memalign_hook;
106 return true;
107}
108
109void hooks_finalize() {
110}
111
112void hooks_get_malloc_leak_info(uint8_t** info, size_t* overall_size,
113 size_t* info_size, size_t* total_memory, size_t* backtrace_size) {
114 *info = nullptr;
115 *overall_size = 0;
116 *info_size = 0;
117 *total_memory = 0;
118 *backtrace_size = 0;
119}
120
121void hooks_free_malloc_leak_info(uint8_t*) {
122}
123
124size_t hooks_malloc_usable_size(void* pointer) {
125 return g_dispatch->malloc_usable_size(pointer);
126}
127
128void* hooks_malloc(size_t size) {
129 if (__malloc_hook != nullptr && __malloc_hook != default_malloc_hook) {
130 return __malloc_hook(size, __builtin_return_address(0));
131 }
132 return g_dispatch->malloc(size);
133}
134
135void hooks_free(void* pointer) {
136 if (__free_hook != nullptr && __free_hook != default_free_hook) {
137 return __free_hook(pointer, __builtin_return_address(0));
138 }
139 return g_dispatch->free(pointer);
140}
141
142void* hooks_memalign(size_t alignment, size_t bytes) {
143 if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
144 return __memalign_hook(alignment, bytes, __builtin_return_address(0));
145 }
146 return g_dispatch->memalign(alignment, bytes);
147}
148
149void* hooks_realloc(void* pointer, size_t bytes) {
150 if (__realloc_hook != nullptr && __realloc_hook != default_realloc_hook) {
151 return __realloc_hook(pointer, bytes, __builtin_return_address(0));
152 }
153 return g_dispatch->realloc(pointer, bytes);
154}
155
156void* hooks_calloc(size_t nmemb, size_t bytes) {
157 if (__malloc_hook != nullptr && __malloc_hook != default_malloc_hook) {
158 size_t size;
159 if (__builtin_mul_overflow(nmemb, bytes, &size)) {
160 return nullptr;
161 }
162 void* ptr = __malloc_hook(size, __builtin_return_address(0));
163 if (ptr != nullptr) {
164 memset(ptr, 0, size);
165 }
166 return ptr;
167 }
168 return g_dispatch->calloc(nmemb, bytes);
169}
170
171struct mallinfo hooks_mallinfo() {
172 return g_dispatch->mallinfo();
173}
174
175int hooks_mallopt(int param, int value) {
176 return g_dispatch->mallopt(param, value);
177}
178
Christopher Ferris6c619a02019-03-01 17:59:51 -0800179int hooks_malloc_info(int options, FILE* fp) {
180 return g_dispatch->malloc_info(options, fp);
181}
182
Christopher Ferrisdb478a62018-02-07 18:42:14 -0800183void* hooks_aligned_alloc(size_t alignment, size_t size) {
184 if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
Christopher Ferrisa22f5d52019-03-01 16:40:59 -0800185 if (!powerof2(alignment) || (size % alignment) != 0) {
Christopher Ferrisdb478a62018-02-07 18:42:14 -0800186 errno = EINVAL;
187 return nullptr;
188 }
189 void* ptr = __memalign_hook(alignment, size, __builtin_return_address(0));
190 if (ptr == nullptr) {
191 errno = ENOMEM;
192 }
193 return ptr;
194 }
195 return g_dispatch->aligned_alloc(alignment, size);
196}
197
198int hooks_posix_memalign(void** memptr, size_t alignment, size_t size) {
199 if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
Christopher Ferris6c619a02019-03-01 17:59:51 -0800200 if (alignment < sizeof(void*) || !powerof2(alignment)) {
Christopher Ferrisdb478a62018-02-07 18:42:14 -0800201 return EINVAL;
202 }
203 *memptr = __memalign_hook(alignment, size, __builtin_return_address(0));
204 if (*memptr == nullptr) {
205 return ENOMEM;
206 }
207 return 0;
208 }
209 return g_dispatch->posix_memalign(memptr, alignment, size);
210}
211
212int hooks_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) {
213 return 0;
214}
215
216void hooks_malloc_disable() {
217}
218
219void hooks_malloc_enable() {
220}
221
222ssize_t hooks_malloc_backtrace(void*, uintptr_t*, size_t) {
223 return 0;
224}
225
Florian Mayer2d6030b2018-06-05 18:26:53 +0100226bool hooks_write_malloc_leak_info(FILE*) {
227 return true;
228}
229
Christopher Ferrisdb478a62018-02-07 18:42:14 -0800230#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
231void* hooks_pvalloc(size_t bytes) {
232 size_t pagesize = getpagesize();
233 size_t size = __BIONIC_ALIGN(bytes, pagesize);
234 if (size < bytes) {
235 // Overflow
236 errno = ENOMEM;
237 return nullptr;
238 }
239 return hooks_memalign(pagesize, size);
240}
241
242void* hooks_valloc(size_t size) {
243 return hooks_memalign(getpagesize(), size);
244}
245#endif