1 /*
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>
32 #include <stdio.h>
33 #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 // ------------------------------------------------------------------------
42 const 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 
51 bool hooks_initialize(const MallocDispatch* malloc_dispatch, bool* zygote_child,
52     const char* options);
53 void hooks_finalize();
54 void 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);
57 ssize_t hooks_malloc_backtrace(void* pointer, uintptr_t* frames, size_t frame_count);
58 void hooks_free_malloc_leak_info(uint8_t* info);
59 size_t hooks_malloc_usable_size(void* pointer);
60 void* hooks_malloc(size_t size);
61 int hooks_malloc_info(int options, FILE* fp);
62 void hooks_free(void* pointer);
63 void* hooks_memalign(size_t alignment, size_t bytes);
64 void* hooks_aligned_alloc(size_t alignment, size_t bytes);
65 void* hooks_realloc(void* pointer, size_t bytes);
66 void* hooks_calloc(size_t nmemb, size_t bytes);
67 struct mallinfo hooks_mallinfo();
68 int hooks_mallopt(int param, int value);
69 int hooks_posix_memalign(void** memptr, size_t alignment, size_t size);
70 int hooks_malloc_iterate(uintptr_t base, size_t size,
71     void (*callback)(uintptr_t base, size_t size, void* arg), void* arg);
72 void hooks_malloc_disable();
73 void hooks_malloc_enable();
74 bool hooks_write_malloc_leak_info(FILE*);
75 
76 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
77 void* hooks_pvalloc(size_t bytes);
78 void* hooks_valloc(size_t size);
79 #endif
80 
default_malloc_hook(size_t bytes,const void *)81 static void* default_malloc_hook(size_t bytes, const void*) {
82   return g_dispatch->malloc(bytes);
83 }
84 
default_realloc_hook(void * pointer,size_t bytes,const void *)85 static void* default_realloc_hook(void* pointer, size_t bytes, const void*) {
86   return g_dispatch->realloc(pointer, bytes);
87 }
88 
default_free_hook(void * pointer,const void *)89 static void default_free_hook(void* pointer, const void*) {
90   g_dispatch->free(pointer);
91 }
92 
default_memalign_hook(size_t alignment,size_t bytes,const void *)93 static 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 
hooks_initialize(const MallocDispatch * malloc_dispatch,bool *,const char *)100 bool hooks_initialize(const MallocDispatch* malloc_dispatch, bool*, 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 
hooks_finalize()109 void hooks_finalize() {
110 }
111 
hooks_get_malloc_leak_info(uint8_t ** info,size_t * overall_size,size_t * info_size,size_t * total_memory,size_t * backtrace_size)112 void 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 
hooks_free_malloc_leak_info(uint8_t *)121 void hooks_free_malloc_leak_info(uint8_t*) {
122 }
123 
hooks_malloc_usable_size(void * pointer)124 size_t hooks_malloc_usable_size(void* pointer) {
125   return g_dispatch->malloc_usable_size(pointer);
126 }
127 
hooks_malloc(size_t size)128 void* 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 
hooks_free(void * pointer)135 void 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 
hooks_memalign(size_t alignment,size_t bytes)142 void* 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 
hooks_realloc(void * pointer,size_t bytes)149 void* 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 
hooks_calloc(size_t nmemb,size_t bytes)156 void* 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 
hooks_mallinfo()171 struct mallinfo hooks_mallinfo() {
172   return g_dispatch->mallinfo();
173 }
174 
hooks_mallopt(int param,int value)175 int hooks_mallopt(int param, int value) {
176   return g_dispatch->mallopt(param, value);
177 }
178 
hooks_malloc_info(int options,FILE * fp)179 int hooks_malloc_info(int options, FILE* fp) {
180   return g_dispatch->malloc_info(options, fp);
181 }
182 
hooks_aligned_alloc(size_t alignment,size_t size)183 void* hooks_aligned_alloc(size_t alignment, size_t size) {
184   if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
185     if (!powerof2(alignment) || (size % alignment) != 0) {
186       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 
hooks_posix_memalign(void ** memptr,size_t alignment,size_t size)198 int hooks_posix_memalign(void** memptr, size_t alignment, size_t size) {
199   if (__memalign_hook != nullptr && __memalign_hook != default_memalign_hook) {
200     if (alignment < sizeof(void*) || !powerof2(alignment)) {
201       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 
hooks_malloc_iterate(uintptr_t,size_t,void (*)(uintptr_t,size_t,void *),void *)212 int hooks_malloc_iterate(uintptr_t, size_t, void (*)(uintptr_t, size_t, void*), void*) {
213   return 0;
214 }
215 
hooks_malloc_disable()216 void hooks_malloc_disable() {
217 }
218 
hooks_malloc_enable()219 void hooks_malloc_enable() {
220 }
221 
hooks_malloc_backtrace(void *,uintptr_t *,size_t)222 ssize_t hooks_malloc_backtrace(void*, uintptr_t*, size_t) {
223   return 0;
224 }
225 
hooks_write_malloc_leak_info(FILE *)226 bool hooks_write_malloc_leak_info(FILE*) {
227   return true;
228 }
229 
230 #if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
hooks_pvalloc(size_t bytes)231 void* 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 
hooks_valloc(size_t size)242 void* hooks_valloc(size_t size) {
243   return hooks_memalign(getpagesize(), size);
244 }
245 #endif
246