diff options
Diffstat (limited to 'lib/libc/stdlib/malloc.c')
-rw-r--r-- | lib/libc/stdlib/malloc.c | 719 |
1 files changed, 357 insertions, 362 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 40a2805..0bfa17b 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -929,30 +929,24 @@ static void *arena_malloc_large(arena_t *arena, size_t size, bool zero); static void *arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size); static size_t arena_salloc(const void *ptr); -static void arena_ralloc_resize_shrink(arena_t *arena, arena_chunk_t *chunk, - void *ptr, size_t size, size_t oldsize); -static bool arena_ralloc_resize_grow(arena_t *arena, arena_chunk_t *chunk, - void *ptr, size_t size, size_t oldsize); -static bool arena_ralloc_resize(void *ptr, size_t size, size_t oldsize); -static void *arena_ralloc(void *ptr, size_t size, size_t oldsize); #ifdef MALLOC_LAZY_FREE static void arena_dalloc_lazy_hard(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t pageind, arena_chunk_map_t *mapelm); #endif static void arena_dalloc_large(arena_t *arena, arena_chunk_t *chunk, void *ptr); +static void arena_ralloc_resize_shrink(arena_t *arena, arena_chunk_t *chunk, + void *ptr, size_t size, size_t oldsize); +static bool arena_ralloc_resize_grow(arena_t *arena, arena_chunk_t *chunk, + void *ptr, size_t size, size_t oldsize); +static bool arena_ralloc_resize(void *ptr, size_t size, size_t oldsize); +static void *arena_ralloc(void *ptr, size_t size, size_t oldsize); static bool arena_new(arena_t *arena); static arena_t *arenas_extend(unsigned ind); static void *huge_malloc(size_t size, bool zero); static void *huge_palloc(size_t alignment, size_t size); static void *huge_ralloc(void *ptr, size_t size, size_t oldsize); static void huge_dalloc(void *ptr); -static void *imalloc(size_t size); -static void *ipalloc(size_t alignment, size_t size); -static void *icalloc(size_t size); -static size_t isalloc(const void *ptr); -static void *iralloc(void *ptr, size_t size); -static void idalloc(void *ptr); static void malloc_print_stats(void); static bool malloc_init_hard(void); @@ -2312,6 +2306,7 @@ arena_run_split(arena_t *arena, arena_run_t *run, size_t size, bool small, == 0) { memset((void *)((uintptr_t)chunk + ((run_ind + i) << pagesize_2pow)), 0, pagesize); + /* CHUNK_MAP_UNTOUCHED is cleared below. */ } } @@ -2379,6 +2374,8 @@ arena_chunk_alloc(arena_t *arena) * Initialize the map to contain one maximal free untouched * run. */ + memset(chunk->map, (CHUNK_MAP_LARGE | CHUNK_MAP_POS_MASK), + arena_chunk_header_npages); memset(&chunk->map[arena_chunk_header_npages], CHUNK_MAP_UNTOUCHED, (chunk_npages - arena_chunk_header_npages)); @@ -2498,7 +2495,8 @@ arena_purge(arena_t *arena) if (chunk->map[i] & CHUNK_MAP_DIRTY) { size_t npages; - chunk->map[i] = 0; + chunk->map[i] = (CHUNK_MAP_LARGE | + CHUNK_MAP_POS_MASK); chunk->ndirty--; arena->ndirty--; /* Find adjacent dirty run(s). */ @@ -2507,7 +2505,8 @@ arena_purge(arena_t *arena) (chunk->map[i - 1] & CHUNK_MAP_DIRTY); npages++) { i--; - chunk->map[i] = 0; + chunk->map[i] = (CHUNK_MAP_LARGE + | CHUNK_MAP_POS_MASK); chunk->ndirty--; arena->ndirty--; } @@ -2556,7 +2555,9 @@ arena_run_dalloc(arena_t *arena, arena_run_t *run, bool dirty) size_t i; for (i = 0; i < run_pages; i++) { - chunk->map[run_ind + i] = CHUNK_MAP_DIRTY; + assert((chunk->map[run_ind + i] & CHUNK_MAP_DIRTY) == + 0); + chunk->map[run_ind + i] |= CHUNK_MAP_DIRTY; chunk->ndirty++; arena->ndirty++; } @@ -3005,6 +3006,28 @@ arena_malloc(arena_t *arena, size_t size, bool zero) return (arena_malloc_large(arena, size, zero)); } +static inline void * +imalloc(size_t size) +{ + + assert(size != 0); + + if (size <= arena_maxclass) + return (arena_malloc(choose_arena(), size, false)); + else + return (huge_malloc(size, false)); +} + +static inline void * +icalloc(size_t size) +{ + + if (size <= arena_maxclass) + return (arena_malloc(choose_arena(), size, true)); + else + return (huge_malloc(size, true)); +} + /* Only handles large allocations that require more than page alignment. */ static void * arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size) @@ -3084,6 +3107,101 @@ arena_palloc(arena_t *arena, size_t alignment, size_t size, size_t alloc_size) return (ret); } +static inline void * +ipalloc(size_t alignment, size_t size) +{ + void *ret; + size_t ceil_size; + + /* + * Round size up to the nearest multiple of alignment. + * + * This done, we can take advantage of the fact that for each small + * size class, every object is aligned at the smallest power of two + * that is non-zero in the base two representation of the size. For + * example: + * + * Size | Base 2 | Minimum alignment + * -----+----------+------------------ + * 96 | 1100000 | 32 + * 144 | 10100000 | 32 + * 192 | 11000000 | 64 + * + * Depending on runtime settings, it is possible that arena_malloc() + * will further round up to a power of two, but that never causes + * correctness issues. + */ + ceil_size = (size + (alignment - 1)) & (-alignment); + /* + * (ceil_size < size) protects against the combination of maximal + * alignment and size greater than maximal alignment. + */ + if (ceil_size < size) { + /* size_t overflow. */ + return (NULL); + } + + if (ceil_size <= pagesize || (alignment <= pagesize + && ceil_size <= arena_maxclass)) + ret = arena_malloc(choose_arena(), ceil_size, false); + else { + size_t run_size; + + /* + * We can't achieve sub-page alignment, so round up alignment + * permanently; it makes later calculations simpler. + */ + alignment = PAGE_CEILING(alignment); + ceil_size = PAGE_CEILING(size); + /* + * (ceil_size < size) protects against very large sizes within + * pagesize of SIZE_T_MAX. + * + * (ceil_size + alignment < ceil_size) protects against the + * combination of maximal alignment and ceil_size large enough + * to cause overflow. This is similar to the first overflow + * check above, but it needs to be repeated due to the new + * ceil_size value, which may now be *equal* to maximal + * alignment, whereas before we only detected overflow if the + * original size was *greater* than maximal alignment. + */ + if (ceil_size < size || ceil_size + alignment < ceil_size) { + /* size_t overflow. */ + return (NULL); + } + + /* + * Calculate the size of the over-size run that arena_palloc() + * would need to allocate in order to guarantee the alignment. + */ + if (ceil_size >= alignment) + run_size = ceil_size + alignment - pagesize; + else { + /* + * It is possible that (alignment << 1) will cause + * overflow, but it doesn't matter because we also + * subtract pagesize, which in the case of overflow + * leaves us with a very large run_size. That causes + * the first conditional below to fail, which means + * that the bogus run_size value never gets used for + * anything important. + */ + run_size = (alignment << 1) - pagesize; + } + + if (run_size <= arena_maxclass) { + ret = arena_palloc(choose_arena(), alignment, ceil_size, + run_size); + } else if (alignment <= chunksize) + ret = huge_malloc(ceil_size, false); + else + ret = huge_palloc(alignment, ceil_size); + } + + assert(((uintptr_t)ret & (alignment - 1)) == 0); + return (ret); +} + /* Return the size of the allocation pointed to by ptr. */ static size_t arena_salloc(const void *ptr) @@ -3099,12 +3217,11 @@ arena_salloc(const void *ptr) chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow); mapelm = chunk->map[pageind]; - if (mapelm != CHUNK_MAP_LARGE) { + if ((mapelm & CHUNK_MAP_LARGE) == 0) { arena_run_t *run; /* Small allocation size is in the run header. */ - assert(mapelm <= CHUNK_MAP_POS_MASK); - pageind -= mapelm; + pageind -= (mapelm & CHUNK_MAP_POS_MASK); run = (arena_run_t *)((uintptr_t)chunk + (pageind << pagesize_2pow)); assert(run->magic == ARENA_RUN_MAGIC); @@ -3127,166 +3244,38 @@ arena_salloc(const void *ptr) return (ret); } -static void -arena_ralloc_resize_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, - size_t size, size_t oldsize) -{ - extent_node_t *node, key; - - assert(size < oldsize); - - /* - * Shrink the run, and make trailing pages available for other - * allocations. - */ - key.addr = (void *)((uintptr_t)ptr); -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else - malloc_spin_lock(&arena->lock); -#endif - node = RB_FIND(extent_tree_ad_s, &arena->runs_alloced_ad, &key); - assert(node != NULL); - arena_run_trim_tail(arena, chunk, node, (arena_run_t *)ptr, oldsize, - size, true); -#ifdef MALLOC_STATS - arena->stats.allocated_large -= oldsize - size; -#endif - malloc_spin_unlock(&arena->lock); -} - -static bool -arena_ralloc_resize_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, - size_t size, size_t oldsize) -{ - extent_node_t *nodeC, key; - - /* Try to extend the run. */ - assert(size > oldsize); - key.addr = (void *)((uintptr_t)ptr + oldsize); -#ifdef MALLOC_BALANCE - arena_lock_balance(arena); -#else - malloc_spin_lock(&arena->lock); -#endif - nodeC = RB_FIND(extent_tree_ad_s, &arena->runs_avail_ad, &key); - if (nodeC != NULL && oldsize + nodeC->size >= size) { - extent_node_t *nodeA, *nodeB; - - /* - * The next run is available and sufficiently large. Split the - * following run, then merge the first part with the existing - * allocation. This results in a bit more tree manipulation - * than absolutely necessary, but it substantially simplifies - * the code. - */ - arena_run_split(arena, (arena_run_t *)nodeC->addr, size - - oldsize, false, false); - - key.addr = ptr; - nodeA = RB_FIND(extent_tree_ad_s, &arena->runs_alloced_ad, - &key); - assert(nodeA != NULL); - - key.addr = (void *)((uintptr_t)ptr + oldsize); - nodeB = RB_FIND(extent_tree_ad_s, &arena->runs_alloced_ad, - &key); - assert(nodeB != NULL); - - nodeA->size += nodeB->size; - - RB_REMOVE(extent_tree_ad_s, &arena->runs_alloced_ad, nodeB); - arena_chunk_node_dealloc(chunk, nodeB); - -#ifdef MALLOC_STATS - arena->stats.allocated_large += size - oldsize; -#endif - malloc_spin_unlock(&arena->lock); - return (false); - } - malloc_spin_unlock(&arena->lock); - - return (true); -} - -/* - * Try to resize a large allocation, in order to avoid copying. This will - * always fail if growing an object, and the following run is already in use. - */ -static bool -arena_ralloc_resize(void *ptr, size_t size, size_t oldsize) +static inline size_t +isalloc(const void *ptr) { + size_t ret; arena_chunk_t *chunk; - arena_t *arena; + + assert(ptr != NULL); chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - arena = chunk->arena; - assert(arena->magic == ARENA_MAGIC); + if (chunk != ptr) { + /* Region. */ + assert(chunk->arena->magic == ARENA_MAGIC); - if (size < oldsize) { - arena_ralloc_resize_shrink(arena, chunk, ptr, size, oldsize); - return (false); + ret = arena_salloc(ptr); } else { - return (arena_ralloc_resize_grow(arena, chunk, ptr, size, - oldsize)); - } -} + extent_node_t *node, key; -static void * -arena_ralloc(void *ptr, size_t size, size_t oldsize) -{ - void *ret; + /* Chunk (huge allocation). */ - /* Try to avoid moving the allocation. */ - if (size < small_min) { - if (oldsize < small_min && - ffs((int)(pow2_ceil(size) >> (TINY_MIN_2POW + 1))) - == ffs((int)(pow2_ceil(oldsize) >> (TINY_MIN_2POW + 1)))) - goto IN_PLACE; /* Same size class. */ - } else if (size <= small_max) { - if (oldsize >= small_min && oldsize <= small_max && - (QUANTUM_CEILING(size) >> opt_quantum_2pow) - == (QUANTUM_CEILING(oldsize) >> opt_quantum_2pow)) - goto IN_PLACE; /* Same size class. */ - } else if (size <= bin_maxclass) { - if (oldsize > small_max && oldsize <= bin_maxclass && - pow2_ceil(size) == pow2_ceil(oldsize)) - goto IN_PLACE; /* Same size class. */ - } else if (oldsize > bin_maxclass && oldsize <= arena_maxclass) { - size_t psize; + malloc_mutex_lock(&huge_mtx); - assert(size > bin_maxclass); - psize = PAGE_CEILING(size); + /* Extract from tree of huge allocations. */ + key.addr = __DECONST(void *, ptr); + node = RB_FIND(extent_tree_ad_s, &huge, &key); + assert(node != NULL); - if (psize == oldsize) - goto IN_PLACE; /* Same size class. */ + ret = node->size; - if (arena_ralloc_resize(ptr, psize, oldsize) == false) - goto IN_PLACE; + malloc_mutex_unlock(&huge_mtx); } - /* - * If we get here, then size and oldsize are different enough that we - * need to move the object. In that case, fall back to allocating new - * space and copying. - */ - ret = arena_malloc(choose_arena(), size, false); - if (ret == NULL) - return (NULL); - - /* Junk/zero-filling were already done by arena_malloc(). */ - if (size < oldsize) - memcpy(ret, ptr, size); - else - memcpy(ret, ptr, oldsize); - idalloc(ptr); return (ret); -IN_PLACE: - if (opt_junk && size < oldsize) - memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size); - else if (opt_zero && size > oldsize) - memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize); - return (ptr); } static inline void @@ -3297,8 +3286,7 @@ arena_dalloc_small(arena_t *arena, arena_chunk_t *chunk, void *ptr, arena_bin_t *bin; size_t size; - assert(mapelm <= CHUNK_MAP_POS_MASK); - pageind -= mapelm; + pageind -= (mapelm & CHUNK_MAP_POS_MASK); run = (arena_run_t *)((uintptr_t)chunk + (pageind << pagesize_2pow)); assert(run->magic == ARENA_RUN_MAGIC); @@ -3486,9 +3474,8 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr) pageind = (((uintptr_t)ptr - (uintptr_t)chunk) >> pagesize_2pow); mapelm = &chunk->map[pageind]; - if (*mapelm != CHUNK_MAP_LARGE) { + if ((*mapelm & CHUNK_MAP_LARGE) == 0) { /* Small allocation. */ - assert(*mapelm <= CHUNK_MAP_POS_MASK); #ifdef MALLOC_LAZY_FREE arena_dalloc_lazy(arena, chunk, ptr, pageind, mapelm); #else @@ -3502,6 +3489,197 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr) } } +static inline void +idalloc(void *ptr) +{ + arena_chunk_t *chunk; + + assert(ptr != NULL); + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + if (chunk != ptr) + arena_dalloc(chunk->arena, chunk, ptr); + else + huge_dalloc(ptr); +} + +static void +arena_ralloc_resize_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, + size_t size, size_t oldsize) +{ + extent_node_t *node, key; + + assert(size < oldsize); + + /* + * Shrink the run, and make trailing pages available for other + * allocations. + */ + key.addr = (void *)((uintptr_t)ptr); +#ifdef MALLOC_BALANCE + arena_lock_balance(arena); +#else + malloc_spin_lock(&arena->lock); +#endif + node = RB_FIND(extent_tree_ad_s, &arena->runs_alloced_ad, &key); + assert(node != NULL); + arena_run_trim_tail(arena, chunk, node, (arena_run_t *)ptr, oldsize, + size, true); +#ifdef MALLOC_STATS + arena->stats.allocated_large -= oldsize - size; +#endif + malloc_spin_unlock(&arena->lock); +} + +static bool +arena_ralloc_resize_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, + size_t size, size_t oldsize) +{ + extent_node_t *nodeC, key; + + /* Try to extend the run. */ + assert(size > oldsize); + key.addr = (void *)((uintptr_t)ptr + oldsize); +#ifdef MALLOC_BALANCE + arena_lock_balance(arena); +#else + malloc_spin_lock(&arena->lock); +#endif + nodeC = RB_FIND(extent_tree_ad_s, &arena->runs_avail_ad, &key); + if (nodeC != NULL && oldsize + nodeC->size >= size) { + extent_node_t *nodeA, *nodeB; + + /* + * The next run is available and sufficiently large. Split the + * following run, then merge the first part with the existing + * allocation. This results in a bit more tree manipulation + * than absolutely necessary, but it substantially simplifies + * the code. + */ + arena_run_split(arena, (arena_run_t *)nodeC->addr, size - + oldsize, false, false); + + key.addr = ptr; + nodeA = RB_FIND(extent_tree_ad_s, &arena->runs_alloced_ad, + &key); + assert(nodeA != NULL); + + key.addr = (void *)((uintptr_t)ptr + oldsize); + nodeB = RB_FIND(extent_tree_ad_s, &arena->runs_alloced_ad, + &key); + assert(nodeB != NULL); + + nodeA->size += nodeB->size; + + RB_REMOVE(extent_tree_ad_s, &arena->runs_alloced_ad, nodeB); + arena_chunk_node_dealloc(chunk, nodeB); + +#ifdef MALLOC_STATS + arena->stats.allocated_large += size - oldsize; +#endif + malloc_spin_unlock(&arena->lock); + return (false); + } + malloc_spin_unlock(&arena->lock); + + return (true); +} + +/* + * Try to resize a large allocation, in order to avoid copying. This will + * always fail if growing an object, and the following run is already in use. + */ +static bool +arena_ralloc_resize(void *ptr, size_t size, size_t oldsize) +{ + arena_chunk_t *chunk; + arena_t *arena; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + arena = chunk->arena; + assert(arena->magic == ARENA_MAGIC); + + if (size < oldsize) { + arena_ralloc_resize_shrink(arena, chunk, ptr, size, oldsize); + return (false); + } else { + return (arena_ralloc_resize_grow(arena, chunk, ptr, size, + oldsize)); + } +} + +static void * +arena_ralloc(void *ptr, size_t size, size_t oldsize) +{ + void *ret; + size_t copysize; + + /* Try to avoid moving the allocation. */ + if (size < small_min) { + if (oldsize < small_min && + ffs((int)(pow2_ceil(size) >> (TINY_MIN_2POW + 1))) + == ffs((int)(pow2_ceil(oldsize) >> (TINY_MIN_2POW + 1)))) + goto IN_PLACE; /* Same size class. */ + } else if (size <= small_max) { + if (oldsize >= small_min && oldsize <= small_max && + (QUANTUM_CEILING(size) >> opt_quantum_2pow) + == (QUANTUM_CEILING(oldsize) >> opt_quantum_2pow)) + goto IN_PLACE; /* Same size class. */ + } else if (size <= bin_maxclass) { + if (oldsize > small_max && oldsize <= bin_maxclass && + pow2_ceil(size) == pow2_ceil(oldsize)) + goto IN_PLACE; /* Same size class. */ + } else if (oldsize > bin_maxclass && oldsize <= arena_maxclass) { + size_t psize; + + assert(size > bin_maxclass); + psize = PAGE_CEILING(size); + + if (psize == oldsize) + goto IN_PLACE; /* Same size class. */ + + if (arena_ralloc_resize(ptr, psize, oldsize) == false) + goto IN_PLACE; + } + + /* + * If we get here, then size and oldsize are different enough that we + * need to move the object. In that case, fall back to allocating new + * space and copying. + */ + ret = arena_malloc(choose_arena(), size, false); + if (ret == NULL) + return (NULL); + + /* Junk/zero-filling were already done by arena_malloc(). */ + copysize = (size < oldsize) ? size : oldsize; + memcpy(ret, ptr, copysize); + idalloc(ptr); + return (ret); +IN_PLACE: + if (opt_junk && size < oldsize) + memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - size); + else if (opt_zero && size > oldsize) + memset((void *)((uintptr_t)ptr + oldsize), 0, size - oldsize); + return (ptr); +} + +static inline void * +iralloc(void *ptr, size_t size) +{ + size_t oldsize; + + assert(ptr != NULL); + assert(size != 0); + + oldsize = isalloc(ptr); + + if (size <= arena_maxclass) + return (arena_ralloc(ptr, size, oldsize)); + else + return (huge_ralloc(ptr, size, oldsize)); +} + static bool arena_new(arena_t *arena) { @@ -3531,12 +3709,10 @@ arena_new(arena_t *arena) #endif #ifdef MALLOC_LAZY_FREE if (opt_lazy_free_2pow >= 0) { - arena->free_cache = (void **) base_alloc(sizeof(void *) + arena->free_cache = (void **) base_calloc(1, sizeof(void *) * (1U << opt_lazy_free_2pow)); if (arena->free_cache == NULL) return (true); - memset(arena->free_cache, 0, sizeof(void *) - * (1U << opt_lazy_free_2pow)); } else arena->free_cache = NULL; #endif @@ -3766,6 +3942,7 @@ static void * huge_ralloc(void *ptr, size_t size, size_t oldsize) { void *ret; + size_t copysize; /* Avoid moving the allocation if the size class would not change. */ if (oldsize > arena_maxclass && @@ -3789,10 +3966,8 @@ huge_ralloc(void *ptr, size_t size, size_t oldsize) if (ret == NULL) return (NULL); - if (size < oldsize) - memcpy(ret, ptr, size); - else - memcpy(ret, ptr, oldsize); + copysize = (size < oldsize) ? size : oldsize; + memcpy(ret, ptr, copysize); idalloc(ptr); return (ret); } @@ -3828,187 +4003,6 @@ huge_dalloc(void *ptr) base_node_dealloc(node); } -static void * -imalloc(size_t size) -{ - - assert(size != 0); - - if (size <= arena_maxclass) - return (arena_malloc(choose_arena(), size, false)); - else - return (huge_malloc(size, false)); -} - -static void * -ipalloc(size_t alignment, size_t size) -{ - void *ret; - size_t ceil_size; - - /* - * Round size up to the nearest multiple of alignment. - * - * This done, we can take advantage of the fact that for each small - * size class, every object is aligned at the smallest power of two - * that is non-zero in the base two representation of the size. For - * example: - * - * Size | Base 2 | Minimum alignment - * -----+----------+------------------ - * 96 | 1100000 | 32 - * 144 | 10100000 | 32 - * 192 | 11000000 | 64 - * - * Depending on runtime settings, it is possible that arena_malloc() - * will further round up to a power of two, but that never causes - * correctness issues. - */ - ceil_size = (size + (alignment - 1)) & (-alignment); - /* - * (ceil_size < size) protects against the combination of maximal - * alignment and size greater than maximal alignment. - */ - if (ceil_size < size) { - /* size_t overflow. */ - return (NULL); - } - - if (ceil_size <= pagesize || (alignment <= pagesize - && ceil_size <= arena_maxclass)) - ret = arena_malloc(choose_arena(), ceil_size, false); - else { - size_t run_size; - - /* - * We can't achieve sub-page alignment, so round up alignment - * permanently; it makes later calculations simpler. - */ - alignment = PAGE_CEILING(alignment); - ceil_size = PAGE_CEILING(size); - /* - * (ceil_size < size) protects against very large sizes within - * pagesize of SIZE_T_MAX. - * - * (ceil_size + alignment < ceil_size) protects against the - * combination of maximal alignment and ceil_size large enough - * to cause overflow. This is similar to the first overflow - * check above, but it needs to be repeated due to the new - * ceil_size value, which may now be *equal* to maximal - * alignment, whereas before we only detected overflow if the - * original size was *greater* than maximal alignment. - */ - if (ceil_size < size || ceil_size + alignment < ceil_size) { - /* size_t overflow. */ - return (NULL); - } - - /* - * Calculate the size of the over-size run that arena_palloc() - * would need to allocate in order to guarantee the alignment. - */ - if (ceil_size >= alignment) - run_size = ceil_size + alignment - pagesize; - else { - /* - * It is possible that (alignment << 1) will cause - * overflow, but it doesn't matter because we also - * subtract pagesize, which in the case of overflow - * leaves us with a very large run_size. That causes - * the first conditional below to fail, which means - * that the bogus run_size value never gets used for - * anything important. - */ - run_size = (alignment << 1) - pagesize; - } - - if (run_size <= arena_maxclass) { - ret = arena_palloc(choose_arena(), alignment, ceil_size, - run_size); - } else if (alignment <= chunksize) - ret = huge_malloc(ceil_size, false); - else - ret = huge_palloc(alignment, ceil_size); - } - - assert(((uintptr_t)ret & (alignment - 1)) == 0); - return (ret); -} - -static void * -icalloc(size_t size) -{ - - if (size <= arena_maxclass) - return (arena_malloc(choose_arena(), size, true)); - else - return (huge_malloc(size, true)); -} - -static size_t -isalloc(const void *ptr) -{ - size_t ret; - arena_chunk_t *chunk; - - assert(ptr != NULL); - - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk != ptr) { - /* Region. */ - assert(chunk->arena->magic == ARENA_MAGIC); - - ret = arena_salloc(ptr); - } else { - extent_node_t *node, key; - - /* Chunk (huge allocation). */ - - malloc_mutex_lock(&huge_mtx); - - /* Extract from tree of huge allocations. */ - key.addr = __DECONST(void *, ptr); - node = RB_FIND(extent_tree_ad_s, &huge, &key); - assert(node != NULL); - - ret = node->size; - - malloc_mutex_unlock(&huge_mtx); - } - - return (ret); -} - -static void * -iralloc(void *ptr, size_t size) -{ - size_t oldsize; - - assert(ptr != NULL); - assert(size != 0); - - oldsize = isalloc(ptr); - - if (size <= arena_maxclass) - return (arena_ralloc(ptr, size, oldsize)); - else - return (huge_ralloc(ptr, size, oldsize)); -} - -static void -idalloc(void *ptr) -{ - arena_chunk_t *chunk; - - assert(ptr != NULL); - - chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); - if (chunk != ptr) - arena_dalloc(chunk->arena, chunk, ptr); - else - huge_dalloc(ptr); -} - static void malloc_print_stats(void) { @@ -4250,10 +4244,11 @@ malloc_init_hard(void) break; case 2: if (_malloc_options != NULL) { - /* - * Use options that were compiled into the program. - */ - opts = _malloc_options; + /* + * Use options that were compiled into the + * program. + */ + opts = _malloc_options; } else { /* No configuration specified. */ buf[0] = '\0'; @@ -4279,10 +4274,10 @@ malloc_init_hard(void) nreps += opts[j] - '0'; break; default: - goto OUT; + goto MALLOC_OUT; } } -OUT: +MALLOC_OUT: if (nseen == false) nreps = 1; |