diff options
author | Alan Modra <amodra@gmail.com> | 2011-05-03 17:35:24 -0500 |
---|---|---|
committer | ryanarn <ryanarn@igoo.rchland.ibm.com> | 2011-07-01 07:43:18 -0500 |
commit | 114814b2f6815d6676ce21d612ed84380d7b5c4f (patch) | |
tree | b34e118f9f7da5d63e367c6711b89af6496f8f72 | |
parent | db90a4844fc2f0eb7d6a45a317d9e625cca370e8 (diff) | |
download | glibc-114814b2f6815d6676ce21d612ed84380d7b5c4f.zip glibc-114814b2f6815d6676ce21d612ed84380d7b5c4f.tar.gz glibc-114814b2f6815d6676ce21d612ed84380d7b5c4f.tar.bz2 |
Static TLS memory leak fix (DTV case)
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | elf/dl-close.c | 46 | ||||
-rw-r--r-- | elf/dl-reloc.c | 20 | ||||
-rw-r--r-- | elf/dl-tls.c | 5 |
4 files changed, 65 insertions, 15 deletions
@@ -1,3 +1,12 @@ +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. Add debug print. + * elf/dl-close.c (_dl_close_worker <TLS_DTV_AT_TP>): Correct code + freeing static tls block. Add debug print. + * elf/fl-tls.c (_dl_determine_tlsoffset): Add debug print. + 2011-06-30 Ryan S. Arnold <rsa@linux.vnet.ibm.com> * nptl/sysdeps/unix/sysv/linux/aio_misc.h diff --git a/elf/dl-close.c b/elf/dl-close.c index 700e765..0e60ed9 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -582,25 +582,51 @@ _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" #endif + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0)) + _dl_debug_printf ("\nstatic tls free: %s\n" + " tls_free_start = %Zu, " + "tls_free_end = %Zu, " + "dl_tls_static_used = %Zu\n", + imap->l_name[0] ? imap->l_name + : rtld_progname, + tls_free_start, tls_free_end, + GL(dl_tls_static_used)); + } } diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 23cb59c..9d07fd6 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -77,23 +77,33 @@ _dl_try_allocate_static_tls (struct link_map *map) map->l_tls_offset = GL(dl_tls_static_used) = offset; #elif TLS_DTV_AT_TP + size_t offset; 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. */ + 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); + 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" #endif + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0)) + _dl_debug_printf ("\nstatic tls: %s\n" + " l_tls_offset = %Zu, l_tls_firstbyte_offset = %Zu," + " dl_tls_static_used = %Zu\n", + map->l_name[0] ? map->l_name : rtld_progname, + map->l_tls_offset, map->l_tls_firstbyte_offset, + GL(dl_tls_static_used)); /* If the object is not yet relocated we cannot initialize the static TLS region. Delay it. */ if (map->l_real->l_relocated) diff --git a/elf/dl-tls.c b/elf/dl-tls.c index 824adc1..8db7c85 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -249,6 +249,11 @@ _dl_determine_tlsoffset (void) # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" #endif + if (__builtin_expect (GLRO(dl_debug_mask) & DL_DEBUG_RELOC, 0)) + _dl_debug_printf ("\ninitial static tls: " + "dl_tls_static_used = %Zu, dl_tls_status_size = %Zu\n", + GL(dl_tls_static_used), GL(dl_tls_static_size)); + /* The alignment requirement for the static TLS block. */ GL(dl_tls_static_align) = max_align; } |