1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

elf: Avoid using memalign for TLS allocations [BZ #17730]

Instead of a flag which indicates the pointer can be freed, dtv_t
now includes the pointer which should be freed.  Due to padding,
the size of dtv_t does not increase.

To avoid using memalign, the new allocate_dtv_entry function
allocates a sufficiently large buffer so that a sub-buffer
can be found in it which starts with an aligned pointer.  Both
the aligned and original pointers are kept, the latter for calling
free later.
This commit is contained in:
Florian Weimer
2016-08-03 16:15:38 +02:00
parent 5bc17330eb
commit a2ff21f825
5 changed files with 77 additions and 38 deletions

View File

@ -494,7 +494,7 @@ _dl_allocate_tls_init (void *result)
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[map->l_tls_modid].pointer.is_static = false;
dtv[map->l_tls_modid].pointer.to_free = NULL;
if (map->l_tls_offset == NO_TLS_OFFSET
|| map->l_tls_offset == FORCED_DYNAMIC_TLS_OFFSET)
@ -551,9 +551,7 @@ _dl_deallocate_tls (void *tcb, bool dealloc_tcb)
/* We need to free the memory allocated for non-static TLS. */
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
if (! dtv[1 + cnt].pointer.is_static
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
free (dtv[1 + cnt].pointer.val);
free (dtv[1 + cnt].pointer.to_free);
/* The array starts with dtv[-1]. */
if (dtv != GL(dl_initial_dtv))
@ -594,21 +592,49 @@ rtld_hidden_def (_dl_deallocate_tls)
# define GET_ADDR_OFFSET ti->ti_offset
# endif
/* Allocate one DTV entry. */
static struct dtv_pointer
allocate_dtv_entry (size_t alignment, size_t size)
{
if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
{
/* The alignment is supported by malloc. */
void *ptr = malloc (size);
return (struct dtv_pointer) { ptr, ptr };
}
static void *
/* Emulate memalign to by manually aligning a pointer returned by
malloc. First compute the size with an overflow check. */
size_t alloc_size = size + alignment;
if (alloc_size < size)
return (struct dtv_pointer) {};
/* Perform the allocation. This is the pointer we need to free
later. */
void *start = malloc (alloc_size);
if (start == NULL)
return (struct dtv_pointer) {};
/* Find the aligned position within the larger allocation. */
void *aligned = (void *) roundup ((uintptr_t) start, alignment);
return (struct dtv_pointer) { .val = aligned, .to_free = start };
}
static struct dtv_pointer
allocate_and_init (struct link_map *map)
{
void *newp;
newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize);
if (newp == NULL)
struct dtv_pointer result = allocate_dtv_entry
(map->l_tls_align, map->l_tls_blocksize);
if (result.val == NULL)
oom ();
/* Initialize the memory. */
memset (__mempcpy (newp, map->l_tls_initimage, map->l_tls_initimage_size),
memset (__mempcpy (result.val, map->l_tls_initimage,
map->l_tls_initimage_size),
'\0', map->l_tls_blocksize - map->l_tls_initimage_size);
return newp;
return result;
}
@ -678,12 +704,9 @@ _dl_update_slotinfo (unsigned long int req_modid)
{
/* If this modid was used at some point the memory
might still be allocated. */
if (! dtv[total + cnt].pointer.is_static
&& (dtv[total + cnt].pointer.val
!= TLS_DTV_UNALLOCATED))
free (dtv[total + cnt].pointer.val);
free (dtv[total + cnt].pointer.to_free);
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
dtv[total + cnt].pointer.is_static = false;
dtv[total + cnt].pointer.to_free = NULL;
}
continue;
@ -708,16 +731,9 @@ _dl_update_slotinfo (unsigned long int req_modid)
dtv entry free it. */
/* XXX Ideally we will at some point create a memory
pool. */
if (! dtv[modid].pointer.is_static
&& dtv[modid].pointer.val != TLS_DTV_UNALLOCATED)
/* Note that free is called for NULL is well. We
deallocate even if it is this dtv entry we are
supposed to load. The reason is that we call
memalign and not malloc. */
free (dtv[modid].pointer.val);
free (dtv[modid].pointer.to_free);
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[modid].pointer.is_static = false;
dtv[modid].pointer.to_free = NULL;
if (modid == req_modid)
the_map = map;
@ -780,7 +796,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
#endif
__rtld_lock_unlock_recursive (GL(dl_load_lock));
dtv[GET_ADDR_MODULE].pointer.is_static = true;
dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
dtv[GET_ADDR_MODULE].pointer.val = p;
return (char *) p + GET_ADDR_OFFSET;
@ -788,10 +804,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
else
__rtld_lock_unlock_recursive (GL(dl_load_lock));
}
void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
assert (!dtv[GET_ADDR_MODULE].pointer.is_static);
struct dtv_pointer result = allocate_and_init (the_map);
dtv[GET_ADDR_MODULE].pointer = result;
assert (result.to_free != NULL);
return (char *) p + GET_ADDR_OFFSET;
return (char *) result.val + GET_ADDR_OFFSET;
}