2009-11-17 23:13:38 +01:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2009 The Android Open Source Project
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* * Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in
|
|
|
|
* the documentation and/or other materials provided with the
|
|
|
|
* distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
|
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
|
|
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Contains definition of structures, global variables, and implementation of
|
|
|
|
// 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
|
|
|
|
// routines to be defined / implemented in libc.so library, regardless
|
|
|
|
// whether or not MALLOC_LEAK_CHECK macro is defined. To make things even
|
|
|
|
// more tricky, malloc leak detection code, implemented in
|
|
|
|
// libc_malloc_debug.so also requires access to these variables and routines
|
|
|
|
// (to fill allocation entry hash table, for example). So, all relevant
|
|
|
|
// variables and routines are defined / implemented here and exported
|
|
|
|
// to all, leak detection code and other components via dynamic (libc.so),
|
|
|
|
// or static (libc.a) linking.
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2012-10-12 01:08:51 +02:00
|
|
|
#include "malloc_debug_common.h"
|
|
|
|
|
2009-11-17 23:13:38 +01:00
|
|
|
#include <pthread.h>
|
2012-10-12 01:08:51 +02:00
|
|
|
#include <stdlib.h>
|
2009-11-17 23:13:38 +01:00
|
|
|
#include <unistd.h>
|
2012-10-12 01:08:51 +02:00
|
|
|
|
2013-10-10 00:50:50 +02:00
|
|
|
#include "private/ScopedPthreadMutexLocker.h"
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-07-10 02:16:07 +02:00
|
|
|
#if defined(USE_JEMALLOC)
|
|
|
|
#include "jemalloc.h"
|
|
|
|
#define Malloc(function) je_ ## function
|
|
|
|
#elif defined(USE_DLMALLOC)
|
|
|
|
#include "dlmalloc.h"
|
|
|
|
#define Malloc(function) dl ## function
|
|
|
|
#else
|
|
|
|
#error "Either one of USE_DLMALLOC or USE_JEMALLOC must be defined."
|
|
|
|
#endif
|
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
// In a VM process, this is set to 1 after fork()ing out of zygote.
|
2009-11-17 23:13:38 +01:00
|
|
|
int gMallocLeakZygoteChild = 0;
|
|
|
|
|
2014-06-04 21:07:11 +02:00
|
|
|
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))) = {
|
2014-06-10 04:14:11 +02:00
|
|
|
Malloc(calloc),
|
|
|
|
Malloc(free),
|
|
|
|
Malloc(mallinfo),
|
|
|
|
Malloc(malloc),
|
|
|
|
Malloc(malloc_usable_size),
|
|
|
|
Malloc(memalign),
|
|
|
|
Malloc(posix_memalign),
|
2014-06-14 03:04:31 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
Malloc(pvalloc),
|
2014-06-14 03:04:31 +02:00
|
|
|
#endif
|
2014-06-10 04:14:11 +02:00
|
|
|
Malloc(realloc),
|
2014-06-14 03:04:31 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
Malloc(valloc),
|
2014-06-14 03:04:31 +02:00
|
|
|
#endif
|
2014-06-04 21:07:11 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
// Selector of dispatch table to use for dispatching malloc calls.
|
2014-06-05 00:18:36 +02:00
|
|
|
// TODO: fix http://b/15432753 and make this static again.
|
|
|
|
const MallocDebug* __libc_malloc_dispatch = &__libc_malloc_default_dispatch;
|
2014-06-04 21:07:11 +02:00
|
|
|
|
|
|
|
// 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
|
2009-11-17 23:13:38 +01:00
|
|
|
|
|
|
|
// =============================================================================
|
|
|
|
// output functions
|
|
|
|
// =============================================================================
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
static int hash_entry_compare(const void* arg1, const void* arg2) {
|
2014-06-10 04:14:11 +02:00
|
|
|
int result;
|
|
|
|
|
|
|
|
const HashEntry* e1 = *static_cast<HashEntry* const*>(arg1);
|
|
|
|
const HashEntry* e2 = *static_cast<HashEntry* const*>(arg2);
|
|
|
|
|
|
|
|
// if one or both arg pointers are null, deal gracefully
|
|
|
|
if (e1 == NULL) {
|
|
|
|
result = (e2 == NULL) ? 0 : 1;
|
|
|
|
} else if (e2 == NULL) {
|
|
|
|
result = -1;
|
|
|
|
} else {
|
|
|
|
size_t nbAlloc1 = e1->allocations;
|
|
|
|
size_t nbAlloc2 = e2->allocations;
|
|
|
|
size_t size1 = e1->size & ~SIZE_FLAG_MASK;
|
|
|
|
size_t size2 = e2->size & ~SIZE_FLAG_MASK;
|
|
|
|
size_t alloc1 = nbAlloc1 * size1;
|
|
|
|
size_t alloc2 = nbAlloc2 * size2;
|
|
|
|
|
|
|
|
// sort in descending order by:
|
|
|
|
// 1) total size
|
|
|
|
// 2) number of allocations
|
|
|
|
//
|
|
|
|
// This is used for sorting, not determination of equality, so we don't
|
|
|
|
// need to compare the bit flags.
|
|
|
|
if (alloc1 > alloc2) {
|
|
|
|
result = -1;
|
|
|
|
} else if (alloc1 < alloc2) {
|
|
|
|
result = 1;
|
2009-11-17 23:13:38 +01:00
|
|
|
} else {
|
2014-06-10 04:14:11 +02:00
|
|
|
if (nbAlloc1 > nbAlloc2) {
|
|
|
|
result = -1;
|
|
|
|
} else if (nbAlloc1 < nbAlloc2) {
|
|
|
|
result = 1;
|
|
|
|
} else {
|
|
|
|
result = 0;
|
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
|
|
|
return result;
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Retrieve native heap information.
|
|
|
|
//
|
|
|
|
// "*info" is set to a buffer we allocate
|
|
|
|
// "*overallSize" is set to the size of the "info" buffer
|
|
|
|
// "*infoSize" is set to the size of a single entry
|
|
|
|
// "*totalMemory" is set to the sum of all allocations we're tracking; does
|
|
|
|
// not include heap overhead
|
|
|
|
// "*backtraceSize" is set to the maximum number of entries in the back trace
|
2014-05-17 01:29:55 +02:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// =============================================================================
|
2014-05-17 01:29:55 +02:00
|
|
|
// Exported for use by ddms.
|
2014-06-10 04:14:11 +02:00
|
|
|
// =============================================================================
|
2014-05-17 01:29:55 +02:00
|
|
|
extern "C" void get_malloc_leak_info(uint8_t** info, size_t* overallSize,
|
2014-06-10 04:14:11 +02:00
|
|
|
size_t* infoSize, size_t* totalMemory, size_t* backtraceSize) {
|
|
|
|
// Don't do anything if we have invalid arguments.
|
|
|
|
if (info == NULL || overallSize == NULL || infoSize == NULL ||
|
|
|
|
totalMemory == NULL || backtraceSize == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*totalMemory = 0;
|
|
|
|
|
|
|
|
ScopedPthreadMutexLocker locker(&g_hash_table.lock);
|
|
|
|
if (g_hash_table.count == 0) {
|
|
|
|
*info = NULL;
|
|
|
|
*overallSize = 0;
|
|
|
|
*infoSize = 0;
|
|
|
|
*backtraceSize = 0;
|
|
|
|
return;
|
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
HashEntry** list = static_cast<HashEntry**>(Malloc(malloc)(sizeof(void*) * g_hash_table.count));
|
|
|
|
|
|
|
|
// Get the entries into an array to be sorted.
|
|
|
|
size_t index = 0;
|
|
|
|
for (size_t i = 0 ; i < HASHTABLE_SIZE ; ++i) {
|
|
|
|
HashEntry* entry = g_hash_table.slots[i];
|
|
|
|
while (entry != NULL) {
|
|
|
|
list[index] = entry;
|
|
|
|
*totalMemory = *totalMemory + ((entry->size & ~SIZE_FLAG_MASK) * entry->allocations);
|
|
|
|
index++;
|
|
|
|
entry = entry->next;
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// XXX: the protocol doesn't allow variable size for the stack trace (yet)
|
|
|
|
*infoSize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * BACKTRACE_SIZE);
|
|
|
|
*overallSize = *infoSize * g_hash_table.count;
|
|
|
|
*backtraceSize = BACKTRACE_SIZE;
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// now get a byte array big enough for this
|
|
|
|
*info = static_cast<uint8_t*>(Malloc(malloc)(*overallSize));
|
|
|
|
if (*info == NULL) {
|
|
|
|
*overallSize = 0;
|
|
|
|
Malloc(free)(list);
|
|
|
|
return;
|
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
qsort(list, g_hash_table.count, sizeof(void*), hash_entry_compare);
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
uint8_t* head = *info;
|
|
|
|
const size_t count = g_hash_table.count;
|
|
|
|
for (size_t i = 0 ; i < count ; ++i) {
|
|
|
|
HashEntry* entry = list[i];
|
|
|
|
size_t entrySize = (sizeof(size_t) * 2) + (sizeof(uintptr_t) * entry->numEntries);
|
|
|
|
if (entrySize < *infoSize) {
|
|
|
|
// We're writing less than a full entry, clear out the rest.
|
|
|
|
memset(head + entrySize, 0, *infoSize - entrySize);
|
|
|
|
} else {
|
|
|
|
// Make sure the amount we're copying doesn't exceed the limit.
|
|
|
|
entrySize = *infoSize;
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
memcpy(head, &(entry->size), entrySize);
|
|
|
|
head += *infoSize;
|
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
Malloc(free)(list);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2014-05-17 01:29:55 +02:00
|
|
|
extern "C" void free_malloc_leak_info(uint8_t* info) {
|
2014-06-10 04:14:11 +02:00
|
|
|
Malloc(free)(info);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// =============================================================================
|
|
|
|
// Allocation functions
|
|
|
|
// =============================================================================
|
|
|
|
extern "C" void* calloc(size_t n_elements, size_t elem_size) {
|
|
|
|
return __libc_malloc_dispatch->calloc(n_elements, elem_size);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void free(void* mem) {
|
|
|
|
__libc_malloc_dispatch->free(mem);
|
2012-08-18 02:28:15 +02:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" struct mallinfo mallinfo() {
|
|
|
|
return __libc_malloc_dispatch->mallinfo();
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void* malloc(size_t bytes) {
|
|
|
|
return __libc_malloc_dispatch->malloc(bytes);
|
2012-08-21 03:28:20 +02:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" size_t malloc_usable_size(const void* mem) {
|
|
|
|
return __libc_malloc_dispatch->malloc_usable_size(mem);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2012-08-28 23:15:04 +02:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void* memalign(size_t alignment, size_t bytes) {
|
|
|
|
return __libc_malloc_dispatch->memalign(alignment, bytes);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2012-08-28 23:15:04 +02:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" int posix_memalign(void** memptr, size_t alignment, size_t size) {
|
|
|
|
return __libc_malloc_dispatch->posix_memalign(memptr, alignment, size);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2012-08-28 23:15:04 +02:00
|
|
|
|
2014-06-14 03:04:31 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void* pvalloc(size_t bytes) {
|
|
|
|
return __libc_malloc_dispatch->pvalloc(bytes);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-14 03:04:31 +02:00
|
|
|
#endif
|
2012-08-28 23:15:04 +02:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void* realloc(void* oldMem, size_t bytes) {
|
|
|
|
return __libc_malloc_dispatch->realloc(oldMem, bytes);
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2014-06-14 03:04:31 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
extern "C" void* valloc(size_t bytes) {
|
|
|
|
return __libc_malloc_dispatch->valloc(bytes);
|
2013-05-22 02:48:01 +02:00
|
|
|
}
|
2014-06-14 03:04:31 +02:00
|
|
|
#endif
|
2013-05-22 02:48:01 +02:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// We implement malloc debugging only in libc.so, so the code below
|
|
|
|
// must be excluded if we compile this file for static libc.a
|
2009-11-17 23:13:38 +01:00
|
|
|
#ifndef LIBC_STATIC
|
|
|
|
#include <sys/system_properties.h>
|
|
|
|
#include <dlfcn.h>
|
2012-08-28 23:15:04 +02:00
|
|
|
#include <stdio.h>
|
2013-10-10 00:50:50 +02:00
|
|
|
#include "private/libc_logging.h"
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2013-05-22 02:48:01 +02:00
|
|
|
template<typename FunctionType>
|
2013-10-03 23:59:05 +02:00
|
|
|
static void InitMallocFunction(void* malloc_impl_handler, FunctionType* func, const char* prefix, const char* suffix) {
|
2014-06-10 04:14:11 +02:00
|
|
|
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", getprogname(), symbol);
|
|
|
|
}
|
2013-05-22 02:48:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void InitMalloc(void* malloc_impl_handler, MallocDebug* table, const char* prefix) {
|
2014-06-10 04:14:11 +02:00
|
|
|
__libc_format_log(ANDROID_LOG_INFO, "libc", "%s: using libc.debug.malloc %d (%s)\n",
|
|
|
|
getprogname(), g_malloc_debug_level, prefix);
|
|
|
|
|
|
|
|
InitMallocFunction<MallocDebugCalloc>(malloc_impl_handler, &table->calloc, prefix, "calloc");
|
|
|
|
InitMallocFunction<MallocDebugFree>(malloc_impl_handler, &table->free, prefix, "free");
|
|
|
|
InitMallocFunction<MallocDebugMallinfo>(malloc_impl_handler, &table->mallinfo, prefix, "mallinfo");
|
|
|
|
InitMallocFunction<MallocDebugMalloc>(malloc_impl_handler, &table->malloc, prefix, "malloc");
|
|
|
|
InitMallocFunction<MallocDebugMallocUsableSize>(malloc_impl_handler, &table->malloc_usable_size, prefix, "malloc_usable_size");
|
|
|
|
InitMallocFunction<MallocDebugMemalign>(malloc_impl_handler, &table->memalign, prefix, "memalign");
|
|
|
|
InitMallocFunction<MallocDebugPosixMemalign>(malloc_impl_handler, &table->posix_memalign, prefix, "posix_memalign");
|
2014-06-14 03:04:31 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
InitMallocFunction<MallocDebugPvalloc>(malloc_impl_handler, &table->pvalloc, prefix, "pvalloc");
|
2014-06-14 03:04:31 +02:00
|
|
|
#endif
|
2014-06-10 04:14:11 +02:00
|
|
|
InitMallocFunction<MallocDebugRealloc>(malloc_impl_handler, &table->realloc, prefix, "realloc");
|
2014-06-14 03:04:31 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
InitMallocFunction<MallocDebugValloc>(malloc_impl_handler, &table->valloc, prefix, "valloc");
|
2014-06-14 03:04:31 +02:00
|
|
|
#endif
|
2012-08-28 23:15:04 +02:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Initializes memory allocation framework once per process.
|
2012-08-28 23:15:04 +02:00
|
|
|
static void malloc_init_impl() {
|
2014-06-10 04:14:11 +02:00
|
|
|
const char* so_name = NULL;
|
|
|
|
MallocDebugInit malloc_debug_initialize = NULL;
|
|
|
|
unsigned int qemu_running = 0;
|
|
|
|
unsigned int memcheck_enabled = 0;
|
|
|
|
char env[PROP_VALUE_MAX];
|
|
|
|
char memcheck_tracing[PROP_VALUE_MAX];
|
|
|
|
char debug_program[PROP_VALUE_MAX];
|
|
|
|
|
|
|
|
// Get custom malloc debug level. Note that emulator started with
|
|
|
|
// memory checking option will have priority over debug level set in
|
|
|
|
// 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.
|
|
|
|
g_malloc_debug_level = 20;
|
|
|
|
memcheck_enabled = 1;
|
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// If debug level has not been set by memcheck option in the emulator,
|
|
|
|
// lets grab it from libc.debug.malloc system property.
|
|
|
|
if (g_malloc_debug_level == 0 && __system_property_get("libc.debug.malloc", env)) {
|
|
|
|
g_malloc_debug_level = atoi(env);
|
|
|
|
}
|
2012-05-30 01:46:17 +02:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Debug level 0 means that we should use default allocation routines.
|
|
|
|
if (g_malloc_debug_level == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2013-01-23 03:35:14 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// If libc.debug.malloc.program is set and is not a substring of progname,
|
|
|
|
// then exit.
|
|
|
|
if (__system_property_get("libc.debug.malloc.program", debug_program)) {
|
|
|
|
if (!strstr(getprogname(), debug_program)) {
|
|
|
|
return;
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// mksh is way too leaky. http://b/7291287.
|
|
|
|
if (g_malloc_debug_level >= 10) {
|
|
|
|
if (strcmp(getprogname(), "sh") == 0 || strcmp(getprogname(), "/system/bin/sh") == 0) {
|
|
|
|
return;
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Choose the appropriate .so for the requested debug level.
|
|
|
|
switch (g_malloc_debug_level) {
|
|
|
|
case 1:
|
|
|
|
case 5:
|
|
|
|
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",
|
|
|
|
getprogname(), g_malloc_debug_level);
|
2010-02-12 17:59:58 +01:00
|
|
|
return;
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
|
|
|
// 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", getprogname());
|
2010-02-12 17:59:58 +01:00
|
|
|
return;
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
|
|
|
so_name = "libc_malloc_debug_qemu.so";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error_log("%s: Debug level %d is unknown\n", getprogname(), g_malloc_debug_level);
|
|
|
|
return;
|
|
|
|
}
|
2010-02-12 17:59:58 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Load .so that implements the required malloc debugging functionality.
|
|
|
|
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",
|
|
|
|
getprogname(), so_name, g_malloc_debug_level, dlerror());
|
|
|
|
return;
|
|
|
|
}
|
2010-02-12 17:59:58 +01:00
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Initialize malloc debugging in the loaded module.
|
|
|
|
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", getprogname(), so_name);
|
|
|
|
dlclose(malloc_impl_handle);
|
|
|
|
return;
|
|
|
|
}
|
2014-07-10 02:16:07 +02:00
|
|
|
if (!malloc_debug_initialize(&g_hash_table, &__libc_malloc_default_dispatch)) {
|
2014-06-10 04:14:11 +02:00
|
|
|
dlclose(malloc_impl_handle);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_malloc_debug_level == 20) {
|
|
|
|
// For memory checker we need to do extra initialization.
|
|
|
|
typedef int (*MemCheckInit)(int, const char*);
|
|
|
|
MemCheckInit memcheck_initialize =
|
|
|
|
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",
|
|
|
|
getprogname(), so_name);
|
|
|
|
dlclose(malloc_impl_handle);
|
|
|
|
return;
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
if (memcheck_initialize(MALLOC_ALIGNMENT, memcheck_tracing)) {
|
|
|
|
dlclose(malloc_impl_handle);
|
|
|
|
return;
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// No need to init the dispatch table because we can only get
|
|
|
|
// here if debug level is 1, 5, 10, or 20.
|
|
|
|
static MallocDebug malloc_dispatch_table __attribute__((aligned(32)));
|
|
|
|
switch (g_malloc_debug_level) {
|
|
|
|
case 1:
|
|
|
|
InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "leak");
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "fill");
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "chk");
|
|
|
|
break;
|
|
|
|
case 20:
|
|
|
|
InitMalloc(malloc_impl_handle, &malloc_dispatch_table, "qemu_instrumented");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure dispatch table is initialized
|
|
|
|
if ((malloc_dispatch_table.calloc == NULL) ||
|
|
|
|
(malloc_dispatch_table.free == NULL) ||
|
|
|
|
(malloc_dispatch_table.mallinfo == NULL) ||
|
|
|
|
(malloc_dispatch_table.malloc == NULL) ||
|
|
|
|
(malloc_dispatch_table.malloc_usable_size == NULL) ||
|
|
|
|
(malloc_dispatch_table.memalign == NULL) ||
|
|
|
|
(malloc_dispatch_table.posix_memalign == NULL) ||
|
2014-06-14 03:04:31 +02:00
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
2014-06-10 04:14:11 +02:00
|
|
|
(malloc_dispatch_table.pvalloc == NULL) ||
|
2014-06-14 03:04:31 +02:00
|
|
|
#endif
|
|
|
|
(malloc_dispatch_table.realloc == NULL)
|
|
|
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
|
|
|
|| (malloc_dispatch_table.valloc == NULL)
|
|
|
|
#endif
|
|
|
|
) {
|
2014-06-10 04:14:11 +02:00
|
|
|
error_log("%s: some symbols for libc.debug.malloc level %d were not found (see above)",
|
|
|
|
getprogname(), g_malloc_debug_level);
|
|
|
|
dlclose(malloc_impl_handle);
|
|
|
|
} else {
|
|
|
|
__libc_malloc_dispatch = &malloc_dispatch_table;
|
|
|
|
libc_malloc_impl_handle = malloc_impl_handle;
|
|
|
|
}
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
|
|
|
|
2012-08-28 23:15:04 +02:00
|
|
|
static void malloc_fini_impl() {
|
2014-06-10 04:14:11 +02:00
|
|
|
// Our BSD stdio implementation doesn't close the standard streams, it only flushes them.
|
|
|
|
// 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);
|
|
|
|
fclose(stdout);
|
|
|
|
fclose(stderr);
|
|
|
|
|
|
|
|
if (libc_malloc_impl_handle != NULL) {
|
|
|
|
MallocDebugFini malloc_debug_finalize =
|
|
|
|
reinterpret_cast<MallocDebugFini>(dlsym(libc_malloc_impl_handle, "malloc_debug_finalize"));
|
|
|
|
if (malloc_debug_finalize != NULL) {
|
|
|
|
malloc_debug_finalize(g_malloc_debug_level);
|
bionic: import heaptracker as chk_malloc
This patch is a rewrite of libc.debug.malloc = 10 (chk_malloc). It provides
the same features as the original (poison freed memory, detect heap overruns
and underruns), except that it provides more debugging information whenever it
detects a problem.
In addition to the original features, the new chk_malloc() implementation
detects multiple frees within a given range of the last N allocations, N being
configurable via the system property libc.debug.malloc.backlog.
Finally, this patch keeps track of all outstanding memory allocations. On
program exit, we walk that list and report each outstanding allocation.
(There is support (not enabled) for a scanner thread periodically walks over
the list of outstanding allocations as well as the backlog of recently-freed
allocations, checking for heap-usage errors.)
Feature overview:
1) memory leaks
2) multiple frees
3) use after free
4) overrun
Implementation:
-- for each allocation, there is a:
1) stack trace at the time the allocation is made
2) if the memory is freed, there is also a stack trace at the point
3) a front and rear guard (fence)
4) the stack traces are kept together with the allocation
-- the following lists and maintained
1) all outstanding memory allocations
3) a backlog of allocations what are freed; when you call free(), instead of
actually freed, the allocation is moved to this backlog;
4) when the backlog of allocations gets full, the oldest entry gets evicted
from it; at that point, the allocation is checked for overruns or
use-after-free errors, and then actually freed.
5) when the program exits, the list of outstanding allocations and the
backlog are inspected for errors, then freed;
To use this, set the following system properties before running the process or
processes you want to inspect:
libc.malloc.debug.backlog # defaults to 100
libc.malloc.debug 10
When a problem is detected, you will see the following on logcat for a multiple
free:
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 BYTES MULTIPLY FREED!
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 4009647c /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 FIRST FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096490 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 NOW BEING FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c6ac /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964a0 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a heap overrun and underrun:
E/libc ( 7233): +++ REAR GUARD MISMATCH [10, 11)
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 HAS A CORRUPTED REAR GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096438 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096462 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 HAS A CORRUPTED FRONT GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964ba /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964e4 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a memory leak:
E/libc ( 7233): +++ THERE ARE 1 LEAKED ALLOCATIONS
E/libc ( 7233): +++ DELETING 4096 BYTES OF LEAKED MEMORY AT 0x404b95e8 (1 REMAINING)
E/libc ( 7233): +++ ALLOCATION 0x404b95e8 SIZE 4096 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 0001bc94 /system/lib/libc.so
E/libc ( 7233): #04 pc 0001edf6 /system/lib/libc.so
E/libc ( 7233): #05 pc 0001b80a /system/lib/libc.so
E/libc ( 7233): #06 pc 0001c086 /system/lib/libc.so
E/libc ( 7233): #07 pc 40096402 /system/bin/malloctest
E/libc ( 7233): #08 pc 00016f24 /system/lib/libc.so
Change-Id: Ic440e9d05a01e2ea86b25e8998714e88bc2d16e0
Signed-off-by: Iliyan Malchev <malchev@google.com>
2012-05-29 23:22:42 +02:00
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
}
|
bionic: import heaptracker as chk_malloc
This patch is a rewrite of libc.debug.malloc = 10 (chk_malloc). It provides
the same features as the original (poison freed memory, detect heap overruns
and underruns), except that it provides more debugging information whenever it
detects a problem.
In addition to the original features, the new chk_malloc() implementation
detects multiple frees within a given range of the last N allocations, N being
configurable via the system property libc.debug.malloc.backlog.
Finally, this patch keeps track of all outstanding memory allocations. On
program exit, we walk that list and report each outstanding allocation.
(There is support (not enabled) for a scanner thread periodically walks over
the list of outstanding allocations as well as the backlog of recently-freed
allocations, checking for heap-usage errors.)
Feature overview:
1) memory leaks
2) multiple frees
3) use after free
4) overrun
Implementation:
-- for each allocation, there is a:
1) stack trace at the time the allocation is made
2) if the memory is freed, there is also a stack trace at the point
3) a front and rear guard (fence)
4) the stack traces are kept together with the allocation
-- the following lists and maintained
1) all outstanding memory allocations
3) a backlog of allocations what are freed; when you call free(), instead of
actually freed, the allocation is moved to this backlog;
4) when the backlog of allocations gets full, the oldest entry gets evicted
from it; at that point, the allocation is checked for overruns or
use-after-free errors, and then actually freed.
5) when the program exits, the list of outstanding allocations and the
backlog are inspected for errors, then freed;
To use this, set the following system properties before running the process or
processes you want to inspect:
libc.malloc.debug.backlog # defaults to 100
libc.malloc.debug 10
When a problem is detected, you will see the following on logcat for a multiple
free:
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 BYTES MULTIPLY FREED!
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 4009647c /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 FIRST FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096490 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 NOW BEING FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c6ac /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964a0 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a heap overrun and underrun:
E/libc ( 7233): +++ REAR GUARD MISMATCH [10, 11)
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 HAS A CORRUPTED REAR GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096438 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096462 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 HAS A CORRUPTED FRONT GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964ba /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964e4 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a memory leak:
E/libc ( 7233): +++ THERE ARE 1 LEAKED ALLOCATIONS
E/libc ( 7233): +++ DELETING 4096 BYTES OF LEAKED MEMORY AT 0x404b95e8 (1 REMAINING)
E/libc ( 7233): +++ ALLOCATION 0x404b95e8 SIZE 4096 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 0001bc94 /system/lib/libc.so
E/libc ( 7233): #04 pc 0001edf6 /system/lib/libc.so
E/libc ( 7233): #05 pc 0001b80a /system/lib/libc.so
E/libc ( 7233): #06 pc 0001c086 /system/lib/libc.so
E/libc ( 7233): #07 pc 40096402 /system/bin/malloctest
E/libc ( 7233): #08 pc 00016f24 /system/lib/libc.so
Change-Id: Ic440e9d05a01e2ea86b25e8998714e88bc2d16e0
Signed-off-by: Iliyan Malchev <malchev@google.com>
2012-05-29 23:22:42 +02:00
|
|
|
}
|
|
|
|
|
2009-11-17 23:13:38 +01:00
|
|
|
#endif // !LIBC_STATIC
|
|
|
|
|
2014-06-10 04:14:11 +02:00
|
|
|
// Initializes memory allocation framework.
|
|
|
|
// This routine is called from __libc_init routines implemented
|
|
|
|
// in libc_init_static.c and libc_init_dynamic.c files.
|
2013-04-12 10:13:34 +02:00
|
|
|
extern "C" __LIBC_HIDDEN__ void malloc_debug_init() {
|
2014-06-10 04:14:11 +02:00
|
|
|
#if !defined(LIBC_STATIC)
|
2014-06-04 21:07:11 +02:00
|
|
|
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.");
|
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
#endif // !LIBC_STATIC
|
2009-11-17 23:13:38 +01:00
|
|
|
}
|
bionic: import heaptracker as chk_malloc
This patch is a rewrite of libc.debug.malloc = 10 (chk_malloc). It provides
the same features as the original (poison freed memory, detect heap overruns
and underruns), except that it provides more debugging information whenever it
detects a problem.
In addition to the original features, the new chk_malloc() implementation
detects multiple frees within a given range of the last N allocations, N being
configurable via the system property libc.debug.malloc.backlog.
Finally, this patch keeps track of all outstanding memory allocations. On
program exit, we walk that list and report each outstanding allocation.
(There is support (not enabled) for a scanner thread periodically walks over
the list of outstanding allocations as well as the backlog of recently-freed
allocations, checking for heap-usage errors.)
Feature overview:
1) memory leaks
2) multiple frees
3) use after free
4) overrun
Implementation:
-- for each allocation, there is a:
1) stack trace at the time the allocation is made
2) if the memory is freed, there is also a stack trace at the point
3) a front and rear guard (fence)
4) the stack traces are kept together with the allocation
-- the following lists and maintained
1) all outstanding memory allocations
3) a backlog of allocations what are freed; when you call free(), instead of
actually freed, the allocation is moved to this backlog;
4) when the backlog of allocations gets full, the oldest entry gets evicted
from it; at that point, the allocation is checked for overruns or
use-after-free errors, and then actually freed.
5) when the program exits, the list of outstanding allocations and the
backlog are inspected for errors, then freed;
To use this, set the following system properties before running the process or
processes you want to inspect:
libc.malloc.debug.backlog # defaults to 100
libc.malloc.debug 10
When a problem is detected, you will see the following on logcat for a multiple
free:
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 BYTES MULTIPLY FREED!
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 4009647c /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 FIRST FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096490 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 NOW BEING FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c6ac /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964a0 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a heap overrun and underrun:
E/libc ( 7233): +++ REAR GUARD MISMATCH [10, 11)
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 HAS A CORRUPTED REAR GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096438 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096462 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 HAS A CORRUPTED FRONT GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964ba /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964e4 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a memory leak:
E/libc ( 7233): +++ THERE ARE 1 LEAKED ALLOCATIONS
E/libc ( 7233): +++ DELETING 4096 BYTES OF LEAKED MEMORY AT 0x404b95e8 (1 REMAINING)
E/libc ( 7233): +++ ALLOCATION 0x404b95e8 SIZE 4096 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 0001bc94 /system/lib/libc.so
E/libc ( 7233): #04 pc 0001edf6 /system/lib/libc.so
E/libc ( 7233): #05 pc 0001b80a /system/lib/libc.so
E/libc ( 7233): #06 pc 0001c086 /system/lib/libc.so
E/libc ( 7233): #07 pc 40096402 /system/bin/malloctest
E/libc ( 7233): #08 pc 00016f24 /system/lib/libc.so
Change-Id: Ic440e9d05a01e2ea86b25e8998714e88bc2d16e0
Signed-off-by: Iliyan Malchev <malchev@google.com>
2012-05-29 23:22:42 +02:00
|
|
|
|
2013-04-12 10:13:34 +02:00
|
|
|
extern "C" __LIBC_HIDDEN__ void malloc_debug_fini() {
|
2014-06-10 04:14:11 +02:00
|
|
|
#if !defined(LIBC_STATIC)
|
2014-06-04 21:07:11 +02:00
|
|
|
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.");
|
|
|
|
}
|
2014-06-10 04:14:11 +02:00
|
|
|
#endif // !LIBC_STATIC
|
bionic: import heaptracker as chk_malloc
This patch is a rewrite of libc.debug.malloc = 10 (chk_malloc). It provides
the same features as the original (poison freed memory, detect heap overruns
and underruns), except that it provides more debugging information whenever it
detects a problem.
In addition to the original features, the new chk_malloc() implementation
detects multiple frees within a given range of the last N allocations, N being
configurable via the system property libc.debug.malloc.backlog.
Finally, this patch keeps track of all outstanding memory allocations. On
program exit, we walk that list and report each outstanding allocation.
(There is support (not enabled) for a scanner thread periodically walks over
the list of outstanding allocations as well as the backlog of recently-freed
allocations, checking for heap-usage errors.)
Feature overview:
1) memory leaks
2) multiple frees
3) use after free
4) overrun
Implementation:
-- for each allocation, there is a:
1) stack trace at the time the allocation is made
2) if the memory is freed, there is also a stack trace at the point
3) a front and rear guard (fence)
4) the stack traces are kept together with the allocation
-- the following lists and maintained
1) all outstanding memory allocations
3) a backlog of allocations what are freed; when you call free(), instead of
actually freed, the allocation is moved to this backlog;
4) when the backlog of allocations gets full, the oldest entry gets evicted
from it; at that point, the allocation is checked for overruns or
use-after-free errors, and then actually freed.
5) when the program exits, the list of outstanding allocations and the
backlog are inspected for errors, then freed;
To use this, set the following system properties before running the process or
processes you want to inspect:
libc.malloc.debug.backlog # defaults to 100
libc.malloc.debug 10
When a problem is detected, you will see the following on logcat for a multiple
free:
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 BYTES MULTIPLY FREED!
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 4009647c /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 FIRST FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096490 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9278 SIZE 10 NOW BEING FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c6ac /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964a0 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a heap overrun and underrun:
E/libc ( 7233): +++ REAR GUARD MISMATCH [10, 11)
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 HAS A CORRUPTED REAR GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096438 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9198 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 40096462 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 HAS A CORRUPTED FRONT GUARD
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964ba /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
E/libc ( 7233): +++ ALLOCATION 0x404b9358 SIZE 10 FREED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c7d2 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d94 /system/lib/libc.so
E/libc ( 7233): #03 pc 400964e4 /system/bin/malloctest
E/libc ( 7233): #04 pc 00016f24 /system/lib/libc.so
The following for a memory leak:
E/libc ( 7233): +++ THERE ARE 1 LEAKED ALLOCATIONS
E/libc ( 7233): +++ DELETING 4096 BYTES OF LEAKED MEMORY AT 0x404b95e8 (1 REMAINING)
E/libc ( 7233): +++ ALLOCATION 0x404b95e8 SIZE 4096 ALLOCATED HERE:
E/libc ( 7233): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
E/libc ( 7233): #00 pc 0000c35a /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #01 pc 0000c658 /system/lib/libc_malloc_debug_leak.so
E/libc ( 7233): #02 pc 00016d80 /system/lib/libc.so
E/libc ( 7233): #03 pc 0001bc94 /system/lib/libc.so
E/libc ( 7233): #04 pc 0001edf6 /system/lib/libc.so
E/libc ( 7233): #05 pc 0001b80a /system/lib/libc.so
E/libc ( 7233): #06 pc 0001c086 /system/lib/libc.so
E/libc ( 7233): #07 pc 40096402 /system/bin/malloctest
E/libc ( 7233): #08 pc 00016f24 /system/lib/libc.so
Change-Id: Ic440e9d05a01e2ea86b25e8998714e88bc2d16e0
Signed-off-by: Iliyan Malchev <malchev@google.com>
2012-05-29 23:22:42 +02:00
|
|
|
}
|