File glibc-tls-init.patch of Package glibc.613

commit d26dfc60edc8c6dd160eefff16a734152a835ca0
Author: Martin von Gagern <Martin.vGagern@gmx.net>
Date:   Sat May 14 21:25:43 2011 -0400

    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.

 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.
	Patch mostly by Martin von Gagern <Martin.vGagern@gmx.net>.

diff --git a/elf/dl-open.c b/elf/dl-open.c
index cf8e8cc..8d90b56 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -347,6 +347,7 @@ dl_open_worker (void *a)
   /* If the file is not loaded now as a dependency, add the search
      list of the newly loaded object to the scope.  */
   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)
     {
       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.  */
 	  _dl_add_to_slotinfo (imap);
 
-	  if (imap->l_need_tls_init)
-	    {
-	      /* 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);
-	    }
+	  if (imap->l_need_tls_init
+	      && first_static_tls == new->l_searchlist.r_nlist)
+	    first_static_tls = i;
 
 	  /* We have to bump the generation counter.  */
 	  any_tls = true;
@@ -460,6 +440,40 @@ cannot load any more object with static TLS"));
     _dl_fatal_printf (N_("\
 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.  */
   _dl_init (new, args->argc, args->argv, args->env);
 
openSUSE Build Service is sponsored by