summaryrefslogtreecommitdiff
path: root/libc/malloc_debug/malloc_debug.cpp
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2020-05-22 01:01:14 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2020-05-22 01:01:14 +0000
commitf731698cf840e5455d1b4b2915bfb1c89bd48a51 (patch)
tree936cf492400fea213549c28e1357f86e869f002f /libc/malloc_debug/malloc_debug.cpp
parentf3b6c50f0ec1b18e08556b693a2783f151828f4c (diff)
parent73ca781f435ff45d85cc8daa3bb79d81c42bdc28 (diff)
Snap for 6520394 from 73ca781f435ff45d85cc8daa3bb79d81c42bdc28 to rvc-release
Change-Id: I086071eeef0e757dfa948634decc44104d53a639
Diffstat (limited to 'libc/malloc_debug/malloc_debug.cpp')
-rw-r--r--libc/malloc_debug/malloc_debug.cpp51
1 files changed, 49 insertions, 2 deletions
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 6eaac7de8..609f030bf 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -30,11 +30,13 @@
#include <inttypes.h>
#include <malloc.h>
#include <pthread.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/cdefs.h>
#include <sys/param.h>
+#include <sys/syscall.h>
#include <unistd.h>
#include <mutex>
@@ -44,8 +46,9 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <bionic/malloc_tagged_pointers.h>
-#include <private/bionic_malloc_dispatch.h>
+#include <platform/bionic/reserved_signals.h>
#include <private/MallocXmlElem.h>
+#include <private/bionic_malloc_dispatch.h>
#include "Config.h"
#include "DebugData.h"
@@ -131,6 +134,40 @@ class ScopedConcurrentLock {
};
pthread_rwlock_t ScopedConcurrentLock::lock_;
+// Use this because the sigprocmask* functions filter out the reserved bionic
+// signals including the signal this code blocks.
+static inline int __rt_sigprocmask(int how, const sigset64_t* new_set, sigset64_t* old_set,
+ size_t sigset_size) {
+ return syscall(SYS_rt_sigprocmask, how, new_set, old_set, sigset_size);
+}
+
+// Need to block the backtrace signal while in malloc debug routines
+// otherwise there is a chance of a deadlock and timeout when unwinding.
+// This can occur if a thread is paused while owning a malloc debug
+// internal lock.
+class ScopedBacktraceSignalBlocker {
+ public:
+ ScopedBacktraceSignalBlocker() {
+ sigemptyset64(&backtrace_set_);
+ sigaddset64(&backtrace_set_, BIONIC_SIGNAL_BACKTRACE);
+ sigset64_t old_set;
+ __rt_sigprocmask(SIG_BLOCK, &backtrace_set_, &old_set, sizeof(backtrace_set_));
+ if (sigismember64(&old_set, BIONIC_SIGNAL_BACKTRACE)) {
+ unblock_ = false;
+ }
+ }
+
+ ~ScopedBacktraceSignalBlocker() {
+ if (unblock_) {
+ __rt_sigprocmask(SIG_UNBLOCK, &backtrace_set_, nullptr, sizeof(backtrace_set_));
+ }
+ }
+
+ private:
+ bool unblock_ = true;
+ sigset64_t backtrace_set_;
+};
+
static void InitAtfork() {
static pthread_once_t atfork_init = PTHREAD_ONCE_INIT;
pthread_once(&atfork_init, []() {
@@ -334,8 +371,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;
+ ScopedBacktraceSignalBlocker blocked;
// Verify the arguments.
if (info == nullptr || overall_size == nullptr || info_size == nullptr || total_memory == nullptr ||
@@ -370,6 +407,7 @@ size_t debug_malloc_usable_size(void* pointer) {
}
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
if (!VerifyPointer(pointer, "malloc_usable_size")) {
return 0;
@@ -434,6 +472,7 @@ void* debug_malloc(size_t size) {
}
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
void* pointer = InternalMalloc(size);
@@ -510,6 +549,7 @@ void debug_free(void* pointer) {
}
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
if (g_debug->config().options() & RECORD_ALLOCS) {
g_debug->record->AddEntry(new FreeEntry(pointer));
@@ -528,6 +568,7 @@ void* debug_memalign(size_t alignment, size_t bytes) {
}
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
if (bytes == 0) {
bytes = 1;
@@ -607,6 +648,7 @@ void* debug_realloc(void* pointer, size_t bytes) {
}
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
if (pointer == nullptr) {
pointer = InternalMalloc(bytes);
@@ -726,6 +768,7 @@ void* debug_calloc(size_t nmemb, size_t bytes) {
}
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
size_t size;
if (__builtin_mul_overflow(nmemb, bytes, &size)) {
@@ -792,6 +835,7 @@ int debug_malloc_info(int options, FILE* fp) {
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
// Avoid any issues where allocations are made that will be freed
// in the fclose.
@@ -880,6 +924,7 @@ ssize_t debug_malloc_backtrace(void* pointer, uintptr_t* frames, size_t max_fram
}
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
if (!(g_debug->config().options() & BACKTRACE)) {
return 0;
@@ -938,6 +983,7 @@ bool debug_write_malloc_leak_info(FILE* fp) {
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
std::lock_guard<std::mutex> guard(g_dump_lock);
@@ -953,6 +999,7 @@ bool debug_write_malloc_leak_info(FILE* fp) {
void debug_dump_heap(const char* file_name) {
ScopedConcurrentLock lock;
ScopedDisableDebugCalls disable;
+ ScopedBacktraceSignalBlocker blocked;
std::lock_guard<std::mutex> guard(g_dump_lock);