blob: 9f7f3ba536d46412b7e2aee64b4030622b49d2f7 [file] [log] [blame]
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -08001/*
2 * Copyright (C) 2009 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
Christopher Ferrisa4037802014-06-09 19:14:11 -070029// Contains definition of structures, global variables, and implementation of
30// routines that are used by malloc leak detection code and other components in
31// the system. The trick is that some components expect these data and
Christopher Ferris6fe376d2014-09-19 12:26:09 -070032// routines to be defined / implemented in libc.so, regardless whether or not
33// malloc leak detection code is going to run. To make things even more tricky,
34// malloc leak detection code, implemented in libc_malloc_debug.so also
35// requires access to these variables and routines (to fill allocation entry
36// hash table, for example). So, all relevant variables and routines are
37// defined / implemented here and exported to all, leak detection code and
38// other components via dynamic (libc.so), or static (libc.a) linking.
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -080039
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -080040#include "malloc_debug_common.h"
41
Elliott Hughes3b297c42012-10-11 16:08:51 -070042#include <pthread.h>
43#include <stdlib.h>
Elliott Hughes05fc1d72015-01-28 18:02:33 -080044#include <string.h>
Elliott Hughes3b297c42012-10-11 16:08:51 -070045#include <unistd.h>
46
Josh Gao3c8fc2f2015-10-08 14:49:26 -070047#include "private/bionic_globals.h"
Elliott Hugheseb847bc2013-10-09 15:50:50 -070048#include "private/ScopedPthreadMutexLocker.h"
Elliott Hughes3b297c42012-10-11 16:08:51 -070049
Christopher Ferrisdda1c6c2014-07-09 17:16:07 -070050#if defined(USE_JEMALLOC)
51#include "jemalloc.h"
52#define Malloc(function) je_ ## function
53#elif defined(USE_DLMALLOC)
54#include "dlmalloc.h"
55#define Malloc(function) dl ## function
56#else
57#error "Either one of USE_DLMALLOC or USE_JEMALLOC must be defined."
58#endif
59
Josh Gao3c8fc2f2015-10-08 14:49:26 -070060static constexpr MallocDebug __libc_malloc_default_dispatch
61 __attribute__((unused)) = {
62 Malloc(calloc),
63 Malloc(free),
64 Malloc(mallinfo),
65 Malloc(malloc),
66 Malloc(malloc_usable_size),
67 Malloc(memalign),
68 Malloc(posix_memalign),
69#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
70 Malloc(pvalloc),
71#endif
72 Malloc(realloc),
73#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
74 Malloc(valloc),
75#endif
76 };
77
Elliott Hughes8e52e8f2014-06-04 12:07:11 -070078// In a VM process, this is set to 1 after fork()ing out of zygote.
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -080079int gMallocLeakZygoteChild = 0;
80
Elliott Hughes8e52e8f2014-06-04 12:07:11 -070081static HashTable g_hash_table;
82
Elliott Hughes8e52e8f2014-06-04 12:07:11 -070083// Handle to shared library where actual memory allocation is implemented.
84// This library is loaded and memory allocation calls are redirected there
85// when libc.debug.malloc environment variable contains value other than
86// zero:
87// 1 - For memory leak detections.
88// 5 - For filling allocated / freed memory with patterns defined by
89// CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros.
90// 10 - For adding pre-, and post- allocation stubs in order to detect
91// buffer overruns.
92// Note that emulator's memory allocation instrumentation is not controlled by
93// libc.debug.malloc value, but rather by emulator, started with -memcheck
94// option. Note also, that if emulator has started with -memcheck option,
95// emulator's instrumented memory allocation will take over value saved in
96// libc.debug.malloc. In other words, if emulator has started with -memcheck
97// option, libc.debug.malloc value is ignored.
98// Actual functionality for debug levels 1-10 is implemented in
99// libc_malloc_debug_leak.so, while functionality for emulator's instrumented
100// allocations is implemented in libc_malloc_debug_qemu.so and can be run inside
101// the emulator only.
102#if !defined(LIBC_STATIC)
103static void* libc_malloc_impl_handle = NULL;
104#endif
105
106
107// The value of libc.debug.malloc.
108#if !defined(LIBC_STATIC)
109static int g_malloc_debug_level = 0;
110#endif
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800111
112// =============================================================================
113// output functions
114// =============================================================================
115
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700116static int hash_entry_compare(const void* arg1, const void* arg2) {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700117 int result;
Christopher Tate52e7d3d2010-08-09 13:43:46 -0700118
Christopher Ferrisa4037802014-06-09 19:14:11 -0700119 const HashEntry* e1 = *static_cast<HashEntry* const*>(arg1);
120 const HashEntry* e2 = *static_cast<HashEntry* const*>(arg2);
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800121
Christopher Ferrisa4037802014-06-09 19:14:11 -0700122 // if one or both arg pointers are null, deal gracefully
123 if (e1 == NULL) {
124 result = (e2 == NULL) ? 0 : 1;
125 } else if (e2 == NULL) {
126 result = -1;
127 } else {
128 size_t nbAlloc1 = e1->allocations;
129 size_t nbAlloc2 = e2->allocations;
130 size_t size1 = e1->size & ~SIZE_FLAG_MASK;
131 size_t size2 = e2->size & ~SIZE_FLAG_MASK;
132 size_t alloc1 = nbAlloc1 * size1;
133 size_t alloc2 = nbAlloc2 * size2;
134
135 // sort in descending order by:
136 // 1) total size
137 // 2) number of allocations
138 //
139 // This is used for sorting, not determination of equality, so we don't
140 // need to compare the bit flags.
141 if (alloc1 > alloc2) {
142 result = -1;
143 } else if (alloc1 < alloc2) {
144 result = 1;
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800145 } else {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700146 if (nbAlloc1 > nbAlloc2) {
147 result = -1;
148 } else if (nbAlloc1 < nbAlloc2) {
149 result = 1;
150 } else {
151 result = 0;
152 }
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800153 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700154 }
155 return result;
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800156}
157
Christopher Ferrisa4037802014-06-09 19:14:11 -0700158// Retrieve native heap information.
159//
160// "*info" is set to a buffer we allocate
161// "*overallSize" is set to the size of the "info" buffer
162// "*infoSize" is set to the size of a single entry
163// "*totalMemory" is set to the sum of all allocations we're tracking; does
164// not include heap overhead
165// "*backtraceSize" is set to the maximum number of entries in the back trace
Elliott Hughes7c9923d2014-05-16 16:29:55 -0700166
Christopher Ferrisa4037802014-06-09 19:14:11 -0700167// =============================================================================
Elliott Hughes7c9923d2014-05-16 16:29:55 -0700168// Exported for use by ddms.
Christopher Ferrisa4037802014-06-09 19:14:11 -0700169// =============================================================================
Elliott Hughes7c9923d2014-05-16 16:29:55 -0700170extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
Christopher Ferrisa4037802014-06-09 19:14:11 -0700171 size_t* infoSize, size_t* totalMemory, size_t* backtraceSize) {
172 // Don't do anything if we have invalid arguments.
173 if (info == NULL || overallSize == NULL || infoSize == NULL ||
174 totalMemory == NULL || backtraceSize == NULL) {
175 return;
176 }
177 *totalMemory = 0;
178
179 ScopedPthreadMutexLocker locker(&g_hash_table.lock);
180 if (g_hash_table.count == 0) {
181 *info = NULL;
182 *overallSize = 0;
183 *infoSize = 0;
184 *backtraceSize = 0;
185 return;
186 }
187
188 HashEntry** list = static_cast<HashEntry**>(Malloc(malloc)(sizeof(void*) * g_hash_table.count));
189
190 // Get the entries into an array to be sorted.
191 size_t index = 0;
192 for (size_t i = 0 ; i < HASHTABLE_SIZE ; ++i) {
193 HashEntry* entry = g_hash_table.slots[i];
194 while (entry != NULL) {
195 list[index] = entry;
196 *totalMemory = *totalMemory + ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations);
197 index++;
198 entry = entry->next;
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800199 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700200 }
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800201
Christopher Ferrisa4037802014-06-09 19:14:11 -0700202 // XXX: the protocol doesn't allow variable size for the stack trace (yet)
203 *infoSize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * BACKTRACE_SIZE);
204 *overallSize = *infoSize * g_hash_table.count;
205 *backtraceSize = BACKTRACE_SIZE;
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800206
Christopher Ferrisa4037802014-06-09 19:14:11 -0700207 // now get a byte array big enough for this
208 *info = static_cast<uint8_t*>(Malloc(malloc)(*overallSize));
209 if (*info == NULL) {
210 *overallSize = 0;
Christopher Ferris72bbd422014-05-08 11:14:03 -0700211 Malloc(free)(list);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700212 return;
213 }
214
215 qsort(list, g_hash_table.count, sizeof(void*), hash_entry_compare);
216
217 uint8_t* head = *info;
218 const size_t count = g_hash_table.count;
219 for (size_t i = 0 ; i < count ; ++i) {
220 HashEntry* entry = list[i];
221 size_t entrySize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * entry->numEntries);
222 if (entrySize < *infoSize) {
223 // We're writing less than a full entry, clear out the rest.
224 memset(head + entrySize, 0, *infoSize - entrySize);
225 } else {
226 // Make sure the amount we're copying doesn't exceed the limit.
227 entrySize = *infoSize;
228 }
229 memcpy(head, &(entry->size), entrySize);
230 head += *infoSize;
231 }
232
233 Malloc(free)(list);
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800234}
235
Elliott Hughes7c9923d2014-05-16 16:29:55 -0700236extern "C" void free_malloc_leak_info(uint8_t* info) {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700237 Malloc(free)(info);
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800238}
239
Christopher Ferrisa4037802014-06-09 19:14:11 -0700240// =============================================================================
241// Allocation functions
242// =============================================================================
243extern "C" void* calloc(size_t n_elements, size_t elem_size) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700244 auto _calloc = __libc_globals->malloc_dispatch.calloc;
245 if (__predict_false(_calloc != nullptr)) {
246 return _calloc(n_elements, elem_size);
247 }
248 return Malloc(calloc)(n_elements, elem_size);
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800249}
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700250
251extern "C" void free(void* mem) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700252 auto _free = __libc_globals->malloc_dispatch.free;
253 if (__predict_false(_free != nullptr)) {
254 _free(mem);
255 } else {
256 Malloc(free)(mem);
257 }
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800258}
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700259
Christopher Ferrisa4037802014-06-09 19:14:11 -0700260extern "C" struct mallinfo mallinfo() {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700261 auto _mallinfo = __libc_globals->malloc_dispatch.mallinfo;
262 if (__predict_false(_mallinfo != nullptr)) {
263 return _mallinfo();
264 }
265 return Malloc(mallinfo)();
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800266}
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700267
Christopher Ferrisa4037802014-06-09 19:14:11 -0700268extern "C" void* malloc(size_t bytes) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700269 auto _malloc = __libc_globals->malloc_dispatch.malloc;
270 if (__predict_false(_malloc != nullptr)) {
271 return _malloc(bytes);
272 }
273 return Malloc(malloc)(bytes);
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800274}
275
Christopher Ferris885f3b92013-05-21 17:48:01 -0700276extern "C" size_t malloc_usable_size(const void* mem) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700277 auto _malloc_usable_size = __libc_globals->malloc_dispatch.malloc_usable_size;
278 if (__predict_false(_malloc_usable_size != nullptr)) {
279 return _malloc_usable_size(mem);
280 }
281 return Malloc(malloc_usable_size)(mem);
Christopher Ferris885f3b92013-05-21 17:48:01 -0700282}
283
Christopher Ferrisa4037802014-06-09 19:14:11 -0700284extern "C" void* memalign(size_t alignment, size_t bytes) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700285 auto _memalign = __libc_globals->malloc_dispatch.memalign;
286 if (__predict_false(_memalign != nullptr)) {
287 return _memalign(alignment, bytes);
288 }
289 return Malloc(memalign)(alignment, bytes);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700290}
291
292extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700293 auto _posix_memalign = __libc_globals->malloc_dispatch.posix_memalign;
294 if (__predict_false(_posix_memalign != nullptr)) {
295 return _posix_memalign(memptr, alignment, size);
296 }
297 return Malloc(posix_memalign)(memptr, alignment, size);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700298}
299
Dan Alberte5fdaa42014-06-14 01:04:31 +0000300#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
Christopher Ferrisa4037802014-06-09 19:14:11 -0700301extern "C" void* pvalloc(size_t bytes) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700302 auto _pvalloc = __libc_globals->malloc_dispatch.pvalloc;
303 if (__predict_false(_pvalloc != nullptr)) {
304 return _pvalloc(bytes);
305 }
306 return Malloc(pvalloc)(bytes);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700307}
Dan Alberte5fdaa42014-06-14 01:04:31 +0000308#endif
Christopher Ferrisa4037802014-06-09 19:14:11 -0700309
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700310extern "C" void* realloc(void* old_mem, size_t bytes) {
311 auto _realloc = __libc_globals->malloc_dispatch.realloc;
312 if (__predict_false(_realloc != nullptr)) {
313 return _realloc(old_mem, bytes);
314 }
315 return Malloc(realloc)(old_mem, bytes);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700316}
317
Dan Alberte5fdaa42014-06-14 01:04:31 +0000318#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
Christopher Ferrisa4037802014-06-09 19:14:11 -0700319extern "C" void* valloc(size_t bytes) {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700320 auto _valloc = __libc_globals->malloc_dispatch.valloc;
321 if (__predict_false(_valloc != nullptr)) {
322 return _valloc(bytes);
323 }
324 return Malloc(valloc)(bytes);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700325}
Dan Alberte5fdaa42014-06-14 01:04:31 +0000326#endif
Christopher Ferrisa4037802014-06-09 19:14:11 -0700327
328// We implement malloc debugging only in libc.so, so the code below
329// must be excluded if we compile this file for static libc.a
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800330#ifndef LIBC_STATIC
331#include <sys/system_properties.h>
332#include <dlfcn.h>
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700333#include <stdio.h>
Elliott Hugheseb847bc2013-10-09 15:50:50 -0700334#include "private/libc_logging.h"
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800335
Christopher Ferris885f3b92013-05-21 17:48:01 -0700336template<typename FunctionType>
Nick Kralevich35c18622013-10-03 14:59:05 -0700337static void InitMallocFunction(void* malloc_impl_handler, FunctionType* func, const char* prefix, const char* suffix) {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700338 char symbol[128];
339 snprintf(symbol, sizeof(symbol), "%s_%s", prefix, suffix);
340 *func = reinterpret_cast<FunctionType>(dlsym(malloc_impl_handler, symbol));
341 if (*func == NULL) {
342 error_log("%s: dlsym(\"%s\") failed", getprogname(), symbol);
343 }
Christopher Ferris885f3b92013-05-21 17:48:01 -0700344}
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700345
Christopher Ferris885f3b92013-05-21 17:48:01 -0700346static void InitMalloc(void* malloc_impl_handler, MallocDebug* table, const char* prefix) {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700347 __libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
348 getprogname(), g_malloc_debug_level, prefix);
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700349
Christopher Ferrisa4037802014-06-09 19:14:11 -0700350 InitMallocFunction<MallocDebugCalloc>(malloc_impl_handler, &table->calloc, prefix, "calloc");
351 InitMallocFunction<MallocDebugFree>(malloc_impl_handler, &table->free, prefix, "free");
352 InitMallocFunction<MallocDebugMallinfo>(malloc_impl_handler, &table->mallinfo, prefix, "mallinfo");
353 InitMallocFunction<MallocDebugMalloc>(malloc_impl_handler, &table->malloc, prefix, "malloc");
354 InitMallocFunction<MallocDebugMallocUsableSize>(malloc_impl_handler, &table->malloc_usable_size, prefix, "malloc_usable_size");
355 InitMallocFunction<MallocDebugMemalign>(malloc_impl_handler, &table->memalign, prefix, "memalign");
356 InitMallocFunction<MallocDebugPosixMemalign>(malloc_impl_handler, &table->posix_memalign, prefix, "posix_memalign");
Dan Alberte5fdaa42014-06-14 01:04:31 +0000357#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
Christopher Ferrisa4037802014-06-09 19:14:11 -0700358 InitMallocFunction<MallocDebugPvalloc>(malloc_impl_handler, &table->pvalloc, prefix, "pvalloc");
Dan Alberte5fdaa42014-06-14 01:04:31 +0000359#endif
Christopher Ferrisa4037802014-06-09 19:14:11 -0700360 InitMallocFunction<MallocDebugRealloc>(malloc_impl_handler, &table->realloc, prefix, "realloc");
Dan Alberte5fdaa42014-06-14 01:04:31 +0000361#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
Christopher Ferrisa4037802014-06-09 19:14:11 -0700362 InitMallocFunction<MallocDebugValloc>(malloc_impl_handler, &table->valloc, prefix, "valloc");
Dan Alberte5fdaa42014-06-14 01:04:31 +0000363#endif
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700364}
365
Christopher Ferrisa4037802014-06-09 19:14:11 -0700366// Initializes memory allocation framework once per process.
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700367static void malloc_init_impl(libc_globals* globals) {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700368 const char* so_name = NULL;
369 MallocDebugInit malloc_debug_initialize = NULL;
370 unsigned int qemu_running = 0;
371 unsigned int memcheck_enabled = 0;
372 char env[PROP_VALUE_MAX];
373 char memcheck_tracing[PROP_VALUE_MAX];
374 char debug_program[PROP_VALUE_MAX];
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800375
Christopher Ferrisa4037802014-06-09 19:14:11 -0700376 // Get custom malloc debug level. Note that emulator started with
377 // memory checking option will have priority over debug level set in
378 // libc.debug.malloc system property.
379 if (__system_property_get("ro.kernel.qemu", env) && atoi(env)) {
380 qemu_running = 1;
381 if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) {
382 if (memcheck_tracing[0] != '0') {
383 // Emulator has started with memory tracing enabled. Enforce it.
384 g_malloc_debug_level = 20;
385 memcheck_enabled = 1;
386 }
Vladimir Chtchetkine75fba682010-02-12 08:59:58 -0800387 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700388 }
Vladimir Chtchetkine75fba682010-02-12 08:59:58 -0800389
Christopher Ferrisa4037802014-06-09 19:14:11 -0700390 // If debug level has not been set by memcheck option in the emulator,
391 // lets grab it from libc.debug.malloc system property.
392 if (g_malloc_debug_level == 0 && __system_property_get("libc.debug.malloc", env)) {
393 g_malloc_debug_level = atoi(env);
394 }
395
396 // Debug level 0 means that we should use default allocation routines.
397 if (g_malloc_debug_level == 0) {
398 return;
399 }
400
401 // If libc.debug.malloc.program is set and is not a substring of progname,
402 // then exit.
403 if (__system_property_get("libc.debug.malloc.program", debug_program)) {
404 if (!strstr(getprogname(), debug_program)) {
405 return;
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800406 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700407 }
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800408
Christopher Ferrisa4037802014-06-09 19:14:11 -0700409 // mksh is way too leaky. http://b/7291287.
410 if (g_malloc_debug_level >= 10) {
411 if (strcmp(getprogname(), "sh") == 0 || strcmp(getprogname(), "/system/bin/sh") == 0) {
412 return;
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800413 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700414 }
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800415
Christopher Ferrisa4037802014-06-09 19:14:11 -0700416 // Choose the appropriate .so for the requested debug level.
417 switch (g_malloc_debug_level) {
418 case 1:
419 case 5:
420 case 10:
421 so_name = "libc_malloc_debug_leak.so";
422 break;
423 case 20:
424 // Quick check: debug level 20 can only be handled in emulator.
425 if (!qemu_running) {
426 error_log("%s: Debug level %d can only be set in emulator\n",
Elliott Hughes8e52e8f2014-06-04 12:07:11 -0700427 getprogname(), g_malloc_debug_level);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700428 return;
429 }
430 // Make sure that memory checking has been enabled in emulator.
431 if (!memcheck_enabled) {
432 error_log("%s: Memory checking is not enabled in the emulator\n", getprogname());
433 return;
434 }
435 so_name = "libc_malloc_debug_qemu.so";
436 break;
437 default:
438 error_log("%s: Debug level %d is unknown\n", getprogname(), g_malloc_debug_level);
439 return;
440 }
441
442 // Load .so that implements the required malloc debugging functionality.
Dmitriy Ivanov84c10c22015-03-23 14:58:45 -0700443 void* malloc_impl_handle = dlopen(so_name, RTLD_NOW);
Christopher Ferrisa4037802014-06-09 19:14:11 -0700444 if (malloc_impl_handle == NULL) {
445 error_log("%s: Missing module %s required for malloc debug level %d: %s",
446 getprogname(), so_name, g_malloc_debug_level, dlerror());
447 return;
448 }
449
450 // Initialize malloc debugging in the loaded module.
451 malloc_debug_initialize = reinterpret_cast<MallocDebugInit>(dlsym(malloc_impl_handle,
452 "malloc_debug_initialize"));
453 if (malloc_debug_initialize == NULL) {
454 error_log("%s: Initialization routine is not found in %s\n", getprogname(), so_name);
455 dlclose(malloc_impl_handle);
456 return;
457 }
Christopher Ferrisdda1c6c2014-07-09 17:16:07 -0700458 if (!malloc_debug_initialize(&g_hash_table, &__libc_malloc_default_dispatch)) {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700459 dlclose(malloc_impl_handle);
460 return;
461 }
462
463 if (g_malloc_debug_level == 20) {
464 // For memory checker we need to do extra initialization.
465 typedef int (*MemCheckInit)(int, const char*);
466 MemCheckInit memcheck_initialize =
467 reinterpret_cast<MemCheckInit>(dlsym(malloc_impl_handle, "memcheck_initialize"));
468 if (memcheck_initialize == NULL) {
469 error_log("%s: memcheck_initialize routine is not found in %s\n",
470 getprogname(), so_name);
471 dlclose(malloc_impl_handle);
472 return;
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800473 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700474
475 if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) {
476 dlclose(malloc_impl_handle);
477 return;
478 }
479 }
480
481 // No need to init the dispatch table because we can only get
482 // here if debug level is 1, 5, 10, or 20.
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700483 MallocDebug malloc_dispatch_table;
Christopher Ferrisa4037802014-06-09 19:14:11 -0700484 switch (g_malloc_debug_level) {
485 case 1:
486 InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "leak");
487 break;
488 case 5:
489 InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "fill");
490 break;
491 case 10:
492 InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "chk");
493 break;
494 case 20:
495 InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "qemu_instrumented");
496 break;
497 default:
498 break;
499 }
500
501 // Make sure dispatch table is initialized
502 if ((malloc_dispatch_table.calloc == NULL) ||
503 (malloc_dispatch_table.free == NULL) ||
504 (malloc_dispatch_table.mallinfo == NULL) ||
505 (malloc_dispatch_table.malloc == NULL) ||
506 (malloc_dispatch_table.malloc_usable_size == NULL) ||
507 (malloc_dispatch_table.memalign == NULL) ||
508 (malloc_dispatch_table.posix_memalign == NULL) ||
Dan Alberte5fdaa42014-06-14 01:04:31 +0000509#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
Christopher Ferrisa4037802014-06-09 19:14:11 -0700510 (malloc_dispatch_table.pvalloc == NULL) ||
Dan Alberte5fdaa42014-06-14 01:04:31 +0000511#endif
512 (malloc_dispatch_table.realloc == NULL)
513#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
514 || (malloc_dispatch_table.valloc == NULL)
515#endif
516 ) {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700517 error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)",
518 getprogname(), g_malloc_debug_level);
519 dlclose(malloc_impl_handle);
520 } else {
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700521 globals->malloc_dispatch = malloc_dispatch_table;
Christopher Ferrisa4037802014-06-09 19:14:11 -0700522 libc_malloc_impl_handle = malloc_impl_handle;
523 }
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800524}
525
Elliott Hughesc4d1fec2012-08-28 14:15:04 -0700526static void malloc_fini_impl() {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700527 if (libc_malloc_impl_handle != NULL) {
528 MallocDebugFini malloc_debug_finalize =
529 reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle, "malloc_debug_finalize"));
530 if (malloc_debug_finalize != NULL) {
Christopher Ferrisefc134d2015-09-03 15:01:59 -0700531 // Our BSD stdio implementation doesn't close the standard streams,
532 // it only flushes them. And it doesn't do that until its atexit
533 // handler is run, and we run first! It's great that other unclosed
534 // FILE*s show up as malloc leaks, but we need to manually clean up
535 // the standard streams ourselves.
536 fclose(stdin);
537 fclose(stdout);
538 fclose(stderr);
539
Christopher Ferrisa4037802014-06-09 19:14:11 -0700540 malloc_debug_finalize(g_malloc_debug_level);
Iliyan Malcheve1dd3c22012-05-29 14:22:42 -0700541 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700542 }
Iliyan Malcheve1dd3c22012-05-29 14:22:42 -0700543}
544
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800545#endif // !LIBC_STATIC
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800546
Christopher Ferrisa4037802014-06-09 19:14:11 -0700547// Initializes memory allocation framework.
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700548// This routine is called from __libc_init routines in libc_init_dynamic.cpp.
549__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) {
550 (void)globals;
Christopher Ferrisa4037802014-06-09 19:14:11 -0700551#if !defined(LIBC_STATIC)
Josh Gao3c8fc2f2015-10-08 14:49:26 -0700552 malloc_init_impl(globals);
553#endif
Vladimir Chtchetkineb74ceb22009-11-17 14:13:38 -0800554}
Iliyan Malcheve1dd3c22012-05-29 14:22:42 -0700555
Kito Chengea489742013-04-12 16:13:34 +0800556extern "C" __LIBC_HIDDEN__ void malloc_debug_fini() {
Christopher Ferrisa4037802014-06-09 19:14:11 -0700557#if !defined(LIBC_STATIC)
Elliott Hughes8e52e8f2014-06-04 12:07:11 -0700558 static pthread_once_t malloc_fini_once_ctl = PTHREAD_ONCE_INIT;
559 if (pthread_once(&malloc_fini_once_ctl, malloc_fini_impl)) {
560 error_log("Unable to finalize malloc_debug component.");
561 }
Christopher Ferrisa4037802014-06-09 19:14:11 -0700562#endif // !LIBC_STATIC
Iliyan Malcheve1dd3c22012-05-29 14:22:42 -0700563}