Implement malloc_usable_size for debug impls.
- Implemented chk_memalign.
- Fixed a few bugs in leak_memalign.
- Implemented {leak,fill,check,qemu}_malloc_usable_size.
- Make malloc_usable_size update at run time.
- Add malloc_test.cpp as a small set of tests for the
malloc debug routines.
- Fix the qemu routines since it's been broken since it moved to C++.
- Add support for the %u format to the out_vformat in libc_logging.cpp.
This is used by the emulator code.
Tested using the bionic-unit-tests with setprop libc.debug.malloc
set to 1, 5, and 10.
I tested as much as possible on the emulator, but tracing doesn't appear
to be working properly.
Bug: 6143477
Merge change from internal master.
(cherry-picked from commit 3d594c258045783fc9e1956ce7a4d91e302f011e)
Change-Id: I4ae00fffba82315a8c283f35893fd554460722fb
diff --git a/libc/bionic/malloc_debug_common.cpp b/libc/bionic/malloc_debug_common.cpp
index 9cc84c3..ccceb14 100644
--- a/libc/bionic/malloc_debug_common.cpp
+++ b/libc/bionic/malloc_debug_common.cpp
@@ -190,10 +190,6 @@
return dlmallinfo();
}
-extern "C" size_t malloc_usable_size(const void* mem) {
- return dlmalloc_usable_size(mem);
-}
-
extern "C" void* valloc(size_t bytes) {
return dlvalloc(bytes);
}
@@ -215,8 +211,9 @@
/* 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))) = {
- dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign
+const MallocDebug __libc_malloc_default_dispatch __attribute__((aligned(32))) =
+{
+ dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign, dlmalloc_usable_size,
};
/* Selector of dispatch table to use for dispatching malloc calls. */
@@ -242,6 +239,10 @@
return __libc_malloc_dispatch->memalign(alignment, bytes);
}
+extern "C" size_t malloc_usable_size(const void* mem) {
+ return __libc_malloc_dispatch->malloc_usable_size(mem);
+}
+
/* We implement malloc debugging only in libc.so, so code below
* must be excluded if we compile this file for static libc.a
*/
@@ -253,7 +254,7 @@
/* Table for dispatching malloc calls, depending on environment. */
static MallocDebug gMallocUse __attribute__((aligned(32))) = {
- dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign
+ dlmalloc, dlfree, dlcalloc, dlrealloc, dlmemalign, dlmalloc_usable_size
};
extern const char* __progname;
@@ -276,15 +277,10 @@
* 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.
+ * the emulator only.
*/
static void* libc_malloc_impl_handle = NULL;
-// This must match the alignment used by dlmalloc.
-#ifndef MALLOC_ALIGNMENT
-#define MALLOC_ALIGNMENT ((size_t)(2 * sizeof(void *)))
-#endif
-
/* 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
@@ -296,41 +292,26 @@
/* 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",
- __progname, gMallocDebugLevel, prefix);
+template<typename FunctionType>
+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);
+ }
+}
- char symbol[128];
+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, gMallocDebugLevel, prefix);
- snprintf(symbol, sizeof(symbol), "%s_malloc", prefix);
- table->malloc = reinterpret_cast<MallocDebugMalloc>(dlsym(libc_malloc_impl_handle, symbol));
- if (table->malloc == NULL) {
- error_log("%s: dlsym(\"%s\") failed", __progname, symbol);
- }
-
- snprintf(symbol, sizeof(symbol), "%s_free", prefix);
- table->free = reinterpret_cast<MallocDebugFree>(dlsym(libc_malloc_impl_handle, symbol));
- if (table->free == NULL) {
- error_log("%s: dlsym(\"%s\") failed", __progname, symbol);
- }
-
- snprintf(symbol, sizeof(symbol), "%s_calloc", prefix);
- table->calloc = reinterpret_cast<MallocDebugCalloc>(dlsym(libc_malloc_impl_handle, symbol));
- if (table->calloc == NULL) {
- error_log("%s: dlsym(\"%s\") failed", __progname, symbol);
- }
-
- snprintf(symbol, sizeof(symbol), "%s_realloc", prefix);
- table->realloc = reinterpret_cast<MallocDebugRealloc>(dlsym(libc_malloc_impl_handle, symbol));
- if (table->realloc == NULL) {
- error_log("%s: dlsym(\"%s\") failed", __progname, symbol);
- }
-
- snprintf(symbol, sizeof(symbol), "%s_memalign", prefix);
- table->memalign = reinterpret_cast<MallocDebugMemalign>(dlsym(libc_malloc_impl_handle, symbol));
- if (table->memalign == NULL) {
- error_log("%s: dlsym(\"%s\") failed", __progname, symbol);
- }
+ InitMallocFunction<MallocDebugMalloc>(malloc_impl_handler, &table->malloc, prefix, "malloc");
+ InitMallocFunction<MallocDebugFree>(malloc_impl_handler, &table->free, prefix, "free");
+ InitMallocFunction<MallocDebugCalloc>(malloc_impl_handler, &table->calloc, prefix, "calloc");
+ InitMallocFunction<MallocDebugRealloc>(malloc_impl_handler, &table->realloc, prefix, "realloc");
+ InitMallocFunction<MallocDebugMemalign>(malloc_impl_handler, &table->memalign, prefix, "memalign");
+ InitMallocFunction<MallocDebugMallocUsableSize>(malloc_impl_handler, &table->malloc_usable_size, prefix, "malloc_usable_size");
}
/* Initializes memory allocation framework once per process. */
@@ -422,24 +403,24 @@
}
// Load .so that implements the required malloc debugging functionality.
- libc_malloc_impl_handle = dlopen(so_name, RTLD_LAZY);
- if (libc_malloc_impl_handle == NULL) {
+ 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, gMallocDebugLevel, dlerror());
return;
}
// Initialize malloc debugging in the loaded module.
- malloc_debug_initialize = reinterpret_cast<MallocDebugInit>(dlsym(libc_malloc_impl_handle,
+ malloc_debug_initialize = reinterpret_cast<MallocDebugInit>(dlsym(malloc_impl_handle,
"malloc_debug_initialize"));
if (malloc_debug_initialize == NULL) {
error_log("%s: Initialization routine is not found in %s\n",
__progname, so_name);
- dlclose(libc_malloc_impl_handle);
+ dlclose(malloc_impl_handle);
return;
}
if (malloc_debug_initialize() == -1) {
- dlclose(libc_malloc_impl_handle);
+ dlclose(malloc_impl_handle);
return;
}
@@ -447,34 +428,35 @@
// For memory checker we need to do extra initialization.
typedef int (*MemCheckInit)(int, const char*);
MemCheckInit memcheck_initialize =
- reinterpret_cast<MemCheckInit>(dlsym(libc_malloc_impl_handle,
+ reinterpret_cast<MemCheckInit>(dlsym(malloc_impl_handle,
"memcheck_initialize"));
if (memcheck_initialize == NULL) {
error_log("%s: memcheck_initialize routine is not found in %s\n",
__progname, so_name);
- dlclose(libc_malloc_impl_handle);
+ dlclose(malloc_impl_handle);
return;
}
if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) {
- dlclose(libc_malloc_impl_handle);
+ dlclose(malloc_impl_handle);
return;
}
}
+
// Initialize malloc dispatch table with appropriate routines.
switch (gMallocDebugLevel) {
case 1:
- InitMalloc(&gMallocUse, "leak");
+ InitMalloc(malloc_impl_handle, &gMallocUse, "leak");
break;
case 5:
- InitMalloc(&gMallocUse, "fill");
+ InitMalloc(malloc_impl_handle, &gMallocUse, "fill");
break;
case 10:
- InitMalloc(&gMallocUse, "chk");
+ InitMalloc(malloc_impl_handle, &gMallocUse, "chk");
break;
case 20:
- InitMalloc(&gMallocUse, "qemu_instrumented");
+ InitMalloc(malloc_impl_handle, &gMallocUse, "qemu_instrumented");
break;
default:
break;
@@ -485,13 +467,14 @@
(gMallocUse.free == NULL) ||
(gMallocUse.calloc == NULL) ||
(gMallocUse.realloc == NULL) ||
- (gMallocUse.memalign == NULL)) {
+ (gMallocUse.memalign == NULL) ||
+ (gMallocUse.malloc_usable_size == NULL)) {
error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)",
__progname, gMallocDebugLevel);
- dlclose(libc_malloc_impl_handle);
- libc_malloc_impl_handle = NULL;
+ dlclose(malloc_impl_handle);
} else {
__libc_malloc_dispatch = &gMallocUse;
+ libc_malloc_impl_handle = malloc_impl_handle;
}
}