From 2fc7f9db3df70b33e1cdf6faa445ec57e81b05df Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 27 Jan 2016 10:58:36 -0800 Subject: [PATCH] Remove unused file. This file should have been deleted with the malloc debug rewrite, but popped back into existence due to a merge conflict. Change-Id: I74e53daaf3febf650b20e3da5329558ac84c5bcd --- libc/bionic/malloc_debug_common.cpp | 556 ---------------------------- 1 file changed, 556 deletions(-) delete mode 100644 libc/bionic/malloc_debug_common.cpp diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp deleted file mode 100644 index 66505bf73..000000000 --- a/libc/bionic/malloc_debug_common.cpp +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS - * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT - * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -// Contains definition of structures, global variables, and implementation of -// routines that are used by malloc leak detection code and other components in -// the system. The trick is that some components expect these data and -// routines to be defined / implemented in libc.so, regardless whether or not -// malloc leak detection code is going to run. To make things even more tricky, -// malloc leak detection code, implemented in libc_malloc_debug.so also -// requires access to these variables and routines (to fill allocation entry -// hash table, for example). So, all relevant variables and routines are -// defined / implemented here and exported to all, leak detection code and -// other components via dynamic (libc.so), or static (libc.a) linking. - -#include "malloc_debug_common.h" - -#include -#include -#include -#include - -#include "private/bionic_globals.h" -#include "private/ScopedPthreadMutexLocker.h" - -#include "jemalloc.h" -#define Malloc(function) je_ ## function - -static constexpr MallocDebug __libc_malloc_default_dispatch - __attribute__((unused)) = { - Malloc(calloc), - Malloc(free), - Malloc(mallinfo), - Malloc(malloc), - Malloc(malloc_usable_size), - Malloc(memalign), - Malloc(posix_memalign), -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) - Malloc(pvalloc), -#endif - Malloc(realloc), -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) - Malloc(valloc), -#endif - }; - -// In a VM process, this is set to 1 after fork()ing out of zygote. -int gMallocLeakZygoteChild = 0; - -static HashTable g_hash_table; - -// Handle to shared library where actual memory allocation is implemented. -// This library is loaded and memory allocation calls are redirected there -// when libc.debug.malloc environment variable contains value other than -// zero: -// 1 - For memory leak detections. -// 5 - For filling allocated / freed memory with patterns defined by -// CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros. -// 10 - For adding pre-, and post- allocation stubs in order to detect -// buffer overruns. -// Note that emulator's memory allocation instrumentation is not controlled by -// libc.debug.malloc value, but rather by emulator, started with -memcheck -// option. Note also, that if emulator has started with -memcheck option, -// emulator's instrumented memory allocation will take over value saved in -// libc.debug.malloc. In other words, if emulator has started with -memcheck -// option, libc.debug.malloc value is ignored. -// Actual functionality for debug levels 1-10 is implemented in -// libc_malloc_debug_leak.so, while functionality for emulator's instrumented -// allocations is implemented in libc_malloc_debug_qemu.so and can be run inside -// the emulator only. -#if !defined(LIBC_STATIC) -static void* libc_malloc_impl_handle = NULL; -#endif - - -// The value of libc.debug.malloc. -#if !defined(LIBC_STATIC) -static int g_malloc_debug_level = 0; -#endif - -// ============================================================================= -// output functions -// ============================================================================= - -static int hash_entry_compare(const void* arg1, const void* arg2) { - int result; - - const HashEntry* e1 = *static_cast(arg1); - const HashEntry* e2 = *static_cast(arg2); - - // if one or both arg pointers are null, deal gracefully - if (e1 == NULL) { - result = (e2 == NULL) ? 0 : 1; - } else if (e2 == NULL) { - result = -1; - } else { - size_t nbAlloc1 = e1->allocations; - size_t nbAlloc2 = e2->allocations; - size_t size1 = e1->size & ~SIZE_FLAG_MASK; - size_t size2 = e2->size & ~SIZE_FLAG_MASK; - size_t alloc1 = nbAlloc1 * size1; - size_t alloc2 = nbAlloc2 * size2; - - // sort in descending order by: - // 1) total size - // 2) number of allocations - // - // This is used for sorting, not determination of equality, so we don't - // need to compare the bit flags. - if (alloc1 > alloc2) { - result = -1; - } else if (alloc1 < alloc2) { - result = 1; - } else { - if (nbAlloc1 > nbAlloc2) { - result = -1; - } else if (nbAlloc1 < nbAlloc2) { - result = 1; - } else { - result = 0; - } - } - } - return result; -} - -// Retrieve native heap information. -// -// "*info" is set to a buffer we allocate -// "*overallSize" is set to the size of the "info" buffer -// "*infoSize" is set to the size of a single entry -// "*totalMemory" is set to the sum of all allocations we're tracking; does -// not include heap overhead -// "*backtraceSize" is set to the maximum number of entries in the back trace - -// ============================================================================= -// Exported for use by ddms. -// ============================================================================= -extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize, - size_t* infoSize, size_t* totalMemory, size_t* backtraceSize) { - // Don't do anything if we have invalid arguments. - if (info == NULL || overallSize == NULL || infoSize == NULL || - totalMemory == NULL || backtraceSize == NULL) { - return; - } - *totalMemory = 0; - - ScopedPthreadMutexLocker locker(&g_hash_table.lock); - if (g_hash_table.count == 0) { - *info = NULL; - *overallSize = 0; - *infoSize = 0; - *backtraceSize = 0; - return; - } - - HashEntry** list = static_cast(Malloc(malloc)(sizeof(void*) * g_hash_table.count)); - - // Get the entries into an array to be sorted. - size_t index = 0; - for (size_t i = 0 ; i < HASHTABLE_SIZE ; ++i) { - HashEntry* entry = g_hash_table.slots[i]; - while (entry != NULL) { - list[index] = entry; - *totalMemory = *totalMemory + ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations); - index++; - entry = entry->next; - } - } - - // XXX: the protocol doesn't allow variable size for the stack trace (yet) - *infoSize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * BACKTRACE_SIZE); - *overallSize = *infoSize * g_hash_table.count; - *backtraceSize = BACKTRACE_SIZE; - - // now get a byte array big enough for this - *info = static_cast(Malloc(malloc)(*overallSize)); - if (*info == NULL) { - *overallSize = 0; - Malloc(free)(list); - return; - } - - qsort(list, g_hash_table.count, sizeof(void*), hash_entry_compare); - - uint8_t* head = *info; - const size_t count = g_hash_table.count; - for (size_t i = 0 ; i < count ; ++i) { - HashEntry* entry = list[i]; - size_t entrySize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * entry->numEntries); - if (entrySize < *infoSize) { - // We're writing less than a full entry, clear out the rest. - memset(head + entrySize, 0, *infoSize - entrySize); - } else { - // Make sure the amount we're copying doesn't exceed the limit. - entrySize = *infoSize; - } - memcpy(head, &(entry->size), entrySize); - head += *infoSize; - } - - Malloc(free)(list); -} - -extern "C" void free_malloc_leak_info(uint8_t* info) { - Malloc(free)(info); -} - -// ============================================================================= -// Allocation functions -// ============================================================================= -extern "C" void* calloc(size_t n_elements, size_t elem_size) { - auto _calloc = __libc_globals->malloc_dispatch.calloc; - if (__predict_false(_calloc != nullptr)) { - return _calloc(n_elements, elem_size); - } - return Malloc(calloc)(n_elements, elem_size); -} - -extern "C" void free(void* mem) { - auto _free = __libc_globals->malloc_dispatch.free; - if (__predict_false(_free != nullptr)) { - _free(mem); - } else { - Malloc(free)(mem); - } -} - -extern "C" struct mallinfo mallinfo() { - auto _mallinfo = __libc_globals->malloc_dispatch.mallinfo; - if (__predict_false(_mallinfo != nullptr)) { - return _mallinfo(); - } - return Malloc(mallinfo)(); -} - -extern "C" void* malloc(size_t bytes) { - auto _malloc = __libc_globals->malloc_dispatch.malloc; - if (__predict_false(_malloc != nullptr)) { - return _malloc(bytes); - } - return Malloc(malloc)(bytes); -} - -extern "C" size_t malloc_usable_size(const void* mem) { - auto _malloc_usable_size = __libc_globals->malloc_dispatch.malloc_usable_size; - if (__predict_false(_malloc_usable_size != nullptr)) { - return _malloc_usable_size(mem); - } - return Malloc(malloc_usable_size)(mem); -} - -extern "C" void* memalign(size_t alignment, size_t bytes) { - auto _memalign = __libc_globals->malloc_dispatch.memalign; - if (__predict_false(_memalign != nullptr)) { - return _memalign(alignment, bytes); - } - return Malloc(memalign)(alignment, bytes); -} - -extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) { - auto _posix_memalign = __libc_globals->malloc_dispatch.posix_memalign; - if (__predict_false(_posix_memalign != nullptr)) { - return _posix_memalign(memptr, alignment, size); - } - return Malloc(posix_memalign)(memptr, alignment, size); -} - -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) -extern "C" void* pvalloc(size_t bytes) { - auto _pvalloc = __libc_globals->malloc_dispatch.pvalloc; - if (__predict_false(_pvalloc != nullptr)) { - return _pvalloc(bytes); - } - return Malloc(pvalloc)(bytes); -} -#endif - -extern "C" void* realloc(void* old_mem, size_t bytes) { - auto _realloc = __libc_globals->malloc_dispatch.realloc; - if (__predict_false(_realloc != nullptr)) { - return _realloc(old_mem, bytes); - } - return Malloc(realloc)(old_mem, bytes); -} - -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) -extern "C" void* valloc(size_t bytes) { - auto _valloc = __libc_globals->malloc_dispatch.valloc; - if (__predict_false(_valloc != nullptr)) { - return _valloc(bytes); - } - return Malloc(valloc)(bytes); -} -#endif - -// We implement malloc debugging only in libc.so, so the code below -// must be excluded if we compile this file for static libc.a -#ifndef LIBC_STATIC -#include -#include -#include -#include "private/libc_logging.h" - -template -static void InitMallocFunction(void* malloc_impl_handler, FunctionType* func, const char* prefix, const char* suffix) { - char symbol[128]; - snprintf(symbol, sizeof(symbol), "%s_%s", prefix, suffix); - *func = reinterpret_cast(dlsym(malloc_impl_handler, symbol)); - if (*func == NULL) { - error_log("%s: dlsym(\"%s\") failed", getprogname(), symbol); - } -} - -static void InitMalloc(void* malloc_impl_handler, MallocDebug* table, const char* prefix) { - __libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n", - getprogname(), g_malloc_debug_level, prefix); - - InitMallocFunction(malloc_impl_handler, &table->calloc, prefix, "calloc"); - InitMallocFunction(malloc_impl_handler, &table->free, prefix, "free"); - InitMallocFunction(malloc_impl_handler, &table->mallinfo, prefix, "mallinfo"); - InitMallocFunction(malloc_impl_handler, &table->malloc, prefix, "malloc"); - InitMallocFunction(malloc_impl_handler, &table->malloc_usable_size, prefix, "malloc_usable_size"); - InitMallocFunction(malloc_impl_handler, &table->memalign, prefix, "memalign"); - InitMallocFunction(malloc_impl_handler, &table->posix_memalign, prefix, "posix_memalign"); -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) - InitMallocFunction(malloc_impl_handler, &table->pvalloc, prefix, "pvalloc"); -#endif - InitMallocFunction(malloc_impl_handler, &table->realloc, prefix, "realloc"); -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) - InitMallocFunction(malloc_impl_handler, &table->valloc, prefix, "valloc"); -#endif -} - -// Initializes memory allocation framework once per process. -static void malloc_init_impl(libc_globals* globals) { - const char* so_name = NULL; - MallocDebugInit malloc_debug_initialize = NULL; - unsigned int qemu_running = 0; - unsigned int memcheck_enabled = 0; - char env[PROP_VALUE_MAX]; - char memcheck_tracing[PROP_VALUE_MAX]; - char debug_program[PROP_VALUE_MAX]; - - // Get custom malloc debug level. Note that emulator started with - // memory checking option will have priority over debug level set in - // libc.debug.malloc system property. - if (__system_property_get("ro.kernel.qemu", env) && atoi(env)) { - qemu_running = 1; - if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) { - if (memcheck_tracing[0] != '0') { - // Emulator has started with memory tracing enabled. Enforce it. - g_malloc_debug_level = 20; - memcheck_enabled = 1; - } - } - } - - // If debug level has not been set by memcheck option in the emulator, - // lets grab it from libc.debug.malloc system property. - if (g_malloc_debug_level == 0 && __system_property_get("libc.debug.malloc", env)) { - g_malloc_debug_level = atoi(env); - } - - // Debug level 0 means that we should use default allocation routines. - if (g_malloc_debug_level == 0) { - return; - } - - // If libc.debug.malloc.program is set and is not a substring of progname, - // then exit. - if (__system_property_get("libc.debug.malloc.program", debug_program)) { - if (!strstr(getprogname(), debug_program)) { - return; - } - } - - // mksh is way too leaky. http://b/7291287. - if (g_malloc_debug_level >= 10) { - if (strcmp(getprogname(), "sh") == 0 || strcmp(getprogname(), "/system/bin/sh") == 0) { - return; - } - } - - // Choose the appropriate .so for the requested debug level. - switch (g_malloc_debug_level) { - case 1: - case 5: - case 10: - so_name = "libc_malloc_debug_leak.so"; - break; - case 20: - // Quick check: debug level 20 can only be handled in emulator. - if (!qemu_running) { - error_log("%s: Debug level %d can only be set in emulator\n", - getprogname(), g_malloc_debug_level); - return; - } - // Make sure that memory checking has been enabled in emulator. - if (!memcheck_enabled) { - error_log("%s: Memory checking is not enabled in the emulator\n", getprogname()); - return; - } - so_name = "libc_malloc_debug_qemu.so"; - break; - default: - error_log("%s: Debug level %d is unknown\n", getprogname(), g_malloc_debug_level); - return; - } - - // Load .so that implements the required malloc debugging functionality. - void* malloc_impl_handle = dlopen(so_name, RTLD_NOW); - if (malloc_impl_handle == NULL) { - error_log("%s: Missing module %s required for malloc debug level %d: %s", - getprogname(), so_name, g_malloc_debug_level, dlerror()); - return; - } - - // Initialize malloc debugging in the loaded module. - malloc_debug_initialize = reinterpret_cast(dlsym(malloc_impl_handle, - "malloc_debug_initialize")); - if (malloc_debug_initialize == NULL) { - error_log("%s: Initialization routine is not found in %s\n", getprogname(), so_name); - dlclose(malloc_impl_handle); - return; - } - if (!malloc_debug_initialize(&g_hash_table, &__libc_malloc_default_dispatch)) { - dlclose(malloc_impl_handle); - return; - } - - if (g_malloc_debug_level == 20) { - // For memory checker we need to do extra initialization. - typedef int (*MemCheckInit)(int, const char*); - MemCheckInit memcheck_initialize = - reinterpret_cast(dlsym(malloc_impl_handle, "memcheck_initialize")); - if (memcheck_initialize == NULL) { - error_log("%s: memcheck_initialize routine is not found in %s\n", - getprogname(), so_name); - dlclose(malloc_impl_handle); - return; - } - - if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) { - dlclose(malloc_impl_handle); - return; - } - } - - // No need to init the dispatch table because we can only get - // here if debug level is 1, 5, 10, or 20. - MallocDebug malloc_dispatch_table; - switch (g_malloc_debug_level) { - case 1: - InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "leak"); - break; - case 5: - InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "fill"); - break; - case 10: - InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "chk"); - break; - case 20: - InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "qemu_instrumented"); - break; - default: - break; - } - - // Make sure dispatch table is initialized - if ((malloc_dispatch_table.calloc == NULL) || - (malloc_dispatch_table.free == NULL) || - (malloc_dispatch_table.mallinfo == NULL) || - (malloc_dispatch_table.malloc == NULL) || - (malloc_dispatch_table.malloc_usable_size == NULL) || - (malloc_dispatch_table.memalign == NULL) || - (malloc_dispatch_table.posix_memalign == NULL) || -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) - (malloc_dispatch_table.pvalloc == NULL) || -#endif - (malloc_dispatch_table.realloc == NULL) -#if defined(HAVE_DEPRECATED_MALLOC_FUNCS) - || (malloc_dispatch_table.valloc == NULL) -#endif - ) { - error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)", - getprogname(), g_malloc_debug_level); - dlclose(malloc_impl_handle); - } else { - globals->malloc_dispatch = malloc_dispatch_table; - libc_malloc_impl_handle = malloc_impl_handle; - } -} - -static void malloc_fini_impl() { - if (libc_malloc_impl_handle != NULL) { - MallocDebugFini malloc_debug_finalize = - reinterpret_cast(dlsym(libc_malloc_impl_handle, "malloc_debug_finalize")); - if (malloc_debug_finalize != NULL) { - // Our BSD stdio implementation doesn't close the standard streams, - // it only flushes them. And it doesn't do that until its atexit - // handler is run, and we run first! It's great that other unclosed - // FILE*s show up as malloc leaks, but we need to manually clean up - // the standard streams ourselves. - fclose(stdin); - fclose(stdout); - fclose(stderr); - - malloc_debug_finalize(g_malloc_debug_level); - } - } -} - -#endif // !LIBC_STATIC - -// Initializes memory allocation framework. -// This routine is called from __libc_init routines in libc_init_dynamic.cpp. -__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals) { - (void)globals; -#if !defined(LIBC_STATIC) - malloc_init_impl(globals); -#endif -} - -extern "C" __LIBC_HIDDEN__ void malloc_debug_fini() { -#if !defined(LIBC_STATIC) - static pthread_once_t malloc_fini_once_ctl = PTHREAD_ONCE_INIT; - if (pthread_once(&malloc_fini_once_ctl, malloc_fini_impl)) { - error_log("Unable to finalize malloc_debug component."); - } -#endif // !LIBC_STATIC -}