From: Stan Shebs Date: Wed, 27 Apr 2016 16:53:33 +0000 (-0700) Subject: Fix infinite loop on process exit. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c93632edca4fc68f5873d53d70d7266833b2b25c;p=thirdparty%2Fglibc.git Fix infinite loop on process exit. --- diff --git a/README.google b/README.google index 1b5b4b76b83..85b310ab956 100644 --- a/README.google +++ b/README.google @@ -566,3 +566,7 @@ sysdeps/powerpc/* sysdeps/powerpc/bits/fenvinline.h For b/27191207, remove use of %s modifier in inline asm. (stanshebs, google-local) + +nptl/sysdeps/unix/sysv/linux/register-atfork.c + For b/28011264, detect and work around loop in fork handler list. + (stanshebs, google-local) diff --git a/nptl/sysdeps/unix/sysv/linux/register-atfork.c b/nptl/sysdeps/unix/sysv/linux/register-atfork.c index 2cc49540b95..bf1deecc41d 100644 --- a/nptl/sysdeps/unix/sysv/linux/register-atfork.c +++ b/nptl/sysdeps/unix/sysv/linux/register-atfork.c @@ -112,6 +112,36 @@ void attribute_hidden __linkin_atfork (struct fork_handler *newp) { + /* GRTE's patches for async-signal-safe TLS can cause a race + condition in which ptmalloc_init is called from more than one + thread. (allocate_dtv normally calls calloc which invokes + ptmalloc_init via hook while creating the first thread, but our + code calls __signal_safe_calloc which does not run hooks.) + ptmalloc_init tries to be idempotent in case of multiple threads, + but in glibc-2.19, it fills in atfork hooks from an + un-lock-protected global static atfork_mem, which is a bad idea; + it can result in the same allocated object being passed to this + routine more than once. This function then sets the object's next + pointer to point to itself, resulting in a hang when the program + tries to exit. + + This problem has been (indirectly) resolved in upstream glibc by + rewriting the whole thing so that thread setup is not done with + atforks or static variables, but the changes are extensive and + would not backport reliably. Our race is somewhat difficult to + trigger - it requires a program to start creating threads + *before* any kind of memory allocation whatsoever. So given all + this, the safest route is simply to detect when the fork handler + is already present, and skip adding it altogether. + + Note that while it's conceivable that calls to pthread_atfork + would result in the atfork_mem object not being at the head of + the list, but testing seems unable to generate such a case. */ + struct fork_handler *scanp; + for (scanp = __fork_handlers; scanp != NULL; scanp = scanp->next) + if (newp == scanp) + return; + do newp->next = __fork_handlers; while (catomic_compare_and_exchange_bool_acq (&__fork_handlers,