From 8189e77bbb47dbaa1a09d565c62c2fed03e358c3 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 9 Apr 2019 16:37:23 -0700 Subject: Remove gMallocLeakZygoteChild. Remove this global variable and change the setting of it to non-zero to a call to android_mallopt. In addition, change the initialize function to use pass a bool* instead of int*. Bug: 130028357 Test: Ran malloc_debug/malloc_hooks/perfetto tests. Change-Id: I20d382bdeaaf38aac6b9dcabea5b3dfab3c945f6 Merged-In: I20d382bdeaaf38aac6b9dcabea5b3dfab3c945f6 (cherry picked from commit 5225b342f0810c027df3d09fbbcef4d324b19b93) --- libc/malloc_debug/malloc_debug.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'libc/malloc_debug/malloc_debug.cpp') diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index 114579626..91e1d2610 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -58,7 +58,7 @@ // ------------------------------------------------------------------------ DebugData* g_debug; -int* g_malloc_zygote_child; +bool* g_zygote_child; const MallocDispatch* g_dispatch; // ------------------------------------------------------------------------ @@ -70,7 +70,7 @@ const MallocDispatch* g_dispatch; // ------------------------------------------------------------------------ __BEGIN_DECLS -bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child, +bool debug_initialize(const MallocDispatch* malloc_dispatch, bool* malloc_zygote_child, const char* options); void debug_finalize(); void debug_dump_heap(const char* file_name); @@ -225,15 +225,15 @@ static void* InitHeader(Header* header, void* orig_pointer, size_t size) { return g_debug->GetPointer(header); } -bool debug_initialize(const MallocDispatch* malloc_dispatch, int* malloc_zygote_child, +bool debug_initialize(const MallocDispatch* malloc_dispatch, bool* zygote_child, const char* options) { - if (malloc_zygote_child == nullptr || options == nullptr) { + if (zygote_child == nullptr || options == nullptr) { return false; } InitAtfork(); - g_malloc_zygote_child = malloc_zygote_child; + g_zygote_child = zygote_child; g_dispatch = malloc_dispatch; -- cgit v1.2.3 From d269fcc935b276502b9e47a575d76693fe1b8455 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 6 May 2019 19:03:59 -0700 Subject: Avoid using malloc debug code after exit. I wrote a new unit test that would fail on the old version of the code. On a walleye big cpu, this costs about 40ns-50ns (going from ~430ns to ~480ns). I think this is an acceptable performance degradation. Bug: 131867816 Test: New unit tests pass. Change-Id: I4c0f4373fb0694bf29c3824dbb1224a8a17e211e --- libc/malloc_debug/malloc_debug.cpp | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'libc/malloc_debug/malloc_debug.cpp') diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index 91e1d2610..53fcead01 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -103,6 +104,32 @@ void* debug_valloc(size_t size); __END_DECLS // ------------------------------------------------------------------------ +class ScopedConcurrentLock { + public: + ScopedConcurrentLock() { + pthread_rwlock_rdlock(&lock_); + } + ~ScopedConcurrentLock() { + pthread_rwlock_unlock(&lock_); + } + + static void Init() { + pthread_rwlockattr_t attr; + // Set the attribute so that when a write lock is pending, read locks are no + // longer granted. + pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP); + pthread_rwlock_init(&lock_, &attr); + } + + static void BlockAllOperations() { + pthread_rwlock_wrlock(&lock_); + } + + private: + static pthread_rwlock_t lock_; +}; +pthread_rwlock_t ScopedConcurrentLock::lock_; + static void InitAtfork() { static pthread_once_t atfork_init = PTHREAD_ONCE_INIT; pthread_once(&atfork_init, []() { @@ -257,6 +284,8 @@ bool debug_initialize(const MallocDispatch* malloc_dispatch, bool* zygote_child, info_log("%s: malloc debug enabled", getprogname()); } + ScopedConcurrentLock::Init(); + return true; } @@ -265,6 +294,10 @@ void debug_finalize() { return; } + // Make sure that there are no other threads doing debug allocations + // before we kill everything. + ScopedConcurrentLock::BlockAllOperations(); + // Turn off capturing allocations calls. DebugDisableSet(true); @@ -292,6 +325,8 @@ void debug_finalize() { void debug_get_malloc_leak_info(uint8_t** info, size_t* overall_size, size_t* info_size, size_t* total_memory, size_t* backtrace_size) { + ScopedConcurrentLock lock; + ScopedDisableDebugCalls disable; // Verify the arguments. @@ -325,6 +360,7 @@ size_t debug_malloc_usable_size(void* pointer) { if (DebugCallsDisabled() || pointer == nullptr) { return g_dispatch->malloc_usable_size(pointer); } + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; if (!VerifyPointer(pointer, "malloc_usable_size")) { @@ -388,6 +424,7 @@ void* debug_malloc(size_t size) { if (DebugCallsDisabled()) { return g_dispatch->malloc(size); } + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; void* pointer = InternalMalloc(size); @@ -463,6 +500,7 @@ void debug_free(void* pointer) { if (DebugCallsDisabled() || pointer == nullptr) { return g_dispatch->free(pointer); } + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; if (g_debug->config().options() & RECORD_ALLOCS) { @@ -480,6 +518,7 @@ void* debug_memalign(size_t alignment, size_t bytes) { if (DebugCallsDisabled()) { return g_dispatch->memalign(alignment, bytes); } + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; if (bytes == 0) { @@ -558,6 +597,7 @@ void* debug_realloc(void* pointer, size_t bytes) { if (DebugCallsDisabled()) { return g_dispatch->realloc(pointer, bytes); } + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; if (pointer == nullptr) { @@ -676,6 +716,7 @@ void* debug_calloc(size_t nmemb, size_t bytes) { if (DebugCallsDisabled()) { return g_dispatch->calloc(nmemb, bytes); } + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; size_t size; @@ -737,6 +778,8 @@ int debug_malloc_info(int options, FILE* fp) { if (DebugCallsDisabled() || !g_debug->TrackPointers()) { return g_dispatch->malloc_info(options, fp); } + ScopedConcurrentLock lock; + ScopedDisableDebugCalls disable; MallocXmlElem root(fp, "malloc", "version=\"debug-malloc-1\""); std::vector list; @@ -786,6 +829,7 @@ int debug_posix_memalign(void** memptr, size_t alignment, size_t size) { int debug_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_t, void*), void* arg) { + ScopedConcurrentLock lock; if (g_debug->TrackPointers()) { // Since malloc is disabled, don't bother acquiring any locks. for (auto it = PointerData::begin(); it != PointerData::end(); ++it) { @@ -800,6 +844,7 @@ int debug_iterate(uintptr_t base, size_t size, void (*callback)(uintptr_t, size_ } void debug_malloc_disable() { + ScopedConcurrentLock lock; g_dispatch->malloc_disable(); if (g_debug->pointer) { g_debug->pointer->PrepareFork(); @@ -807,6 +852,7 @@ void debug_malloc_disable() { } void debug_malloc_enable() { + ScopedConcurrentLock lock; if (g_debug->pointer) { g_debug->pointer->PostForkParent(); } @@ -817,6 +863,7 @@ ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t max_fram if (DebugCallsDisabled() || pointer == nullptr) { return 0; } + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; if (!(g_debug->config().options() & BACKTRACE)) { @@ -870,6 +917,7 @@ static void write_dump(FILE* fp) { } bool debug_write_malloc_leak_info(FILE* fp) { + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; std::lock_guard guard(g_dump_lock); @@ -883,6 +931,7 @@ bool debug_write_malloc_leak_info(FILE* fp) { } void debug_dump_heap(const char* file_name) { + ScopedConcurrentLock lock; ScopedDisableDebugCalls disable; std::lock_guard guard(g_dump_lock); -- cgit v1.2.3 From 705de3c6398d53b780d731008bafc3c2dafbbf85 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 22 May 2019 13:39:57 -0700 Subject: Disable malloc debug when asan enabled. Bug: 123312263 Test: Verified with asan enabled, malloc debug does not initialize. Test: Ran tests on non-asan build and verify they pass. Change-Id: I3c37c170bf6c1de42740972f2113ae991351d931 --- libc/malloc_debug/malloc_debug.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'libc/malloc_debug/malloc_debug.cpp') diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp index 53fcead01..c030d5429 100644 --- a/libc/malloc_debug/malloc_debug.cpp +++ b/libc/malloc_debug/malloc_debug.cpp @@ -252,12 +252,19 @@ static void* InitHeader(Header* header, void* orig_pointer, size_t size) { return g_debug->GetPointer(header); } +extern "C" void __asan_init() __attribute__((weak)); + bool debug_initialize(const MallocDispatch* malloc_dispatch, bool* zygote_child, const char* options) { if (zygote_child == nullptr || options == nullptr) { return false; } + if (__asan_init != 0) { + error_log("malloc debug cannot be enabled alongside ASAN"); + return false; + } + InitAtfork(); g_zygote_child = zygote_child; -- cgit v1.2.3