Add a way to disable backtracing in malloc debug.
The property libc.debug.malloc.nobacktrace set to non-zero disables
getting backtracing when using mode 1 or mode 10.
Bug: 16874447
Change-Id: I7650ba9f4385b5110b743cab01e877fc69545b3c
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp
index 94ba6f5..dee03fa 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -48,6 +48,7 @@
#include "debug_mapinfo.h"
#include "debug_stacktrace.h"
+#include "malloc_debug_backtrace.h"
#include "malloc_debug_common.h"
#include "malloc_debug_disable.h"
#include "private/bionic_macros.h"
@@ -123,6 +124,10 @@
// It determines the size of the backlog we use to detect multiple frees.
static unsigned g_malloc_debug_backlog = 100;
+// This variable is set to false if the property libc.debug.malloc.nobacktrace
+// is set to non-zero.
+__LIBC_HIDDEN__ bool g_backtrace_enabled = true;
+
__LIBC_HIDDEN__ HashTable* g_hash_table;
__LIBC_HIDDEN__ const MallocDebug* g_malloc_dispatch;
@@ -273,7 +278,7 @@
valid = check_guards(hdr, safe);
}
- if (!valid && *safe) {
+ if (!valid && *safe && g_backtrace_enabled) {
log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
user(hdr), hdr->size);
log_backtrace(hdr->bt, hdr->bt_depth);
@@ -344,7 +349,7 @@
hdr_t* hdr = static_cast<hdr_t*>(g_malloc_dispatch->malloc(size));
if (hdr) {
hdr->base = hdr;
- hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
+ hdr->bt_depth = GET_BACKTRACE(hdr->bt, MAX_BACKTRACE_DEPTH);
add(hdr, bytes);
return user(hdr);
}
@@ -385,7 +390,7 @@
hdr_t* hdr = meta(reinterpret_cast<void*>(ptr));
hdr->base = base;
- hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
+ hdr->bt_depth = GET_BACKTRACE(hdr->bt, MAX_BACKTRACE_DEPTH);
add(hdr, bytes);
return user(hdr);
}
@@ -405,27 +410,31 @@
if (del(hdr) < 0) {
uintptr_t bt[MAX_BACKTRACE_DEPTH];
- int depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH);
+ int depth = GET_BACKTRACE(bt, MAX_BACKTRACE_DEPTH);
if (hdr->tag == BACKLOG_TAG) {
log_message("+++ ALLOCATION %p SIZE %d BYTES MULTIPLY FREED!\n",
user(hdr), hdr->size);
- log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
- user(hdr), hdr->size);
- log_backtrace(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);
- log_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
- log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n",
- user(hdr), hdr->size);
- log_backtrace(bt, depth);
+ if (g_backtrace_enabled) {
+ log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
+ user(hdr), hdr->size);
+ log_backtrace(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);
+ log_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+ log_message("+++ ALLOCATION %p SIZE %d NOW BEING FREED HERE:\n",
+ user(hdr), hdr->size);
+ log_backtrace(bt, depth);
+ }
} else {
log_message("+++ ALLOCATION %p IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
user(hdr));
- log_backtrace(bt, depth);
+ if (g_backtrace_enabled) {
+ log_backtrace(bt, depth);
+ }
}
} else {
- hdr->freed_bt_depth = get_backtrace(hdr->freed_bt, MAX_BACKTRACE_DEPTH);
+ hdr->freed_bt_depth = GET_BACKTRACE(hdr->freed_bt, MAX_BACKTRACE_DEPTH);
add_to_backlog(hdr);
}
}
@@ -451,22 +460,24 @@
if (del(hdr) < 0) {
uintptr_t bt[MAX_BACKTRACE_DEPTH];
- int depth = get_backtrace(bt, MAX_BACKTRACE_DEPTH);
+ int depth = GET_BACKTRACE(bt, MAX_BACKTRACE_DEPTH);
if (hdr->tag == BACKLOG_TAG) {
log_message("+++ REALLOCATION %p SIZE %d OF FREED MEMORY!\n",
user(hdr), bytes, hdr->size);
- log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
- user(hdr), hdr->size);
- log_backtrace(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);
- log_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
- log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n",
- user(hdr), hdr->size);
- log_backtrace(bt, depth);
+ if (g_backtrace_enabled) {
+ log_message("+++ ALLOCATION %p SIZE %d ALLOCATED HERE:\n",
+ user(hdr), hdr->size);
+ log_backtrace(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);
+ log_backtrace(hdr->freed_bt, hdr->freed_bt_depth);
+ log_message("+++ ALLOCATION %p SIZE %d NOW BEING REALLOCATED HERE:\n",
+ user(hdr), hdr->size);
+ log_backtrace(bt, depth);
+ }
- /* We take the memory out of the backlog and fall through so the
+ /* We take the memory out of the backlog and fall through so the
* reallocation below succeeds. Since we didn't really free it, we
* can default to this behavior.
*/
@@ -474,7 +485,9 @@
} else {
log_message("+++ REALLOCATION %p SIZE %d IS CORRUPTED OR NOT ALLOCATED VIA TRACKER!\n",
user(hdr), bytes);
- log_backtrace(bt, depth);
+ if (g_backtrace_enabled) {
+ log_backtrace(bt, depth);
+ }
// just get a whole new allocation and leak the old one
return g_malloc_dispatch->realloc(0, bytes);
// return realloc(user(hdr), bytes); // assuming it was allocated externally
@@ -501,7 +514,7 @@
}
if (hdr) {
hdr->base = hdr;
- hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
+ hdr->bt_depth = GET_BACKTRACE(hdr->bt, MAX_BACKTRACE_DEPTH);
add(hdr, bytes);
return user(hdr);
}
@@ -523,7 +536,7 @@
hdr_t* hdr = static_cast<hdr_t*>(g_malloc_dispatch->calloc(1, size));
if (hdr) {
hdr->base = hdr;
- hdr->bt_depth = get_backtrace(hdr->bt, MAX_BACKTRACE_DEPTH);
+ hdr->bt_depth = GET_BACKTRACE(hdr->bt, MAX_BACKTRACE_DEPTH);
add(hdr, total_bytes);
return user(hdr);
}
@@ -611,7 +624,7 @@
hdr_t* block = head;
log_message("+++ %s leaked block of size %d at %p (leak %d of %d)",
exe, block->size, user(block), index++, total);
- if (del_leak(block, &safe)) {
+ if (del_leak(block, &safe) && g_backtrace_enabled) {
/* safe == 1, because the allocation is valid */
log_backtrace(block->bt, block->bt_depth);
}
@@ -636,7 +649,17 @@
info_log("%s: setting backlog length to %d\n", getprogname(), g_malloc_debug_backlog);
}
- backtrace_startup();
+ // Check if backtracing should be disabled.
+ char env[PROP_VALUE_MAX];
+ if (__system_property_get("libc.debug.malloc.nobacktrace", env) && atoi(env) != 0) {
+ g_backtrace_enabled = false;
+ __libc_format_log(ANDROID_LOG_INFO, "libc", "not gathering backtrace information\n");
+ }
+
+ if (g_backtrace_enabled) {
+ backtrace_startup();
+ }
+
return true;
}
@@ -645,7 +668,9 @@
if (malloc_debug_level == 10) {
ReportMemoryLeaks();
}
- backtrace_shutdown();
+ if (g_backtrace_enabled) {
+ backtrace_shutdown();
+ }
pthread_setspecific(g_debug_calls_disabled, NULL);
}