mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-24 02:03:35 +08: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:
parent
5bc17330eb
commit
a2ff21f825
22
ChangeLog
22
ChangeLog
@ -1,3 +1,25 @@
|
|||||||
|
2016-08-03 Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
|
[BZ #17730]
|
||||||
|
Avoid using memalign for TLS allocations.
|
||||||
|
* sysdeps/generic/dl-dtv.h (struct dtv_pointer): New. Replaces
|
||||||
|
is_static member with to_free member.
|
||||||
|
(union dtv): Use struct dtv_pointer.
|
||||||
|
* csu/libc-tls.c (__libc_setup_tls): Set to_free member of struct
|
||||||
|
dtv_pointer instead of is_static.
|
||||||
|
* elf/dl-tls.c (_dl_allocate_tls_init): Likewise.
|
||||||
|
(_dl_deallocate_tls): Free to_free member of struct dtv_pointer
|
||||||
|
instead of val.
|
||||||
|
(allocate_dtv_entry): New function.
|
||||||
|
(allocate_and_init): Return struct dtv_pointer. Call
|
||||||
|
allocate_dtv_entry instead of __libc_memalign.
|
||||||
|
(_dl_update_slotinfo): Free to_free member of struct dtv_pointer
|
||||||
|
instead of val.
|
||||||
|
(tls_get_addr_tail): Set to_free member of struct dtv_pointer
|
||||||
|
instead of is_static. Adjust call to allocate_and_init.
|
||||||
|
* nptl/allocatestack.c (get_cached_stack): Free to_free member of
|
||||||
|
struct dtv_pointer instead of val.
|
||||||
|
|
||||||
2016-08-03 Florian Weimer <fweimer@redhat.com>
|
2016-08-03 Florian Weimer <fweimer@redhat.com>
|
||||||
|
|
||||||
* malloc/malloc.c (INTERNAL_SIZE_T, SIZE_SZ, MALLOC_ALIGNMENT)
|
* malloc/malloc.c (INTERNAL_SIZE_T, SIZE_SZ, MALLOC_ALIGNMENT)
|
||||||
|
@ -175,7 +175,7 @@ __libc_setup_tls (size_t tcbsize, size_t tcbalign)
|
|||||||
#else
|
#else
|
||||||
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
# error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
|
||||||
#endif
|
#endif
|
||||||
_dl_static_dtv[2].pointer.is_static = true;
|
_dl_static_dtv[2].pointer.to_free = NULL;
|
||||||
/* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
|
/* sbrk gives us zero'd memory, so we don't need to clear the remainder. */
|
||||||
memcpy (_dl_static_dtv[2].pointer.val, initimage, filesz);
|
memcpy (_dl_static_dtv[2].pointer.val, initimage, filesz);
|
||||||
|
|
||||||
|
75
elf/dl-tls.c
75
elf/dl-tls.c
@ -494,7 +494,7 @@ _dl_allocate_tls_init (void *result)
|
|||||||
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
|
maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);
|
||||||
|
|
||||||
dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
|
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
|
if (map->l_tls_offset == NO_TLS_OFFSET
|
||||||
|| map->l_tls_offset == FORCED_DYNAMIC_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. */
|
/* We need to free the memory allocated for non-static TLS. */
|
||||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||||
if (! dtv[1 + cnt].pointer.is_static
|
free (dtv[1 + cnt].pointer.to_free);
|
||||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
|
||||||
free (dtv[1 + cnt].pointer.val);
|
|
||||||
|
|
||||||
/* The array starts with dtv[-1]. */
|
/* The array starts with dtv[-1]. */
|
||||||
if (dtv != GL(dl_initial_dtv))
|
if (dtv != GL(dl_initial_dtv))
|
||||||
@ -594,21 +592,49 @@ rtld_hidden_def (_dl_deallocate_tls)
|
|||||||
# define GET_ADDR_OFFSET ti->ti_offset
|
# define GET_ADDR_OFFSET ti->ti_offset
|
||||||
# endif
|
# 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)
|
allocate_and_init (struct link_map *map)
|
||||||
{
|
{
|
||||||
void *newp;
|
struct dtv_pointer result = allocate_dtv_entry
|
||||||
|
(map->l_tls_align, map->l_tls_blocksize);
|
||||||
newp = __libc_memalign (map->l_tls_align, map->l_tls_blocksize);
|
if (result.val == NULL)
|
||||||
if (newp == NULL)
|
|
||||||
oom ();
|
oom ();
|
||||||
|
|
||||||
/* Initialize the memory. */
|
/* 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);
|
'\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
|
/* If this modid was used at some point the memory
|
||||||
might still be allocated. */
|
might still be allocated. */
|
||||||
if (! dtv[total + cnt].pointer.is_static
|
free (dtv[total + cnt].pointer.to_free);
|
||||||
&& (dtv[total + cnt].pointer.val
|
|
||||||
!= TLS_DTV_UNALLOCATED))
|
|
||||||
free (dtv[total + cnt].pointer.val);
|
|
||||||
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
|
dtv[total + cnt].pointer.val = TLS_DTV_UNALLOCATED;
|
||||||
dtv[total + cnt].pointer.is_static = false;
|
dtv[total + cnt].pointer.to_free = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@ -708,16 +731,9 @@ _dl_update_slotinfo (unsigned long int req_modid)
|
|||||||
dtv entry free it. */
|
dtv entry free it. */
|
||||||
/* XXX Ideally we will at some point create a memory
|
/* XXX Ideally we will at some point create a memory
|
||||||
pool. */
|
pool. */
|
||||||
if (! dtv[modid].pointer.is_static
|
free (dtv[modid].pointer.to_free);
|
||||||
&& 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);
|
|
||||||
|
|
||||||
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
|
||||||
dtv[modid].pointer.is_static = false;
|
dtv[modid].pointer.to_free = NULL;
|
||||||
|
|
||||||
if (modid == req_modid)
|
if (modid == req_modid)
|
||||||
the_map = map;
|
the_map = map;
|
||||||
@ -780,7 +796,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
|
|||||||
#endif
|
#endif
|
||||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
__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;
|
dtv[GET_ADDR_MODULE].pointer.val = p;
|
||||||
|
|
||||||
return (char *) p + GET_ADDR_OFFSET;
|
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
|
else
|
||||||
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
__rtld_lock_unlock_recursive (GL(dl_load_lock));
|
||||||
}
|
}
|
||||||
void *p = dtv[GET_ADDR_MODULE].pointer.val = allocate_and_init (the_map);
|
struct dtv_pointer result = allocate_and_init (the_map);
|
||||||
assert (!dtv[GET_ADDR_MODULE].pointer.is_static);
|
dtv[GET_ADDR_MODULE].pointer = result;
|
||||||
|
assert (result.to_free != NULL);
|
||||||
|
|
||||||
return (char *) p + GET_ADDR_OFFSET;
|
return (char *) result.val + GET_ADDR_OFFSET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -245,9 +245,7 @@ get_cached_stack (size_t *sizep, void **memp)
|
|||||||
/* Clear the DTV. */
|
/* Clear the DTV. */
|
||||||
dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
|
dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
|
||||||
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
|
||||||
if (! dtv[1 + cnt].pointer.is_static
|
free (dtv[1 + cnt].pointer.to_free);
|
||||||
&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
|
|
||||||
free (dtv[1 + cnt].pointer.val);
|
|
||||||
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
memset (dtv, '\0', (dtv[-1].counter + 1) * sizeof (dtv_t));
|
||||||
|
|
||||||
/* Re-initialize the TLS. */
|
/* Re-initialize the TLS. */
|
||||||
|
@ -19,15 +19,17 @@
|
|||||||
#ifndef _DL_DTV_H
|
#ifndef _DL_DTV_H
|
||||||
#define _DL_DTV_H
|
#define _DL_DTV_H
|
||||||
|
|
||||||
|
struct dtv_pointer
|
||||||
|
{
|
||||||
|
void *val; /* Pointer to data, or TLS_DTV_UNALLOCATED. */
|
||||||
|
void *to_free; /* Unaligned pointer, for deallocation. */
|
||||||
|
};
|
||||||
|
|
||||||
/* Type for the dtv. */
|
/* Type for the dtv. */
|
||||||
typedef union dtv
|
typedef union dtv
|
||||||
{
|
{
|
||||||
size_t counter;
|
size_t counter;
|
||||||
struct
|
struct dtv_pointer pointer;
|
||||||
{
|
|
||||||
void *val;
|
|
||||||
bool is_static;
|
|
||||||
} pointer;
|
|
||||||
} dtv_t;
|
} dtv_t;
|
||||||
|
|
||||||
/* Value used for dtv entries for which the allocation is delayed. */
|
/* Value used for dtv entries for which the allocation is delayed. */
|
||||||
|
Loading…
Reference in New Issue
Block a user