about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--elf/Makefile15
-rw-r--r--elf/tst-tlsgap-mod0.c2
-rw-r--r--elf/tst-tlsgap-mod1.c2
-rw-r--r--elf/tst-tlsgap-mod2.c2
-rw-r--r--elf/tst-tlsgap.c92
5 files changed, 113 insertions, 0 deletions
diff --git a/elf/Makefile b/elf/Makefile
index c00e2ccfc5..1a05a6aaca 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -459,6 +459,7 @@ tests += \
   tst-tls21 \
   tst-tlsalign \
   tst-tlsalign-extern \
+  tst-tlsgap \
   tst-unique1 \
   tst-unique2 \
   tst-unwind-ctor \
@@ -883,6 +884,9 @@ modules-names += \
   tst-tls20mod-bad \
   tst-tls21mod \
   tst-tlsalign-lib \
+  tst-tlsgap-mod0 \
+  tst-tlsgap-mod1 \
+  tst-tlsgap-mod2 \
   tst-tlsmod1 \
   tst-tlsmod10 \
   tst-tlsmod11 \
@@ -3009,3 +3013,14 @@ LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed
 $(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so
 $(objpfx)tst-dlclose-lazy.out: \
   $(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so
+
+$(objpfx)tst-tlsgap: $(shared-thread-library)
+$(objpfx)tst-tlsgap.out: \
+  $(objpfx)tst-tlsgap-mod0.so \
+  $(objpfx)tst-tlsgap-mod1.so \
+  $(objpfx)tst-tlsgap-mod2.so
+ifeq (yes,$(have-mtls-dialect-gnu2))
+CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=gnu2
+CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2
+CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2
+endif
diff --git a/elf/tst-tlsgap-mod0.c b/elf/tst-tlsgap-mod0.c
new file mode 100644
index 0000000000..1478b0beac
--- /dev/null
+++ b/elf/tst-tlsgap-mod0.c
@@ -0,0 +1,2 @@
+int __thread tls0;
+int *f0(void) { return &tls0; }
diff --git a/elf/tst-tlsgap-mod1.c b/elf/tst-tlsgap-mod1.c
new file mode 100644
index 0000000000..b10fc3702c
--- /dev/null
+++ b/elf/tst-tlsgap-mod1.c
@@ -0,0 +1,2 @@
+int __thread tls1[100]; /* Size > glibc.rtld.optional_static_tls / 2.  */
+int *f1(void) { return tls1; }
diff --git a/elf/tst-tlsgap-mod2.c b/elf/tst-tlsgap-mod2.c
new file mode 100644
index 0000000000..166c27d7f3
--- /dev/null
+++ b/elf/tst-tlsgap-mod2.c
@@ -0,0 +1,2 @@
+int __thread tls2;
+int *f2(void) { return &tls2; }
diff --git a/elf/tst-tlsgap.c b/elf/tst-tlsgap.c
new file mode 100644
index 0000000000..4932885076
--- /dev/null
+++ b/elf/tst-tlsgap.c
@@ -0,0 +1,92 @@
+/* TLS modid gap reuse regression test for bug 29039.
+   Copyright (C) 2023 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+#include <support/check.h>
+
+static void *mod[3];
+#define MOD(i) "tst-tlsgap-mod" #i ".so"
+static const char *modname[3] = { MOD(0), MOD(1), MOD(2) };
+#undef MOD
+
+static void
+open_mod (int i)
+{
+  mod[i] = xdlopen (modname[i], RTLD_LAZY);
+  printf ("open %s\n", modname[i]);
+}
+
+static void
+close_mod (int i)
+{
+  xdlclose (mod[i]);
+  mod[i] = NULL;
+  printf ("close %s\n", modname[i]);
+}
+
+static void
+access_mod (int i, const char *sym)
+{
+  int *(*f) (void) = xdlsym (mod[i], sym);
+  int *p = f ();
+  printf ("access %s: %s() = %p\n", modname[i], sym, p);
+  TEST_VERIFY_EXIT (p != NULL);
+  ++*p;
+}
+
+static void *
+start (void *arg)
+{
+  /* The DTV generation is at the last dlopen of mod0 and the
+     entry for mod1 is NULL.  */
+
+  open_mod (1); /* Reuse modid of mod1. Uses dynamic TLS.  */
+
+  /* DTV is unchanged: dlopen only updates the DTV to the latest
+     generation if static TLS is allocated for a loaded module.
+
+     With bug 29039, the TLSDESC relocation in mod1 uses the old
+     dlclose generation of mod1 instead of the new dlopen one so
+     DTV is not updated on TLS access.  */
+
+  access_mod (1, "f1");
+
+  return arg;
+}
+
+static int
+do_test (void)
+{
+  open_mod (0);
+  open_mod (1);
+  open_mod (2);
+  close_mod (0);
+  close_mod (1); /* Create modid gap at mod1.  */
+  open_mod (0); /* Reuse modid of mod0, bump generation count.  */
+
+  /* Create a thread where DTV of mod1 is NULL.  */
+  pthread_t t = xpthread_create (NULL, start, NULL);
+  xpthread_join (t);
+  return 0;
+}
+
+#include <support/test-driver.c>