From 66bdbaa4522f561d4ea90a77af243c004ecf642c Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sat, 7 May 2011 21:27:51 -0400 Subject: [PATCH] static tls memory leak on TLS_DTV_AT_TP archs --- ChangeLog | 8 ++++++++ elf/dl-close.c | 36 ++++++++++++++++++++++++++---------- elf/dl-reloc.c | 26 +++++++++++--------------- 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 40a4ceb..7d2da4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2011-03-15 Alan Modra + + * elf/dl-reloc.c (_dl_try_allocate_static_tls ): 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 ): Correct code + freeing static tls block. + 2011-03-05 Jonathan Nieder * sysdeps/unix/sysv/linux/sys/param.h: Fix an #ifndef __undef_ARG_MAX diff --git a/elf/dl-close.c b/elf/dl-close.c index efb2b58..229e288 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -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" diff --git a/elf/dl-reloc.c b/elf/dl-reloc.c index 23cb59c..7294112 100644 --- a/elf/dl-reloc.c +++ b/elf/dl-reloc.c @@ -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" -- 2.7.4