diff options
author | Elliott Hughes <enh@google.com> | 2013-01-17 18:36:06 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2013-01-18 22:20:06 -0800 |
commit | 1e980b6bc8315d00a07312b25486531247abd98c (patch) | |
tree | 539f2c0c63fca27d5eb6ba184d658bb0e11a32d9 /libc/bionic/malloc_debug_check.cpp | |
parent | e4ca88d9fa8757e4fb4056fcafa5bc15b406a2fd (diff) | |
download | android_bionic-1e980b6bc8315d00a07312b25486531247abd98c.tar.gz android_bionic-1e980b6bc8315d00a07312b25486531247abd98c.tar.bz2 android_bionic-1e980b6bc8315d00a07312b25486531247abd98c.zip |
Fix the duplication in the debugging code.
We had two copies of the backtrace code, and two copies of the
libcorkscrew /proc/pid/maps code. This patch gets us down to one.
We also had hacks so we could log in the malloc debugging code.
This patch pulls the non-allocating "printf" code out of the
dynamic linker so everyone can share.
This patch also makes the leak diagnostics easier to read, and
makes it possible to paste them directly into the 'stack' tool (by
using relative PCs).
This patch also fixes the stdio standard stream leak that was
causing a leak warning every time tf_daemon ran.
Bug: 7291287
Change-Id: I66e4083ac2c5606c8d2737cb45c8ac8a32c7cfe8
Diffstat (limited to 'libc/bionic/malloc_debug_check.cpp')
-rw-r--r-- | libc/bionic/malloc_debug_check.cpp | 94 |
1 files changed, 31 insertions, 63 deletions
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp index 5ad3486f3..60ee0cc20 100644 --- a/libc/bionic/malloc_debug_check.cpp +++ b/libc/bionic/malloc_debug_check.cpp @@ -45,18 +45,19 @@ #include <unistd.h> #include <unwind.h> +#include "debug_mapinfo.h" +#include "debug_stacktrace.h" #include "dlmalloc.h" #include "logd.h" -#include "malloc_debug_check_mapinfo.h" #include "malloc_debug_common.h" #include "ScopedPthreadMutexLocker.h" -static mapinfo *milist; +static mapinfo_t* gMapInfo; /* libc.debug.malloc.backlog */ extern unsigned int malloc_double_free_backlog; -#define MAX_BACKTRACE_DEPTH 15 +#define MAX_BACKTRACE_DEPTH 16 #define ALLOCATION_TAG 0x1ee7d00d #define BACKLOG_TAG 0xbabecafe #define FREE_POISON 0xa5 @@ -67,20 +68,10 @@ extern unsigned int malloc_double_free_backlog; #define REAR_GUARD_LEN (1<<5) static void log_message(const char* format, ...) { - extern const MallocDebug __libc_malloc_default_dispatch; - extern const MallocDebug* __libc_malloc_dispatch; - extern pthread_mutex_t gAllocationsMutex; - - va_list args; - { - ScopedPthreadMutexLocker locker(&gAllocationsMutex); - const MallocDebug* current_dispatch = __libc_malloc_dispatch; - __libc_malloc_dispatch = &__libc_malloc_default_dispatch; - va_start(args, format); - __libc_android_log_vprint(ANDROID_LOG_ERROR, "libc", format, args); - va_end(args); - __libc_malloc_dispatch = current_dispatch; - } + va_list args; + va_start(args, format); + __libc_format_log_va_list(ANDROID_LOG_ERROR, "libc", format, args); + va_end(args); } struct hdr_t { @@ -121,28 +112,6 @@ static hdr_t *backlog_tail; static hdr_t *backlog_head; static pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER; -extern __LIBC_HIDDEN__ int get_backtrace(intptr_t* addrs, size_t max_entries); - -static void print_backtrace(const intptr_t *bt, unsigned int depth) { - const mapinfo *mi; - unsigned int cnt; - unsigned int rel_pc; - intptr_t self_bt[MAX_BACKTRACE_DEPTH]; - - if (!bt) { - depth = get_backtrace(self_bt, MAX_BACKTRACE_DEPTH); - bt = self_bt; - } - - log_message("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); - for (cnt = 0; cnt < depth && cnt < MAX_BACKTRACE_DEPTH; cnt++) { - mi = pc_to_mapinfo(milist, bt[cnt], &rel_pc); - log_message("\t#%02d pc %08x %s\n", cnt, - mi ? (intptr_t)rel_pc : bt[cnt], - mi ? mi->name : "(unknown)"); - } -} - static inline void init_front_guard(hdr_t *hdr) { memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN); } @@ -292,11 +261,11 @@ static inline int check_allocation_locked(hdr_t *hdr, int *safe) { if (!valid && *safe) { log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->bt, hdr->bt_depth); + log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth); if (hdr->tag == BACKLOG_TAG) { log_message("+++ ALLOCATION %p SIZE %d FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth); } } @@ -381,18 +350,18 @@ extern "C" void chk_free(void *ptr) { user(hdr), hdr->size); log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->bt, hdr->bt_depth); + log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth); /* hdr->freed_bt_depth should be nonzero here */ log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth); log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); } else { log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", user(hdr)); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); /* Leak here so that we do not crash */ //dlfree(user(hdr)); } @@ -428,14 +397,14 @@ extern "C" void *chk_realloc(void *ptr, size_t size) { user(hdr), size, hdr->size); log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->bt, hdr->bt_depth); + log_backtrace(gMapInfo, hdr->bt, hdr->bt_depth); /* hdr->freed_bt_depth should be nonzero here */ log_message("+++ ALLOCATION %p SIZE %d FIRST FREED HERE:\n", user(hdr), hdr->size); - print_backtrace(hdr->freed_bt, hdr->freed_bt_depth); + log_backtrace(gMapInfo, hdr->freed_bt, hdr->freed_bt_depth); log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n", user(hdr), hdr->size); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); /* We take the memory out of the backlog and fall through so the * reallocation below succeeds. Since we didn't really free it, we @@ -445,7 +414,7 @@ extern "C" void *chk_realloc(void *ptr, size_t size) { } else { log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n", user(hdr), size); - print_backtrace(bt, depth); + log_backtrace(gMapInfo, bt, depth); // just get a whole new allocation and leak the old one return dlrealloc(0, size); // return dlrealloc(user(hdr), size); // assuming it was allocated externally @@ -467,8 +436,7 @@ extern "C" void *chk_calloc(int nmemb, size_t size) { size_t total_size = nmemb * size; hdr_t* hdr = static_cast<hdr_t*>(dlcalloc(1, sizeof(hdr_t) + total_size + sizeof(ftr_t))); if (hdr) { - hdr->bt_depth = get_backtrace( - hdr->bt, MAX_BACKTRACE_DEPTH); + hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH); add(hdr, total_size); return user(hdr); } @@ -476,21 +444,20 @@ extern "C" void *chk_calloc(int nmemb, size_t size) { } static void heaptracker_free_leaked_memory() { + size_t total = num; if (num) { - log_message("+++ THERE ARE %d LEAKED ALLOCATIONS\n", num); + log_message("+++ Leaked allocations: %d\n", num); } hdr_t *del = NULL; while (head) { int safe; del = head; - log_message("+++ DELETING %d BYTES OF LEAKED MEMORY AT %p (%d REMAINING)\n", - del->size, user(del), num); + log_message("+++ Leaked block of size %d at %p (leak %d of %d)\n", + del->size, user(del), 1 + total - num, total); if (del_leak(del, &safe)) { /* safe == 1, because the allocation is valid */ - log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n", - user(del), del->size); - print_backtrace(del->bt, del->bt_depth); + log_backtrace(gMapInfo, del->bt, del->bt_depth); } dlfree(del); } @@ -507,13 +474,14 @@ static void heaptracker_free_leaked_memory() { * See comments on MallocDebugInit in malloc_debug_common.h */ extern "C" int malloc_debug_initialize() { - if (!malloc_double_free_backlog) - malloc_double_free_backlog = BACKLOG_DEFAULT_LEN; - milist = init_mapinfo(getpid()); - return 0; + if (!malloc_double_free_backlog) { + malloc_double_free_backlog = BACKLOG_DEFAULT_LEN; + } + gMapInfo = mapinfo_create(getpid()); + return 0; } extern "C" void malloc_debug_finalize() { - heaptracker_free_leaked_memory(); - deinit_mapinfo(milist); + heaptracker_free_leaked_memory(); + mapinfo_destroy(gMapInfo); } |