Merge "Don't claim there were no leaks if we weren't even checking."

This commit is contained in:
Elliott Hughes 2013-02-02 01:18:44 +00:00 committed by Gerrit Code Review
commit 3dc6b57cf5
2 changed files with 39 additions and 35 deletions

View File

@ -53,13 +53,13 @@
#include "ScopedPthreadMutexLocker.h" #include "ScopedPthreadMutexLocker.h"
/* libc.debug.malloc.backlog */ /* libc.debug.malloc.backlog */
extern unsigned int malloc_double_free_backlog; extern unsigned int gMallocDebugBacklog;
extern int gMallocDebugLevel;
#define MAX_BACKTRACE_DEPTH 16 #define MAX_BACKTRACE_DEPTH 16
#define ALLOCATION_TAG 0x1ee7d00d #define ALLOCATION_TAG 0x1ee7d00d
#define BACKLOG_TAG 0xbabecafe #define BACKLOG_TAG 0xbabecafe
#define FREE_POISON 0xa5 #define FREE_POISON 0xa5
#define BACKLOG_DEFAULT_LEN 100
#define FRONT_GUARD 0xaa #define FRONT_GUARD 0xaa
#define FRONT_GUARD_LEN (1<<5) #define FRONT_GUARD_LEN (1<<5)
#define REAR_GUARD 0xbb #define REAR_GUARD 0xbb
@ -306,7 +306,7 @@ static inline void add_to_backlog(hdr_t *hdr) {
add_locked(hdr, &backlog_tail, &backlog_head); add_locked(hdr, &backlog_tail, &backlog_head);
poison(hdr); poison(hdr);
/* If we've exceeded the maximum backlog, clear it up */ /* If we've exceeded the maximum backlog, clear it up */
while (backlog_num > malloc_double_free_backlog) { while (backlog_num > gMallocDebugBacklog) {
hdr_t *gone = backlog_tail; hdr_t *gone = backlog_tail;
del_from_backlog_locked(gone); del_from_backlog_locked(gone);
dlfree(gone); dlfree(gone);
@ -436,7 +436,12 @@ extern "C" void *chk_calloc(int nmemb, size_t size) {
return NULL; return NULL;
} }
static void heaptracker_free_leaked_memory() { static void ReportMemoryLeaks() {
// We only track leaks at level 10.
if (gMallocDebugLevel != 10) {
return;
}
// Use /proc/self/exe link to obtain the program name for logging // Use /proc/self/exe link to obtain the program name for logging
// purposes. If it's not available, we set it to "<unknown>". // purposes. If it's not available, we set it to "<unknown>".
char exe[PATH_MAX]; char exe[PATH_MAX];
@ -471,14 +476,11 @@ static void heaptracker_free_leaked_memory() {
} }
extern "C" int malloc_debug_initialize() { extern "C" int malloc_debug_initialize() {
if (!malloc_double_free_backlog) {
malloc_double_free_backlog = BACKLOG_DEFAULT_LEN;
}
backtrace_startup(); backtrace_startup();
return 0; return 0;
} }
extern "C" void malloc_debug_finalize() { extern "C" void malloc_debug_finalize() {
heaptracker_free_leaked_memory(); ReportMemoryLeaks();
backtrace_shutdown(); backtrace_shutdown();
} }

View File

@ -288,14 +288,17 @@ static void* libc_malloc_impl_handle = NULL;
/* This variable is set to the value of property libc.debug.malloc.backlog, /* This variable is set to the value of property libc.debug.malloc.backlog,
* when the value of libc.debug.malloc = 10. It determines the size of the * when the value of libc.debug.malloc = 10. It determines the size of the
* backlog we use to detect multiple frees. If the property is not set, the * backlog we use to detect multiple frees. If the property is not set, the
* backlog length defaults to an internal constant defined in * backlog length defaults to BACKLOG_DEFAULT_LEN.
* malloc_debug_check.cpp.
*/ */
unsigned int malloc_double_free_backlog; unsigned int gMallocDebugBacklog;
#define BACKLOG_DEFAULT_LEN 100
static void InitMalloc(MallocDebug* table, int debug_level, const char* prefix) { /* The value of libc.debug.malloc. */
int gMallocDebugLevel;
static void InitMalloc(MallocDebug* table, const char* prefix) {
__libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n", __libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
__progname, debug_level, prefix); __progname, gMallocDebugLevel, prefix);
char symbol[128]; char symbol[128];
@ -335,7 +338,6 @@ static void malloc_init_impl() {
const char* so_name = NULL; const char* so_name = NULL;
MallocDebugInit malloc_debug_initialize = NULL; MallocDebugInit malloc_debug_initialize = NULL;
unsigned int qemu_running = 0; unsigned int qemu_running = 0;
unsigned int debug_level = 0;
unsigned int memcheck_enabled = 0; unsigned int memcheck_enabled = 0;
char env[PROP_VALUE_MAX]; char env[PROP_VALUE_MAX];
char memcheck_tracing[PROP_VALUE_MAX]; char memcheck_tracing[PROP_VALUE_MAX];
@ -349,7 +351,7 @@ static void malloc_init_impl() {
if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) { if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) {
if (memcheck_tracing[0] != '0') { if (memcheck_tracing[0] != '0') {
// Emulator has started with memory tracing enabled. Enforce it. // Emulator has started with memory tracing enabled. Enforce it.
debug_level = 20; gMallocDebugLevel = 20;
memcheck_enabled = 1; memcheck_enabled = 1;
} }
} }
@ -357,13 +359,13 @@ static void malloc_init_impl() {
/* If debug level has not been set by memcheck option in the emulator, /* If debug level has not been set by memcheck option in the emulator,
* lets grab it from libc.debug.malloc system property. */ * lets grab it from libc.debug.malloc system property. */
if (debug_level == 0 && __system_property_get("libc.debug.malloc", env)) { if (gMallocDebugLevel == 0 && __system_property_get("libc.debug.malloc", env)) {
debug_level = atoi(env); gMallocDebugLevel = atoi(env);
} }
/* Debug level 0 means that we should use dlxxx allocation /* Debug level 0 means that we should use dlxxx allocation
* routines (default). */ * routines (default). */
if (debug_level == 0) { if (gMallocDebugLevel == 0) {
return; return;
} }
@ -377,24 +379,25 @@ static void malloc_init_impl() {
} }
// mksh is way too leaky. http://b/7291287. // mksh is way too leaky. http://b/7291287.
if (debug_level >= 10) { if (gMallocDebugLevel >= 10) {
if (strcmp(__progname, "sh") == 0 || strcmp(__progname, "/system/bin/sh") == 0) { if (strcmp(__progname, "sh") == 0 || strcmp(__progname, "/system/bin/sh") == 0) {
return; return;
} }
} }
// Choose the appropriate .so for the requested debug level. // Choose the appropriate .so for the requested debug level.
switch (debug_level) { switch (gMallocDebugLevel) {
case 1: case 1:
case 5: case 5:
case 10: { case 10: {
char debug_backlog[PROP_VALUE_MAX]; char debug_backlog[PROP_VALUE_MAX];
if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) { if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
malloc_double_free_backlog = atoi(debug_backlog); gMallocDebugBacklog = atoi(debug_backlog);
info_log("%s: setting backlog length to %d\n", info_log("%s: setting backlog length to %d\n", __progname, gMallocDebugBacklog);
__progname, malloc_double_free_backlog); }
if (gMallocDebugBacklog == 0) {
gMallocDebugBacklog = BACKLOG_DEFAULT_LEN;
} }
so_name = "/system/lib/libc_malloc_debug_leak.so"; so_name = "/system/lib/libc_malloc_debug_leak.so";
break; break;
} }
@ -402,7 +405,7 @@ static void malloc_init_impl() {
// Quick check: debug level 20 can only be handled in emulator. // Quick check: debug level 20 can only be handled in emulator.
if (!qemu_running) { if (!qemu_running) {
error_log("%s: Debug level %d can only be set in emulator\n", error_log("%s: Debug level %d can only be set in emulator\n",
__progname, debug_level); __progname, gMallocDebugLevel);
return; return;
} }
// Make sure that memory checking has been enabled in emulator. // Make sure that memory checking has been enabled in emulator.
@ -414,8 +417,7 @@ static void malloc_init_impl() {
so_name = "/system/lib/libc_malloc_debug_qemu.so"; so_name = "/system/lib/libc_malloc_debug_qemu.so";
break; break;
default: default:
error_log("%s: Debug level %d is unknown\n", error_log("%s: Debug level %d is unknown\n", __progname, gMallocDebugLevel);
__progname, debug_level);
return; return;
} }
@ -423,7 +425,7 @@ static void malloc_init_impl() {
libc_malloc_impl_handle = dlopen(so_name, RTLD_LAZY); libc_malloc_impl_handle = dlopen(so_name, RTLD_LAZY);
if (libc_malloc_impl_handle == NULL) { if (libc_malloc_impl_handle == NULL) {
error_log("%s: Missing module %s required for malloc debug level %d: %s", error_log("%s: Missing module %s required for malloc debug level %d: %s",
__progname, so_name, debug_level, dlerror()); __progname, so_name, gMallocDebugLevel, dlerror());
return; return;
} }
@ -441,7 +443,7 @@ static void malloc_init_impl() {
return; return;
} }
if (debug_level == 20) { if (gMallocDebugLevel == 20) {
// For memory checker we need to do extra initialization. // For memory checker we need to do extra initialization.
typedef int (*MemCheckInit)(int, const char*); typedef int (*MemCheckInit)(int, const char*);
MemCheckInit memcheck_initialize = MemCheckInit memcheck_initialize =
@ -461,18 +463,18 @@ static void malloc_init_impl() {
} }
// Initialize malloc dispatch table with appropriate routines. // Initialize malloc dispatch table with appropriate routines.
switch (debug_level) { switch (gMallocDebugLevel) {
case 1: case 1:
InitMalloc(&gMallocUse, debug_level, "leak"); InitMalloc(&gMallocUse, "leak");
break; break;
case 5: case 5:
InitMalloc(&gMallocUse, debug_level, "fill"); InitMalloc(&gMallocUse, "fill");
break; break;
case 10: case 10:
InitMalloc(&gMallocUse, debug_level, "chk"); InitMalloc(&gMallocUse, "chk");
break; break;
case 20: case 20:
InitMalloc(&gMallocUse, debug_level, "qemu_instrumented"); InitMalloc(&gMallocUse, "qemu_instrumented");
break; break;
default: default:
break; break;
@ -485,7 +487,7 @@ static void malloc_init_impl() {
(gMallocUse.realloc == NULL) || (gMallocUse.realloc == NULL) ||
(gMallocUse.memalign == NULL)) { (gMallocUse.memalign == NULL)) {
error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)", error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)",
__progname, debug_level); __progname, gMallocDebugLevel);
dlclose(libc_malloc_impl_handle); dlclose(libc_malloc_impl_handle);
libc_malloc_impl_handle = NULL; libc_malloc_impl_handle = NULL;
} else { } else {