+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>
* malloc/malloc.c (INTERNAL_SIZE_T, SIZE_SZ, MALLOC_ALIGNMENT)
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)
/* 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))
# 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;
}
{
/* 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;
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;
#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;
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;
}