Gentoo bug #52374. ================== Note, this patch includes both: ----- 2005-01-10 Ulrich Drepper * sysdeps/generic/dl-tls.c (_dl_next_tls_modid): Fix assertion and recognition of last entry. ----- and: ----- 2005-03-15 Jakub Jelinek [BZ#786] * sysdeps/generic/dl-tls.c (_dl_next_tls_modid): Handle GL(dl_tls_static_nelem) == GL(dl_tls_max_dtv_idx). * elf/Makefile: Add rules to build and run tst-tls15. * elf/tst-tls15.c: New test. * elf/tst-tlsmod15a.c: New file. * elf/tst-tlsmod15b.c: New file. ----- ================================================================================ On Sun, Mar 13, 2005 at 09:39:04PM +0200, Martin Schlemmer wrote: > Basically the issue above. This is valid for glibc 2.3.[234] if I did > not miss anything. Here is a good test case: > > http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=219352#msg122 > > I came up with attached patch that seems to work and passes all the > tests (except for the one or two usual ones). Is this the correct fix, > or are the problem deeper? > >--- glibc-2.3.4/sysdeps/generic/dl-tls.c.az 2005-03-13 19:26:55.000000000 +0200 >+++ glibc-2.3.4/sysdeps/generic/dl-tls.c 2005-03-13 19:29:14.000000000 +0200 >@@ -69,7 +69,10 @@ > result = GL(dl_tls_static_nelem) + 1; > /* If the following would not be true we mustn't have assumed > there is a gap. */ >- assert (result <= GL(dl_tls_max_dtv_idx)); >+ /* The +1 is needed, as we add +1 above, but dl_tls_static_nelem >+ is only once set as far as I can see in dl_main (elf/rtld.c), >+ and that is equal to dl_tls_max_dtv_idx ... */ >+ assert (result <= (GL(dl_tls_max_dtv_idx) + 1)); > do > { > while (result - disp < runp->len) >@@ -92,7 +95,8 @@ > { > /* The new index must indeed be exactly one higher than the > previous high. */ >- assert (result == GL(dl_tls_max_dtv_idx)); >+ /* Once again +1 for the same reasons as above ... */ >+ assert (result == (GL(dl_tls_max_dtv_idx) + 1)); > > /* There is no gap anymore. */ > GL(dl_tls_dtv_gaps) = false; > That patch certainly doesn't apply to neither HEAD nor glibc-2_3-branch, see especially: 2005-01-10 Ulrich Drepper * sysdeps/generic/dl-tls.c (_dl_next_tls_modid): Fix assertion and recognition of last entry. The fix can either be that dl-open.c only sets GL(dl_tls_dtv_gaps) to true if GL(dl_tls_static_nelem) < GL(dl_tls_max_dtv_idx) (if it is equal, there are certainly no gaps), or handling that case in _dl_next_tls_modid. In _dl_next_tls_modid, the choices are either to do what the patch below does, i.e. just clear GL(dl_tls_dtv_gaps) if that happens, or just change the assert and let the do ... while loop run, it shouldn't increment result anyway. 2005-03-15 Jakub Jelinek [BZ#786] * sysdeps/generic/dl-tls.c (_dl_next_tls_modid): Handle GL(dl_tls_static_nelem) == GL(dl_tls_max_dtv_idx). * elf/Makefile: Add rules to build and run tst-tls15. * elf/tst-tls15.c: New test. * elf/tst-tlsmod15a.c: New file. * elf/tst-tlsmod15b.c: New file. diff -urpN glibc-2.3.4.az/elf/Makefile glibc-2.3.4/elf/Makefile --- glibc-2.3.4.az/elf/Makefile 2005-03-15 17:38:36.000000000 +0200 +++ glibc-2.3.4/elf/Makefile 2005-03-15 17:39:07.000000000 +0200 @@ -152,7 +152,7 @@ tests += loadtest restest1 preloadtest l neededtest3 neededtest4 unload2 lateglobal initfirst global \ restest2 next dblload dblunload reldep5 reldep6 reldep7 reldep8 \ circleload1 tst-tls3 tst-tls4 tst-tls5 tst-tls6 tst-tls7 tst-tls8 \ - tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-align \ + tst-tls10 tst-tls11 tst-tls12 tst-tls13 tst-tls14 tst-tls15 tst-align \ $(tests-execstack-$(have-z-execstack)) tst-dlmodcount \ tst-dlopenrpath tst-deep1 tst-dlmopen1 tst-dlmopen2 tst-dlmopen3 # reldep9 @@ -182,6 +182,7 @@ modules-names = testobj1 testobj2 testob tst-tlsmod5 tst-tlsmod6 tst-tlsmod7 tst-tlsmod8 \ tst-tlsmod9 tst-tlsmod10 tst-tlsmod11 tst-tlsmod12 \ tst-tlsmod13 tst-tlsmod13a tst-tlsmod14a tst-tlsmod14b \ + tst-tlsmod15a tst-tlsmod15b \ circlemod1 circlemod1a circlemod2 circlemod2a \ circlemod3 circlemod3a \ reldep8mod1 reldep8mod2 reldep8mod3 \ @@ -454,6 +455,7 @@ tst-tlsmod10.so-no-z-defs = yes tst-tlsmod12.so-no-z-defs = yes tst-tlsmod14a.so-no-z-defs = yes tst-tlsmod14b.so-no-z-defs = yes +tst-tlsmod15a.so-no-z-defs = yes circlemod2.so-no-z-defs = yes circlemod3.so-no-z-defs = yes circlemod3a.so-no-z-defs = yes @@ -664,8 +666,11 @@ $(objpfx)tst-tls12: $(objpfx)tst-tlsmod1 $(objpfx)tst-tls13: $(libdl) $(objpfx)tst-tls13.out: $(objpfx)tst-tlsmod13a.so -$(objpfx)tst-tls14: $(objpfx)tst-tlsmod14a.so $(libdl) -$(objpfx)tst-tls14.out:$(objpfx)tst-tlsmod14b.so +$(objpfx)tst-tls14: $(objpfx)tst-tlsmod14a.so $(libdl) +$(objpfx)tst-tls14.out: $(objpfx)tst-tlsmod14b.so + +$(objpfx)tst-tls15: $(libdl) +$(objpfx)tst-tls15.out: $(objpfx)tst-tlsmod15a.so $(objpfx)tst-tlsmod15b.so CFLAGS-tst-align.c = $(stack-align-test-flags) CFLAGS-tst-alignmod.c = $(stack-align-test-flags) diff -urpN glibc-2.3.4.az/elf/tst-tls15.c glibc-2.3.4/elf/tst-tls15.c --- glibc-2.3.4.az/elf/tst-tls15.c 1970-01-01 02:00:00.000000000 +0200 +++ glibc-2.3.4/elf/tst-tls15.c 2005-03-15 17:39:07.000000000 +0200 @@ -0,0 +1,32 @@ +#include +#include + +static int +do_test (void) +{ + void *h = dlopen ("tst-tlsmod15a.so", RTLD_NOW); + if (h != NULL) + { + puts ("unexpectedly succeeded to open tst-tlsmod15a.so"); + exit (1); + } + + h = dlopen ("tst-tlsmod15b.so", RTLD_NOW); + if (h == NULL) + { + puts ("failed to open tst-tlsmod15b.so"); + exit (1); + } + + int (*fp) (void) = (int (*) (void)) dlsym (h, "in_dso"); + if (fp == NULL) + { + puts ("cannot find in_dso"); + exit (1); + } + + return fp (); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff -urpN glibc-2.3.4.az/elf/tst-tlsmod15a.c glibc-2.3.4/elf/tst-tlsmod15a.c --- glibc-2.3.4.az/elf/tst-tlsmod15a.c 1970-01-01 02:00:00.000000000 +0200 +++ glibc-2.3.4/elf/tst-tlsmod15a.c 2005-03-15 17:39:07.000000000 +0200 @@ -0,0 +1,6 @@ +extern int nonexistent_dummy_var; +int * +foo (void) +{ + return &nonexistent_dummy_var; +} diff -urpN glibc-2.3.4.az/elf/tst-tlsmod15b.c glibc-2.3.4/elf/tst-tlsmod15b.c --- glibc-2.3.4.az/elf/tst-tlsmod15b.c 1970-01-01 02:00:00.000000000 +0200 +++ glibc-2.3.4/elf/tst-tlsmod15b.c 2005-03-15 17:39:07.000000000 +0200 @@ -0,0 +1,17 @@ +#include "tst-tls10.h" + +#ifdef USE_TLS__THREAD +__thread int mod15b_var __attribute__((tls_model("initial-exec"))); + +int +in_dso (void) +{ + return mod15b_var; +} +#else +int +in_dso (void) +{ + return 0; +} +#endif diff -urpN glibc-2.3.4.az/sysdeps/generic/dl-tls.c glibc-2.3.4/sysdeps/generic/dl-tls.c --- glibc-2.3.4.az/sysdeps/generic/dl-tls.c 2005-03-15 17:40:56.000000000 +0200 +++ glibc-2.3.4/sysdeps/generic/dl-tls.c 2005-03-15 17:39:07.000000000 +0200 @@ -65,34 +65,35 @@ _dl_next_tls_modid (void) /* Note that this branch will never be executed during program start since there are no gaps at that time. Therefore it does not matter that the dl_tls_dtv_slotinfo is not allocated - yet when the function is called for the first times. */ - result = GL(dl_tls_static_nelem) + 1; - /* If the following would not be true we mustn't have assumed - there is a gap. */ - assert (result <= GL(dl_tls_max_dtv_idx)); - do - { - while (result - disp < runp->len) - { - if (runp->slotinfo[result - disp].map == NULL) - break; - - ++result; - assert (result <= GL(dl_tls_max_dtv_idx) + 1); - } + yet when the function is called for the first times. - if (result - disp < runp->len) - break; - - disp += runp->len; - } - while ((runp = runp->next) != NULL); + NB: the offset +1 is due to the fact that DTV[0] is used + for something else. */ + result = GL(dl_tls_static_nelem) + 1; + if (result <= GL(dl_tls_max_dtv_idx)) + do + { + while (result - disp < runp->len) + { + if (runp->slotinfo[result - disp].map == NULL) + break; + + ++result; + assert (result <= GL(dl_tls_max_dtv_idx) + 1); + } + + if (result - disp < runp->len) + break; + + disp += runp->len; + } + while ((runp = runp->next) != NULL); - if (result >= GL(dl_tls_max_dtv_idx)) + if (result > GL(dl_tls_max_dtv_idx)) { /* The new index must indeed be exactly one higher than the previous high. */ - assert (result == GL(dl_tls_max_dtv_idx)); + assert (result == GL(dl_tls_max_dtv_idx) + 1); /* There is no gap anymore. */ GL(dl_tls_dtv_gaps) = false; @@ -577,7 +578,7 @@ __tls_get_addr (GET_ADDR_ARGS) { size_t cnt; - for (cnt = total = 0 ? 1 : 0; cnt < listp->len; ++cnt) + for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt) { size_t gen = listp->slotinfo[cnt].gen; struct link_map *map;