Merge "Use libunwindbacktrace for debug malloc code."
This commit is contained in:
commit
4ad5066e1d
@ -980,8 +980,6 @@ LOCAL_SRC_FILES := \
|
|||||||
$(libc_arch_dynamic_src_files) \
|
$(libc_arch_dynamic_src_files) \
|
||||||
$(libc_static_common_src_files) \
|
$(libc_static_common_src_files) \
|
||||||
bionic/malloc_debug_common.cpp \
|
bionic/malloc_debug_common.cpp \
|
||||||
bionic/debug_mapinfo.cpp \
|
|
||||||
bionic/debug_stacktrace.cpp \
|
|
||||||
bionic/libc_init_dynamic.cpp \
|
bionic/libc_init_dynamic.cpp \
|
||||||
bionic/NetdClient.cpp \
|
bionic/NetdClient.cpp \
|
||||||
|
|
||||||
@ -1047,7 +1045,10 @@ LOCAL_CFLAGS := \
|
|||||||
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
|
LOCAL_CONLYFLAGS := $(libc_common_conlyflags)
|
||||||
LOCAL_CPPFLAGS := $(libc_common_cppflags)
|
LOCAL_CPPFLAGS := $(libc_common_cppflags)
|
||||||
|
|
||||||
LOCAL_C_INCLUDES := $(libc_common_c_includes)
|
# Make sure that unwind.h comes from libunwind.
|
||||||
|
LOCAL_C_INCLUDES := \
|
||||||
|
external/libunwind/include \
|
||||||
|
$(libc_common_c_includes) \
|
||||||
|
|
||||||
LOCAL_SRC_FILES := \
|
LOCAL_SRC_FILES := \
|
||||||
bionic/debug_mapinfo.cpp \
|
bionic/debug_mapinfo.cpp \
|
||||||
@ -1062,6 +1063,7 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(libc_common_additional_dependencies)
|
|||||||
|
|
||||||
LOCAL_SHARED_LIBRARIES := libc libdl
|
LOCAL_SHARED_LIBRARIES := libc libdl
|
||||||
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
LOCAL_SYSTEM_SHARED_LIBRARIES :=
|
||||||
|
LOCAL_WHOLE_STATIC_LIBRARIES := libunwindbacktrace
|
||||||
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
|
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
|
||||||
|
|
||||||
# Don't install on release build
|
# Don't install on release build
|
||||||
|
@ -26,39 +26,48 @@
|
|||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/mman.h>
|
|
||||||
|
|
||||||
#include "debug_mapinfo.h"
|
#include "debug_mapinfo.h"
|
||||||
|
#include "malloc_debug_disable.h"
|
||||||
|
|
||||||
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
|
// Format of /proc/<PID>/maps:
|
||||||
// 012345678901234567890123456789012345678901234567890123456789
|
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
|
||||||
// 0 1 2 3 4 5
|
|
||||||
|
|
||||||
static mapinfo_t* parse_maps_line(char* line) {
|
static mapinfo_t* parse_maps_line(char* line) {
|
||||||
int len = strlen(line);
|
uintptr_t start;
|
||||||
|
uintptr_t end;
|
||||||
|
int name_pos;
|
||||||
|
if (sscanf(line, "%" PRIxPTR "-%" PRIxPTR " %*4s %*x %*x:%*x %*d%n", &start,
|
||||||
|
&end, &name_pos) < 2) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (len < 1) return 0;
|
while (isspace(line[name_pos])) {
|
||||||
line[--len] = 0;
|
name_pos += 1;
|
||||||
|
}
|
||||||
if (len < 50) return 0;
|
const char* name = line + name_pos;
|
||||||
if (line[20] != 'x') return 0;
|
size_t name_len = strlen(name);
|
||||||
|
if (name_len && name[name_len - 1] == '\n') {
|
||||||
mapinfo_t* mi = static_cast<mapinfo_t*>(
|
name_len -= 1;
|
||||||
mmap(NULL, sizeof(mapinfo_t) + (len - 47), PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0));
|
}
|
||||||
if (mi == MAP_FAILED) return 0;
|
|
||||||
|
|
||||||
mi->start = strtoul(line, 0, 16);
|
|
||||||
mi->end = strtoul(line + 9, 0, 16);
|
|
||||||
mi->next = 0;
|
|
||||||
strcpy(mi->name, line + 49);
|
|
||||||
|
|
||||||
|
mapinfo_t* mi = reinterpret_cast<mapinfo_t*>(calloc(1, sizeof(mapinfo_t) + name_len + 1));
|
||||||
|
if (mi) {
|
||||||
|
mi->start = start;
|
||||||
|
mi->end = end;
|
||||||
|
memcpy(mi->name, name, name_len);
|
||||||
|
mi->name[name_len] = '\0';
|
||||||
|
}
|
||||||
return mi;
|
return mi;
|
||||||
}
|
}
|
||||||
|
|
||||||
__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(pid_t pid) {
|
__LIBC_HIDDEN__ mapinfo_t* mapinfo_create(pid_t pid) {
|
||||||
|
ScopedDisableDebugCalls disable;
|
||||||
|
|
||||||
struct mapinfo_t* milist = NULL;
|
struct mapinfo_t* milist = NULL;
|
||||||
char data[1024]; // Used to read lines as well as to construct the filename.
|
char data[1024]; // Used to read lines as well as to construct the filename.
|
||||||
snprintf(data, sizeof(data), "/proc/%d/maps", pid);
|
snprintf(data, sizeof(data), "/proc/%d/maps", pid);
|
||||||
@ -77,10 +86,12 @@ __LIBC_HIDDEN__ mapinfo_t* mapinfo_create(pid_t pid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
|
__LIBC_HIDDEN__ void mapinfo_destroy(mapinfo_t* mi) {
|
||||||
|
ScopedDisableDebugCalls disable;
|
||||||
|
|
||||||
while (mi != NULL) {
|
while (mi != NULL) {
|
||||||
mapinfo_t* del = mi;
|
mapinfo_t* del = mi;
|
||||||
mi = mi->next;
|
mi = mi->next;
|
||||||
munmap(del, sizeof(mapinfo_t) + strlen(del->name) + 2);
|
free(del);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@
|
|||||||
|
|
||||||
struct mapinfo_t {
|
struct mapinfo_t {
|
||||||
struct mapinfo_t* next;
|
struct mapinfo_t* next;
|
||||||
unsigned start;
|
uintptr_t start;
|
||||||
unsigned end;
|
uintptr_t end;
|
||||||
char name[];
|
char name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "debug_mapinfo.h"
|
#include "debug_mapinfo.h"
|
||||||
|
#include "malloc_debug_disable.h"
|
||||||
#include "private/libc_logging.h"
|
#include "private/libc_logging.h"
|
||||||
|
|
||||||
#if defined(__LP64__)
|
#if defined(__LP64__)
|
||||||
@ -56,6 +57,8 @@ typedef char* (*DemanglerFn)(const char*, char*, size_t*, int*);
|
|||||||
static DemanglerFn g_demangler_fn = NULL;
|
static DemanglerFn g_demangler_fn = NULL;
|
||||||
|
|
||||||
__LIBC_HIDDEN__ void backtrace_startup() {
|
__LIBC_HIDDEN__ void backtrace_startup() {
|
||||||
|
ScopedDisableDebugCalls disable;
|
||||||
|
|
||||||
g_map_info = mapinfo_create(getpid());
|
g_map_info = mapinfo_create(getpid());
|
||||||
g_demangler = dlopen("libgccdemangle.so", RTLD_NOW);
|
g_demangler = dlopen("libgccdemangle.so", RTLD_NOW);
|
||||||
if (g_demangler != NULL) {
|
if (g_demangler != NULL) {
|
||||||
@ -65,6 +68,8 @@ __LIBC_HIDDEN__ void backtrace_startup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
__LIBC_HIDDEN__ void backtrace_shutdown() {
|
__LIBC_HIDDEN__ void backtrace_shutdown() {
|
||||||
|
ScopedDisableDebugCalls disable;
|
||||||
|
|
||||||
mapinfo_destroy(g_map_info);
|
mapinfo_destroy(g_map_info);
|
||||||
dlclose(g_demangler);
|
dlclose(g_demangler);
|
||||||
}
|
}
|
||||||
@ -98,7 +103,7 @@ static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg)
|
|||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __arm__
|
#if defined(__arm__)
|
||||||
/*
|
/*
|
||||||
* The instruction pointer is pointing at the instruction after the bl(x), and
|
* The instruction pointer is pointing at the instruction after the bl(x), and
|
||||||
* the _Unwind_Backtrace routine already masks the Thumb mode indicator (LSB
|
* the _Unwind_Backtrace routine already masks the Thumb mode indicator (LSB
|
||||||
@ -121,12 +126,16 @@ static _Unwind_Reason_Code trace_function(__unwind_context* context, void* arg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
__LIBC_HIDDEN__ int get_backtrace(uintptr_t* frames, size_t max_depth) {
|
__LIBC_HIDDEN__ int get_backtrace(uintptr_t* frames, size_t max_depth) {
|
||||||
|
ScopedDisableDebugCalls disable;
|
||||||
|
|
||||||
stack_crawl_state_t state(frames, max_depth);
|
stack_crawl_state_t state(frames, max_depth);
|
||||||
_Unwind_Backtrace(trace_function, &state);
|
_Unwind_Backtrace(trace_function, &state);
|
||||||
return state.frame_count;
|
return state.frame_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
__LIBC_HIDDEN__ void log_backtrace(uintptr_t* frames, size_t frame_count) {
|
__LIBC_HIDDEN__ void log_backtrace(uintptr_t* frames, size_t frame_count) {
|
||||||
|
ScopedDisableDebugCalls disable;
|
||||||
|
|
||||||
uintptr_t self_bt[16];
|
uintptr_t self_bt[16];
|
||||||
if (frames == NULL) {
|
if (frames == NULL) {
|
||||||
frame_count = get_backtrace(self_bt, 16);
|
frame_count = get_backtrace(self_bt, 16);
|
||||||
@ -146,7 +155,7 @@ __LIBC_HIDDEN__ void log_backtrace(uintptr_t* frames, size_t frame_count) {
|
|||||||
symbol = info.dli_sname;
|
symbol = info.dli_sname;
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t rel_pc;
|
uintptr_t rel_pc = offset;
|
||||||
const mapinfo_t* mi = (g_map_info != NULL) ? mapinfo_find(g_map_info, frames[i], &rel_pc) : NULL;
|
const mapinfo_t* mi = (g_map_info != NULL) ? mapinfo_find(g_map_info, frames[i], &rel_pc) : NULL;
|
||||||
const char* soname = (mi != NULL) ? mi->name : info.dli_fname;
|
const char* soname = (mi != NULL) ? mi->name : info.dli_fname;
|
||||||
if (soname == NULL) {
|
if (soname == NULL) {
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "debug_mapinfo.h"
|
#include "debug_mapinfo.h"
|
||||||
#include "debug_stacktrace.h"
|
#include "debug_stacktrace.h"
|
||||||
#include "malloc_debug_common.h"
|
#include "malloc_debug_common.h"
|
||||||
|
#include "malloc_debug_disable.h"
|
||||||
#include "private/bionic_macros.h"
|
#include "private/bionic_macros.h"
|
||||||
#include "private/libc_logging.h"
|
#include "private/libc_logging.h"
|
||||||
#include "private/ScopedPthreadMutexLocker.h"
|
#include "private/ScopedPthreadMutexLocker.h"
|
||||||
@ -331,6 +332,9 @@ static inline void add_to_backlog(hdr_t* hdr) {
|
|||||||
|
|
||||||
extern "C" void* chk_malloc(size_t bytes) {
|
extern "C" void* chk_malloc(size_t bytes) {
|
||||||
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->malloc(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
size_t size = sizeof(hdr_t) + bytes + sizeof(ftr_t);
|
size_t size = sizeof(hdr_t) + bytes + sizeof(ftr_t);
|
||||||
if (size < bytes) { // Overflow
|
if (size < bytes) { // Overflow
|
||||||
@ -348,6 +352,10 @@ extern "C" void* chk_malloc(size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* chk_memalign(size_t alignment, size_t bytes) {
|
extern "C" void* chk_memalign(size_t alignment, size_t bytes) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->memalign(alignment, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (alignment <= MALLOC_ALIGNMENT) {
|
if (alignment <= MALLOC_ALIGNMENT) {
|
||||||
return chk_malloc(bytes);
|
return chk_malloc(bytes);
|
||||||
}
|
}
|
||||||
@ -386,6 +394,9 @@ extern "C" void* chk_memalign(size_t alignment, size_t bytes) {
|
|||||||
|
|
||||||
extern "C" void chk_free(void* ptr) {
|
extern "C" void chk_free(void* ptr) {
|
||||||
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ptr) /* ignore free(NULL) */
|
if (!ptr) /* ignore free(NULL) */
|
||||||
return;
|
return;
|
||||||
@ -421,6 +432,9 @@ extern "C" void chk_free(void* ptr) {
|
|||||||
|
|
||||||
extern "C" void* chk_realloc(void* ptr, size_t bytes) {
|
extern "C" void* chk_realloc(void* ptr, size_t bytes) {
|
||||||
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->realloc(ptr, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
return chk_malloc(bytes);
|
return chk_malloc(bytes);
|
||||||
@ -496,6 +510,10 @@ extern "C" void* chk_realloc(void* ptr, size_t bytes) {
|
|||||||
|
|
||||||
extern "C" void* chk_calloc(size_t nmemb, size_t bytes) {
|
extern "C" void* chk_calloc(size_t nmemb, size_t bytes) {
|
||||||
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
// log_message("%s: %s\n", __FILE__, __FUNCTION__);
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->calloc(nmemb, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
size_t total_bytes = nmemb * bytes;
|
size_t total_bytes = nmemb * bytes;
|
||||||
size_t size = sizeof(hdr_t) + total_bytes + sizeof(ftr_t);
|
size_t size = sizeof(hdr_t) + total_bytes + sizeof(ftr_t);
|
||||||
if (size < total_bytes || (nmemb && SIZE_MAX / nmemb < bytes)) { // Overflow
|
if (size < total_bytes || (nmemb && SIZE_MAX / nmemb < bytes)) { // Overflow
|
||||||
@ -513,6 +531,10 @@ extern "C" void* chk_calloc(size_t nmemb, size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" size_t chk_malloc_usable_size(const void* ptr) {
|
extern "C" size_t chk_malloc_usable_size(const void* ptr) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->malloc_usable_size(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
// malloc_usable_size returns 0 for NULL and unknown blocks.
|
// malloc_usable_size returns 0 for NULL and unknown blocks.
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
@ -529,6 +551,10 @@ extern "C" struct mallinfo chk_mallinfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int chk_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
extern "C" int chk_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->posix_memalign(memptr, alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (!powerof2(alignment)) {
|
if (!powerof2(alignment)) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -538,7 +564,12 @@ extern "C" int chk_posix_memalign(void** memptr, size_t alignment, size_t size)
|
|||||||
return (*memptr != NULL) ? 0 : ENOMEM;
|
return (*memptr != NULL) ? 0 : ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
||||||
extern "C" void* chk_pvalloc(size_t bytes) {
|
extern "C" void* chk_pvalloc(size_t bytes) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->pvalloc(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
size_t pagesize = getpagesize();
|
size_t pagesize = getpagesize();
|
||||||
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
||||||
if (size < bytes) { // Overflow
|
if (size < bytes) { // Overflow
|
||||||
@ -548,10 +579,16 @@ extern "C" void* chk_pvalloc(size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* chk_valloc(size_t size) {
|
extern "C" void* chk_valloc(size_t size) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->valloc(size);
|
||||||
|
}
|
||||||
return chk_memalign(getpagesize(), size);
|
return chk_memalign(getpagesize(), size);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static void ReportMemoryLeaks() {
|
static void ReportMemoryLeaks() {
|
||||||
|
ScopedDisableDebugCalls disable;
|
||||||
|
|
||||||
// Use /proc/self/exe link to obtain the program name for logging
|
// Use /proc/self/exe link to obtain the program name for logging
|
||||||
// purposes. If it's not available, we set it to "<unknown>".
|
// purposes. If it's not available, we set it to "<unknown>".
|
||||||
char exe[PATH_MAX];
|
char exe[PATH_MAX];
|
||||||
@ -585,10 +622,14 @@ static void ReportMemoryLeaks() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pthread_key_t g_debug_calls_disabled;
|
||||||
|
|
||||||
extern "C" bool malloc_debug_initialize(HashTable* hash_table, const MallocDebug* malloc_dispatch) {
|
extern "C" bool malloc_debug_initialize(HashTable* hash_table, const MallocDebug* malloc_dispatch) {
|
||||||
g_hash_table = hash_table;
|
g_hash_table = hash_table;
|
||||||
g_malloc_dispatch = malloc_dispatch;
|
g_malloc_dispatch = malloc_dispatch;
|
||||||
|
|
||||||
|
pthread_key_create(&g_debug_calls_disabled, NULL);
|
||||||
|
|
||||||
char debug_backlog[PROP_VALUE_MAX];
|
char debug_backlog[PROP_VALUE_MAX];
|
||||||
if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
|
if (__system_property_get("libc.debug.malloc.backlog", debug_backlog)) {
|
||||||
g_malloc_debug_backlog = atoi(debug_backlog);
|
g_malloc_debug_backlog = atoi(debug_backlog);
|
||||||
@ -605,4 +646,6 @@ extern "C" void malloc_debug_finalize(int malloc_debug_level) {
|
|||||||
ReportMemoryLeaks();
|
ReportMemoryLeaks();
|
||||||
}
|
}
|
||||||
backtrace_shutdown();
|
backtrace_shutdown();
|
||||||
|
|
||||||
|
pthread_setspecific(g_debug_calls_disabled, NULL);
|
||||||
}
|
}
|
||||||
|
64
libc/bionic/malloc_debug_disable.h
Normal file
64
libc/bionic/malloc_debug_disable.h
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MALLOC_DEBUG_DISABLE_H
|
||||||
|
#define MALLOC_DEBUG_DISABLE_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "private/bionic_macros.h"
|
||||||
|
|
||||||
|
// =============================================================================
|
||||||
|
// Used to disable the debug allocation calls.
|
||||||
|
// =============================================================================
|
||||||
|
extern pthread_key_t g_debug_calls_disabled;
|
||||||
|
|
||||||
|
static inline bool DebugCallsDisabled() {
|
||||||
|
return pthread_getspecific(g_debug_calls_disabled) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ScopedDisableDebugCalls {
|
||||||
|
public:
|
||||||
|
ScopedDisableDebugCalls() : disabled_(DebugCallsDisabled()) {
|
||||||
|
if (!disabled_) {
|
||||||
|
pthread_setspecific(g_debug_calls_disabled, reinterpret_cast<const void*>(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~ScopedDisableDebugCalls() {
|
||||||
|
if (!disabled_) {
|
||||||
|
pthread_setspecific(g_debug_calls_disabled, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool disabled_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(ScopedDisableDebugCalls);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // MALLOC_DEBUG_DISABLE_H
|
@ -48,6 +48,7 @@
|
|||||||
|
|
||||||
#include "debug_stacktrace.h"
|
#include "debug_stacktrace.h"
|
||||||
#include "malloc_debug_common.h"
|
#include "malloc_debug_common.h"
|
||||||
|
#include "malloc_debug_disable.h"
|
||||||
|
|
||||||
#include "private/bionic_macros.h"
|
#include "private/bionic_macros.h"
|
||||||
#include "private/libc_logging.h"
|
#include "private/libc_logging.h"
|
||||||
@ -267,6 +268,7 @@ extern "C" int fill_posix_memalign(void** memptr, size_t alignment, size_t size)
|
|||||||
return (*memptr != NULL) ? 0 : ENOMEM;
|
return (*memptr != NULL) ? 0 : ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
||||||
extern "C" void* fill_pvalloc(size_t bytes) {
|
extern "C" void* fill_pvalloc(size_t bytes) {
|
||||||
size_t pagesize = getpagesize();
|
size_t pagesize = getpagesize();
|
||||||
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
||||||
@ -279,6 +281,7 @@ extern "C" void* fill_pvalloc(size_t bytes) {
|
|||||||
extern "C" void* fill_valloc(size_t size) {
|
extern "C" void* fill_valloc(size_t size) {
|
||||||
return fill_memalign(getpagesize(), size);
|
return fill_memalign(getpagesize(), size);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
// malloc leak functions
|
// malloc leak functions
|
||||||
@ -287,6 +290,10 @@ extern "C" void* fill_valloc(size_t size) {
|
|||||||
static uint32_t MEMALIGN_GUARD = 0xA1A41520;
|
static uint32_t MEMALIGN_GUARD = 0xA1A41520;
|
||||||
|
|
||||||
extern "C" void* leak_malloc(size_t bytes) {
|
extern "C" void* leak_malloc(size_t bytes) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->malloc(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
// allocate enough space infront of the allocation to store the pointer for
|
// allocate enough space infront of the allocation to store the pointer for
|
||||||
// the alloc structure. This will making free'ing the structer really fast!
|
// the alloc structure. This will making free'ing the structer really fast!
|
||||||
|
|
||||||
@ -319,6 +326,10 @@ extern "C" void* leak_malloc(size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void leak_free(void* mem) {
|
extern "C" void leak_free(void* mem) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
if (mem == NULL) {
|
if (mem == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -355,6 +366,10 @@ extern "C" void leak_free(void* mem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
|
extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->calloc(n_elements, elem_size);
|
||||||
|
}
|
||||||
|
|
||||||
// Fail on overflow - just to be safe even though this code runs only
|
// Fail on overflow - just to be safe even though this code runs only
|
||||||
// within the debugging C library, not the production one.
|
// within the debugging C library, not the production one.
|
||||||
if (n_elements && SIZE_MAX / n_elements < elem_size) {
|
if (n_elements && SIZE_MAX / n_elements < elem_size) {
|
||||||
@ -370,6 +385,10 @@ extern "C" void* leak_calloc(size_t n_elements, size_t elem_size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* leak_realloc(void* oldMem, size_t bytes) {
|
extern "C" void* leak_realloc(void* oldMem, size_t bytes) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->realloc(oldMem, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (oldMem == NULL) {
|
if (oldMem == NULL) {
|
||||||
return leak_malloc(bytes);
|
return leak_malloc(bytes);
|
||||||
}
|
}
|
||||||
@ -398,6 +417,10 @@ extern "C" void* leak_realloc(void* oldMem, size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* leak_memalign(size_t alignment, size_t bytes) {
|
extern "C" void* leak_memalign(size_t alignment, size_t bytes) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->memalign(alignment, bytes);
|
||||||
|
}
|
||||||
|
|
||||||
// we can just use malloc
|
// we can just use malloc
|
||||||
if (alignment <= MALLOC_ALIGNMENT) {
|
if (alignment <= MALLOC_ALIGNMENT) {
|
||||||
return leak_malloc(bytes);
|
return leak_malloc(bytes);
|
||||||
@ -439,6 +462,10 @@ extern "C" void* leak_memalign(size_t alignment, size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" size_t leak_malloc_usable_size(const void* mem) {
|
extern "C" size_t leak_malloc_usable_size(const void* mem) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->malloc_usable_size(mem);
|
||||||
|
}
|
||||||
|
|
||||||
if (mem != NULL) {
|
if (mem != NULL) {
|
||||||
// Check the guard to make sure it is valid.
|
// Check the guard to make sure it is valid.
|
||||||
const AllocationEntry* header = const_to_header((void*)mem);
|
const AllocationEntry* header = const_to_header((void*)mem);
|
||||||
@ -467,6 +494,10 @@ extern "C" struct mallinfo leak_mallinfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" int leak_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
extern "C" int leak_posix_memalign(void** memptr, size_t alignment, size_t size) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->posix_memalign(memptr, alignment, size);
|
||||||
|
}
|
||||||
|
|
||||||
if (!powerof2(alignment)) {
|
if (!powerof2(alignment)) {
|
||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
@ -476,7 +507,12 @@ extern "C" int leak_posix_memalign(void** memptr, size_t alignment, size_t size)
|
|||||||
return (*memptr != NULL) ? 0 : ENOMEM;
|
return (*memptr != NULL) ? 0 : ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_DEPRECATED_MALLOC_FUNCS)
|
||||||
extern "C" void* leak_pvalloc(size_t bytes) {
|
extern "C" void* leak_pvalloc(size_t bytes) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->pvalloc(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
size_t pagesize = getpagesize();
|
size_t pagesize = getpagesize();
|
||||||
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
size_t size = BIONIC_ALIGN(bytes, pagesize);
|
||||||
if (size < bytes) { // Overflow
|
if (size < bytes) { // Overflow
|
||||||
@ -486,5 +522,10 @@ extern "C" void* leak_pvalloc(size_t bytes) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void* leak_valloc(size_t size) {
|
extern "C" void* leak_valloc(size_t size) {
|
||||||
|
if (DebugCallsDisabled()) {
|
||||||
|
return g_malloc_dispatch->valloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
return leak_memalign(getpagesize(), size);
|
return leak_memalign(getpagesize(), size);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user