From 3e2d2936b0447ed2f0b0aab3625494b2533cd422 Mon Sep 17 00:00:00 2001 From: Kirill Artamonov Date: Fri, 31 Aug 2012 09:19:16 -0700 Subject: [PATCH] Avoid malloc lock while calling pthread_atfork. Expecting the memory in a forked child process to be sane wrt threading is a bad idea. An example of a problem is when the parent process has the malloc lock and a child process is forked. The malloc lock in the child will appear locked by a thread that doesn't exist. This change aims to make bionic more compatible with glibc by reseting the malloc lock in the child forked process, as well as holding it during the fork. This is a feature in dlmalloc 2.8.6 called LOCK_AT_FORK. In general this feature isn't necessary as a forked process will then exec. Some bad applications rely on being able to use features like malloc before the exec and having multiple threads running in the parent program. This isn't a problem with glibc and this patch makes it not a problem for bionic. Unfortunately for use in bionic, LOCK_AT_FORK has an issue as internally it uses pthread_atfork that in bionic uses malloc. This leads to the LOCK_AT_FORK initialization deadlocking with pthread_atfork's call to malloc due to the malloc lock. This change moves the pthread_atfork logic in LOCK_AT_FORK to be called without the malloc lock held. Change-Id: Id68175a564a6abb936ee4488b44d9479f7311f69 --- libc/bionic/dlmalloc.h | 1 + libc/upstream-dlmalloc/malloc.c | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libc/bionic/dlmalloc.h b/libc/bionic/dlmalloc.h index b34165e6e..a00a583c3 100644 --- a/libc/bionic/dlmalloc.h +++ b/libc/bionic/dlmalloc.h @@ -24,6 +24,7 @@ #define REALLOC_ZERO_BYTES_FREES 1 #define USE_DL_PREFIX 1 #define USE_LOCKS 1 +#define LOCK_AT_FORK 1 #define USE_RECURSIVE_LOCK 0 #define USE_SPIN_LOCKS 0 diff --git a/libc/upstream-dlmalloc/malloc.c b/libc/upstream-dlmalloc/malloc.c index 5e675b459..c6a32c8c4 100644 --- a/libc/upstream-dlmalloc/malloc.c +++ b/libc/upstream-dlmalloc/malloc.c @@ -3099,6 +3099,9 @@ static void post_fork_child(void) { INITIAL_LOCK(&(gm)->mutex); } /* Initialize mparams */ static int init_mparams(void) { + /* BEGIN android-added: move pthread_atfork outside of lock */ + int first_run = 0; + /* END android-added */ #ifdef NEED_GLOBAL_LOCK_INIT if (malloc_global_mutex_status <= 0) init_malloc_global_mutex(); @@ -3109,6 +3112,9 @@ static int init_mparams(void) { size_t magic; size_t psize; size_t gsize; + /* BEGIN android-added: move pthread_atfork outside of lock */ + first_run = 1; + /* END android-added */ #ifndef WIN32 psize = malloc_getpagesize; @@ -3153,9 +3159,11 @@ static int init_mparams(void) { gm->mflags = mparams.default_mflags; (void)INITIAL_LOCK(&gm->mutex); #endif -#if LOCK_AT_FORK + /* BEGIN android-removed: move pthread_atfork outside of lock */ +#if 0 && LOCK_AT_FORK pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child); #endif + /* END android-removed */ { #if USE_DEV_RANDOM @@ -3184,6 +3192,13 @@ static int init_mparams(void) { } RELEASE_MALLOC_GLOBAL_LOCK(); + /* BEGIN android-added: move pthread_atfork outside of lock */ +#if LOCK_AT_FORK + if (first_run != 0) { + pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child); + } +#endif + /* END android-added */ return 1; }