summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2014-06-04 12:07:11 -0700
committerElliott Hughes <enh@google.com>2014-06-04 14:08:20 -0700
commit8e52e8fe83632c667521c1c8e4f640e94c09baed (patch)
tree2611bc51cde66365817942ba7febf72910f36034
parente120cba31df5249b720579312e799bd1c65f8e3d (diff)
downloadbionic-8e52e8fe83632c667521c1c8e4f640e94c09baed.zip
bionic-8e52e8fe83632c667521c1c8e4f640e94c09baed.tar.gz
bionic-8e52e8fe83632c667521c1c8e4f640e94c09baed.tar.bz2
Fix debug malloc.
Previously the dynamically-loaded part of the debug malloc implementation wanted to access hidden symbols in libc itself. Bug: 15426546 Change-Id: I6a366ef626854d1af1d705ca24842817b1c02a19
-rw-r--r--libc/bionic/malloc_debug_check.cpp34
-rw-r--r--libc/bionic/malloc_debug_common.cpp190
-rw-r--r--libc/bionic/malloc_debug_common.h21
-rw-r--r--libc/bionic/malloc_debug_leak.cpp124
-rw-r--r--libc/bionic/malloc_debug_qemu.cpp15
5 files changed, 177 insertions, 207 deletions
diff --git a/libc/bionic/malloc_debug_check.cpp b/libc/bionic/malloc_debug_check.cpp
index 2590ce7..0575595 100644
--- a/libc/bionic/malloc_debug_check.cpp
+++ b/libc/bionic/malloc_debug_check.cpp
@@ -51,10 +51,6 @@
#include "malloc_debug_common.h"
#include "private/ScopedPthreadMutexLocker.h"
-/* libc.debug.malloc.backlog */
-extern unsigned int g_malloc_debug_backlog;
-extern int g_malloc_debug_level;
-
#define MAX_BACKTRACE_DEPTH 16
#define ALLOCATION_TAG 0x1ee7d00d
#define BACKLOG_TAG 0xbabecafe
@@ -120,6 +116,12 @@ static hdr_t* backlog_tail;
static hdr_t* backlog_head;
static pthread_mutex_t backlog_lock = PTHREAD_MUTEX_INITIALIZER;
+// This variable is set to the value of property libc.debug.malloc.backlog.
+// It determines the size of the backlog we use to detect multiple frees.
+static unsigned g_malloc_debug_backlog = 100;
+
+__LIBC_HIDDEN__ HashTable* g_hash_table;
+
static inline void init_front_guard(hdr_t* hdr) {
memset(hdr->front_guard, FRONT_GUARD, FRONT_GUARD_LEN);
}
@@ -508,11 +510,6 @@ extern "C" size_t chk_malloc_usable_size(const void* ptr) {
}
static void ReportMemoryLeaks() {
- // We only track leaks at level 10.
- if (g_malloc_debug_level != 10) {
- return;
- }
-
// Use /proc/self/exe link to obtain the program name for logging
// purposes. If it's not available, we set it to "<unknown>".
char exe[PATH_MAX];
@@ -546,12 +543,23 @@ static void ReportMemoryLeaks() {
}
}
-extern "C" int malloc_debug_initialize() {
+extern "C" bool malloc_debug_initialize(HashTable* hash_table) {
+ g_hash_table = hash_table;
+
+ char debug_backlog[PROP_VALUE_MAX];
+ if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
+ g_malloc_debug_backlog = atoi(debug_backlog);
+ info_log("%s: setting backlog length to %d\n", getprogname(), g_malloc_debug_backlog);
+ }
+
backtrace_startup();
- return 0;
+ return true;
}
-extern "C" void malloc_debug_finalize() {
- ReportMemoryLeaks();
+extern "C" void malloc_debug_finalize(int malloc_debug_level) {
+ // We only track leaks at level 10.
+ if (malloc_debug_level == 10) {
+ ReportMemoryLeaks();
+ }
backtrace_shutdown();
}
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index db3f995..19524bb 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -48,13 +48,48 @@
#include "private/ScopedPthreadMutexLocker.h"
-/*
- * In a VM process, this is set to 1 after fork()ing out of zygote.
- */
+// In a VM process, this is set to 1 after fork()ing out of zygote.
int gMallocLeakZygoteChild = 0;
-__LIBC_HIDDEN__ pthread_mutex_t g_allocations_mutex = PTHREAD_MUTEX_INITIALIZER;
-__LIBC_HIDDEN__ HashTable g_hash_table;
+static HashTable g_hash_table;
+
+// Support for malloc debugging.
+// Table for dispatching malloc calls, initialized with default dispatchers.
+static const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) = {
+ Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size),
+};
+
+// Selector of dispatch table to use for dispatching malloc calls.
+static const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
+
+// 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
@@ -123,7 +158,7 @@ extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
}
*totalMemory = 0;
- ScopedPthreadMutexLocker locker(&g_allocations_mutex);
+ ScopedPthreadMutexLocker locker(&g_hash_table.lock);
if (g_hash_table.count == 0) {
*info = NULL;
@@ -204,17 +239,6 @@ extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
return Malloc(posix_memalign)(memptr, alignment, size);
}
-// Support for malloc debugging.
-// Table for dispatching malloc calls, initialized with default dispatchers.
-extern const MallocDebug __libc_malloc_default_dispatch;
-const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) =
-{
- Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size),
-};
-
-/* Selector of dispatch table to use for dispatching malloc calls. */
-const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
-
extern "C" void* malloc(size_t bytes) {
return __libc_malloc_dispatch->malloc(bytes);
}
@@ -248,59 +272,19 @@ extern "C" size_t malloc_usable_size(const void* mem) {
#include <stdio.h>
#include "private/libc_logging.h"
-/* Table for dispatching malloc calls, depending on environment. */
-static MallocDebug g_malloc_dispatch_table __attribute__((aligned(32))) = {
- Malloc(malloc), Malloc(free), Malloc(calloc), Malloc(realloc), Malloc(memalign), Malloc(malloc_usable_size)
-};
-
-extern const char* __progname;
-
-/* 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 emultor's instrumented
- * allocations is implemented in libc_malloc_debug_qemu.so and can be run inside
- * the emulator only.
- */
-static void* libc_malloc_impl_handle = NULL;
-
-/* 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
- * backlog we use to detect multiple frees. If the property is not set, the
- * backlog length defaults to BACKLOG_DEFAULT_LEN.
- */
-__LIBC_HIDDEN__ unsigned int g_malloc_debug_backlog;
-#define BACKLOG_DEFAULT_LEN 100
-
-/* The value of libc.debug.malloc. */
-__LIBC_HIDDEN__ int g_malloc_debug_level;
-
template<typename FunctionType>
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<FunctionType>(dlsym(malloc_impl_handler, symbol));
if (*func == NULL) {
- error_log("%s: dlsym(\"%s\") failed", __progname, symbol);
+ 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",
- __progname, g_malloc_debug_level, prefix);
+ getprogname(), g_malloc_debug_level, prefix);
InitMallocFunction<MallocDebugMalloc>(malloc_impl_handler, &table->malloc, prefix, "malloc");
InitMallocFunction<MallocDebugFree>(malloc_impl_handler, &table->free, prefix, "free");
@@ -349,14 +333,14 @@ static void malloc_init_impl() {
* then exit.
*/
if (__system_property_get("libc.debug.malloc.program", debug_program)) {
- if (!strstr(__progname, debug_program)) {
+ if (!strstr(getprogname(), debug_program)) {
return;
}
}
// mksh is way too leaky. http://b/7291287.
if (g_malloc_debug_level >= 10) {
- if (strcmp(__progname, "sh") == 0 || strcmp(__progname, "/system/bin/sh") == 0) {
+ if (strcmp(getprogname(), "sh") == 0 || strcmp(getprogname(), "/system/bin/sh") == 0) {
return;
}
}
@@ -365,35 +349,26 @@ static void malloc_init_impl() {
switch (g_malloc_debug_level) {
case 1:
case 5:
- case 10: {
- char debug_backlog[PROP_VALUE_MAX];
- if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
- g_malloc_debug_backlog = atoi(debug_backlog);
- info_log("%s: setting backlog length to %d\n", __progname, g_malloc_debug_backlog);
- }
- if (g_malloc_debug_backlog == 0) {
- g_malloc_debug_backlog = BACKLOG_DEFAULT_LEN;
- }
+ 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",
- __progname, g_malloc_debug_level);
+ 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",
- __progname);
+ getprogname());
return;
}
so_name = "libc_malloc_debug_qemu.so";
break;
default:
- error_log("%s: Debug level %d is unknown\n", __progname, g_malloc_debug_level);
+ error_log("%s: Debug level %d is unknown\n", getprogname(), g_malloc_debug_level);
return;
}
@@ -401,7 +376,7 @@ static void malloc_init_impl() {
void* malloc_impl_handle = dlopen(so_name, RTLD_LAZY);
if (malloc_impl_handle == NULL) {
error_log("%s: Missing module %s required for malloc debug level %d: %s",
- __progname, so_name, g_malloc_debug_level, dlerror());
+ getprogname(), so_name, g_malloc_debug_level, dlerror());
return;
}
@@ -410,11 +385,11 @@ static void malloc_init_impl() {
"malloc_debug_initialize"));
if (malloc_debug_initialize == NULL) {
error_log("%s: Initialization routine is not found in %s\n",
- __progname, so_name);
+ getprogname(), so_name);
dlclose(malloc_impl_handle);
return;
}
- if (malloc_debug_initialize() == -1) {
+ if (malloc_debug_initialize(&g_hash_table) == -1) {
dlclose(malloc_impl_handle);
return;
}
@@ -427,7 +402,7 @@ static void malloc_init_impl() {
"memcheck_initialize"));
if (memcheck_initialize == NULL) {
error_log("%s: memcheck_initialize routine is not found in %s\n",
- __progname, so_name);
+ getprogname(), so_name);
dlclose(malloc_impl_handle);
return;
}
@@ -438,44 +413,52 @@ static void malloc_init_impl() {
}
}
-
// Initialize malloc dispatch table with appropriate routines.
+ static MallocDebug malloc_dispatch_table __attribute__((aligned(32))) = {
+ Malloc(malloc),
+ Malloc(free),
+ Malloc(calloc),
+ Malloc(realloc),
+ Malloc(memalign),
+ Malloc(malloc_usable_size)
+ };
+
switch (g_malloc_debug_level) {
case 1:
- InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "leak");
+ InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "leak");
break;
case 5:
- InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "fill");
+ InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "fill");
break;
case 10:
- InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "chk");
+ InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "chk");
break;
case 20:
- InitMalloc(malloc_impl_handle, &g_malloc_dispatch_table, "qemu_instrumented");
+ InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "qemu_instrumented");
break;
default:
break;
}
// Make sure dispatch table is initialized
- if ((g_malloc_dispatch_table.malloc == NULL) ||
- (g_malloc_dispatch_table.free == NULL) ||
- (g_malloc_dispatch_table.calloc == NULL) ||
- (g_malloc_dispatch_table.realloc == NULL) ||
- (g_malloc_dispatch_table.memalign == NULL) ||
- (g_malloc_dispatch_table.malloc_usable_size == NULL)) {
+ if ((malloc_dispatch_table.malloc == NULL) ||
+ (malloc_dispatch_table.free == NULL) ||
+ (malloc_dispatch_table.calloc == NULL) ||
+ (malloc_dispatch_table.realloc == NULL) ||
+ (malloc_dispatch_table.memalign == NULL) ||
+ (malloc_dispatch_table.malloc_usable_size == NULL)) {
error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)",
- __progname, g_malloc_debug_level);
+ getprogname(), g_malloc_debug_level);
dlclose(malloc_impl_handle);
} else {
- __libc_malloc_dispatch = &g_malloc_dispatch_table;
+ __libc_malloc_dispatch = &malloc_dispatch_table;
libc_malloc_impl_handle = malloc_impl_handle;
}
}
static void malloc_fini_impl() {
// Our BSD stdio implementation doesn't close the standard streams, it only flushes them.
- // And it doesn't do that until its atexit handler (_cleanup) is run, and we run first!
+ // 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);
@@ -487,14 +470,11 @@ static void malloc_fini_impl() {
reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle,
"malloc_debug_finalize"));
if (malloc_debug_finalize != NULL) {
- malloc_debug_finalize();
+ malloc_debug_finalize(g_malloc_debug_level);
}
}
}
-static pthread_once_t malloc_init_once_ctl = PTHREAD_ONCE_INIT;
-static pthread_once_t malloc_fini_once_ctl = PTHREAD_ONCE_INIT;
-
#endif // !LIBC_STATIC
/* Initializes memory allocation framework.
@@ -502,21 +482,19 @@ static pthread_once_t malloc_fini_once_ctl = PTHREAD_ONCE_INIT;
* in libc_init_static.c and libc_init_dynamic.c files.
*/
extern "C" __LIBC_HIDDEN__ void malloc_debug_init() {
- /* We need to initialize malloc iff we implement here custom
- * malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so */
#if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
- if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
- error_log("Unable to initialize malloc_debug component.");
- }
+ static pthread_once_t malloc_init_once_ctl = PTHREAD_ONCE_INIT;
+ if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
+ error_log("Unable to initialize malloc_debug component.");
+ }
#endif // USE_DL_PREFIX && !LIBC_STATIC
}
extern "C" __LIBC_HIDDEN__ void malloc_debug_fini() {
- /* We need to finalize malloc iff we implement here custom
- * malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so */
#if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
- if (pthread_once(&malloc_fini_once_ctl, malloc_fini_impl)) {
- error_log("Unable to finalize malloc_debug component.");
- }
+ 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 // USE_DL_PREFIX && !LIBC_STATIC
}
diff --git a/libc/bionic/malloc_debug_common.h b/libc/bionic/malloc_debug_common.h
index c1c3c89..21cb44c 100644
--- a/libc/bionic/malloc_debug_common.h
+++ b/libc/bionic/malloc_debug_common.h
@@ -33,6 +33,8 @@
#ifndef MALLOC_DEBUG_COMMON_H
#define MALLOC_DEBUG_COMMON_H
+#include <pthread.h>
+#include <stdint.h>
#include <stdlib.h>
#include "private/libc_logging.h"
@@ -43,8 +45,6 @@
#define SIZE_FLAG_ZYGOTE_CHILD (1<<31)
#define SIZE_FLAG_MASK (SIZE_FLAG_ZYGOTE_CHILD)
-#define MAX_SIZE_T (~(size_t)0)
-
// This must match the alignment used by the malloc implementation.
#ifndef MALLOC_ALIGNMENT
#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))
@@ -77,6 +77,7 @@ struct HashEntry {
};
struct HashTable {
+ pthread_mutex_t lock;
size_t count;
HashEntry* slots[HASHTABLE_SIZE];
};
@@ -97,20 +98,8 @@ struct MallocDebug {
MallocDebugMallocUsableSize malloc_usable_size;
};
-/* Malloc debugging initialization and finalization routines.
- *
- * These routines must be implemented in .so modules that implement malloc
- * debugging. The are is called once per process from malloc_init_impl and
- * malloc_fini_impl respectively.
- *
- * They are implemented in bionic/libc/bionic/malloc_debug_common.c when malloc
- * debugging gets initialized for the process.
- *
- * MallocDebugInit returns:
- * 0 on success, -1 on failure.
- */
-typedef int (*MallocDebugInit)();
-typedef void (*MallocDebugFini)();
+typedef bool (*MallocDebugInit)(HashTable*);
+typedef void (*MallocDebugFini)(int);
// =============================================================================
// log functions
diff --git a/libc/bionic/malloc_debug_leak.cpp b/libc/bionic/malloc_debug_leak.cpp
index 035765f..aa7c072 100644
--- a/libc/bionic/malloc_debug_leak.cpp
+++ b/libc/bionic/malloc_debug_leak.cpp
@@ -58,10 +58,8 @@
#error MALLOC_LEAK_CHECK is not defined.
#endif // !MALLOC_LEAK_CHECK
-// Global variables defined in malloc_debug_common.c
extern int gMallocLeakZygoteChild;
-extern pthread_mutex_t g_allocations_mutex;
-extern HashTable g_hash_table;
+extern HashTable* g_hash_table;
// =============================================================================
// stack trace functions
@@ -137,7 +135,7 @@ static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size
size |= SIZE_FLAG_ZYGOTE_CHILD;
}
- HashEntry* entry = find_entry(&g_hash_table, slot, backtrace, numEntries, size);
+ HashEntry* entry = find_entry(g_hash_table, slot, backtrace, numEntries, size);
if (entry != NULL) {
entry->allocations++;
@@ -150,58 +148,54 @@ static HashEntry* record_backtrace(uintptr_t* backtrace, size_t numEntries, size
entry->allocations = 1;
entry->slot = slot;
entry->prev = NULL;
- entry->next = g_hash_table.slots[slot];
+ entry->next = g_hash_table->slots[slot];
entry->numEntries = numEntries;
entry->size = size;
memcpy(entry->backtrace, backtrace, numEntries * sizeof(uintptr_t));
- g_hash_table.slots[slot] = entry;
+ g_hash_table->slots[slot] = entry;
if (entry->next != NULL) {
entry->next->prev = entry;
}
// we just added an entry, increase the size of the hashtable
- g_hash_table.count++;
+ g_hash_table->count++;
}
return entry;
}
static int is_valid_entry(HashEntry* entry) {
- if (entry != NULL) {
- int i;
- for (i = 0 ; i < HASHTABLE_SIZE ; i++) {
- HashEntry* e1 = g_hash_table.slots[i];
-
- while (e1 != NULL) {
- if (e1 == entry) {
- return 1;
- }
-
- e1 = e1->next;
- }
+ if (entry != NULL) {
+ for (size_t i = 0; i < HASHTABLE_SIZE; ++i) {
+ HashEntry* e1 = g_hash_table->slots[i];
+ while (e1 != NULL) {
+ if (e1 == entry) {
+ return 1;
}
+ e1 = e1->next;
+ }
}
-
- return 0;
+ }
+ return 0;
}
static void remove_entry(HashEntry* entry) {
- HashEntry* prev = entry->prev;
- HashEntry* next = entry->next;
+ HashEntry* prev = entry->prev;
+ HashEntry* next = entry->next;
- if (prev != NULL) entry->prev->next = next;
- if (next != NULL) entry->next->prev = prev;
+ if (prev != NULL) entry->prev->next = next;
+ if (next != NULL) entry->next->prev = prev;
- if (prev == NULL) {
- // we are the head of the list. set the head to be next
- g_hash_table.slots[entry->slot] = entry->next;
- }
+ if (prev == NULL) {
+ // we are the head of the list. set the head to be next
+ g_hash_table->slots[entry->slot] = entry->next;
+ }
- // we just removed and entry, decrease the size of the hashtable
- g_hash_table.count--;
+ // we just removed and entry, decrease the size of the hashtable
+ g_hash_table->count--;
}
// =============================================================================
@@ -276,7 +270,7 @@ extern "C" void* leak_malloc(size_t bytes) {
void* base = Malloc(malloc)(size);
if (base != NULL) {
- ScopedPthreadMutexLocker locker(&g_allocations_mutex);
+ ScopedPthreadMutexLocker locker(&g_hash_table->lock);
uintptr_t backtrace[BACKTRACE_SIZE];
size_t numEntries = get_backtrace(backtrace, BACKTRACE_SIZE);
@@ -294,43 +288,45 @@ extern "C" void* leak_malloc(size_t bytes) {
}
extern "C" void leak_free(void* mem) {
- if (mem != NULL) {
- ScopedPthreadMutexLocker locker(&g_allocations_mutex);
-
- // check the guard to make sure it is valid
- AllocationEntry* header = to_header(mem);
-
- if (header->guard != GUARD) {
- // could be a memaligned block
- if (header->guard == MEMALIGN_GUARD) {
- // For memaligned blocks, header->entry points to the memory
- // allocated through leak_malloc.
- header = to_header(header->entry);
- }
- }
+ if (mem == NULL) {
+ return;
+ }
- if (header->guard == GUARD || is_valid_entry(header->entry)) {
- // decrement the allocations
- HashEntry* entry = header->entry;
- entry->allocations--;
- if (entry->allocations <= 0) {
- remove_entry(entry);
- Malloc(free)(entry);
- }
-
- // now free the memory!
- Malloc(free)(header);
- } else {
- debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
- header->guard, header->entry);
- }
+ ScopedPthreadMutexLocker locker(&g_hash_table->lock);
+
+ // check the guard to make sure it is valid
+ AllocationEntry* header = to_header(mem);
+
+ if (header->guard != GUARD) {
+ // could be a memaligned block
+ if (header->guard == MEMALIGN_GUARD) {
+ // For memaligned blocks, header->entry points to the memory
+ // allocated through leak_malloc.
+ header = to_header(header->entry);
+ }
+ }
+
+ if (header->guard == GUARD || is_valid_entry(header->entry)) {
+ // decrement the allocations
+ HashEntry* entry = header->entry;
+ entry->allocations--;
+ if (entry->allocations <= 0) {
+ remove_entry(entry);
+ Malloc(free)(entry);
}
+
+ // now free the memory!
+ Malloc(free)(header);
+ } else {
+ debug_log("WARNING bad header guard: '0x%x'! and invalid entry: %p\n",
+ header->guard, header->entry);
+ }
}
extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
- /* Fail on overflow - just to be safe even though this code runs only
- * within the debugging C library, not the production one */
- if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
+ // Fail on overflow - just to be safe even though this code runs only
+ // within the debugging C library, not the production one.
+ if (n_elements && SIZE_MAX / n_elements < elem_size) {
return NULL;
}
size_t size = n_elements * elem_size;
diff --git a/libc/bionic/malloc_debug_qemu.cpp b/libc/bionic/malloc_debug_qemu.cpp
index ac60c3b..2dda767 100644
--- a/libc/bionic/malloc_debug_qemu.cpp
+++ b/libc/bionic/malloc_debug_qemu.cpp
@@ -589,7 +589,7 @@ extern "C" size_t qemu_instrumented_malloc_usable_size(const void* mem);
* Return:
* 0 on success, or -1 on failure.
*/
-extern "C" int malloc_debug_initialize() {
+extern "C" bool malloc_debug_initialize(HashTable*) {
/* We will be using emulator's magic page to report memory allocation
* activities. In essence, what magic page does, it translates writes to
* the memory mapped spaces into writes to an I/O port that emulator
@@ -598,7 +598,7 @@ extern "C" int malloc_debug_initialize() {
int fd = open("/dev/qemu_trace", O_RDWR);
if (fd < 0) {
error_log("Unable to open /dev/qemu_trace");
- return -1;
+ return false;
} else {
qtrace = mmap(NULL, PAGESIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
close(fd);
@@ -606,14 +606,13 @@ extern "C" int malloc_debug_initialize() {
if (qtrace == MAP_FAILED) {
qtrace = NULL;
error_log("Unable to mmap /dev/qemu_trace");
- return -1;
+ return false;
}
}
/* Cache pid of the process this library has been initialized for. */
malloc_pid = getpid();
-
- return 0;
+ return true;
}
/* Completes malloc debugging instrumentation for the emulator.
@@ -759,9 +758,9 @@ extern "C" void* qemu_instrumented_calloc(size_t n_elements, size_t elem_size) {
return qemu_instrumented_malloc(0);
}
- /* Fail on overflow - just to be safe even though this code runs only
- * within the debugging C library, not the production one */
- if (n_elements && MAX_SIZE_T / n_elements < elem_size) {
+ // Fail on overflow - just to be safe even though this code runs only
+ // within the debugging C library, not the production one.
+ if (n_elements && SIZE_MAX / n_elements < elem_size) {
return NULL;
}