Merge memory checking functionality from sandbox
Change-Id: I304c789a752c9f4af4944ca14b9bf1e7644da15a
This commit is contained in:
parent
5c734644ee
commit
75fba6888a
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
*.pyc
|
*.pyc
|
||||||
|
*.*~
|
||||||
libc/kernel/original
|
libc/kernel/original
|
||||||
|
@ -27,8 +27,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Contains definition of global variables and implementation of routines
|
* Contains definition of structures, global variables, and implementation of
|
||||||
* that are used by malloc leak detection code and other components in
|
* routines that are used by malloc leak detection code and other components in
|
||||||
* the system. The trick is that some components expect these data and
|
* the system. The trick is that some components expect these data and
|
||||||
* routines to be defined / implemented in libc.so library, regardless
|
* routines to be defined / implemented in libc.so library, regardless
|
||||||
* whether or not MALLOC_LEAK_CHECK macro is defined. To make things even
|
* whether or not MALLOC_LEAK_CHECK macro is defined. To make things even
|
||||||
@ -237,11 +237,11 @@ void* memalign(size_t alignment, size_t bytes) {
|
|||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
||||||
#define debug_log(format, ...) \
|
#define debug_log(format, ...) \
|
||||||
__libc_android_log_print(ANDROID_LOG_DEBUG, "libc", (format), ##__VA_ARGS__ )
|
__libc_android_log_print(ANDROID_LOG_DEBUG, "libc", (format), ##__VA_ARGS__ )
|
||||||
#define error_log(format, ...) \
|
#define error_log(format, ...) \
|
||||||
__libc_android_log_print(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
|
__libc_android_log_print(ANDROID_LOG_ERROR, "libc", (format), ##__VA_ARGS__ )
|
||||||
#define info_log(format, ...) \
|
#define info_log(format, ...) \
|
||||||
__libc_android_log_print(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
|
__libc_android_log_print(ANDROID_LOG_INFO, "libc", (format), ##__VA_ARGS__ )
|
||||||
|
|
||||||
/* Table for dispatching malloc calls, depending on environment. */
|
/* Table for dispatching malloc calls, depending on environment. */
|
||||||
static MallocDebug gMallocUse __attribute__((aligned(32))) = {
|
static MallocDebug gMallocUse __attribute__((aligned(32))) = {
|
||||||
@ -259,43 +259,64 @@ extern char* __progname;
|
|||||||
* CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros.
|
* CHK_SENTINEL_VALUE, and CHK_FILL_FREE macros.
|
||||||
* 10 - For adding pre-, and post- allocation stubs in order to detect
|
* 10 - For adding pre-, and post- allocation stubs in order to detect
|
||||||
* buffer overruns.
|
* buffer overruns.
|
||||||
* 20 - For enabling emulator memory allocation instrumentation detecting
|
* Note that emulator's memory allocation instrumentation is not controlled by
|
||||||
* memory leaks and buffer overruns.
|
* 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
|
* Actual functionality for debug levels 1-10 is implemented in
|
||||||
* libc_malloc_debug_leak.so, while functionality for debug level 20 is
|
* libc_malloc_debug_leak.so, while functionality for emultor's instrumented
|
||||||
* implemented in libc_malloc_debug_qemu.so and can be run inside the
|
* allocations is implemented in libc_malloc_debug_qemu.so and can be run inside
|
||||||
* emulator only.
|
* the emulator only.
|
||||||
*/
|
*/
|
||||||
static void* libc_malloc_impl_handle = NULL;
|
static void* libc_malloc_impl_handle = NULL;
|
||||||
|
|
||||||
|
/* Make sure we have MALLOC_ALIGNMENT that matches the one that is
|
||||||
|
* used in dlmalloc. Emulator's memchecker needs this value to properly
|
||||||
|
* align its guarding zones.
|
||||||
|
*/
|
||||||
|
#ifndef MALLOC_ALIGNMENT
|
||||||
|
#define MALLOC_ALIGNMENT ((size_t)8U)
|
||||||
|
#endif /* MALLOC_ALIGNMENT */
|
||||||
|
|
||||||
/* Initializes memory allocation framework once per process. */
|
/* Initializes memory allocation framework once per process. */
|
||||||
static void malloc_init_impl(void)
|
static void malloc_init_impl(void)
|
||||||
{
|
{
|
||||||
const char* so_name = NULL;
|
const char* so_name = NULL;
|
||||||
unsigned int debug_level = 0;
|
MallocDebugInit malloc_debug_initialize = NULL;
|
||||||
unsigned int qemu_running = 0;
|
unsigned int qemu_running = 0;
|
||||||
int len;
|
unsigned int debug_level = 0;
|
||||||
|
unsigned int memcheck_enabled = 0;
|
||||||
char env[PROP_VALUE_MAX];
|
char env[PROP_VALUE_MAX];
|
||||||
|
char memcheck_tracing[PROP_VALUE_MAX];
|
||||||
|
|
||||||
// Get custom malloc debug level.
|
/* Get custom malloc debug level. Note that emulator started with
|
||||||
len = __system_property_get("libc.debug.malloc", env);
|
* memory checking option will have priority over debug level set in
|
||||||
if (len) {
|
* libc.debug.malloc system property. */
|
||||||
|
if (__system_property_get("ro.kernel.qemu", env) && atoi(env)) {
|
||||||
|
qemu_running = 1;
|
||||||
|
if (__system_property_get("ro.kernel.memcheck", memcheck_tracing)) {
|
||||||
|
if (memcheck_tracing[0] != '0') {
|
||||||
|
// Emulator has started with memory tracing enabled. Enforce it.
|
||||||
|
debug_level = 20;
|
||||||
|
memcheck_enabled = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If debug level has not been set by memcheck option in the emulator,
|
||||||
|
* lets grab it from libc.debug.malloc system property. */
|
||||||
|
if (!debug_level && __system_property_get("libc.debug.malloc", env)) {
|
||||||
debug_level = atoi(env);
|
debug_level = 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) {
|
if (!debug_level) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get emulator running status.
|
|
||||||
len = __system_property_get("ro.kernel.qemu", env);
|
|
||||||
if (len) {
|
|
||||||
qemu_running = atoi(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lets see which .so must be loaded for the requested debug level
|
// Lets see which .so must be loaded for the requested debug level
|
||||||
switch (debug_level) {
|
switch (debug_level) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -304,17 +325,23 @@ static void malloc_init_impl(void)
|
|||||||
so_name = "/system/lib/libc_malloc_debug_leak.so";
|
so_name = "/system/lib/libc_malloc_debug_leak.so";
|
||||||
break;
|
break;
|
||||||
case 20:
|
case 20:
|
||||||
// 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) {
|
||||||
info_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, 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);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
so_name = "/system/lib/libc_malloc_debug_qemu.so";
|
so_name = "/system/lib/libc_malloc_debug_qemu.so";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
info_log("%s: Debug level %d is unknown\n",
|
error_log("%s: Debug level %d is unknown\n",
|
||||||
__progname, debug_level);
|
__progname, debug_level);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -326,6 +353,36 @@ static void malloc_init_impl(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Initialize malloc debugging in the loaded module.
|
||||||
|
malloc_debug_initialize =
|
||||||
|
dlsym(libc_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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (malloc_debug_initialize()) {
|
||||||
|
dlclose(libc_malloc_impl_handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug_level == 20) {
|
||||||
|
// For memory checker we need to do extra initialization.
|
||||||
|
int (*memcheck_initialize)(int, const char*) =
|
||||||
|
dlsym(libc_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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) {
|
||||||
|
dlclose(libc_malloc_impl_handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize malloc dispatch table with appropriate routines.
|
// Initialize malloc dispatch table with appropriate routines.
|
||||||
switch (debug_level) {
|
switch (debug_level) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -374,8 +431,8 @@ static void malloc_init_impl(void)
|
|||||||
break;
|
break;
|
||||||
case 20:
|
case 20:
|
||||||
__libc_android_log_print(ANDROID_LOG_INFO, "libc",
|
__libc_android_log_print(ANDROID_LOG_INFO, "libc",
|
||||||
"%s using MALLOC_DEBUG = %d (instrumented for emulator)\n",
|
"%s[%u] using MALLOC_DEBUG = %d (instrumented for emulator)\n",
|
||||||
__progname, debug_level);
|
__progname, getpid(), debug_level);
|
||||||
gMallocUse.malloc =
|
gMallocUse.malloc =
|
||||||
dlsym(libc_malloc_impl_handle, "qemu_instrumented_malloc");
|
dlsym(libc_malloc_impl_handle, "qemu_instrumented_malloc");
|
||||||
gMallocUse.free =
|
gMallocUse.free =
|
||||||
@ -421,9 +478,8 @@ static pthread_once_t malloc_init_once_ctl = PTHREAD_ONCE_INIT;
|
|||||||
*/
|
*/
|
||||||
void malloc_debug_init(void)
|
void malloc_debug_init(void)
|
||||||
{
|
{
|
||||||
/* We need to initialize malloc iff we impelement here custom
|
/* We need to initialize malloc iff we implement here custom
|
||||||
* malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so
|
* malloc routines (i.e. USE_DL_PREFIX is defined) for libc.so */
|
||||||
*/
|
|
||||||
#if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
|
#if defined(USE_DL_PREFIX) && !defined(LIBC_STATIC)
|
||||||
if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
|
if (pthread_once(&malloc_init_once_ctl, malloc_init_impl)) {
|
||||||
error_log("Unable to initialize malloc_debug component.");
|
error_log("Unable to initialize malloc_debug component.");
|
||||||
|
@ -70,13 +70,28 @@ struct HashTable {
|
|||||||
/* Entry in malloc dispatch table. */
|
/* Entry in malloc dispatch table. */
|
||||||
typedef struct MallocDebug MallocDebug;
|
typedef struct MallocDebug MallocDebug;
|
||||||
struct MallocDebug {
|
struct MallocDebug {
|
||||||
|
/* Address of the actual malloc routine. */
|
||||||
void* (*malloc)(size_t bytes);
|
void* (*malloc)(size_t bytes);
|
||||||
|
/* Address of the actual free routine. */
|
||||||
void (*free)(void* mem);
|
void (*free)(void* mem);
|
||||||
|
/* Address of the actual calloc routine. */
|
||||||
void* (*calloc)(size_t n_elements, size_t elem_size);
|
void* (*calloc)(size_t n_elements, size_t elem_size);
|
||||||
|
/* Address of the actual realloc routine. */
|
||||||
void* (*realloc)(void* oldMem, size_t bytes);
|
void* (*realloc)(void* oldMem, size_t bytes);
|
||||||
|
/* Address of the actual memalign routine. */
|
||||||
void* (*memalign)(size_t alignment, size_t bytes);
|
void* (*memalign)(size_t alignment, size_t bytes);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Malloc debugging initialization routine.
|
||||||
|
* This routine must be implemented in .so modules that implement malloc
|
||||||
|
* debugging. This routine is called once per process from malloc_init_impl
|
||||||
|
* routine implemented in bionic/libc/bionic/malloc_debug_common.c when malloc
|
||||||
|
* debugging gets initialized for the process.
|
||||||
|
* Return:
|
||||||
|
* 0 on success, -1 on failure.
|
||||||
|
*/
|
||||||
|
typedef int (*MallocDebugInit)(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}; /* end of extern "C" */
|
}; /* end of extern "C" */
|
||||||
#endif
|
#endif
|
||||||
|
@ -629,3 +629,12 @@ void* leak_memalign(size_t alignment, size_t bytes)
|
|||||||
}
|
}
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initializes malloc debugging framework.
|
||||||
|
* See comments on MallocDebugInit in malloc_debug_common.h
|
||||||
|
*/
|
||||||
|
int malloc_debug_initialize(void)
|
||||||
|
{
|
||||||
|
// We don't really have anything that requires initialization here.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user