[git commit master] ldso_tls: Refetch dtv from memory if THREAD_DTV has changed

Carmelo Amoroso carmelo.amoroso at st.com
Fri Apr 23 14:31:55 UTC 2010


commit: http://git.uclibc.org/uClibc/commit/?id=b3d31460fbf188997c7337296a61409529f7c974
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/master

_dl_update_slotinfo might change THREAD_DTV () (if it needs to reallocate it),
but the caller (__tls_get_addr) doesn't refetch dtv from memory, it uses its
cached copy. This may crash (if dtv[GET_ADDR_MODULE] is off the cliff, or
might read uninitialized memory and return it.
Typically dtv[GET_ADDR_MODULE].pointer.val is NULL and so __tls_get_addr
returns NULL + offset_within_PT_TLS. The next time __tls_get_addr is called
for the same library it will return correct address as _dl_update_slotinfo
won't need to be called.

Signed-off-by: Jakub Jelinek <jakub at redhat.com>
Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono at st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso at st.com>
---
 ldso/ldso/dl-tls.c       |    5 ++++-
 test/tls/Makefile.in     |   11 ++++++++++-
 test/tls/tst-tls18.c     |   38 ++++++++++++++++++++++++++++++++++++++
 test/tls/tst-tlsmod18a.c |   21 +++++++++++++++++++++
 4 files changed, 73 insertions(+), 2 deletions(-)
 create mode 100644 test/tls/tst-tls18.c
 create mode 100644 test/tls/tst-tlsmod18a.c

diff --git a/ldso/ldso/dl-tls.c b/ldso/ldso/dl-tls.c
index 52b7aa5..d2808f9 100644
--- a/ldso/ldso/dl-tls.c
+++ b/ldso/ldso/dl-tls.c
@@ -842,7 +842,10 @@ __tls_get_addr (GET_ADDR_ARGS)
   void *p;
 
   if (__builtin_expect (dtv[0].counter != _dl_tls_generation, 0))
-    the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+    {
+      the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
+      dtv = THREAD_DTV ();
+    }
 
   p = dtv[GET_ADDR_MODULE].pointer.val;
 
diff --git a/test/tls/Makefile.in b/test/tls/Makefile.in
index 082ab1c..69a8eaf 100644
--- a/test/tls/Makefile.in
+++ b/test/tls/Makefile.in
@@ -3,7 +3,7 @@
 
 TESTS := tst-tls1 tst-tls2 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7	\
 	tst-tls8 tst-tls9 tst-tls10 tst-tls11 tst-tls12 tst-tls13	\
-	tst-tls14 tst-tls15 tst-tls16 tst-tls17 tst-tls-at-ctor \
+	tst-tls14 tst-tls15 tst-tls16 tst-tls17 tst-tls18 tst-tls-at-ctor \
 	tst-tls1-static tst-tls2-static tst-tls9-static
 TESTS_DISABLED := tst-tls1-static tst-tls2-static tst-tls9-static
 
@@ -27,6 +27,7 @@ EXTRA_CFLAGS := -DNOT_IN_libc=1 \
 	-include $(top_builddir)include/libc-symbols.h
 
 tlsmod17a-suffixes := 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
+tlsmod18a-suffixes := 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
 CFLAGS_tst-tlsmod1.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod2.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod3.so := -fPIC -DSHARED -shared
@@ -49,6 +50,7 @@ CFLAGS_tst-tlsmod16a.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod16b.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod17a.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod17b.so := -fPIC -DSHARED -shared
+CFLAGS_tst-tlsmod18a.so := -fPIC -DSHARED -shared
 CFLAGS_tst-tlsmod-at-ctor.so := -fPIC -DSHARED -shared
 
 LDFLAGS_tst-tlsmod1.so := -shared -static-libgcc -L$(top_builddir)lib
@@ -80,6 +82,7 @@ LDFLAGS_tst-tlsmod16b.so := -shared -static-libgcc -L$(top_builddir)lib
 LDFLAGS_tst-tlsmod17a.so := -shared -static-libgcc -L$(top_builddir)lib
 LDFLAGS_tst-tlsmod17b.so := -shared -static-libgcc -L$(top_builddir)lib \
 	$(patsubst %,tst-tlsmod17a%.so,$(tlsmod17a-suffixes))
+LDFLAGS_tst-tlsmod18a.so := -shared -static-libgcc -L$(top_builddir)lib
 LDFLAGS_tst-tlsmod-at-ctor.so := -shared -static-libgcc -L$(top_builddir)lib
 
 LDFLAGS_tst-tls3 := tst-tlsmod1.so tst-tlsmod4.so
@@ -97,6 +100,7 @@ LDFLAGS_tst-tls14 := -ldl -Wl,-rpath-link=. tst-tlsmod14a.so
 LDFLAGS_tst-tls15 := -ldl -Wl,-rpath-link=.
 LDFLAGS_tst-tls16 := -ldl -Wl,-rpath-link=.
 LDFLAGS_tst-tls17 := -ldl -Wl,-rpath-link=.
+LDFLAGS_tst-tls18 := -ldl -Wl,-rpath-link=.
 LDFLAGS_tst-tls-at-ctor := tst-tlsmod-at-ctor.so
 
 tst-tls3: tst-tlsmod1.so tst-tlsmod4.so
@@ -119,6 +123,11 @@ tst-tlsmod17a%.so: tst-tlsmod17a.c
 	$(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_tst-tlsmod17a.so) $< -o $@ \
 	-DN=$* -Wl,-soname,$@ $(LDFLAGS) $(EXTRA_LIBS) \
 	$(LDFLAGS_tst-tlsmod17a.so)
+tst-tls18: $(patsubst %,tst-tlsmod18a%.so,$(tlsmod18a-suffixes))
+tst-tlsmod18a%.so: tst-tlsmod18a.c
+	$(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_tst-tlsmod18a.so) $< -o $@ \
+	-DN=$* -Wl,-soname,$@ $(LDFLAGS) $(EXTRA_LIBS) \
+	$(LDFLAGS_tst-tlsmod18a.so)
 tst-tls-at-ctor: tst-tlsmod-at-ctor.so
 
 RET_tst-tls13 := 1
diff --git a/test/tls/tst-tls18.c b/test/tls/tst-tls18.c
new file mode 100644
index 0000000..00dcdff
--- /dev/null
+++ b/test/tls/tst-tls18.c
@@ -0,0 +1,38 @@
+#include <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+static int
+do_test (void)
+{
+  char modname[sizeof "tst-tlsmod18aXX.so"];
+  void *h[20];
+  for (int i = 0; i < 20; i++)
+    {
+      snprintf (modname, sizeof modname, "tst-tlsmod18a%d.so", i);
+      h[i] = dlopen (modname, RTLD_LAZY);
+      if (h[i] == NULL)
+	{
+	  printf ("unexpectedly failed to open %s", modname);
+	  exit (1);
+	}
+    }
+
+  for (int i = 0; i < 20; i++)
+    {
+      int (*fp) (void) = (int (*) (void)) dlsym (h[i], "test");
+      if (fp == NULL)
+	{
+	  printf ("cannot find test in tst-tlsmod18a%d.so", i);
+	  exit (1);
+	}
+
+      if (fp ())
+	exit (1);
+    }
+
+  return 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/test/tls/tst-tlsmod18a.c b/test/tls/tst-tlsmod18a.c
new file mode 100644
index 0000000..9aba607
--- /dev/null
+++ b/test/tls/tst-tlsmod18a.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+
+#ifndef N
+# define N 0
+#endif
+
+static __thread int var = 4;
+
+int
+test (void)
+{
+  int *p = &var;
+  /* GCC assumes &var is never NULL, add optimization barrier.  */
+  __asm __volatile ("" : "+r" (p));
+  if (p == NULL || *p != 4)
+    {
+      printf ("fail %d %p\n", N, p);
+      return 1;
+    }
+  return 0;
+}
-- 
1.6.3.3



More information about the uClibc-cvs mailing list