SHA256
1
0
forked from pool/glibc
glibc/pthread-join-deadlock.patch
Andreas Schwab f7b73d687a Accepting request 311391 from home:Andreas_Schwab:Factory
- Add /usr/include/gnu/lib-names-.*.h to baselibs
- pthread-join-deadlock.patch: Don't require rtld lock to store static TLS
  offset in the DTV (bsc#930015, BZ #18457)
- heap-top-corruption.patch: Do not corrupt the top of a threaded heap if
  top chunk is MINSIZE (BZ #18502)

OBS-URL: https://build.opensuse.org/request/show/311391
OBS-URL: https://build.opensuse.org/package/show/Base:System/glibc?expand=0&rev=405
2015-06-10 07:15:17 +00:00

153 lines
5.5 KiB
Diff

[PR dynamic-link/18457]
* elf/dl-tls.c (tls_get_addr_tail): Don't take the rtld lock
if we already have a final static TLS offset.
* nptl/tst-join7.c, nptl/tst-join7mod.c: New.
Index: glibc-2.21/elf/dl-tls.c
===================================================================
--- glibc-2.21.orig/elf/dl-tls.c
+++ glibc-2.21/elf/dl-tls.c
@@ -755,30 +755,44 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t
the_map = listp->slotinfo[idx].map;
}
- /* Make sure that, if a dlopen running in parallel forces the
- variable into static storage, we'll wait until the address in the
- static TLS block is set up, and use that. If we're undecided
- yet, make sure we make the decision holding the lock as well. */
- if (__glibc_unlikely (the_map->l_tls_offset
- != FORCED_DYNAMIC_TLS_OFFSET))
+ /* If the TLS block for the map is already assigned to dynamic or to
+ static TLS, avoid the lock. Be careful to use the same value for
+ both tests; if we reloaded it, the second test might mistake
+ forced dynamic for an offset. Now, if the decision hasn't been
+ made, take the rtld lock, so that an ongoing dlopen gets a chance
+ to complete, and then retest; if the decision is still pending,
+ force the module to dynamic TLS. */
+ ptrdiff_t offset = atomic_load_relaxed (&the_map->l_tls_offset);
+ if (__glibc_unlikely (offset != FORCED_DYNAMIC_TLS_OFFSET))
{
+ if (__glibc_unlikely (offset != NO_TLS_OFFSET))
+ goto static_tls;
__rtld_lock_lock_recursive (GL(dl_load_lock));
- if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
+ offset = the_map->l_tls_offset;
+ if (__glibc_likely (offset == NO_TLS_OFFSET))
{
the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
- else if (__glibc_likely (the_map->l_tls_offset
- != FORCED_DYNAMIC_TLS_OFFSET))
+ else if (__glibc_likely (offset != FORCED_DYNAMIC_TLS_OFFSET))
{
+ /* The decision is made, and it is final. We use the value
+ we've already loaded, but we could even load the offset
+ after releasing the lock, since it won't change. Should
+ the module be released while another thread references
+ one of its TLS variables, that's undefined behavior. */
+ __rtld_lock_unlock_recursive (GL(dl_load_lock));
+
+ static_tls:
+ ;
+
#if TLS_TCB_AT_TP
- void *p = (char *) THREAD_SELF - the_map->l_tls_offset;
+ void *p = (char *) THREAD_SELF - offset;
#elif TLS_DTV_AT_TP
- void *p = (char *) THREAD_SELF + the_map->l_tls_offset + TLS_PRE_TCB_SIZE;
+ void *p = (char *) THREAD_SELF + offset + TLS_PRE_TCB_SIZE;
#else
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
#endif
- __rtld_lock_unlock_recursive (GL(dl_load_lock));
dtv[GET_ADDR_MODULE].pointer.is_static = true;
dtv[GET_ADDR_MODULE].pointer.val = p;
Index: glibc-2.21/nptl/Makefile
===================================================================
--- glibc-2.21.orig/nptl/Makefile
+++ glibc-2.21/nptl/Makefile
@@ -234,7 +234,7 @@ tests = tst-typesizes \
tst-basic7 \
tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
tst-raise1 \
- tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \
+ tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 tst-join7 \
tst-detach1 \
tst-eintr1 tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 \
tst-tsd1 tst-tsd2 tst-tsd3 tst-tsd4 tst-tsd5 tst-tsd6 \
@@ -312,7 +312,8 @@ endif
modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
- tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod
+ tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \
+ tst-join7mod
extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o
test-extras += $(modules-names) tst-cleanup4aux
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
@@ -517,6 +518,11 @@ $(objpfx)tst-tls6.out: tst-tls6.sh $(obj
$(evaluate-test)
endif
+$(objpfx)tst-join7: $(libdl) $(shared-thread-library)
+$(objpfx)tst-join7.out: $(objpfx)tst-join7mod.so
+$(objpfx)tst-join7mod.so: $(shared-thread-library)
+LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so
+
$(objpfx)tst-dlsym1: $(libdl) $(shared-thread-library)
$(objpfx)tst-fini1: $(shared-thread-library) $(objpfx)tst-fini1mod.so
Index: glibc-2.21/nptl/tst-join7.c
===================================================================
--- /dev/null
+++ glibc-2.21/nptl/tst-join7.c
@@ -0,0 +1,12 @@
+#include <dlfcn.h>
+
+int
+do_test (void)
+{
+ void *f = dlopen ("tst-join7mod.so", RTLD_NOW | RTLD_GLOBAL);
+ if (f) dlclose (f); else return 1;
+ return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
Index: glibc-2.21/nptl/tst-join7mod.c
===================================================================
--- /dev/null
+++ glibc-2.21/nptl/tst-join7mod.c
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <pthread.h>
+
+static pthread_t th;
+static int running = 1;
+
+static void *
+test_run (void *p)
+{
+ while (running)
+ fprintf (stderr, "XXX test_run\n");
+ fprintf (stderr, "XXX test_run FINISHED\n");
+ return NULL;
+}
+
+static void __attribute__ ((constructor))
+do_init (void)
+{
+ pthread_create (&th, NULL, test_run, NULL);
+}
+
+static void __attribute__ ((destructor))
+do_end (void)
+{
+ running = 0;
+ fprintf (stderr, "thread_join...\n");
+ pthread_join (th, NULL);
+ fprintf (stderr, "thread_join DONE\n");
+}