diff options
Diffstat (limited to 'malloc')
-rw-r--r-- | malloc/Makefile | 7 | ||||
-rw-r--r-- | malloc/arena.c | 85 | ||||
-rw-r--r-- | malloc/hooks.c | 32 | ||||
-rw-r--r-- | malloc/malloc.c | 416 | ||||
-rw-r--r-- | malloc/obstack.h | 2 | ||||
-rw-r--r-- | malloc/tst-memalign.c | 114 | ||||
-rw-r--r-- | malloc/tst-posix_memalign.c | 118 | ||||
-rw-r--r-- | malloc/tst-pvalloc.c | 99 | ||||
-rw-r--r-- | malloc/tst-realloc.c | 146 | ||||
-rw-r--r-- | malloc/tst-valloc.c | 108 |
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" |