aboutsummaryrefslogtreecommitdiffstats
path: root/libc/bionic/malloc_debug_check.cpp
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2013-01-17 18:36:06 -0800
committerElliott Hughes <enh@google.com>2013-01-18 22:20:06 -0800
commit1e980b6bc8315d00a07312b25486531247abd98c (patch)
tree539f2c0c63fca27d5eb6ba184d658bb0e11a32d9 /libc/bionic/malloc_debug_check.cpp
parente4ca88d9fa8757e4fb4056fcafa5bc15b406a2fd (diff)
downloadandroid_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.cpp94
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);
}