From e1a8ef98132e737d3e7c4045a3e6e6e7ae20242e Mon Sep 17 00:00:00 2001 From: Maxim Ostapenko Date: Wed, 31 May 2017 07:28:09 +0000 Subject: [sanitizer] Avoid possible deadlock in child process after fork This patch addresses https://github.com/google/sanitizers/issues/774. When we fork a multi-threaded process it's possible to deadlock if some thread acquired StackDepot or allocator internal lock just before fork. In this case the lock will never be released in child process causing deadlock on following memory alloc/dealloc routine. While calling alloc/dealloc routines after multi-threaded fork is not allowed, most of modern allocators (Glibc, tcmalloc, jemalloc) are actually fork safe. Let's do the same for sanitizers except TSan that has complex locking rules. Differential Revision: https://reviews.llvm.org/D33325 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@304285 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/asan/asan_allocator.cc | 4 +--- lib/asan/asan_allocator.h | 2 ++ lib/asan/asan_interceptors.cc | 13 +++++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'lib/asan') diff --git a/lib/asan/asan_allocator.cc b/lib/asan/asan_allocator.cc index 7010b6023..db5a683e2 100644 --- a/lib/asan/asan_allocator.cc +++ b/lib/asan/asan_allocator.cc @@ -47,8 +47,6 @@ static u32 RZSize2Log(u32 rz_size) { return res; } -static AsanAllocator &get_allocator(); - // The memory chunk allocated from the underlying allocator looks like this: // L L L L L L H H U U U U U U R R // L -- left redzone words (0 or more bytes) @@ -719,7 +717,7 @@ struct Allocator { static Allocator instance(LINKER_INITIALIZED); -static AsanAllocator &get_allocator() { +AsanAllocator &get_allocator() { return instance.allocator; } diff --git a/lib/asan/asan_allocator.h b/lib/asan/asan_allocator.h index ad1aeb58a..ce3e25dc5 100644 --- a/lib/asan/asan_allocator.h +++ b/lib/asan/asan_allocator.h @@ -213,5 +213,7 @@ void asan_mz_force_unlock(); void PrintInternalAllocatorStats(); void AsanSoftRssLimitExceededCallback(bool exceeded); +AsanAllocator &get_allocator(); + } // namespace __asan #endif // ASAN_ALLOCATOR_H diff --git a/lib/asan/asan_interceptors.cc b/lib/asan/asan_interceptors.cc index cb2214f96..1f0dc9e2d 100644 --- a/lib/asan/asan_interceptors.cc +++ b/lib/asan/asan_interceptors.cc @@ -22,6 +22,7 @@ #include "asan_stats.h" #include "asan_suppressions.h" #include "lsan/lsan_common.h" +#include "sanitizer_common/sanitizer_stackdepot.h" #include "sanitizer_common/sanitizer_libc.h" #if SANITIZER_POSIX @@ -705,11 +706,23 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg, #endif // ASAN_INTERCEPT___CXA_ATEXIT #if ASAN_INTERCEPT_FORK +static void BeforeFork() { + get_allocator().ForceLock(); + StackDepotLockAll(); +} + +static void AfterFork() { + StackDepotUnlockAll(); + get_allocator().ForceUnlock(); +} + INTERCEPTOR(int, fork, void) { ENSURE_ASAN_INITED(); + BeforeFork(); if (common_flags()->coverage) CovBeforeFork(); int pid = REAL(fork)(); if (common_flags()->coverage) CovAfterFork(pid); + AfterFork(); return pid; } #endif // ASAN_INTERCEPT_FORK -- cgit v1.2.3