|
|
|
#
|
|
|
|
# Based on this upstream commit:
|
|
|
|
#
|
|
|
|
# commit d8dd00805b8f3a011735d7a407097fb1c408d867
|
|
|
|
# Author: H.J. Lu <hjl.tools@gmail.com>
|
|
|
|
# Date: Fri Nov 28 07:54:07 2014 -0800
|
|
|
|
#
|
|
|
|
# Resize DTV if the current DTV isn't big enough
|
|
|
|
#
|
|
|
|
# This patch changes _dl_allocate_tls_init to resize DTV if the current DTV
|
|
|
|
# isn't big enough. Tested on X86-64, x32 and ia32.
|
|
|
|
#
|
|
|
|
# [BZ #13862]
|
|
|
|
# * elf/dl-tls.c: Include <atomic.h>.
|
|
|
|
# (oom): Remove #ifdef SHARED/#endif.
|
|
|
|
# (_dl_static_dtv, _dl_initial_dtv): Moved before ...
|
|
|
|
# (_dl_resize_dtv): This. Extracted from _dl_update_slotinfo.
|
|
|
|
# (_dl_allocate_tls_init): Resize DTV if the current DTV isn't
|
|
|
|
# big enough.
|
|
|
|
# (_dl_update_slotinfo): Call _dl_resize_dtv to resize DTV.
|
|
|
|
# * nptl/Makefile (tests): Add tst-stack4.
|
|
|
|
# (modules-names): Add tst-stack4mod.
|
|
|
|
# ($(objpfx)tst-stack4): New.
|
|
|
|
# (tst-stack4mod.sos): Likewise.
|
|
|
|
# ($(objpfx)tst-stack4.out): Likewise.
|
|
|
|
# ($(tst-stack4mod.sos)): Likewise.
|
|
|
|
# (clean): Likewise.
|
|
|
|
# * nptl/tst-stack4.c: New file.
|
|
|
|
# * nptl/tst-stack4mod.c: Likewise.
|
|
|
|
#
|
|
|
|
diff -urN glibc-2.17-c758a686/elf/dl-tls.c glibc-2.17-c758a686/elf/dl-tls.c
|
|
|
|
--- glibc-2.17-c758a686/elf/dl-tls.c 2015-02-18 14:15:28.078461873 -0500
|
|
|
|
+++ glibc-2.17-c758a686/elf/dl-tls.c 2015-02-18 14:38:37.630374771 -0500
|
|
|
|
@@ -24,6 +24,7 @@
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/param.h>
|
|
|
|
+#include <atomic.h>
|
|
|
|
|
|
|
|
#include <tls.h>
|
|
|
|
#include <dl-tls.h>
|
|
|
|
@@ -35,14 +36,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
/* Out-of-memory handler. */
|
|
|
|
-#ifdef SHARED
|
|
|
|
static void
|
|
|
|
__attribute__ ((__noreturn__))
|
|
|
|
oom (void)
|
|
|
|
{
|
|
|
|
_dl_fatal_printf ("cannot allocate memory for thread-local data: ABORT\n");
|
|
|
|
}
|
|
|
|
-#endif
|
|
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
@@ -392,6 +391,52 @@
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static dtv_t *
|
|
|
|
+_dl_resize_dtv (dtv_t *dtv)
|
|
|
|
+{
|
|
|
|
+ /* Resize the dtv. */
|
|
|
|
+ dtv_t *newp;
|
|
|
|
+ /* Load GL(dl_tls_max_dtv_idx) atomically since it may be written to by
|
|
|
|
+ other threads concurrently. -- We don't have the required atomic
|
|
|
|
+ infrastructure to load dl_tls_max_dtv_idx atomically, but on all the
|
|
|
|
+ architectures we care about it should load atomically. If this had
|
|
|
|
+ an atomic_load_acquire we would still be missing the releases for
|
|
|
|
+ the writes. */
|
|
|
|
+ size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
|
|
|
|
+ size_t oldsize = dtv[-1].counter;
|
|
|
|
+
|
|
|
|
+#if SHARED
|
|
|
|
+ if (dtv == GL(dl_initial_dtv))
|
|
|
|
+ {
|
|
|
|
+ /* This is the initial dtv that was either statically allocated in
|
|
|
|
+ __libc_setup_tls or allocated during rtld startup using the
|
|
|
|
+ dl-minimal.c malloc instead of the real malloc. We can't free
|
|
|
|
+ it, we have to abandon the old storage. */
|
|
|
|
+
|
|
|
|
+ newp = malloc ((2 + newsize) * sizeof (dtv_t));
|
|
|
|
+ if (newp == NULL)
|
|
|
|
+ oom ();
|
|
|
|
+ memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+#endif
|
|
|
|
+ {
|
|
|
|
+ newp = realloc (&dtv[-1],
|
|
|
|
+ (2 + newsize) * sizeof (dtv_t));
|
|
|
|
+ if (newp == NULL)
|
|
|
|
+ oom ();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ newp[0].counter = newsize;
|
|
|
|
+
|
|
|
|
+ /* Clear the newly allocated part. */
|
|
|
|
+ memset (newp + 2 + oldsize, '\0',
|
|
|
|
+ (newsize - oldsize) * sizeof (dtv_t));
|
|
|
|
+
|
|
|
|
+ /* Return the generation counter. */
|
|
|
|
+ return &newp[1];
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
|
|
|
|
void *
|
|
|
|
internal_function
|
|
|
|
@@ -406,6 +451,16 @@
|
|
|
|
size_t total = 0;
|
|
|
|
size_t maxgen = 0;
|
|
|
|
|
|
|
|
+ /* Check if the current dtv is big enough. */
|
|
|
|
+ if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
|
|
|
|
+ {
|
|
|
|
+ /* Resize the dtv. */
|
|
|
|
+ dtv = _dl_resize_dtv (dtv);
|
|
|
|
+
|
|
|
|
+ /* Install this new dtv in the thread data structures. */
|
|
|
|
+ INSTALL_DTV (result, &dtv[-1]);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
/* We have to prepare the dtv for all currently loaded modules using
|
|
|
|
TLS. For those which are dynamically loaded we add the values
|
|
|
|
indicating deferred allocation. */
|
|
|
|
@@ -637,41 +692,10 @@
|
|
|
|
assert (total + cnt == modid);
|
|
|
|
if (dtv[-1].counter < modid)
|
|
|
|
{
|
|
|
|
- /* Reallocate the dtv. */
|
|
|
|
- dtv_t *newp;
|
|
|
|
- size_t newsize = GL(dl_tls_max_dtv_idx) + DTV_SURPLUS;
|
|
|
|
- size_t oldsize = dtv[-1].counter;
|
|
|
|
-
|
|
|
|
- assert (map->l_tls_modid <= newsize);
|
|
|
|
-
|
|
|
|
- if (dtv == GL(dl_initial_dtv))
|
|
|
|
- {
|
|
|
|
- /* This is the initial dtv that was allocated
|
|
|
|
- during rtld startup using the dl-minimal.c
|
|
|
|
- malloc instead of the real malloc. We can't
|
|
|
|
- free it, we have to abandon the old storage. */
|
|
|
|
-
|
|
|
|
- newp = malloc ((2 + newsize) * sizeof (dtv_t));
|
|
|
|
- if (newp == NULL)
|
|
|
|
- oom ();
|
|
|
|
- memcpy (newp, &dtv[-1], (2 + oldsize) * sizeof (dtv_t));
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- newp = realloc (&dtv[-1],
|
|
|
|
- (2 + newsize) * sizeof (dtv_t));
|
|
|
|
- if (newp == NULL)
|
|
|
|
- oom ();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- newp[0].counter = newsize;
|
|
|
|
-
|
|
|
|
- /* Clear the newly allocated part. */
|
|
|
|
- memset (newp + 2 + oldsize, '\0',
|
|
|
|
- (newsize - oldsize) * sizeof (dtv_t));
|
|
|
|
+ /* Resize the dtv. */
|
|
|
|
+ dtv = _dl_resize_dtv (dtv);
|
|
|
|
|
|
|
|
- /* Point dtv to the generation counter. */
|
|
|
|
- dtv = &newp[1];
|
|
|
|
+ assert (modid <= dtv[-1].counter);
|
|
|
|
|
|
|
|
/* Install this new dtv in the thread data
|
|
|
|
structures. */
|
|
|
|
diff -urN glibc-2.17-c758a686/nptl/Makefile glibc-2.17-c758a686/nptl/Makefile
|
|
|
|
--- glibc-2.17-c758a686/nptl/Makefile 2015-02-18 14:15:28.073462028 -0500
|
|
|
|
+++ glibc-2.17-c758a686/nptl/Makefile 2015-02-18 14:15:49.817786667 -0500
|
|
|
|
@@ -251,7 +251,7 @@
|
|
|
|
tst-exec1 tst-exec2 tst-exec3 tst-exec4 \
|
|
|
|
tst-exit1 tst-exit2 tst-exit3 \
|
|
|
|
tst-stdio1 tst-stdio2 \
|
|
|
|
- tst-stack1 tst-stack2 tst-stack3 tst-pthread-getattr \
|
|
|
|
+ tst-stack1 tst-stack2 tst-stack3 tst-stack4 tst-pthread-getattr \
|
|
|
|
tst-unload \
|
|
|
|
tst-dlsym1 \
|
|
|
|
tst-sysconf \
|
|
|
|
@@ -297,7 +297,7 @@
|
|
|
|
|
|
|
|
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-tls5modd tst-tls5mode tst-tls5modf tst-stack4mod \
|
|
|
|
tst-_res1mod1 tst-_res1mod2 tst-execstack-mod tst-fini1mod
|
|
|
|
extra-test-objs += $(addsuffix .os,$(strip $(modules-names))) tst-cleanup4aux.o
|
|
|
|
test-extras += $(modules-names) tst-cleanup4aux
|
|
|
|
@@ -459,6 +459,19 @@
|
|
|
|
$(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@
|
|
|
|
generated += tst-stack3-mem tst-stack3.mtrace
|
|
|
|
|
|
|
|
+$(objpfx)tst-stack4: $(libdl) $(shared-thread-library)
|
|
|
|
+tst-stack4mod.sos=$(shell for i in 0 1 2 3 4 5 6 7 8 9 10 \
|
|
|
|
+ 11 12 13 14 15 16 17 18 19; do \
|
|
|
|
+ for j in 0 1 2 3 4 5 6 7 8 9 10 \
|
|
|
|
+ 11 12 13 14 15 16 17 18 19; do \
|
|
|
|
+ echo $(objpfx)tst-stack4mod-$$i-$$j.so; \
|
|
|
|
+ done; done)
|
|
|
|
+$(objpfx)tst-stack4.out: $(tst-stack4mod.sos)
|
|
|
|
+$(tst-stack4mod.sos): $(objpfx)tst-stack4mod.so
|
|
|
|
+ cp -f $< $@
|
|
|
|
+clean:
|
|
|
|
+ rm -f $(tst-stack4mod.sos)
|
|
|
|
+
|
|
|
|
$(objpfx)tst-cleanup4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
|
|
|
|
$(objpfx)tst-cleanupx4: $(objpfx)tst-cleanup4aux.o $(shared-thread-library)
|
|
|
|
|
|
|
|
diff -urN glibc-2.17-c758a686/nptl/tst-stack4.c glibc-2.17-c758a686/nptl/tst-stack4.c
|
|
|
|
--- glibc-2.17-c758a686/nptl/tst-stack4.c 1969-12-31 19:00:00.000000000 -0500
|
|
|
|
+++ glibc-2.17-c758a686/nptl/tst-stack4.c 2015-02-18 14:15:49.817786667 -0500
|
|
|
|
@@ -0,0 +1,159 @@
|
|
|
|
+/* Test DTV size oveflow when pthread_create reuses old DTV and TLS is
|
|
|
|
+ used by dlopened shared object.
|
|
|
|
+ Copyright (C) 2014 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 <stdint.h>
|
|
|
|
+#include <dlfcn.h>
|
|
|
|
+#include <assert.h>
|
|
|
|
+#include <pthread.h>
|
|
|
|
+
|
|
|
|
+/* The choices of thread count, and file counts are arbitary.
|
|
|
|
+ The point is simply to run enough threads that an exiting
|
|
|
|
+ thread has it's stack reused by another thread at the same
|
|
|
|
+ time as new libraries have been loaded. */
|
|
|
|
+#define DSO_SHARED_FILES 20
|
|
|
|
+#define DSO_OPEN_THREADS 20
|
|
|
|
+#define DSO_EXEC_THREADS 2
|
|
|
|
+
|
|
|
|
+/* Used to make sure that only one thread is calling dlopen and dlclose
|
|
|
|
+ at a time. */
|
|
|
|
+pthread_mutex_t g_lock;
|
|
|
|
+
|
|
|
|
+typedef void (*function) (void);
|
|
|
|
+
|
|
|
|
+void *
|
|
|
|
+dso_invoke(void *dso_fun)
|
|
|
|
+{
|
|
|
|
+ function *fun_vec = (function *) dso_fun;
|
|
|
|
+ int dso;
|
|
|
|
+
|
|
|
|
+ for (dso = 0; dso < DSO_SHARED_FILES; dso++)
|
|
|
|
+ (*fun_vec[dso]) ();
|
|
|
|
+
|
|
|
|
+ pthread_exit (NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void *
|
|
|
|
+dso_process (void * p)
|
|
|
|
+{
|
|
|
|
+ void *handle[DSO_SHARED_FILES];
|
|
|
|
+ function fun_vec[DSO_SHARED_FILES];
|
|
|
|
+ char dso_path[DSO_SHARED_FILES][100];
|
|
|
|
+ int dso;
|
|
|
|
+ uintptr_t t = (uintptr_t) p;
|
|
|
|
+
|
|
|
|
+ /* Open DSOs and get a function. */
|
|
|
|
+ for (dso = 0; dso < DSO_SHARED_FILES; dso++)
|
|
|
|
+ {
|
|
|
|
+ sprintf (dso_path[dso], "tst-stack4mod-%i-%i.so", t, dso);
|
|
|
|
+
|
|
|
|
+ pthread_mutex_lock (&g_lock);
|
|
|
|
+
|
|
|
|
+ handle[dso] = dlopen (dso_path[dso], RTLD_NOW);
|
|
|
|
+ assert (handle[dso]);
|
|
|
|
+
|
|
|
|
+ fun_vec[dso] = (function) dlsym (handle[dso], "function");
|
|
|
|
+ assert (fun_vec[dso]);
|
|
|
|
+
|
|
|
|
+ pthread_mutex_unlock (&g_lock);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Spawn workers. */
|
|
|
|
+ pthread_t thread[DSO_EXEC_THREADS];
|
|
|
|
+ int i, ret;
|
|
|
|
+ uintptr_t result = 0;
|
|
|
|
+ for (i = 0; i < DSO_EXEC_THREADS; i++)
|
|
|
|
+ {
|
|
|
|
+ pthread_mutex_lock (&g_lock);
|
|
|
|
+ ret = pthread_create (&thread[i], NULL, dso_invoke, (void *) fun_vec);
|
|
|
|
+ if (ret != 0)
|
|
|
|
+ {
|
|
|
|
+ printf ("pthread_create failed: %d\n", ret);
|
|
|
|
+ result = 1;
|
|
|
|
+ }
|
|
|
|
+ pthread_mutex_unlock (&g_lock);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!result)
|
|
|
|
+ for (i = 0; i < DSO_EXEC_THREADS; i++)
|
|
|
|
+ {
|
|
|
|
+ ret = pthread_join (thread[i], NULL);
|
|
|
|
+ if (ret != 0)
|
|
|
|
+ {
|
|
|
|
+ printf ("pthread_join failed: %d\n", ret);
|
|
|
|
+ result = 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Close all DSOs. */
|
|
|
|
+ for (dso = 0; dso < DSO_SHARED_FILES; dso++)
|
|
|
|
+ {
|
|
|
|
+ pthread_mutex_lock (&g_lock);
|
|
|
|
+ dlclose (handle[dso]);
|
|
|
|
+ pthread_mutex_unlock (&g_lock);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Exit. */
|
|
|
|
+ pthread_exit ((void *) result);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+do_test (void)
|
|
|
|
+{
|
|
|
|
+ pthread_t thread[DSO_OPEN_THREADS];
|
|
|
|
+ int i,j;
|
|
|
|
+ int ret;
|
|
|
|
+ int result = 0;
|
|
|
|
+
|
|
|
|
+ pthread_mutex_init (&g_lock, NULL);
|
|
|
|
+
|
|
|
|
+ /* 100 is arbitrary here and is known to trigger PR 13862. */
|
|
|
|
+ for (j = 0; j < 100; j++)
|
|
|
|
+ {
|
|
|
|
+ for (i = 0; i < DSO_OPEN_THREADS; i++)
|
|
|
|
+ {
|
|
|
|
+ ret = pthread_create (&thread[i], NULL, dso_process,
|
|
|
|
+ (void *) (uintptr_t) i);
|
|
|
|
+ if (ret != 0)
|
|
|
|
+ {
|
|
|
|
+ printf ("pthread_create failed: %d\n", ret);
|
|
|
|
+ result = 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (result)
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < DSO_OPEN_THREADS; i++)
|
|
|
|
+ {
|
|
|
|
+ ret = pthread_join (thread[i], NULL);
|
|
|
|
+ if (ret != 0)
|
|
|
|
+ {
|
|
|
|
+ printf ("pthread_join failed: %d\n", ret);
|
|
|
|
+ result = 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return result;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define TEST_FUNCTION do_test ()
|
|
|
|
+#define TIMEOUT 100
|
|
|
|
+#include "../test-skeleton.c"
|
|
|
|
diff -urN glibc-2.17-c758a686/nptl/tst-stack4mod.c glibc-2.17-c758a686/nptl/tst-stack4mod.c
|
|
|
|
--- glibc-2.17-c758a686/nptl/tst-stack4mod.c 1969-12-31 19:00:00.000000000 -0500
|
|
|
|
+++ glibc-2.17-c758a686/nptl/tst-stack4mod.c 2015-02-18 14:15:49.817786667 -0500
|
|
|
|
@@ -0,0 +1,28 @@
|
|
|
|
+/* This tests DTV usage with TLS in dlopened shared object.
|
|
|
|
+ Copyright (C) 2014 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/>. */
|
|
|
|
+
|
|
|
|
+/* 256 is arbitrary here and is known to trigger PR 13862. */
|
|
|
|
+__thread int var[256] attribute_hidden = {0};
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+function (void)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+ for (i = 0; i < sizeof (var) / sizeof (int); i++)
|
|
|
|
+ var[i] = i;
|
|
|
|
+}
|