diff options
Diffstat (limited to 'libc/malloc')
-rw-r--r-- | libc/malloc/Makefile | 4 | ||||
-rw-r--r-- | libc/malloc/arena.c | 11 | ||||
-rw-r--r-- | libc/malloc/hooks.c | 11 | ||||
-rw-r--r-- | libc/malloc/malloc.c | 77 | ||||
-rw-r--r-- | libc/malloc/tst-memalign.c | 99 | ||||
-rw-r--r-- | libc/malloc/tst-posix_memalign.c | 108 | ||||
-rw-r--r-- | libc/malloc/tst-pvalloc.c | 99 | ||||
-rw-r--r-- | libc/malloc/tst-realloc.c | 146 | ||||
-rw-r--r-- | libc/malloc/tst-valloc.c | 108 |
9 files changed, 627 insertions, 36 deletions
diff --git a/libc/malloc/Makefile b/libc/malloc/Makefile index be81dd3b8..9ca8edf67 100644 --- a/libc/malloc/Makefile +++ b/libc/malloc/Makefile @@ -27,7 +27,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 diff --git a/libc/malloc/arena.c b/libc/malloc/arena.c index 12a48ad7b..d81ed0d68 100644 --- a/libc/malloc/arena.c +++ b/libc/malloc/arena.c @@ -581,6 +581,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 +607,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 +635,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 +677,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,6 +740,7 @@ _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); @@ -774,6 +779,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,9 +816,11 @@ 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; @@ -891,6 +899,7 @@ arena_get2(mstate a_tsd, size_t size, mstate avoid_arena) if (retried) (void)mutex_unlock(&list_lock); THREAD_STAT(++(a->stat_lock_loop)); + LIBC_PROBE (memory_arena_reuse, 2, a, a_tsd); tsd_setspecific(arena_key, (void *)a); return a; } @@ -903,6 +912,7 @@ arena_get2(mstate a_tsd, size_t size, mstate avoid_arena) locks. */ if(!retried && mutex_trylock(&list_lock)) { /* We will block to not run in a busy loop. */ + LIBC_PROBE (memory_arena_reuse_wait, 3, &list_lock, NULL, a_tsd); (void)mutex_lock(&list_lock); /* Since we blocked there might be an arena available now. */ @@ -926,6 +936,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; diff --git a/libc/malloc/hooks.c b/libc/malloc/hooks.c index 8c2584633..3f663bb6b 100644 --- a/libc/malloc/hooks.c +++ b/libc/malloc/hooks.c @@ -361,10 +361,13 @@ 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; - } + /* Check for overflow. */ + if (bytes > SIZE_MAX - alignment - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + (void)mutex_lock(&main_arena.mutex); mem = (top_check() >= 0) ? _int_memalign(&main_arena, alignment, bytes+1) : NULL; diff --git a/libc/malloc/malloc.c b/libc/malloc/malloc.c index dd295f522..1a18c3f5f 100644 --- a/libc/malloc/malloc.c +++ b/libc/malloc/malloc.c @@ -1878,6 +1878,8 @@ static int perturb_byte; #define free_perturb(p, n) memset (p, perturb_byte & 0xff, n) +#include <stap-probe.h> + /* ------------------- Support for multiple arenas -------------------- */ #include "arena.c" @@ -2214,15 +2216,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 @@ -2446,8 +2439,10 @@ 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. */ @@ -2745,6 +2740,8 @@ static int systrim(size_t pad, mstate av) (*hook) (); new_brk = (char*)(MORECORE(0)); + LIBC_PROBE (memory_sbrk_less, 2, new_brk, extra); + if (new_brk != (char*)MORECORE_FAILURE) { released = (long)(current_brk - new_brk); @@ -2854,6 +2851,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); @@ -2894,6 +2892,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; @@ -2973,6 +2973,7 @@ __libc_realloc(void* oldmem, size_t bytes) #endif #if !defined PER_THREAD + LIBC_PROBE (memory_arena_reuse_realloc, 1, ar_ptr); /* As in malloc(), remember this arena for the next allocation. */ tsd_setspecific(arena_key, (void *)ar_ptr); #endif @@ -2986,6 +2987,7 @@ __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) { @@ -3015,11 +3017,19 @@ __libc_memalign(size_t alignment, size_t bytes) /* Otherwise, ensure that it is at least a minimum chunk size */ if (alignment < MINSIZE) alignment = MINSIZE; + /* Check for overflow. */ + if (bytes > SIZE_MAX - alignment - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + 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); @@ -3046,6 +3056,13 @@ __libc_valloc(size_t bytes) size_t pagesz = GLRO(dl_pagesize); + /* Check for overflow. */ + if (bytes > SIZE_MAX - pagesz - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + void *(*hook) (size_t, size_t, const void *) = force_reg (__memalign_hook); if (__builtin_expect (hook != NULL, 0)) @@ -3056,6 +3073,7 @@ __libc_valloc(size_t bytes) return 0; p = _int_valloc(ar_ptr, bytes); if(!p) { + LIBC_PROBE (memory_valloc_retry, 1, bytes); ar_ptr = arena_get_retry (ar_ptr, bytes); if (__builtin_expect(ar_ptr != NULL, 1)) { p = _int_memalign(ar_ptr, pagesz, bytes); @@ -3082,6 +3100,13 @@ __libc_pvalloc(size_t bytes) size_t page_mask = GLRO(dl_pagesize) - 1; size_t rounded_bytes = (bytes + page_mask) & ~(page_mask); + /* Check for overflow. */ + if (bytes > SIZE_MAX - 2*pagesz - MINSIZE) + { + __set_errno (ENOMEM); + return 0; + } + void *(*hook) (size_t, size_t, const void *) = force_reg (__memalign_hook); if (__builtin_expect (hook != NULL, 0)) @@ -3090,6 +3115,7 @@ __libc_pvalloc(size_t bytes) arena_get(ar_ptr, bytes + 2*pagesz + MINSIZE); p = _int_pvalloc(ar_ptr, bytes); if(!p) { + LIBC_PROBE (memory_pvalloc_retry, 1, bytes); 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); @@ -3166,6 +3192,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); @@ -4674,21 +4701,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,33 +4734,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 } diff --git a/libc/malloc/tst-memalign.c b/libc/malloc/tst-memalign.c new file mode 100644 index 000000000..1c5975248 --- /dev/null +++ b/libc/malloc/tst-memalign.c @@ -0,0 +1,99 @@ +/* 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); + + /* 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/libc/malloc/tst-posix_memalign.c b/libc/malloc/tst-posix_memalign.c new file mode 100644 index 000000000..27c0dd2bd --- /dev/null +++ b/libc/malloc/tst-posix_memalign.c @@ -0,0 +1,108 @@ +/* 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; + + /* 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/libc/malloc/tst-pvalloc.c b/libc/malloc/tst-pvalloc.c new file mode 100644 index 000000000..1c8129492 --- /dev/null +++ b/libc/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/libc/malloc/tst-realloc.c b/libc/malloc/tst-realloc.c new file mode 100644 index 000000000..9d290d24c --- /dev/null +++ b/libc/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/libc/malloc/tst-valloc.c b/libc/malloc/tst-valloc.c index 643a0dda4..4fd0dbb96 100644 --- a/libc/malloc/tst-valloc.c +++ b/libc/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" |