]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
static tls memory leak on TLS_DTV_AT_TP archs
authorAlan Modra <amodra@gmail.com>
Sun, 8 May 2011 01:27:51 +0000 (21:27 -0400)
committerUlrich Drepper <drepper@gmail.com>
Sun, 8 May 2011 01:27:51 +0000 (21:27 -0400)
ChangeLog
elf/dl-close.c
elf/dl-reloc.c

index 40a4cebac1aea2d888009bd57a4eb4c4e6122421..7d2da4e83641b4120dfe06351a7af12576ee82d1 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2011-03-15  Alan Modra  <amodra@gmail.com>
+
+       * elf/dl-reloc.c (_dl_try_allocate_static_tls <TLS_DTV_AT_TP>): Handle
+       l_tls_firstbyte_offset non-zero.  Save padding offset in
+       l_tls_firstbyte_offset for later use.
+       * elf/dl-close.c (_dl_close_worker <TLS_DTV_AT_TP>): Correct code
+       freeing static tls block.
+
 2011-03-05  Jonathan Nieder  <jrnieder@gmail.com>
 
        * sysdeps/unix/sysv/linux/sys/param.h: Fix an #ifndef __undef_ARG_MAX
index efb2b584f2a13556428155189ce17d40c5acafba..229e288ef6a9a7df605d96c4cf3a06d0c0b2ac66 100644 (file)
@@ -591,21 +591,37 @@ _dl_close_worker (struct link_map *map)
                        }
                    }
 #elif TLS_DTV_AT_TP
-                 if ((size_t) imap->l_tls_offset == tls_free_end)
+                 if (tls_free_start == NO_TLS_OFFSET)
+                   {
+                     tls_free_start = imap->l_tls_firstbyte_offset;
+                     tls_free_end = (imap->l_tls_offset
+                                     + imap->l_tls_blocksize);
+                   }
+                 else if (imap->l_tls_firstbyte_offset == tls_free_end)
                    /* Extend the contiguous chunk being reclaimed.  */
-                   tls_free_end -= imap->l_tls_blocksize;
+                   tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
                  else if (imap->l_tls_offset + imap->l_tls_blocksize
                           == tls_free_start)
                    /* Extend the chunk backwards.  */
-                   tls_free_start = imap->l_tls_offset;
-                 else
+                   tls_free_start = imap->l_tls_firstbyte_offset;
+                 /* This isn't contiguous with the last chunk freed.
+                    One of them will be leaked unless we can free
+                    one block right away.  */
+                 else if (imap->l_tls_offset + imap->l_tls_blocksize
+                          == GL(dl_tls_static_used))
+                   GL(dl_tls_static_used) = imap->l_tls_firstbyte_offset;
+                 else if (tls_free_end == GL(dl_tls_static_used))
                    {
-                     /* This isn't contiguous with the last chunk freed.
-                        One of them will be leaked.  */
-                     if (tls_free_end == GL(dl_tls_static_used))
-                       GL(dl_tls_static_used) = tls_free_start;
-                     tls_free_start = imap->l_tls_offset;
-                     tls_free_end = tls_free_start + imap->l_tls_blocksize;
+                     GL(dl_tls_static_used) = tls_free_start;
+                     tls_free_start = imap->l_tls_firstbyte_offset;
+                     tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
+                   }
+                 else if (tls_free_end < imap->l_tls_firstbyte_offset)
+                   {
+                     /* We pick the later block.  It has a chance to
+                        be freed.  */
+                     tls_free_start = imap->l_tls_firstbyte_offset;
+                     tls_free_end = imap->l_tls_offset + imap->l_tls_blocksize;
                    }
 #else
 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
index 23cb59cbc89cf65c5c3f8c56b0459daf8949383f..729411234650904b030e195de257a566222e96d0 100644 (file)
@@ -1,5 +1,5 @@
 /* Relocate a shared object and resolve its references to other loaded objects.
-   Copyright (C) 1995-2006, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1995-2006, 2008-2010, 2011 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
@@ -57,38 +57,34 @@ _dl_try_allocate_static_tls (struct link_map *map)
     }
 
 #if TLS_TCB_AT_TP
-  size_t freebytes;
-  size_t n;
-  size_t blsize;
-
-  freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used);
+  size_t freebytes = GL(dl_tls_static_size) - GL(dl_tls_static_used);
   if (freebytes < TLS_TCB_SIZE)
     goto fail;
   freebytes -= TLS_TCB_SIZE;
 
-  blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
+  size_t blsize = map->l_tls_blocksize + map->l_tls_firstbyte_offset;
   if (freebytes < blsize)
     goto fail;
 
-  n = (freebytes - blsize) / map->l_tls_align;
+  size_t n = (freebytes - blsize) / map->l_tls_align;
 
   size_t offset = GL(dl_tls_static_used) + (freebytes - n * map->l_tls_align
                                            - map->l_tls_firstbyte_offset);
 
   map->l_tls_offset = GL(dl_tls_static_used) = offset;
 #elif TLS_DTV_AT_TP
-  size_t used;
-  size_t check;
-
-  size_t offset = roundup (GL(dl_tls_static_used), map->l_tls_align);
-  used = offset + map->l_tls_blocksize;
-  check = used;
   /* dl_tls_static_used includes the TCB at the beginning.  */
+  size_t offset = (((GL(dl_tls_static_used)
+                    - map->l_tls_firstbyte_offset
+                    + map->l_tls_align - 1) & -map->l_tls_align)
+                  + map->l_tls_firstbyte_offset);
+  size_t used = offset + map->l_tls_blocksize;
 
-  if (check > GL(dl_tls_static_size))
+  if (used > GL(dl_tls_static_size))
     goto fail;
 
   map->l_tls_offset = offset;
+  map->l_tls_firstbyte_offset = GL(dl_tls_static_used);
   GL(dl_tls_static_used) = used;
 #else
 # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"