mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
Fix handling of static TLS in dlopen'ed objects
When dynamically loading a library along with several dependencies, calls to _dl_add_to_slotinfo and _dl_update_slotinfo can become intermixed. As a consequence, _dl_update_slotinfo will update the generation counter of the dtv although not all of the slots belonging to that generation have been added. Subsequent calls to _dl_add_to_slotinfo will add more slots to the same generation, for which no storage will be allocated, as the dtv generation checks will claim no work is necessary. This will lead to uninitialized dtv entries and will likely cause a SIGSEGV when thread local variables are accessed.
This commit is contained in:
parent
a79a1c704b
commit
d26dfc60ed
10
ChangeLog
10
ChangeLog
@ -1,5 +1,15 @@
|
|||||||
2011-05-14 Ulrich Drepper <drepper@gmail.com>
|
2011-05-14 Ulrich Drepper <drepper@gmail.com>
|
||||||
|
|
||||||
|
[BZ #12453]
|
||||||
|
* elf/dl-open.c (dl_open_worker): Delay calls to _dl_update_slotinfo
|
||||||
|
until all modules are registered in the DTV.
|
||||||
|
* elf/Makefile: Add rules to build and run tst-tls19.
|
||||||
|
* elf/tst-tls19.c: New file.
|
||||||
|
* elf/tst-tls19mod1.c: New file.
|
||||||
|
* elf/tst-tls19mod2.c: New file.
|
||||||
|
* elf/tst-tls19mod3.c: New file.
|
||||||
|
Patch mostly by Martin von Gagern <Martin.vGagern@gmx.net>.
|
||||||
|
|
||||||
[BZ #12083]
|
[BZ #12083]
|
||||||
* sysdeps/pthread/aio_misc.c (__aio_init): Compute optim.aio_num
|
* sysdeps/pthread/aio_misc.c (__aio_init): Compute optim.aio_num
|
||||||
correctly.
|
correctly.
|
||||||
|
8
NEWS
8
NEWS
@ -11,10 +11,10 @@ Version 2.14
|
|||||||
|
|
||||||
386, 11257, 11258, 11487, 11532, 11578, 11653, 11668, 11724, 11945, 11947,
|
386, 11257, 11258, 11487, 11532, 11578, 11653, 11668, 11724, 11945, 11947,
|
||||||
12052, 12083, 12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445,
|
12052, 12083, 12158, 12178, 12200, 12346, 12393, 12420, 12432, 12445,
|
||||||
12449, 12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518, 12527,
|
12449, 12453, 12454, 12460, 12469, 12489, 12509, 12510, 12511, 12518,
|
||||||
12541, 12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611, 12625,
|
12527, 12541, 12545, 12551, 12582, 12583, 12587, 12597, 12601, 12611,
|
||||||
12626, 12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711, 12713,
|
12625, 12626, 12631, 12650, 12653, 12655, 12660, 12681, 12685, 12711,
|
||||||
12714, 12717, 12723, 12724, 12734, 12738
|
12713, 12714, 12717, 12723, 12724, 12734, 12738
|
||||||
|
|
||||||
* The RPC implementation in libc is obsoleted. Old programs keep working
|
* The RPC implementation in libc is obsoleted. Old programs keep working
|
||||||
but new programs cannot be linked with the routines in libc anymore.
|
but new programs cannot be linked with the routines in libc anymore.
|
||||||
|
@ -76,6 +76,7 @@ distribute := rtld-Rules \
|
|||||||
tst-tlsmod12.c tst-tls10.h tst-alignmod.c tst-alignmod2.c \
|
tst-tlsmod12.c tst-tls10.h tst-alignmod.c tst-alignmod2.c \
|
||||||
circlemod1.c circlemod1a.c circlemod2.c circlemod2a.c \
|
circlemod1.c circlemod1a.c circlemod2.c circlemod2a.c \
|
||||||
circlemod3.c circlemod3a.c nodlopenmod2.c \
|
circlemod3.c circlemod3a.c nodlopenmod2.c \
|
||||||
|
tst-tls19mod1.c tst-tls19mod2.c tst-tls19mod3.c \
|
||||||
tls-macros.h \
|
tls-macros.h \
|
||||||
reldep8mod1.c reldep8mod2.c reldep8mod3.c \
|
reldep8mod1.c reldep8mod2.c reldep8mod3.c \
|
||||||
nodel2mod1.c nodel2mod2.c nodel2mod3.c \
|
nodel2mod1.c nodel2mod2.c nodel2mod3.c \
|
||||||
@ -194,7 +195,7 @@ tests += loadtest restest1 preloadtest loadfail multiload origtest resolvfail \
|
|||||||
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
|
restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \
|
||||||
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
|
circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \
|
||||||
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
|
tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 \
|
||||||
tst-tls16 tst-tls17 tst-tls18 tst-tls-dlinfo \
|
tst-tls16 tst-tls17 tst-tls18 tst-tls19 tst-tls-dlinfo \
|
||||||
tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
|
tst-align tst-align2 $(tests-execstack-$(have-z-execstack)) \
|
||||||
tst-dlmodcount tst-dlopenrpath tst-deep1 \
|
tst-dlmodcount tst-dlopenrpath tst-deep1 \
|
||||||
tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
|
tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 \
|
||||||
@ -240,6 +241,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
|
|||||||
tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
|
tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \
|
||||||
tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \
|
tst-tlsmod15a tst-tlsmod15b tst-tlsmod16a tst-tlsmod16b \
|
||||||
$(tlsmod17a-modules) tst-tlsmod17b $(tlsmod18a-modules) \
|
$(tlsmod17a-modules) tst-tlsmod17b $(tlsmod18a-modules) \
|
||||||
|
tst-tls19mod1 tst-tls19mod2 tst-tls19mod3 \
|
||||||
circlemod1 circlemod1a circlemod2 circlemod2a \
|
circlemod1 circlemod1a circlemod2 circlemod2a \
|
||||||
circlemod3 circlemod3a \
|
circlemod3 circlemod3a \
|
||||||
reldep8mod1 reldep8mod2 reldep8mod3 \
|
reldep8mod1 reldep8mod2 reldep8mod3 \
|
||||||
@ -525,6 +527,8 @@ $(objpfx)tst-tlsmod13a.so: $(objpfx)tst-tlsmod13.so
|
|||||||
# For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED
|
# For tst-tls9-static, make sure the modules it dlopens have libc.so in DT_NEEDED
|
||||||
$(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so
|
$(objpfx)tst-tlsmod5.so: $(common-objpfx)libc.so
|
||||||
$(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so
|
$(objpfx)tst-tlsmod6.so: $(common-objpfx)libc.so
|
||||||
|
$(objpfx)tst-tls19mod1.so: $(objpfx)tst-tls19mod2.so $(objpfx)tst-tls19mod3.so
|
||||||
|
$(objpfx)tst-tls19mod3.so: $(objpfx)ld.so
|
||||||
$(objpfx)reldep8mod3.so: $(objpfx)reldep8mod1.so $(objpfx)reldep8mod2.so
|
$(objpfx)reldep8mod3.so: $(objpfx)reldep8mod1.so $(objpfx)reldep8mod2.so
|
||||||
$(objpfx)nodel2mod3.so: $(objpfx)nodel2mod1.so $(objpfx)nodel2mod2.so
|
$(objpfx)nodel2mod3.so: $(objpfx)nodel2mod1.so $(objpfx)nodel2mod2.so
|
||||||
$(objpfx)reldep9mod2.so: $(objpfx)reldep9mod1.so
|
$(objpfx)reldep9mod2.so: $(objpfx)reldep9mod1.so
|
||||||
@ -822,6 +826,9 @@ $(patsubst %,$(objpfx)%.os,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.os : t
|
|||||||
$(compile-command.c) -DN=$*
|
$(compile-command.c) -DN=$*
|
||||||
$(patsubst %,$(objpfx)%.so,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.so: $(objpfx)ld.so
|
$(patsubst %,$(objpfx)%.so,$(tlsmod18a-modules)): $(objpfx)tst-tlsmod18a%.so: $(objpfx)ld.so
|
||||||
|
|
||||||
|
$(objpfx)tst-tls19: $(libdl)
|
||||||
|
$(objpfx)tst-tls19.out: $(objpfx)tst-tls19mod1.so
|
||||||
|
|
||||||
CFLAGS-tst-align.c = $(stack-align-test-flags)
|
CFLAGS-tst-align.c = $(stack-align-test-flags)
|
||||||
CFLAGS-tst-align2.c = $(stack-align-test-flags)
|
CFLAGS-tst-align2.c = $(stack-align-test-flags)
|
||||||
CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
|
CFLAGS-tst-alignmod.c = $(stack-align-test-flags)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Load a shared object at runtime, relocate it, and run its initializer.
|
/* Load a shared object at runtime, relocate it, and run its initializer.
|
||||||
Copyright (C) 1996-2007, 2009, 2010 Free Software Foundation, Inc.
|
Copyright (C) 1996-2007, 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -347,6 +347,7 @@ dl_open_worker (void *a)
|
|||||||
/* If the file is not loaded now as a dependency, add the search
|
/* If the file is not loaded now as a dependency, add the search
|
||||||
list of the newly loaded object to the scope. */
|
list of the newly loaded object to the scope. */
|
||||||
bool any_tls = false;
|
bool any_tls = false;
|
||||||
|
unsigned int first_static_tls = new->l_searchlist.r_nlist;
|
||||||
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
for (unsigned int i = 0; i < new->l_searchlist.r_nlist; ++i)
|
||||||
{
|
{
|
||||||
struct link_map *imap = new->l_searchlist.r_list[i];
|
struct link_map *imap = new->l_searchlist.r_list[i];
|
||||||
@ -425,30 +426,9 @@ dl_open_worker (void *a)
|
|||||||
might have to increase its size. */
|
might have to increase its size. */
|
||||||
_dl_add_to_slotinfo (imap);
|
_dl_add_to_slotinfo (imap);
|
||||||
|
|
||||||
if (imap->l_need_tls_init)
|
if (imap->l_need_tls_init
|
||||||
{
|
&& first_static_tls == new->l_searchlist.r_nlist)
|
||||||
/* For static TLS we have to allocate the memory here
|
first_static_tls = i;
|
||||||
and now. This includes allocating memory in the DTV.
|
|
||||||
But we cannot change any DTV other than our own. So,
|
|
||||||
if we cannot guarantee that there is room in the DTV
|
|
||||||
we don't even try it and fail the load.
|
|
||||||
|
|
||||||
XXX We could track the minimum DTV slots allocated in
|
|
||||||
all threads. */
|
|
||||||
if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
|
|
||||||
_dl_signal_error (0, "dlopen", NULL, N_("\
|
|
||||||
cannot load any more object with static TLS"));
|
|
||||||
|
|
||||||
imap->l_need_tls_init = 0;
|
|
||||||
#ifdef SHARED
|
|
||||||
/* Update the slot information data for at least the
|
|
||||||
generation of the DSO we are allocating data for. */
|
|
||||||
_dl_update_slotinfo (imap->l_tls_modid);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GL(dl_init_static_tls) (imap);
|
|
||||||
assert (imap->l_need_tls_init == 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We have to bump the generation counter. */
|
/* We have to bump the generation counter. */
|
||||||
any_tls = true;
|
any_tls = true;
|
||||||
@ -460,6 +440,40 @@ cannot load any more object with static TLS"));
|
|||||||
_dl_fatal_printf (N_("\
|
_dl_fatal_printf (N_("\
|
||||||
TLS generation counter wrapped! Please report this."));
|
TLS generation counter wrapped! Please report this."));
|
||||||
|
|
||||||
|
/* We need a second pass for static tls data, because _dl_update_slotinfo
|
||||||
|
must not be run while calls to _dl_add_to_slotinfo are still pending. */
|
||||||
|
for (unsigned int i = first_static_tls; i < new->l_searchlist.r_nlist; ++i)
|
||||||
|
{
|
||||||
|
struct link_map *imap = new->l_searchlist.r_list[i];
|
||||||
|
|
||||||
|
if (imap->l_need_tls_init
|
||||||
|
&& ! imap->l_init_called
|
||||||
|
&& imap->l_tls_blocksize > 0)
|
||||||
|
{
|
||||||
|
/* For static TLS we have to allocate the memory here and
|
||||||
|
now. This includes allocating memory in the DTV. But we
|
||||||
|
cannot change any DTV other than our own. So, if we
|
||||||
|
cannot guarantee that there is room in the DTV we don't
|
||||||
|
even try it and fail the load.
|
||||||
|
|
||||||
|
XXX We could track the minimum DTV slots allocated in
|
||||||
|
all threads. */
|
||||||
|
if (! RTLD_SINGLE_THREAD_P && imap->l_tls_modid > DTV_SURPLUS)
|
||||||
|
_dl_signal_error (0, "dlopen", NULL, N_("\
|
||||||
|
cannot load any more object with static TLS"));
|
||||||
|
|
||||||
|
imap->l_need_tls_init = 0;
|
||||||
|
#ifdef SHARED
|
||||||
|
/* Update the slot information data for at least the
|
||||||
|
generation of the DSO we are allocating data for. */
|
||||||
|
_dl_update_slotinfo (imap->l_tls_modid);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
GL(dl_init_static_tls) (imap);
|
||||||
|
assert (imap->l_need_tls_init == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Run the initializer functions of new objects. */
|
/* Run the initializer functions of new objects. */
|
||||||
_dl_init (new, args->argc, args->argv, args->env);
|
_dl_init (new, args->argc, args->argv, args->env);
|
||||||
|
|
||||||
|
27
elf/tst-tls19.c
Normal file
27
elf/tst-tls19.c
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
// BZ 12453
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
do_test (void)
|
||||||
|
{
|
||||||
|
void* dl = dlopen ("tst-tls19mod1.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||||
|
if (dl == NULL)
|
||||||
|
{
|
||||||
|
printf ("Error loading tst-tls19mod1.so: %s\n", dlerror ());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int (*fn) (void) = dlsym (dl, "foo");
|
||||||
|
if (fn == NULL)
|
||||||
|
{
|
||||||
|
printf("Error obtaining symbol foo\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fn ();
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TEST_FUNCTION do_test ()
|
||||||
|
#include "../test-skeleton.c"
|
15
elf/tst-tls19mod1.c
Normal file
15
elf/tst-tls19mod1.c
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern int bar (void);
|
||||||
|
extern int baz (void);
|
||||||
|
|
||||||
|
int
|
||||||
|
foo (void)
|
||||||
|
{
|
||||||
|
int v1 = bar ();
|
||||||
|
int v2 = baz ();
|
||||||
|
|
||||||
|
printf ("bar=%d, baz=%d\n", v1, v2);
|
||||||
|
|
||||||
|
return v1 != 666 || v2 != 42;
|
||||||
|
}
|
13
elf/tst-tls19mod2.c
Normal file
13
elf/tst-tls19mod2.c
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
static int __thread tbar __attribute__ ((tls_model ("initial-exec"))) = 666;
|
||||||
|
|
||||||
|
void
|
||||||
|
setter (int a)
|
||||||
|
{
|
||||||
|
tbar = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
bar (void)
|
||||||
|
{
|
||||||
|
return tbar;
|
||||||
|
}
|
16
elf/tst-tls19mod3.c
Normal file
16
elf/tst-tls19mod3.c
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static int __thread tbaz __attribute__ ((tls_model ("local-dynamic"))) = 42;
|
||||||
|
|
||||||
|
void
|
||||||
|
setter2 (int a)
|
||||||
|
{
|
||||||
|
tbaz = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
baz (void)
|
||||||
|
{
|
||||||
|
printf ("&tbaz=%p\n", &tbaz);
|
||||||
|
return tbaz;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user