summaryrefslogtreecommitdiff
path: root/malloc
diff options
context:
space:
mode:
Diffstat (limited to 'malloc')
-rw-r--r--malloc/Makefile7
-rw-r--r--malloc/arena.c85
-rw-r--r--malloc/hooks.c32
-rw-r--r--malloc/malloc.c416
-rw-r--r--malloc/obstack.h2
-rw-r--r--malloc/tst-memalign.c114
-rw-r--r--malloc/tst-posix_memalign.c118
-rw-r--r--malloc/tst-pvalloc.c99
-rw-r--r--malloc/tst-realloc.c146
-rw-r--r--malloc/tst-valloc.c108
10 files changed, 780 insertions, 347 deletions
diff --git a/malloc/Makefile b/malloc/Makefile
index 0fe31a4a02..0c1e19f65c 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -25,7 +25,9 @@ all:
dist-headers := malloc.h
headers := $(dist-headers) obstack.h mcheck.h
tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
- tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 tst-malloc-usable
+ tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
+ tst-malloc-usable tst-realloc tst-posix_memalign \
+ tst-pvalloc tst-memalign
test-srcs = tst-mtrace
routines = malloc morecore mcheck mtrace obstack
@@ -76,7 +78,7 @@ install-bin-script += memusage
generated += memusagestat memusage
extra-objs += memusagestat.o
-# The configure.in check for libgd and its headers did not use $SYSINCLUDES.
+# The configure.ac check for libgd and its headers did not use $SYSINCLUDES.
# The directory specified by --with-headers usually contains only the basic
# kernel interface headers, not something like libgd. So the simplest thing
# is to presume that the standard system headers will be ok for this file.
@@ -117,7 +119,6 @@ endif
tst-mcheck-ENV = MALLOC_CHECK_=3
tst-malloc-usable-ENV = MALLOC_CHECK_=3
-CPPFLAGS-malloc.c += -DPER_THREAD
# Uncomment this for test releases. For public releases it is too expensive.
#CPPFLAGS-malloc.o += -DMALLOC_DEBUG=1
diff --git a/malloc/arena.c b/malloc/arena.c
index 12a48ad7ba..9d49f93265 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -75,10 +75,8 @@ extern int sanity_check_heap_info_alignment[(sizeof (heap_info)
static tsd_key_t arena_key;
static mutex_t list_lock = MUTEX_INITIALIZER;
-#ifdef PER_THREAD
static size_t narenas = 1;
static mstate free_list;
-#endif
#if THREAD_STATS
static int stat_n_heaps;
@@ -114,21 +112,12 @@ int __malloc_initialized = -1;
ptr = (mstate)tsd_getspecific(arena_key, vptr); \
} while(0)
-#ifdef PER_THREAD
# define arena_lock(ptr, size) do { \
if(ptr) \
(void)mutex_lock(&ptr->mutex); \
else \
ptr = arena_get2(ptr, (size), NULL); \
} while(0)
-#else
-# define arena_lock(ptr, size) do { \
- if(ptr && !mutex_trylock(&ptr->mutex)) { \
- THREAD_STAT(++(ptr->stat_lock_direct)); \
- } else \
- ptr = arena_get2(ptr, (size), NULL); \
-} while(0)
-#endif
/* find the heap and corresponding arena for a given ptr */
@@ -292,17 +281,13 @@ ptmalloc_unlock_all2 (void)
tsd_setspecific(arena_key, save_arena);
__malloc_hook = save_malloc_hook;
__free_hook = save_free_hook;
-#ifdef PER_THREAD
free_list = NULL;
-#endif
for(ar_ptr = &main_arena;;) {
mutex_init(&ar_ptr->mutex);
-#ifdef PER_THREAD
if (ar_ptr != save_arena) {
ar_ptr->next_free = free_list;
free_list = ar_ptr;
}
-#endif
ar_ptr = ar_ptr->next;
if(ar_ptr == &main_arena) break;
}
@@ -423,13 +408,10 @@ ptmalloc_init (void)
{
if (memcmp (envline, "MMAP_MAX_", 9) == 0)
__libc_mallopt(M_MMAP_MAX, atoi(&envline[10]));
-#ifdef PER_THREAD
else if (memcmp (envline, "ARENA_MAX", 9) == 0)
__libc_mallopt(M_ARENA_MAX, atoi(&envline[10]));
-#endif
}
break;
-#ifdef PER_THREAD
case 10:
if (! __builtin_expect (__libc_enable_secure, 0))
{
@@ -437,7 +419,6 @@ ptmalloc_init (void)
__libc_mallopt(M_ARENA_TEST, atoi(&envline[11]));
}
break;
-#endif
case 15:
if (! __builtin_expect (__libc_enable_secure, 0))
{
@@ -457,7 +438,7 @@ ptmalloc_init (void)
if (check_action != 0)
__malloc_check_init();
}
- void (*hook) (void) = force_reg (__malloc_initialize_hook);
+ void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
if (hook != NULL)
(*hook)();
__malloc_initialized = 1;
@@ -581,6 +562,7 @@ new_heap(size_t size, size_t top_pad)
h->size = size;
h->mprotect_size = size;
THREAD_STAT(stat_n_heaps++);
+ LIBC_PROBE (memory_heap_new, 2, h, h->size);
return h;
}
@@ -606,6 +588,7 @@ grow_heap(heap_info *h, long diff)
}
h->size = new_size;
+ LIBC_PROBE (memory_heap_more, 2, h, h->size);
return 0;
}
@@ -633,6 +616,7 @@ shrink_heap(heap_info *h, long diff)
/*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/
h->size = new_size;
+ LIBC_PROBE (memory_heap_less, 2, h, h->size);
return 0;
}
@@ -674,6 +658,7 @@ heap_trim(heap_info *heap, size_t pad)
break;
ar_ptr->system_mem -= heap->size;
arena_mem -= heap->size;
+ LIBC_PROBE (memory_heap_free, 2, heap, heap->size);
delete_heap(heap);
heap = prev_heap;
if(!prev_inuse(p)) { /* consolidate backward */
@@ -736,22 +721,19 @@ _int_new_arena(size_t size)
top(a) = (mchunkptr)ptr;
set_head(top(a), (((char*)h + h->size) - ptr) | PREV_INUSE);
+ LIBC_PROBE (memory_arena_new, 2, a, size);
tsd_setspecific(arena_key, (void *)a);
mutex_init(&a->mutex);
(void)mutex_lock(&a->mutex);
-#ifdef PER_THREAD
(void)mutex_lock(&list_lock);
-#endif
/* Add the new arena to the global list. */
a->next = main_arena.next;
atomic_write_barrier ();
main_arena.next = a;
-#ifdef PER_THREAD
(void)mutex_unlock(&list_lock);
-#endif
THREAD_STAT(++(a->stat_lock_loop));
@@ -759,7 +741,6 @@ _int_new_arena(size_t size)
}
-#ifdef PER_THREAD
static mstate
get_free_list (void)
{
@@ -774,6 +755,7 @@ get_free_list (void)
if (result != NULL)
{
+ LIBC_PROBE (memory_arena_reuse_free_list, 1, result);
(void)mutex_lock(&result->mutex);
tsd_setspecific(arena_key, (void *)result);
THREAD_STAT(++(result->stat_lock_loop));
@@ -810,16 +792,17 @@ reused_arena (mstate avoid_arena)
result = result->next;
/* No arena available. Wait for the next in line. */
+ LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena);
(void)mutex_lock(&result->mutex);
out:
+ LIBC_PROBE (memory_arena_reuse, 2, result, avoid_arena);
tsd_setspecific(arena_key, (void *)result);
THREAD_STAT(++(result->stat_lock_loop));
next_to_use = result->next;
return result;
}
-#endif
static mstate
internal_function
@@ -827,7 +810,6 @@ arena_get2(mstate a_tsd, size_t size, mstate avoid_arena)
{
mstate a;
-#ifdef PER_THREAD
static size_t narenas_limit;
a = get_free_list ();
@@ -870,52 +852,6 @@ arena_get2(mstate a_tsd, size_t size, mstate avoid_arena)
else
a = reused_arena (avoid_arena);
}
-#else
- if(!a_tsd)
- a = a_tsd = &main_arena;
- else {
- a = a_tsd->next;
- if(!a) {
- /* This can only happen while initializing the new arena. */
- (void)mutex_lock(&main_arena.mutex);
- THREAD_STAT(++(main_arena.stat_lock_wait));
- return &main_arena;
- }
- }
-
- /* Check the global, circularly linked list for available arenas. */
- bool retried = false;
- repeat:
- do {
- if(!mutex_trylock(&a->mutex)) {
- if (retried)
- (void)mutex_unlock(&list_lock);
- THREAD_STAT(++(a->stat_lock_loop));
- tsd_setspecific(arena_key, (void *)a);
- return a;
- }
- a = a->next;
- } while(a != a_tsd);
-
- /* If not even the list_lock can be obtained, try again. This can
- happen during `atfork', or for example on systems where thread
- creation makes it temporarily impossible to obtain _any_
- locks. */
- if(!retried && mutex_trylock(&list_lock)) {
- /* We will block to not run in a busy loop. */
- (void)mutex_lock(&list_lock);
-
- /* Since we blocked there might be an arena available now. */
- retried = true;
- a = a_tsd;
- goto repeat;
- }
-
- /* Nothing immediately available, so generate a new arena. */
- a = _int_new_arena(size);
- (void)mutex_unlock(&list_lock);
-#endif
-
return a;
}
@@ -926,6 +862,7 @@ arena_get2(mstate a_tsd, size_t size, mstate avoid_arena)
static mstate
arena_get_retry (mstate ar_ptr, size_t bytes)
{
+ LIBC_PROBE (memory_arena_retry, 2, bytes, ar_ptr);
if(ar_ptr != &main_arena) {
(void)mutex_unlock(&ar_ptr->mutex);
ar_ptr = &main_arena;
@@ -940,7 +877,6 @@ arena_get_retry (mstate ar_ptr, size_t bytes)
return ar_ptr;
}
-#ifdef PER_THREAD
static void __attribute__ ((section ("__libc_thread_freeres_fn")))
arena_thread_freeres (void)
{
@@ -957,7 +893,6 @@ arena_thread_freeres (void)
}
}
text_set_element (__libc_thread_subfreeres, arena_thread_freeres);
-#endif
/*
* Local variables:
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 8c25846330..7010fe66f8 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -236,7 +236,7 @@ top_check(void)
return -1;
}
/* Call the `morecore' hook if necessary. */
- void (*hook) (void) = force_reg (__after_morecore_hook);
+ void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
if (hook)
(*hook) ();
main_arena.system_mem = (new_brk - mp_.sbrk_base) + sbrk_size;
@@ -330,7 +330,7 @@ realloc_check(void* oldmem, size_t bytes, const void *caller)
if (top_check() >= 0)
newmem = _int_malloc(&main_arena, bytes+1);
if (newmem) {
- MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ memcpy(newmem, oldmem, oldsize - 2*SIZE_SZ);
munmap_chunk(oldp);
}
}
@@ -361,10 +361,28 @@ memalign_check(size_t alignment, size_t bytes, const void *caller)
if (alignment <= MALLOC_ALIGNMENT) return malloc_check(bytes, NULL);
if (alignment < MINSIZE) alignment = MINSIZE;
- if (bytes+1 == 0) {
- __set_errno (ENOMEM);
- return NULL;
+ /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
+ power of 2 and will cause overflow in the check below. */
+ if (alignment > SIZE_MAX / 2 + 1)
+ {
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ /* Check for overflow. */
+ if (bytes > SIZE_MAX - alignment - MINSIZE)
+ {
+ __set_errno (ENOMEM);
+ return 0;
+ }
+
+ /* Make sure alignment is power of 2. */
+ if (!powerof2(alignment)) {
+ size_t a = MALLOC_ALIGNMENT * 2;
+ while (a < alignment) a <<= 1;
+ alignment = a;
}
+
(void)mutex_lock(&main_arena.mutex);
mem = (top_check() >= 0) ? _int_memalign(&main_arena, alignment, bytes+1) :
NULL;
@@ -458,11 +476,9 @@ __malloc_get_state(void)
ms->max_mmapped_mem = mp_.max_mmapped_mem;
ms->using_malloc_checking = using_malloc_checking;
ms->max_fast = get_max_fast();
-#ifdef PER_THREAD
ms->arena_test = mp_.arena_test;
ms->arena_max = mp_.arena_max;
ms->narenas = narenas;
-#endif
(void)mutex_unlock(&main_arena.mutex);
return (void*)ms;
}
@@ -559,11 +575,9 @@ __malloc_set_state(void* msptr)
}
}
if (ms->version >= 4) {
-#ifdef PER_THREAD
mp_.arena_test = ms->arena_test;
mp_.arena_max = ms->arena_max;
narenas = ms->narenas;
-#endif
}
check_malloc_state(&main_arena);
diff --git a/malloc/malloc.c b/malloc/malloc.c
index dd295f522c..b1668b501b 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -238,6 +238,9 @@
/* For va_arg, va_start, va_end. */
#include <stdarg.h>
+/* For MIN, MAX, powerof2. */
+#include <sys/param.h>
+
/*
Debugging:
@@ -403,13 +406,6 @@ void *(*__morecore)(ptrdiff_t) = __default_morecore;
#include <string.h>
-
-/* Force a value to be in a register and stop the compiler referring
- to the source (mostly memory location) again. */
-#define force_reg(val) \
- ({ __typeof (val) _v; asm ("" : "=r" (_v) : "0" (val)); _v; })
-
-
/*
MORECORE-related declarations. By default, rely on sbrk
*/
@@ -1054,8 +1050,8 @@ static void _int_free(mstate, mchunkptr, int);
static void* _int_realloc(mstate, mchunkptr, INTERNAL_SIZE_T,
INTERNAL_SIZE_T);
static void* _int_memalign(mstate, size_t, size_t);
-static void* _int_valloc(mstate, size_t);
-static void* _int_pvalloc(mstate, size_t);
+static void* _mid_memalign(size_t, size_t, void *);
+
static void malloc_printerr(int action, const char *str, void *ptr);
static void* internal_function mem2mem_check(void *p, size_t sz);
@@ -1076,19 +1072,6 @@ static void* malloc_atfork(size_t sz, const void *caller);
static void free_atfork(void* mem, const void *caller);
#endif
-
-/* ------------- Optional versions of memcopy ---------------- */
-
-
-/*
- Note: memcpy is ONLY invoked with non-overlapping regions,
- so the (usually slower) memmove is not needed.
-*/
-
-#define MALLOC_COPY(dest, src, nbytes) memcpy(dest, src, nbytes)
-#define MALLOC_ZERO(dest, nbytes) memset(dest, 0, nbytes)
-
-
/* ------------------ MMAP support ------------------ */
@@ -1711,10 +1694,8 @@ struct malloc_state {
/* Linked list */
struct malloc_state *next;
-#ifdef PER_THREAD
/* Linked list for free arenas. */
struct malloc_state *next_free;
-#endif
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
@@ -1726,10 +1707,8 @@ struct malloc_par {
unsigned long trim_threshold;
INTERNAL_SIZE_T top_pad;
INTERNAL_SIZE_T mmap_threshold;
-#ifdef PER_THREAD
INTERNAL_SIZE_T arena_test;
INTERNAL_SIZE_T arena_max;
-#endif
/* Memory map support */
int n_mmaps;
@@ -1771,18 +1750,14 @@ static struct malloc_par mp_ =
.n_mmaps_max = DEFAULT_MMAP_MAX,
.mmap_threshold = DEFAULT_MMAP_THRESHOLD,
.trim_threshold = DEFAULT_TRIM_THRESHOLD,
-#ifdef PER_THREAD
# define NARENAS_FROM_NCORES(n) ((n) * (sizeof(long) == 4 ? 2 : 8))
.arena_test = NARENAS_FROM_NCORES (1)
-#endif
};
-#ifdef PER_THREAD
/* Non public mallopt parameters. */
#define M_ARENA_TEST -7
#define M_ARENA_MAX -8
-#endif
/* Maximum size of memory handled in fastbins. */
@@ -1874,10 +1849,24 @@ static int check_action = DEFAULT_CHECK_ACTION;
static int perturb_byte;
-#define alloc_perturb(p, n) memset (p, (perturb_byte ^ 0xff) & 0xff, n)
-#define free_perturb(p, n) memset (p, perturb_byte & 0xff, n)
+static inline void
+alloc_perturb (char *p, size_t n)
+{
+ if (__glibc_unlikely (perturb_byte))
+ memset (p, perturb_byte ^ 0xff, n);
+}
+
+static inline void
+free_perturb (char *p, size_t n)
+{
+ if (__glibc_unlikely (perturb_byte))
+ memset (p, perturb_byte, n);
+}
+
+#include <stap-probe.h>
+
/* ------------------- Support for multiple arenas -------------------- */
#include "arena.c"
@@ -2214,15 +2203,6 @@ static void do_check_malloc_state(mstate av)
/* top chunk is OK */
check_chunk(av, av->top);
- /* sanity checks for statistics */
-
- assert(mp_.n_mmaps <= mp_.max_n_mmaps);
-
- assert((unsigned long)(av->system_mem) <=
- (unsigned long)(av->max_system_mem));
-
- assert((unsigned long)(mp_.mmapped_mem) <=
- (unsigned long)(mp_.max_mmapped_mem));
}
#endif
@@ -2260,7 +2240,6 @@ static void* sysmalloc(INTERNAL_SIZE_T nb, mstate av)
mchunkptr remainder; /* remainder from allocation */
unsigned long remainder_size; /* its size */
- unsigned long sum; /* for updating stats */
size_t pagemask = GLRO(dl_pagesize) - 1;
bool tried_mmap = false;
@@ -2332,12 +2311,12 @@ static void* sysmalloc(INTERNAL_SIZE_T nb, mstate av)
/* update statistics */
- if (++mp_.n_mmaps > mp_.max_n_mmaps)
- mp_.max_n_mmaps = mp_.n_mmaps;
+ int new = atomic_exchange_and_add (&mp_.n_mmaps, 1) + 1;
+ atomic_max (&mp_.max_n_mmaps, new);
- sum = mp_.mmapped_mem += size;
- if (sum > (unsigned long)(mp_.max_mmapped_mem))
- mp_.max_mmapped_mem = sum;
+ unsigned long sum;
+ sum = atomic_exchange_and_add(&mp_.mmapped_mem, size) + size;
+ atomic_max (&mp_.max_mmapped_mem, sum);
check_chunk(av, p);
@@ -2446,12 +2425,14 @@ static void* sysmalloc(INTERNAL_SIZE_T nb, mstate av)
below even if we cannot call MORECORE.
*/
- if (size > 0)
+ if (size > 0) {
brk = (char*)(MORECORE(size));
+ LIBC_PROBE (memory_sbrk_more, 2, brk, size);
+ }
if (brk != (char*)(MORECORE_FAILURE)) {
/* Call the `morecore' hook if necessary. */
- void (*hook) (void) = force_reg (__after_morecore_hook);
+ void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
if (__builtin_expect (hook != NULL, 0))
(*hook) ();
} else {
@@ -2589,7 +2570,7 @@ static void* sysmalloc(INTERNAL_SIZE_T nb, mstate av)
snd_brk = (char*)(MORECORE(0));
} else {
/* Call the `morecore' hook if necessary. */
- void (*hook) (void) = force_reg (__after_morecore_hook);
+ void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
if (__builtin_expect (hook != NULL, 0))
(*hook) ();
}
@@ -2712,50 +2693,54 @@ static int systrim(size_t pad, mstate av)
char* current_brk; /* address returned by pre-check sbrk call */
char* new_brk; /* address returned by post-check sbrk call */
size_t pagesz;
+ long top_area;
pagesz = GLRO(dl_pagesize);
top_size = chunksize(av->top);
+ top_area = top_size - MINSIZE - 1;
+ if (top_area <= pad)
+ return 0;
+
/* Release in pagesize units, keeping at least one page */
- extra = (top_size - pad - MINSIZE - 1) & ~(pagesz - 1);
+ extra = (top_area - pad) & ~(pagesz - 1);
- if (extra > 0) {
+ /*
+ Only proceed if end of memory is where we last set it.
+ This avoids problems if there were foreign sbrk calls.
+ */
+ current_brk = (char*)(MORECORE(0));
+ if (current_brk == (char*)(av->top) + top_size) {
/*
- Only proceed if end of memory is where we last set it.
- This avoids problems if there were foreign sbrk calls.
+ Attempt to release memory. We ignore MORECORE return value,
+ and instead call again to find out where new end of memory is.
+ This avoids problems if first call releases less than we asked,
+ of if failure somehow altered brk value. (We could still
+ encounter problems if it altered brk in some very bad way,
+ but the only thing we can do is adjust anyway, which will cause
+ some downstream failure.)
*/
- current_brk = (char*)(MORECORE(0));
- if (current_brk == (char*)(av->top) + top_size) {
- /*
- Attempt to release memory. We ignore MORECORE return value,
- and instead call again to find out where new end of memory is.
- This avoids problems if first call releases less than we asked,
- of if failure somehow altered brk value. (We could still
- encounter problems if it altered brk in some very bad way,
- but the only thing we can do is adjust anyway, which will cause
- some downstream failure.)
- */
+ MORECORE(-extra);
+ /* Call the `morecore' hook if necessary. */
+ void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
+ if (__builtin_expect (hook != NULL, 0))
+ (*hook) ();
+ new_brk = (char*)(MORECORE(0));
- MORECORE(-extra);
- /* Call the `morecore' hook if necessary. */
- void (*hook) (void) = force_reg (__after_morecore_hook);
- if (__builtin_expect (hook != NULL, 0))
- (*hook) ();
- new_brk = (char*)(MORECORE(0));
-
- if (new_brk != (char*)MORECORE_FAILURE) {
- released = (long)(current_brk - new_brk);
-
- if (released != 0) {
- /* Success. Adjust top. */
- av->system_mem -= released;
- set_head(av->top, (top_size - released) | PREV_INUSE);
- check_malloc_state(av);
- return 1;
- }
- }
+ LIBC_PROBE (memory_sbrk_less, 2, new_brk, extra);
+
+ if (new_brk != (char*)MORECORE_FAILURE) {
+ released = (long)(current_brk - new_brk);
+
+ if (released != 0) {
+ /* Success. Adjust top. */
+ av->system_mem -= released;
+ set_head(av->top, (top_size - released) | PREV_INUSE);
+ check_malloc_state(av);
+ return 1;
+ }
}
}
return 0;
@@ -2783,8 +2768,8 @@ munmap_chunk(mchunkptr p)
return;
}
- mp_.n_mmaps--;
- mp_.mmapped_mem -= total_size;
+ atomic_decrement (&mp_.n_mmaps);
+ atomic_add (&mp_.mmapped_mem, -total_size);
/* If munmap failed the process virtual memory address space is in a
bad shape. Just leave the block hanging around, the process will
@@ -2825,10 +2810,10 @@ mremap_chunk(mchunkptr p, size_t new_size)
assert((p->prev_size == offset));
set_head(p, (new_size - offset)|IS_MMAPPED);
- mp_.mmapped_mem -= size + offset;
- mp_.mmapped_mem += new_size;
- if ((unsigned long)mp_.mmapped_mem > (unsigned long)mp_.max_mmapped_mem)
- mp_.max_mmapped_mem = mp_.mmapped_mem;
+ INTERNAL_SIZE_T new;
+ new = atomic_exchange_and_add (&mp_.mmapped_mem, new_size - size - offset)
+ + new_size - size - offset;
+ atomic_max (&mp_.max_mmapped_mem, new);
return p;
}
@@ -2843,7 +2828,7 @@ __libc_malloc(size_t bytes)
void *victim;
void *(*hook) (size_t, const void *)
- = force_reg (__malloc_hook);
+ = atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
return (*hook)(bytes, RETURN_ADDRESS (0));
@@ -2854,6 +2839,7 @@ __libc_malloc(size_t bytes)
return 0;
victim = _int_malloc(ar_ptr, bytes);
if(!victim) {
+ LIBC_PROBE (memory_malloc_retry, 1, bytes);
ar_ptr = arena_get_retry(ar_ptr, bytes);
if (__builtin_expect(ar_ptr != NULL, 1)) {
victim = _int_malloc(ar_ptr, bytes);
@@ -2874,7 +2860,7 @@ __libc_free(void* mem)
mchunkptr p; /* chunk corresponding to mem */
void (*hook) (void *, const void *)
- = force_reg (__free_hook);
+ = atomic_forced_read (__free_hook);
if (__builtin_expect (hook != NULL, 0)) {
(*hook)(mem, RETURN_ADDRESS (0));
return;
@@ -2894,6 +2880,8 @@ __libc_free(void* mem)
{
mp_.mmap_threshold = chunksize (p);
mp_.trim_threshold = 2 * mp_.mmap_threshold;
+ LIBC_PROBE (memory_mallopt_free_dyn_thresholds, 2,
+ mp_.mmap_threshold, mp_.trim_threshold);
}
munmap_chunk(p);
return;
@@ -2913,7 +2901,7 @@ __libc_realloc(void* oldmem, size_t bytes)
void* newp; /* chunk to return */
void *(*hook) (void *, size_t, const void *) =
- force_reg (__realloc_hook);
+ atomic_forced_read (__realloc_hook);
if (__builtin_expect (hook != NULL, 0))
return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
@@ -2955,7 +2943,7 @@ __libc_realloc(void* oldmem, size_t bytes)
/* Must alloc, copy, free. */
newmem = __libc_malloc(bytes);
if (newmem == 0) return 0; /* propagate failure */
- MALLOC_COPY(newmem, oldmem, oldsize - 2*SIZE_SZ);
+ memcpy(newmem, oldmem, oldsize - 2*SIZE_SZ);
munmap_chunk(oldp);
return newmem;
}
@@ -2972,10 +2960,6 @@ __libc_realloc(void* oldmem, size_t bytes)
(void)mutex_lock(&ar_ptr->mutex);
#endif
-#if !defined PER_THREAD
- /* As in malloc(), remember this arena for the next allocation. */
- tsd_setspecific(arena_key, (void *)ar_ptr);
-#endif
newp = _int_realloc(ar_ptr, oldp, oldsize, nb);
@@ -2986,10 +2970,11 @@ __libc_realloc(void* oldmem, size_t bytes)
if (newp == NULL)
{
/* Try harder to allocate memory in other arenas. */
+ LIBC_PROBE (memory_realloc_retry, 2, bytes, oldmem);
newp = __libc_malloc(bytes);
if (newp != NULL)
{
- MALLOC_COPY (newp, oldmem, oldsize - SIZE_SZ);
+ memcpy (newp, oldmem, oldsize - SIZE_SZ);
_int_free(ar_ptr, oldp, 0);
}
}
@@ -3001,25 +2986,56 @@ libc_hidden_def (__libc_realloc)
void*
__libc_memalign(size_t alignment, size_t bytes)
{
+ void *address = RETURN_ADDRESS (0);
+ return _mid_memalign (alignment, bytes, address);
+}
+
+static void *
+_mid_memalign (size_t alignment, size_t bytes, void *address)
+{
mstate ar_ptr;
void *p;
void *(*hook) (size_t, size_t, const void *) =
- force_reg (__memalign_hook);
+ atomic_forced_read (__memalign_hook);
if (__builtin_expect (hook != NULL, 0))
- return (*hook)(alignment, bytes, RETURN_ADDRESS (0));
+ return (*hook)(alignment, bytes, address);
- /* If need less alignment than we give anyway, just relay to malloc */
+ /* If we need less alignment than we give anyway, just relay to malloc. */
if (alignment <= MALLOC_ALIGNMENT) return __libc_malloc(bytes);
/* Otherwise, ensure that it is at least a minimum chunk size */
if (alignment < MINSIZE) alignment = MINSIZE;
+ /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
+ power of 2 and will cause overflow in the check below. */
+ if (alignment > SIZE_MAX / 2 + 1)
+ {
+ __set_errno (EINVAL);
+ return 0;
+ }
+
+ /* Check for overflow. */
+ if (bytes > SIZE_MAX - alignment - MINSIZE)
+ {
+ __set_errno (ENOMEM);
+ return 0;
+ }
+
+
+ /* Make sure alignment is power of 2. */
+ if (!powerof2(alignment)) {
+ size_t a = MALLOC_ALIGNMENT * 2;
+ while (a < alignment) a <<= 1;
+ alignment = a;
+ }
+
arena_get(ar_ptr, bytes + alignment + MINSIZE);
if(!ar_ptr)
return 0;
p = _int_memalign(ar_ptr, alignment, bytes);
if(!p) {
+ LIBC_PROBE (memory_memalign_retry, 2, bytes, alignment);
ar_ptr = arena_get_retry (ar_ptr, bytes);
if (__builtin_expect(ar_ptr != NULL, 1)) {
p = _int_memalign(ar_ptr, alignment, bytes);
@@ -3038,69 +3054,34 @@ libc_hidden_def (__libc_memalign)
void*
__libc_valloc(size_t bytes)
{
- mstate ar_ptr;
- void *p;
-
if(__malloc_initialized < 0)
ptmalloc_init ();
+ void *address = RETURN_ADDRESS (0);
size_t pagesz = GLRO(dl_pagesize);
-
- void *(*hook) (size_t, size_t, const void *) =
- force_reg (__memalign_hook);
- if (__builtin_expect (hook != NULL, 0))
- return (*hook)(pagesz, bytes, RETURN_ADDRESS (0));
-
- arena_get(ar_ptr, bytes + pagesz + MINSIZE);
- if(!ar_ptr)
- return 0;
- p = _int_valloc(ar_ptr, bytes);
- if(!p) {
- ar_ptr = arena_get_retry (ar_ptr, bytes);
- if (__builtin_expect(ar_ptr != NULL, 1)) {
- p = _int_memalign(ar_ptr, pagesz, bytes);
- (void)mutex_unlock(&ar_ptr->mutex);
- }
- } else
- (void)mutex_unlock (&ar_ptr->mutex);
- assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
- ar_ptr == arena_for_chunk(mem2chunk(p)));
-
- return p;
+ return _mid_memalign (pagesz, bytes, address);
}
void*
__libc_pvalloc(size_t bytes)
{
- mstate ar_ptr;
- void *p;
if(__malloc_initialized < 0)
ptmalloc_init ();
+ void *address = RETURN_ADDRESS (0);
size_t pagesz = GLRO(dl_pagesize);
size_t page_mask = GLRO(dl_pagesize) - 1;
size_t rounded_bytes = (bytes + page_mask) & ~(page_mask);
- void *(*hook) (size_t, size_t, const void *) =
- force_reg (__memalign_hook);
- if (__builtin_expect (hook != NULL, 0))
- return (*hook)(pagesz, rounded_bytes, RETURN_ADDRESS (0));
-
- arena_get(ar_ptr, bytes + 2*pagesz + MINSIZE);
- p = _int_pvalloc(ar_ptr, bytes);
- if(!p) {
- ar_ptr = arena_get_retry (ar_ptr, bytes + 2*pagesz + MINSIZE);
- if (__builtin_expect(ar_ptr != NULL, 1)) {
- p = _int_memalign(ar_ptr, pagesz, rounded_bytes);
- (void)mutex_unlock(&ar_ptr->mutex);
+ /* Check for overflow. */
+ if (bytes > SIZE_MAX - 2*pagesz - MINSIZE)
+ {
+ __set_errno (ENOMEM);
+ return 0;
}
- } else
- (void)mutex_unlock(&ar_ptr->mutex);
- assert(!p || chunk_is_mmapped(mem2chunk(p)) ||
- ar_ptr == arena_for_chunk(mem2chunk(p)));
- return p;
+ return _mid_memalign (pagesz, rounded_bytes, address);
}
void*
@@ -3126,7 +3107,7 @@ __libc_calloc(size_t n, size_t elem_size)
}
void *(*hook) (size_t, const void *) =
- force_reg (__malloc_hook);
+ atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0)) {
sz = bytes;
mem = (*hook)(sz, RETURN_ADDRESS (0));
@@ -3166,6 +3147,7 @@ __libc_calloc(size_t n, size_t elem_size)
av == arena_for_chunk(mem2chunk(mem)));
if (mem == 0) {
+ LIBC_PROBE (memory_calloc_retry, 1, sz);
av = arena_get_retry (av, sz);
if (__builtin_expect(av != NULL, 1)) {
mem = _int_malloc(av, sz);
@@ -3180,7 +3162,7 @@ __libc_calloc(size_t n, size_t elem_size)
if (chunk_is_mmapped (p))
{
if (__builtin_expect (perturb_byte, 0))
- MALLOC_ZERO (mem, sz);
+ return memset (mem, 0, sz);
return mem;
}
@@ -3202,7 +3184,7 @@ __libc_calloc(size_t n, size_t elem_size)
assert(nclears >= 3);
if (nclears > 9)
- MALLOC_ZERO(d, clearsize);
+ return memset(d, 0, clearsize);
else {
*(d+0) = 0;
@@ -3291,8 +3273,7 @@ _int_malloc(mstate av, size_t bytes)
}
check_remalloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
- if (__builtin_expect (perturb_byte, 0))
- alloc_perturb (p, bytes);
+ alloc_perturb (p, bytes);
return p;
}
}
@@ -3327,8 +3308,7 @@ _int_malloc(mstate av, size_t bytes)
victim->size |= NON_MAIN_ARENA;
check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
- if (__builtin_expect (perturb_byte, 0))
- alloc_perturb (p, bytes);
+ alloc_perturb (p, bytes);
return p;
}
}
@@ -3407,8 +3387,7 @@ _int_malloc(mstate av, size_t bytes)
check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
- if (__builtin_expect (perturb_byte, 0))
- alloc_perturb (p, bytes);
+ alloc_perturb (p, bytes);
return p;
}
@@ -3424,8 +3403,7 @@ _int_malloc(mstate av, size_t bytes)
victim->size |= NON_MAIN_ARENA;
check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
- if (__builtin_expect (perturb_byte, 0))
- alloc_perturb (p, bytes);
+ alloc_perturb (p, bytes);
return p;
}
@@ -3549,8 +3527,7 @@ _int_malloc(mstate av, size_t bytes)
}
check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
- if (__builtin_expect (perturb_byte, 0))
- alloc_perturb (p, bytes);
+ alloc_perturb (p, bytes);
return p;
}
}
@@ -3653,8 +3630,7 @@ _int_malloc(mstate av, size_t bytes)
}
check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
- if (__builtin_expect (perturb_byte, 0))
- alloc_perturb (p, bytes);
+ alloc_perturb (p, bytes);
return p;
}
}
@@ -3688,8 +3664,7 @@ _int_malloc(mstate av, size_t bytes)
check_malloced_chunk(av, victim, nb);
void *p = chunk2mem(victim);
- if (__builtin_expect (perturb_byte, 0))
- alloc_perturb (p, bytes);
+ alloc_perturb (p, bytes);
return p;
}
@@ -3709,7 +3684,7 @@ _int_malloc(mstate av, size_t bytes)
*/
else {
void *p = sysmalloc(nb, av);
- if (p != NULL && __builtin_expect (perturb_byte, 0))
+ if (p != NULL)
alloc_perturb (p, bytes);
return p;
}
@@ -3802,8 +3777,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
}
}
- if (__builtin_expect (perturb_byte, 0))
- free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+ free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
set_fastchunks(av);
unsigned int idx = fastbin_index(size);
@@ -3885,8 +3859,7 @@ _int_free(mstate av, mchunkptr p, int have_lock)
goto errout;
}
- if (__builtin_expect (perturb_byte, 0))
- free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
+ free_perturb (chunk2mem(p), size - 2 * SIZE_SZ);
/* consolidate backward */
if (!prev_inuse(p)) {
@@ -4215,7 +4188,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
assert(ncopies >= 3);
if (ncopies > 9)
- MALLOC_COPY(d, s, copysize);
+ memcpy(d, s, copysize);
else {
*(d+0) = *(s+0);
@@ -4284,20 +4257,7 @@ _int_memalign(mstate av, size_t alignment, size_t bytes)
unsigned long remainder_size; /* its size */
INTERNAL_SIZE_T size;
- /* If need less alignment than we give anyway, just relay to malloc */
- if (alignment <= MALLOC_ALIGNMENT) return _int_malloc(av, bytes);
-
- /* Otherwise, ensure that it is at least a minimum chunk size */
-
- if (alignment < MINSIZE) alignment = MINSIZE;
-
- /* Make sure alignment is power of 2 (in case MINSIZE is not). */
- if ((alignment & (alignment - 1)) != 0) {
- size_t a = MALLOC_ALIGNMENT * 2;
- while ((unsigned long)a < (unsigned long)alignment) a <<= 1;
- alignment = a;
- }
checked_request2size(bytes, nb);
@@ -4372,35 +4332,6 @@ _int_memalign(mstate av, size_t alignment, size_t bytes)
/*
- ------------------------------ valloc ------------------------------
-*/
-
-static void*
-_int_valloc(mstate av, size_t bytes)
-{
- /* Ensure initialization/consolidation */
- if (have_fastchunks(av)) malloc_consolidate(av);
- return _int_memalign(av, GLRO(dl_pagesize), bytes);
-}
-
-/*
- ------------------------------ pvalloc ------------------------------
-*/
-
-
-static void*
-_int_pvalloc(mstate av, size_t bytes)
-{
- size_t pagesz;
-
- /* Ensure initialization/consolidation */
- if (have_fastchunks(av)) malloc_consolidate(av);
- pagesz = GLRO(dl_pagesize);
- return _int_memalign(av, pagesz, (bytes + pagesz - 1) & ~(pagesz - 1));
-}
-
-
-/*
------------------------------ malloc_trim ------------------------------
*/
@@ -4674,21 +4605,29 @@ int __libc_mallopt(int param_number, int value)
/* Ensure initialization/consolidation */
malloc_consolidate(av);
+ LIBC_PROBE (memory_mallopt, 2, param_number, value);
+
switch(param_number) {
case M_MXFAST:
- if (value >= 0 && value <= MAX_FAST_SIZE) {
- set_max_fast(value);
- }
+ if (value >= 0 && value <= MAX_FAST_SIZE)
+ {
+ LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
+ set_max_fast(value);
+ }
else
res = 0;
break;
case M_TRIM_THRESHOLD:
+ LIBC_PROBE (memory_mallopt_trim_threshold, 3, value,
+ mp_.trim_threshold, mp_.no_dyn_threshold);
mp_.trim_threshold = value;
mp_.no_dyn_threshold = 1;
break;
case M_TOP_PAD:
+ LIBC_PROBE (memory_mallopt_top_pad, 3, value,
+ mp_.top_pad, mp_.no_dyn_threshold);
mp_.top_pad = value;
mp_.no_dyn_threshold = 1;
break;
@@ -4699,35 +4638,45 @@ int __libc_mallopt(int param_number, int value)
res = 0;
else
{
+ LIBC_PROBE (memory_mallopt_mmap_threshold, 3, value,
+ mp_.mmap_threshold, mp_.no_dyn_threshold);
mp_.mmap_threshold = value;
mp_.no_dyn_threshold = 1;
}
break;
case M_MMAP_MAX:
+ LIBC_PROBE (memory_mallopt_mmap_max, 3, value,
+ mp_.n_mmaps_max, mp_.no_dyn_threshold);
mp_.n_mmaps_max = value;
mp_.no_dyn_threshold = 1;
break;
case M_CHECK_ACTION:
+ LIBC_PROBE (memory_mallopt_check_action, 2, value, check_action);
check_action = value;
break;
case M_PERTURB:
+ LIBC_PROBE (memory_mallopt_perturb, 2, value, perturb_byte);
perturb_byte = value;
break;
-#ifdef PER_THREAD
case M_ARENA_TEST:
if (value > 0)
- mp_.arena_test = value;
+ {
+ LIBC_PROBE (memory_mallopt_arena_test, 2, value, mp_.arena_test);
+ mp_.arena_test = value;
+ }
break;
case M_ARENA_MAX:
if (value > 0)
- mp_.arena_max = value;
+ {
+ LIBC_PROBE (memory_mallopt_arena_max, 2, value, mp_.arena_max);
+ mp_.arena_max = value;
+ }
break;
-#endif
}
(void)mutex_unlock(&av->mutex);
return res;
@@ -4899,8 +4848,6 @@ malloc_printerr(int action, const char *str, void *ptr)
abort ();
}
-#include <sys/param.h>
-
/* We need a wrapper function for one of the additions of POSIX. */
int
__posix_memalign (void **memptr, size_t alignment, size_t size)
@@ -4914,14 +4861,9 @@ __posix_memalign (void **memptr, size_t alignment, size_t size)
|| alignment == 0)
return EINVAL;
- /* Call the hook here, so that caller is posix_memalign's caller
- and not posix_memalign itself. */
- void *(*hook) (size_t, size_t, const void *) =
- force_reg (__memalign_hook);
- if (__builtin_expect (hook != NULL, 0))
- mem = (*hook)(alignment, size, RETURN_ADDRESS (0));
- else
- mem = __libc_memalign (alignment, size);
+
+ void *address = RETURN_ADDRESS (0);
+ mem = _mid_memalign (alignment, size, address);
if (mem != NULL) {
*memptr = mem;
@@ -4995,23 +4937,11 @@ malloc_info (int options, FILE *fp)
sizes[i].total = sizes[i].count * sizes[i].to;
}
- mbinptr bin = bin_at (ar_ptr, 1);
- struct malloc_chunk *r = bin->fd;
- if (r != NULL)
- {
- while (r != bin)
- {
- ++sizes[NFASTBINS].count;
- sizes[NFASTBINS].total += r->size;
- sizes[NFASTBINS].from = MIN (sizes[NFASTBINS].from, r->size);
- sizes[NFASTBINS].to = MAX (sizes[NFASTBINS].to, r->size);
- r = r->fd;
- }
- nblocks += sizes[NFASTBINS].count;
- avail += sizes[NFASTBINS].total;
- }
- for (size_t i = 2; i < NBINS; ++i)
+ mbinptr bin;
+ struct malloc_chunk *r;
+
+ for (size_t i = 1; i < NBINS; ++i)
{
bin = bin_at (ar_ptr, i);
r = bin->fd;
diff --git a/malloc/obstack.h b/malloc/obstack.h
index d2e056bf38..e786d1fef0 100644
--- a/malloc/obstack.h
+++ b/malloc/obstack.h
@@ -185,7 +185,7 @@ extern int _obstack_begin_1 (struct obstack *, int, int,
void (*) (void *, void *), void *);
extern int _obstack_memory_used (struct obstack *);
-void obstack_free (struct obstack *__obstack, void *__block);
+void obstack_free (struct obstack *__obstack, void *__glibc_block);
/* Error handler called when `obstack_chunk_alloc' failed to allocate
diff --git a/malloc/tst-memalign.c b/malloc/tst-memalign.c
new file mode 100644
index 0000000000..cf48e7ed1f
--- /dev/null
+++ b/malloc/tst-memalign.c
@@ -0,0 +1,114 @@
+/* Test for memalign.
+ Copyright (C) 2013 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+ ++errors;
+ printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+ void *p;
+ unsigned long pagesize = getpagesize ();
+ unsigned long ptrval;
+ int save;
+
+ errno = 0;
+
+ /* An attempt to allocate a huge value should return NULL and set
+ errno to ENOMEM. */
+ p = memalign (sizeof (void *), -1);
+
+ save = errno;
+
+ if (p != NULL)
+ merror ("memalign (sizeof (void *), -1) succeeded.");
+
+ if (p == NULL && save != ENOMEM)
+ merror ("memalign (sizeof (void *), -1) errno is not set correctly");
+
+ free (p);
+
+ errno = 0;
+
+ /* Test to expose integer overflow in malloc internals from BZ #15857. */
+ p = memalign (pagesize, -pagesize);
+
+ save = errno;
+
+ if (p != NULL)
+ merror ("memalign (pagesize, -pagesize) succeeded.");
+
+ if (p == NULL && save != ENOMEM)
+ merror ("memalign (pagesize, -pagesize) errno is not set correctly");
+
+ free (p);
+
+ errno = 0;
+
+ /* Test to expose integer overflow in malloc internals from BZ #16038. */
+ p = memalign (-1, pagesize);
+
+ save = errno;
+
+ if (p != NULL)
+ merror ("memalign (-1, pagesize) succeeded.");
+
+ if (p == NULL && save != EINVAL)
+ merror ("memalign (-1, pagesize) errno is not set correctly");
+
+ free (p);
+
+ /* A zero-sized allocation should succeed with glibc, returning a
+ non-NULL value. */
+ p = memalign (sizeof (void *), 0);
+
+ if (p == NULL)
+ merror ("memalign (sizeof (void *), 0) failed.");
+
+ free (p);
+
+ /* Check the alignment of the returned pointer is correct. */
+ p = memalign (0x100, 10);
+
+ if (p == NULL)
+ merror ("memalign (0x100, 10) failed.");
+
+ ptrval = (unsigned long) p;
+
+ if ((ptrval & 0xff) != 0)
+ merror ("pointer is not aligned to 0x100");
+
+ free (p);
+
+ return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/malloc/tst-posix_memalign.c b/malloc/tst-posix_memalign.c
new file mode 100644
index 0000000000..7f34e37bd2
--- /dev/null
+++ b/malloc/tst-posix_memalign.c
@@ -0,0 +1,118 @@
+/* Test for posix_memalign.
+ Copyright (C) 2013 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+ ++errors;
+ printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+ void *p;
+ int ret;
+ unsigned long pagesize = getpagesize ();
+ unsigned long ptrval;
+
+ p = NULL;
+
+ /* An attempt to allocate a huge value should return ENOMEM and
+ p should remain NULL. */
+ ret = posix_memalign (&p, sizeof (void *), -1);
+
+ if (ret != ENOMEM)
+ merror ("posix_memalign (&p, sizeof (void *), -1) succeeded.");
+
+ if (ret == ENOMEM && p != NULL)
+ merror ("returned an error but pointer was modified");
+
+ free (p);
+
+ p = NULL;
+
+ /* Test to expose integer overflow in malloc internals from BZ #15857. */
+ ret = posix_memalign (&p, pagesize, -pagesize);
+
+ if (ret != ENOMEM)
+ merror ("posix_memalign (&p, pagesize, -pagesize) succeeded.");
+
+ free (p);
+
+ p = NULL;
+
+ /* Test to expose integer overflow in malloc internals from BZ #16038. */
+ ret = posix_memalign (&p, -1, pagesize);
+
+ if (ret != EINVAL)
+ merror ("posix_memalign (&p, -1, pagesize) succeeded.");
+
+ free (p);
+
+ p = NULL;
+
+ /* A zero-sized allocation should succeed with glibc, returning zero
+ and setting p to a non-NULL value. */
+ ret = posix_memalign (&p, sizeof (void *), 0);
+
+ if (ret != 0 || p == NULL)
+ merror ("posix_memalign (&p, sizeof (void *), 0) failed.");
+
+ free (p);
+
+ ret = posix_memalign (&p, 0x300, 10);
+
+ if (ret != EINVAL)
+ merror ("posix_memalign (&p, 0x300, 10) succeeded.");
+
+ ret = posix_memalign (&p, 0, 10);
+
+ if (ret != EINVAL)
+ merror ("posix_memalign (&p, 0, 10) succeeded.");
+
+ p = NULL;
+
+ ret = posix_memalign (&p, 0x100, 10);
+
+ if (ret != 0)
+ merror ("posix_memalign (&p, 0x100, 10) failed.");
+
+ if (ret == 0 && p == NULL)
+ merror ("returned success but pointer is NULL");
+
+ ptrval = (unsigned long) p;
+
+ if (ret == 0 && (ptrval & 0xff) != 0)
+ merror ("pointer is not aligned to 0x100");
+
+ free (p);
+
+ return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/malloc/tst-pvalloc.c b/malloc/tst-pvalloc.c
new file mode 100644
index 0000000000..1c81294926
--- /dev/null
+++ b/malloc/tst-pvalloc.c
@@ -0,0 +1,99 @@
+/* Test for pvalloc.
+ Copyright (C) 2013 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+ ++errors;
+ printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+ void *p;
+ unsigned long pagesize = getpagesize ();
+ unsigned long ptrval;
+ int save;
+
+ errno = 0;
+
+ /* An attempt to allocate a huge value should return NULL and set
+ errno to ENOMEM. */
+ p = pvalloc (-1);
+
+ save = errno;
+
+ if (p != NULL)
+ merror ("pvalloc (-1) succeeded.");
+
+ if (p == NULL && save != ENOMEM)
+ merror ("pvalloc (-1) errno is not set correctly");
+
+ free (p);
+
+ errno = 0;
+
+ /* Test to expose integer overflow in malloc internals from BZ #15855. */
+ p = pvalloc (-pagesize);
+
+ save = errno;
+
+ if (p != NULL)
+ merror ("pvalloc (-pagesize) succeeded.");
+
+ if (p == NULL && save != ENOMEM)
+ merror ("pvalloc (-pagesize) errno is not set correctly");
+
+ free (p);
+
+ /* A zero-sized allocation should succeed with glibc, returning a
+ non-NULL value. */
+ p = pvalloc (0);
+
+ if (p == NULL)
+ merror ("pvalloc (0) failed.");
+
+ free (p);
+
+ /* Check the alignment of the returned pointer is correct. */
+ p = pvalloc (32);
+
+ if (p == NULL)
+ merror ("pvalloc (32) failed.");
+
+ ptrval = (unsigned long) p;
+
+ if ((ptrval & (pagesize - 1)) != 0)
+ merror ("returned pointer is not page aligned.");
+
+ free (p);
+
+ return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/malloc/tst-realloc.c b/malloc/tst-realloc.c
new file mode 100644
index 0000000000..9d290d24c0
--- /dev/null
+++ b/malloc/tst-realloc.c
@@ -0,0 +1,146 @@
+/* Copyright (C) 2013 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+ ++errors;
+ printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
+{
+ void *p;
+ unsigned char *c;
+ int save, i, ok;
+
+ errno = 0;
+
+ /* realloc (NULL, ...) behaves similarly to malloc (C89). */
+ p = realloc (NULL, -1);
+ save = errno;
+
+ if (p != NULL)
+ merror ("realloc (NULL, -1) succeeded.");
+
+ /* errno should be set to ENOMEM on failure (POSIX). */
+ if (p == NULL && save != ENOMEM)
+ merror ("errno is not set correctly");
+
+ errno = 0;
+
+ /* realloc (NULL, ...) behaves similarly to malloc (C89). */
+ p = realloc (NULL, 10);
+ save = errno;
+
+ if (p == NULL)
+ merror ("realloc (NULL, 10) failed.");
+
+ /* errno should be clear on success (POSIX). */
+ if (p != NULL && save != 0)
+ merror ("errno is set but should not be");
+
+ free (p);
+
+ p = calloc (20, 1);
+ if (p == NULL)
+ merror ("calloc (20, 1) failed.");
+
+ /* Check increasing size preserves contents (C89). */
+ p = realloc (p, 200);
+ if (p == NULL)
+ merror ("realloc (p, 200) failed.");
+
+ c = p;
+ ok = 1;
+
+ for (i = 0; i < 20; i++)
+ {
+ if (c[i] != 0)
+ ok = 0;
+ }
+
+ if (ok == 0)
+ merror ("first 20 bytes were not cleared");
+
+ free (p);
+
+ p = realloc (NULL, 100);
+ if (p == NULL)
+ merror ("realloc (NULL, 100) failed.");
+
+ memset (p, 0xff, 100);
+
+ /* Check decreasing size preserves contents (C89). */
+ p = realloc (p, 16);
+ if (p == NULL)
+ merror ("realloc (p, 16) failed.");
+
+ c = p;
+ ok = 1;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (c[i] != 0xff)
+ ok = 0;
+ }
+
+ if (ok == 0)
+ merror ("first 16 bytes were not correct");
+
+ /* Check failed realloc leaves original untouched (C89). */
+ c = realloc (p, -1);
+ if (c != NULL)
+ merror ("realloc (p, -1) succeeded.");
+
+ c = p;
+ ok = 1;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (c[i] != 0xff)
+ ok = 0;
+ }
+
+ if (ok == 0)
+ merror ("first 16 bytes were not correct after failed realloc");
+
+ /* realloc (p, 0) frees p (C89) and returns NULL (glibc). */
+ p = realloc (p, 0);
+ if (p != NULL)
+ merror ("realloc (p, 0) returned non-NULL.");
+
+ /* realloc (NULL, 0) acts like malloc (0) (glibc). */
+ p = realloc (NULL, 0);
+ if (p == NULL)
+ merror ("realloc (NULL, 0) returned NULL.");
+
+ free (p);
+
+ return errors != 0;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/malloc/tst-valloc.c b/malloc/tst-valloc.c
index 643a0dda4a..4fd0dbb964 100644
--- a/malloc/tst-valloc.c
+++ b/malloc/tst-valloc.c
@@ -1,23 +1,99 @@
-/* Test case by Stephen Tweedie <sct@redhat.com>. */
-#include <unistd.h>
-#include <stdio.h>
+/* Test for valloc.
+ Copyright (C) 2013 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
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
-int
-main (void)
+static int errors = 0;
+
+static void
+merror (const char *msg)
+{
+ ++errors;
+ printf ("Error: %s\n", msg);
+}
+
+static int
+do_test (void)
{
- char *p;
- int pagesize = getpagesize ();
- int i;
+ void *p;
+ unsigned long pagesize = getpagesize ();
+ unsigned long ptrval;
+ int save;
+
+ errno = 0;
+
+ /* An attempt to allocate a huge value should return NULL and set
+ errno to ENOMEM. */
+ p = valloc (-1);
+
+ save = errno;
+
+ if (p != NULL)
+ merror ("valloc (-1) succeeded.");
- p = valloc (pagesize);
- i = (long int) p;
+ if (p == NULL && save != ENOMEM)
+ merror ("valloc (-1) errno is not set correctly");
- if ((i & (pagesize-1)) != 0)
- {
- fprintf (stderr, "Alignment problem: valloc returns %p\n", p);
- exit (1);
- }
+ free (p);
- return 0;
+ errno = 0;
+
+ /* Test to expose integer overflow in malloc internals from BZ #15856. */
+ p = valloc (-pagesize);
+
+ save = errno;
+
+ if (p != NULL)
+ merror ("valloc (-pagesize) succeeded.");
+
+ if (p == NULL && save != ENOMEM)
+ merror ("valloc (-pagesize) errno is not set correctly");
+
+ free (p);
+
+ /* A zero-sized allocation should succeed with glibc, returning a
+ non-NULL value. */
+ p = valloc (0);
+
+ if (p == NULL)
+ merror ("valloc (0) failed.");
+
+ free (p);
+
+ /* Check the alignment of the returned pointer is correct. */
+ p = valloc (32);
+
+ if (p == NULL)
+ merror ("valloc (32) failed.");
+
+ ptrval = (unsigned long) p;
+
+ if ((ptrval & (pagesize - 1)) != 0)
+ merror ("returned pointer is not page aligned.");
+
+ free (p);
+
+ return errors != 0;
}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"