diff options
author | Stan Shebs <stanshebs@google.com> | 2016-04-27 09:53:33 -0700 |
---|---|---|
committer | Stan Shebs <stanshebs@google.com> | 2016-04-27 09:53:33 -0700 |
commit | c93632edca4fc68f5873d53d70d7266833b2b25c (patch) | |
tree | cebd045d8a886831db982cc0a1bc6032357278bd | |
parent | 000f2cf415b761b4c990b067276f3bb209cc1f95 (diff) | |
download | glibc-c93632edca4fc68f5873d53d70d7266833b2b25c.tar.gz glibc-c93632edca4fc68f5873d53d70d7266833b2b25c.tar.xz glibc-c93632edca4fc68f5873d53d70d7266833b2b25c.zip |
Fix infinite loop on process exit.
-rw-r--r-- | README.google | 4 | ||||
-rw-r--r-- | nptl/sysdeps/unix/sysv/linux/register-atfork.c | 30 |
2 files changed, 34 insertions, 0 deletions
diff --git a/README.google b/README.google index 1b5b4b76b8..85b310ab95 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 2cc49540b9..bf1deecc41 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, |