|
|
12745e |
commit e400f3ccd36fe91d432cc7d45b4ccc799dece763
|
|
|
12745e |
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
|
|
|
12745e |
Date: Fri Jul 24 19:13:38 2015 +0530
|
|
|
12745e |
|
|
|
12745e |
Use IE model for static variables in libc.so, libpthread.so and rtld
|
|
|
12745e |
|
|
|
12745e |
The recently introduced TLS variables in the thread-local destructor
|
|
|
12745e |
implementation (__cxa_thread_atexit_impl) used the default GD access
|
|
|
12745e |
model, resulting in a call to __tls_get_addr. This causes a deadlock
|
|
|
12745e |
with recent changes to the way TLS is initialized because DTV
|
|
|
12745e |
allocations are delayed and hence despite knowing the offset to the
|
|
|
12745e |
variable inside its TLS block, the thread has to take the global rtld
|
|
|
12745e |
lock to safely update the TLS offset.
|
|
|
12745e |
|
|
|
12745e |
This causes deadlocks when a thread is instantiated and joined inside
|
|
|
12745e |
a destructor of a dlopen'd DSO. The correct long term fix is to
|
|
|
12745e |
somehow not take the lock, but that will need a lot deeper change set
|
|
|
12745e |
to alter the way in which the big rtld lock is used.
|
|
|
12745e |
|
|
|
12745e |
Instead, this patch just eliminates the call to __tls_get_addr for the
|
|
|
12745e |
thread-local variables inside libc.so, libpthread.so and rtld by
|
|
|
12745e |
building all of their units with -mtls-model=initial-exec.
|
|
|
12745e |
|
|
|
12745e |
There were concerns that the static storage for TLS is limited and
|
|
|
12745e |
hence we should not be using it. Additionally, dynamically loaded
|
|
|
12745e |
modules may result in libc.so looking for this static storage pretty
|
|
|
12745e |
late in static binaries. Both concerns are valid when using TLSDESC
|
|
|
12745e |
since that is where one may attempt to allocate a TLS block from
|
|
|
12745e |
static storage for even those variables that are not IE. They're not
|
|
|
12745e |
very strong arguments for the traditional TLS model though, since it
|
|
|
12745e |
assumes that the static storage would be used sparingly and definitely
|
|
|
12745e |
not by default. Hence, for now this would only theoretically affect
|
|
|
12745e |
ARM architectures.
|
|
|
12745e |
|
|
|
12745e |
The impact is hence limited to statically linked binaries that dlopen
|
|
|
12745e |
modules that in turn load libc.so, all that on arm hardware. It seems
|
|
|
12745e |
like a small enough impact to justify fixing the larger problem that
|
|
|
12745e |
currently affects everything everywhere.
|
|
|
12745e |
|
|
|
12745e |
This still does not solve the original problem completely. That is,
|
|
|
12745e |
it is still possible to deadlock on the big rtld lock with a small
|
|
|
12745e |
tweak to the test case attached to this patch. That problem is
|
|
|
12745e |
however not a regression in 2.22 and hence could be tackled as a
|
|
|
12745e |
separate project. The test case is picked up as is from Alex's patch.
|
|
|
12745e |
|
|
|
12745e |
This change has been tested to verify that it does not cause any
|
|
|
12745e |
issues on x86_64.
|
|
|
12745e |
|
|
|
12745e |
ChangeLog:
|
|
|
12745e |
|
|
|
12745e |
[BZ #18457]
|
|
|
12745e |
* nptl/Makefile (tests): New test case tst-join7.
|
|
|
12745e |
(modules-names): New test case module tst-join7mod.
|
|
|
12745e |
* nptl/tst-join7.c: New file.
|
|
|
12745e |
* nptl/tst-join7mod.c: New file.
|
|
|
12745e |
* Makeconfig (tls-model): Pass -ftls-model=initial-exec for
|
|
|
12745e |
all translation units in libc.so, libpthread.so and rtld.
|
|
|
12745e |
|
|
|
12745e |
diff --git a/nptl/Makefile b/nptl/Makefile
|
|
|
12745e |
index 140f063..aaca0a4 100644
|
|
|
12745e |
--- a/nptl/Makefile
|
|
|
12745e |
+++ b/nptl/Makefile
|
|
|
12745e |
@@ -245,7 +245,7 @@ tests = tst-typesizes \
|
|
|
12745e |
tst-basic7 \
|
|
|
12745e |
tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
|
|
|
12745e |
tst-raise1 \
|
|
|
12745e |
- tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 \
|
|
|
12745e |
+ tst-join1 tst-join2 tst-join3 tst-join4 tst-join5 tst-join6 tst-join7 \
|
|
|
12745e |
tst-detach1 \
|
|
|
12745e |
tst-eintr1 tst-eintr2 tst-eintr3 tst-eintr4 tst-eintr5 \
|
|
|
12745e |
tst-tsd1 tst-tsd2 tst-tsd3 tst-tsd4 tst-tsd5 tst-tsd6 \
|
|
|
12745e |
@@ -327,7 +327,8 @@ endif
|
|
|
12745e |
modules-names = tst-atfork2mod tst-tls3mod tst-tls4moda tst-tls4modb \
|
|
|
12745e |
tst-tls5mod tst-tls5moda tst-tls5modb tst-tls5modc \
|
|
|
12745e |
tst-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
|
|
|
12745e |
- tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod
|
|
|
12745e |
+ tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod \
|
|
|
12745e |
+ tst-join7mod
|
|
|
12745e |
extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o
|
|
|
12745e |
test-extras += $(modules-names) tst-cleanup4aux
|
|
|
12745e |
test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
|
|
|
12745e |
@@ -532,6 +533,11 @@ $(objpfx)tst-tls6.out: tst-tls6.sh $(objpfx)tst-tls5 \
|
|
|
12745e |
$(rtld-installed-name) '$(test-wrapper-env)'
|
|
|
12745e |
endif
|
|
|
12745e |
|
|
|
12745e |
+$(objpfx)tst-join7: $(libdl) $(shared-thread-library)
|
|
|
12745e |
+$(objpfx)tst-join7.out: $(objpfx)tst-join7mod.so
|
|
|
12745e |
+$(objpfx)tst-join7mod.so: $(shared-thread-library)
|
|
|
12745e |
+LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so
|
|
|
12745e |
+
|
|
|
12745e |
$(objpfx)tst-dlsym1: $(libdl) $(shared-thread-library)
|
|
|
12745e |
|
|
|
12745e |
$(objpfx)tst-fini1: $(shared-thread-library) $(objpfx)tst-fini1mod.so
|
|
|
12745e |
diff --git a/nptl/tst-join7.c b/nptl/tst-join7.c
|
|
|
12745e |
new file mode 100644
|
|
|
12745e |
index 0000000..439d0fc
|
|
|
12745e |
--- /dev/null
|
|
|
12745e |
+++ b/nptl/tst-join7.c
|
|
|
12745e |
@@ -0,0 +1,46 @@
|
|
|
12745e |
+/* Verify that TLS access in separate thread in a dlopened library does not
|
|
|
12745e |
+ deadlock.
|
|
|
12745e |
+ Copyright (C) 2015 Free Software Foundation, Inc.
|
|
|
12745e |
+ This file is part of the GNU C Library.
|
|
|
12745e |
+
|
|
|
12745e |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
12745e |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
12745e |
+ License as published by the Free Software Foundation; either
|
|
|
12745e |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
12745e |
+
|
|
|
12745e |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
12745e |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
12745e |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
12745e |
+ Lesser General Public License for more details.
|
|
|
12745e |
+
|
|
|
12745e |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
12745e |
+ License along with the GNU C Library; if not, see
|
|
|
12745e |
+ <http://www.gnu.org/licenses/>. */
|
|
|
12745e |
+
|
|
|
12745e |
+#include <dlfcn.h>
|
|
|
12745e |
+
|
|
|
12745e |
+/* When one dynamically loads a module, which spawns a thread to perform some
|
|
|
12745e |
+ activities, it could be possible that TLS storage is accessed for the first
|
|
|
12745e |
+ time in that thread. This results in an allocation request within the
|
|
|
12745e |
+ thread, which could result in an attempt to take the rtld load_lock. This
|
|
|
12745e |
+ is a problem because it would then deadlock with the dlopen (which owns the
|
|
|
12745e |
+ lock), if the main thread is waiting for the spawned thread to exit. We can
|
|
|
12745e |
+ at least ensure that this problem does not occur due to accesses within
|
|
|
12745e |
+ libc.so, by marking TLS variables within libc.so as IE. The problem of an
|
|
|
12745e |
+ arbitrary variable being accessed and constructed within such a thread still
|
|
|
12745e |
+ exists but this test case does not verify that. */
|
|
|
12745e |
+
|
|
|
12745e |
+int
|
|
|
12745e |
+do_test (void)
|
|
|
12745e |
+{
|
|
|
12745e |
+ void *f = dlopen ("tst-join7mod.so", RTLD_NOW | RTLD_GLOBAL);
|
|
|
12745e |
+ if (f)
|
|
|
12745e |
+ dlclose (f);
|
|
|
12745e |
+ else
|
|
|
12745e |
+ return 1;
|
|
|
12745e |
+
|
|
|
12745e |
+ return 0;
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+#define TEST_FUNCTION do_test ()
|
|
|
12745e |
+#include "../test-skeleton.c"
|
|
|
12745e |
diff --git a/nptl/tst-join7mod.c b/nptl/tst-join7mod.c
|
|
|
12745e |
new file mode 100644
|
|
|
12745e |
index 0000000..92bb381
|
|
|
12745e |
--- /dev/null
|
|
|
12745e |
+++ b/nptl/tst-join7mod.c
|
|
|
12745e |
@@ -0,0 +1,61 @@
|
|
|
12745e |
+/* Verify that TLS access in separate thread in a dlopened library does not
|
|
|
12745e |
+ deadlock - the module.
|
|
|
12745e |
+ Copyright (C) 2015 Free Software Foundation, Inc.
|
|
|
12745e |
+ This file is part of the GNU C Library.
|
|
|
12745e |
+
|
|
|
12745e |
+ The GNU C Library is free software; you can redistribute it and/or
|
|
|
12745e |
+ modify it under the terms of the GNU Lesser General Public
|
|
|
12745e |
+ License as published by the Free Software Foundation; either
|
|
|
12745e |
+ version 2.1 of the License, or (at your option) any later version.
|
|
|
12745e |
+
|
|
|
12745e |
+ The GNU C Library is distributed in the hope that it will be useful,
|
|
|
12745e |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
12745e |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
12745e |
+ Lesser General Public License for more details.
|
|
|
12745e |
+
|
|
|
12745e |
+ You should have received a copy of the GNU Lesser General Public
|
|
|
12745e |
+ License along with the GNU C Library; if not, see
|
|
|
12745e |
+ <http://www.gnu.org/licenses/>. */
|
|
|
12745e |
+
|
|
|
12745e |
+#include <stdio.h>
|
|
|
12745e |
+#include <pthread.h>
|
|
|
12745e |
+#include <atomic.h>
|
|
|
12745e |
+
|
|
|
12745e |
+static pthread_t th;
|
|
|
12745e |
+static int running = 1;
|
|
|
12745e |
+
|
|
|
12745e |
+static void *
|
|
|
12745e |
+test_run (void *p)
|
|
|
12745e |
+{
|
|
|
12745e |
+ while (atomic_load_relaxed (&running))
|
|
|
12745e |
+ printf ("Test running\n");
|
|
|
12745e |
+ printf ("Test finished\n");
|
|
|
12745e |
+ return NULL;
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+static void __attribute__ ((constructor))
|
|
|
12745e |
+do_init (void)
|
|
|
12745e |
+{
|
|
|
12745e |
+ int ret = pthread_create (&th, NULL, test_run, NULL);
|
|
|
12745e |
+
|
|
|
12745e |
+ if (ret != 0)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ printf ("failed to create thread: %s (%d)\n", strerror (ret), ret);
|
|
|
12745e |
+ exit (1);
|
|
|
12745e |
+ }
|
|
|
12745e |
+}
|
|
|
12745e |
+
|
|
|
12745e |
+static void __attribute__ ((destructor))
|
|
|
12745e |
+do_end (void)
|
|
|
12745e |
+{
|
|
|
12745e |
+ atomic_store_relaxed (&running, 0);
|
|
|
12745e |
+ int ret = pthread_join (th, NULL);
|
|
|
12745e |
+
|
|
|
12745e |
+ if (ret != 0)
|
|
|
12745e |
+ {
|
|
|
12745e |
+ printf ("pthread_join: %s(%d)\n", strerror (ret), ret);
|
|
|
12745e |
+ exit (1);
|
|
|
12745e |
+ }
|
|
|
12745e |
+
|
|
|
12745e |
+ printf ("Thread joined\n");
|
|
|
12745e |
+}
|
|
|
12745e |
diff -pruN a/string/strerror_l.c b/string/strerror_l.c
|
|
|
12745e |
--- a/string/strerror_l.c
|
|
|
12745e |
+++ b/string/strerror_l.c
|
|
|
12745e |
@@ -23,7 +23,7 @@
|
|
|
12745e |
#include <sys/param.h>
|
|
|
12745e |
|
|
|
12745e |
|
|
|
12745e |
-static __thread char *last_value;
|
|
|
12745e |
+static __thread char *last_value attribute_tls_model_ie;
|
|
|
12745e |
|
|
|
12745e |
|
|
|
12745e |
static const char *
|