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
This commit is contained in:
Elliott Hughes 2014-06-04 12:07:11 -07:00
parent e120cba31d
commit 8e52e8fe83
5 changed files with 175 additions and 205 deletions

View file

@ -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();
}

View file

@ -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
}

View file

@ -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

View file

@ -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);
if (mem == NULL) {
return;
}
// check the guard to make sure it is valid
AllocationEntry* header = to_header(mem);
ScopedPthreadMutexLocker locker(&g_hash_table->lock);
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);
}
}
// check the guard to make sure it is valid
AllocationEntry* header = to_header(mem);
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);
}
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;

View file

@ -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;
}