diff options
Diffstat (limited to 'malloc')
-rw-r--r-- | malloc/malloc.c | 115 |
1 files changed, 109 insertions, 6 deletions
diff --git a/malloc/malloc.c b/malloc/malloc.c index 74ad92dbd0..9a45707ee7 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -3141,8 +3141,13 @@ __libc_pvalloc (size_t bytes) void * __libc_calloc (size_t n, size_t elem_size) { - INTERNAL_SIZE_T bytes; + mstate av; + mchunkptr oldtop, p; + INTERNAL_SIZE_T bytes, sz, csz, oldtopsize; void *mem; + unsigned long clearsize; + unsigned long nclears; + INTERNAL_SIZE_T *d; /* size_t is unsigned so the behavior on overflow is defined. */ bytes = n * elem_size; @@ -3161,15 +3166,113 @@ __libc_calloc (size_t n, size_t elem_size) atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) { - mem = (*hook)(bytes, RETURN_ADDRESS (0)); + sz = bytes; + mem = (*hook)(sz, RETURN_ADDRESS (0)); + if (mem == 0) + return 0; + + return memset (mem, 0, sz); } - else - mem = __libc_malloc (bytes); - if (mem == 0) + sz = bytes; + + arena_get (av, sz); + if (!av) return 0; - return memset (mem, 0, bytes); + /* Check if we hand out the top chunk, in which case there may be no + need to clear. */ +#if MORECORE_CLEARS + oldtop = top (av); + oldtopsize = chunksize (top (av)); +# if MORECORE_CLEARS < 2 + /* Only newly allocated memory is guaranteed to be cleared. */ + if (av == &main_arena && + oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *) oldtop) + oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *) oldtop); +# endif + if (av != &main_arena) + { + heap_info *heap = heap_for_ptr (oldtop); + if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop) + oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop; + } +#endif + mem = _int_malloc (av, sz); + + + assert (!mem || chunk_is_mmapped (mem2chunk (mem)) || + 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); + (void) mutex_unlock (&av->mutex); + } + if (mem == 0) + return 0; + } + else + (void) mutex_unlock (&av->mutex); + p = mem2chunk (mem); + + /* Two optional cases in which clearing not necessary */ + if (chunk_is_mmapped (p)) + { + if (__builtin_expect (perturb_byte, 0)) + return memset (mem, 0, sz); + + return mem; + } + + csz = chunksize (p); + +#if MORECORE_CLEARS + if (perturb_byte == 0 && (p == oldtop && csz > oldtopsize)) + { + /* clear only the bytes from non-freshly-sbrked memory */ + csz = oldtopsize; + } +#endif + + /* Unroll clear of <= 36 bytes (72 if 8byte sizes). We know that + contents have an odd number of INTERNAL_SIZE_T-sized words; + minimally 3. */ + d = (INTERNAL_SIZE_T *) mem; + clearsize = csz - SIZE_SZ; + nclears = clearsize / sizeof (INTERNAL_SIZE_T); + assert (nclears >= 3); + + if (nclears > 9) + return memset (d, 0, clearsize); + + else + { + *(d + 0) = 0; + *(d + 1) = 0; + *(d + 2) = 0; + if (nclears > 4) + { + *(d + 3) = 0; + *(d + 4) = 0; + if (nclears > 6) + { + *(d + 5) = 0; + *(d + 6) = 0; + if (nclears > 8) + { + *(d + 7) = 0; + *(d + 8) = 0; + } + } + } + } + + return mem; } /* |