Fix error detection for ipalloc() when profiling.

sa2u() returns 0 on overflow, but the profiling code was blindly calling
sa2u() and allowing the error to silently propagate, ultimately ending
in a later assertion failure.  Refactor all ipalloc() callers to call
sa2u(), check for overflow before calling ipalloc(), and pass usize
rather than size.  This allows ipalloc() to avoid calling sa2u() in the
common case.
This commit is contained in:
Jason Evans 2011-03-23 00:37:29 -07:00
parent eacb896c01
commit 38d9210c46
4 changed files with 105 additions and 62 deletions

View File

@ -589,7 +589,7 @@ thread_allocated_get(void)
#ifndef JEMALLOC_ENABLE_INLINE #ifndef JEMALLOC_ENABLE_INLINE
void *imalloc(size_t size); void *imalloc(size_t size);
void *icalloc(size_t size); void *icalloc(size_t size);
void *ipalloc(size_t size, size_t alignment, bool zero); void *ipalloc(size_t usize, size_t alignment, bool zero);
size_t isalloc(const void *ptr); size_t isalloc(const void *ptr);
# ifdef JEMALLOC_IVSALLOC # ifdef JEMALLOC_IVSALLOC
size_t ivsalloc(const void *ptr); size_t ivsalloc(const void *ptr);
@ -623,28 +623,39 @@ icalloc(size_t size)
} }
JEMALLOC_INLINE void * JEMALLOC_INLINE void *
ipalloc(size_t size, size_t alignment, bool zero) ipalloc(size_t usize, size_t alignment, bool zero)
{ {
void *ret; void *ret;
size_t usize;
size_t run_size
# ifdef JEMALLOC_CC_SILENCE
= 0
# endif
;
usize = sa2u(size, alignment, &run_size); assert(usize != 0);
if (usize == 0) assert(usize == sa2u(usize, alignment, NULL));
return (NULL);
if (usize <= arena_maxclass && alignment <= PAGE_SIZE) if (usize <= arena_maxclass && alignment <= PAGE_SIZE)
ret = arena_malloc(usize, zero); ret = arena_malloc(usize, zero);
else if (run_size <= arena_maxclass) { else {
ret = arena_palloc(choose_arena(), usize, run_size, alignment, size_t run_size
zero); #ifdef JEMALLOC_CC_SILENCE
} else if (alignment <= chunksize) = 0
ret = huge_malloc(usize, zero); #endif
else ;
ret = huge_palloc(usize, alignment, zero);
/*
* Ideally we would only ever call sa2u() once per aligned
* allocation request, and the caller of this function has
* already done so once. However, it's rather burdensome to
* require every caller to pass in run_size, especially given
* that it's only relevant to large allocations. Therefore,
* just call it again here in order to get run_size.
*/
sa2u(usize, alignment, &run_size);
if (run_size <= arena_maxclass) {
ret = arena_palloc(choose_arena(), usize, run_size,
alignment, zero);
} else if (alignment <= chunksize)
ret = huge_malloc(usize, zero);
else
ret = huge_palloc(usize, alignment, zero);
}
assert(((uintptr_t)ret & (alignment - 1)) == 0); assert(((uintptr_t)ret & (alignment - 1)) == 0);
return (ret); return (ret);
@ -715,7 +726,7 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1)) if (alignment != 0 && ((uintptr_t)ptr & ((uintptr_t)alignment-1))
!= 0) { != 0) {
size_t copysize; size_t usize, copysize;
/* /*
* Existing object alignment is inadquate; allocate new space * Existing object alignment is inadquate; allocate new space
@ -723,12 +734,18 @@ iralloc(void *ptr, size_t size, size_t extra, size_t alignment, bool zero,
*/ */
if (no_move) if (no_move)
return (NULL); return (NULL);
ret = ipalloc(size + extra, alignment, zero); usize = sa2u(size + extra, alignment, NULL);
if (usize == 0)
return (NULL);
ret = ipalloc(usize, alignment, zero);
if (ret == NULL) { if (ret == NULL) {
if (extra == 0) if (extra == 0)
return (NULL); return (NULL);
/* Try again, without extra this time. */ /* Try again, without extra this time. */
ret = ipalloc(size, alignment, zero); usize = sa2u(size, alignment, NULL);
if (usize == 0)
return (NULL);
ret = ipalloc(usize, alignment, zero);
if (ret == NULL) if (ret == NULL)
return (NULL); return (NULL);
} }

View File

@ -2165,24 +2165,29 @@ arena_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
if (ret != NULL) if (ret != NULL)
return (ret); return (ret);
/* /*
* size and oldsize are different enough that we need to move the * size and oldsize are different enough that we need to move the
* object. In that case, fall back to allocating new space and * object. In that case, fall back to allocating new space and
* copying. * copying.
*/ */
if (alignment != 0) if (alignment != 0) {
ret = ipalloc(size + extra, alignment, zero); size_t usize = sa2u(size + extra, alignment, NULL);
else if (usize == 0)
return (NULL);
ret = ipalloc(usize, alignment, zero);
} else
ret = arena_malloc(size + extra, zero); ret = arena_malloc(size + extra, zero);
if (ret == NULL) { if (ret == NULL) {
if (extra == 0) if (extra == 0)
return (NULL); return (NULL);
/* Try again, this time without extra. */ /* Try again, this time without extra. */
if (alignment != 0) if (alignment != 0) {
ret = ipalloc(size, alignment, zero); size_t usize = sa2u(size, alignment, NULL);
else if (usize == 0)
return (NULL);
ret = ipalloc(usize, alignment, zero);
} else
ret = arena_malloc(size, zero); ret = arena_malloc(size, zero);
if (ret == NULL) if (ret == NULL)

View File

@ -262,9 +262,15 @@ ckh_grow(ckh_t *ckh)
lg_prevbuckets = ckh->lg_curbuckets; lg_prevbuckets = ckh->lg_curbuckets;
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS; lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS;
while (true) { while (true) {
size_t usize;
lg_curcells++; lg_curcells++;
tab = (ckhc_t *)ipalloc(sizeof(ckhc_t) << lg_curcells, usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE, NULL);
ZU(1) << LG_CACHELINE, true); if (usize == 0) {
ret = true;
goto RETURN;
}
tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
if (tab == NULL) { if (tab == NULL) {
ret = true; ret = true;
goto RETURN; goto RETURN;
@ -295,7 +301,7 @@ static void
ckh_shrink(ckh_t *ckh) ckh_shrink(ckh_t *ckh)
{ {
ckhc_t *tab, *ttab; ckhc_t *tab, *ttab;
size_t lg_curcells; size_t lg_curcells, usize;
unsigned lg_prevbuckets; unsigned lg_prevbuckets;
/* /*
@ -304,8 +310,10 @@ ckh_shrink(ckh_t *ckh)
*/ */
lg_prevbuckets = ckh->lg_curbuckets; lg_prevbuckets = ckh->lg_curbuckets;
lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1; lg_curcells = ckh->lg_curbuckets + LG_CKH_BUCKET_CELLS - 1;
tab = (ckhc_t *)ipalloc(sizeof(ckhc_t) << lg_curcells, usize = sa2u(sizeof(ckhc_t) << lg_curcells, CACHELINE, NULL);
ZU(1) << LG_CACHELINE, true); if (usize == 0)
return;
tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
if (tab == NULL) { if (tab == NULL) {
/* /*
* An OOM error isn't worth propagating, since it doesn't * An OOM error isn't worth propagating, since it doesn't
@ -340,7 +348,7 @@ bool
ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp) ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp)
{ {
bool ret; bool ret;
size_t mincells; size_t mincells, usize;
unsigned lg_mincells; unsigned lg_mincells;
assert(minitems > 0); assert(minitems > 0);
@ -375,8 +383,12 @@ ckh_new(ckh_t *ckh, size_t minitems, ckh_hash_t *hash, ckh_keycomp_t *keycomp)
ckh->hash = hash; ckh->hash = hash;
ckh->keycomp = keycomp; ckh->keycomp = keycomp;
ckh->tab = (ckhc_t *)ipalloc(sizeof(ckhc_t) << lg_mincells, usize = sa2u(sizeof(ckhc_t) << lg_mincells, CACHELINE, NULL);
(ZU(1) << LG_CACHELINE), true); if (usize == 0) {
ret = true;
goto RETURN;
}
ckh->tab = (ckhc_t *)ipalloc(usize, CACHELINE, true);
if (ckh->tab == NULL) { if (ckh->tab == NULL) {
ret = true; ret = true;
goto RETURN; goto RETURN;

View File

@ -993,14 +993,12 @@ int
JEMALLOC_P(posix_memalign)(void **memptr, size_t alignment, size_t size) JEMALLOC_P(posix_memalign)(void **memptr, size_t alignment, size_t size)
{ {
int ret; int ret;
void *result;
#if (defined(JEMALLOC_PROF) || defined(JEMALLOC_STATS))
size_t usize size_t usize
# ifdef JEMALLOC_CC_SILENCE #ifdef JEMALLOC_CC_SILENCE
= 0 = 0
# endif
;
#endif #endif
;
void *result;
#ifdef JEMALLOC_PROF #ifdef JEMALLOC_PROF
prof_thr_cnt_t *cnt prof_thr_cnt_t *cnt
# ifdef JEMALLOC_CC_SILENCE # ifdef JEMALLOC_CC_SILENCE
@ -1050,34 +1048,37 @@ JEMALLOC_P(posix_memalign)(void **memptr, size_t alignment, size_t size)
goto RETURN; goto RETURN;
} }
usize = sa2u(size, alignment, NULL);
if (usize == 0) {
result = NULL;
ret = ENOMEM;
goto RETURN;
}
#ifdef JEMALLOC_PROF #ifdef JEMALLOC_PROF
if (opt_prof) { if (opt_prof) {
usize = sa2u(size, alignment, NULL);
if ((cnt = prof_alloc_prep(usize)) == NULL) { if ((cnt = prof_alloc_prep(usize)) == NULL) {
result = NULL; result = NULL;
ret = EINVAL; ret = EINVAL;
} else { } else {
if (prof_promote && (uintptr_t)cnt != if (prof_promote && (uintptr_t)cnt !=
(uintptr_t)1U && usize <= small_maxclass) { (uintptr_t)1U && usize <= small_maxclass) {
result = ipalloc(small_maxclass+1, assert(sa2u(small_maxclass+1,
alignment, false); alignment, NULL) != 0);
result = ipalloc(sa2u(small_maxclass+1,
alignment, NULL), alignment, false);
if (result != NULL) { if (result != NULL) {
arena_prof_promoted(result, arena_prof_promoted(result,
usize); usize);
} }
} else { } else {
result = ipalloc(size, alignment, result = ipalloc(usize, alignment,
false); false);
} }
} }
} else } else
#endif #endif
{ result = ipalloc(usize, alignment, false);
#ifdef JEMALLOC_STATS
usize = sa2u(size, alignment, NULL);
#endif
result = ipalloc(size, alignment, false);
}
} }
if (result == NULL) { if (result == NULL) {
@ -1531,15 +1532,18 @@ JEMALLOC_P(mallctlbymib)(const size_t *mib, size_t miblen, void *oldp,
} }
JEMALLOC_INLINE void * JEMALLOC_INLINE void *
iallocm(size_t size, size_t alignment, bool zero) iallocm(size_t usize, size_t alignment, bool zero)
{ {
assert(usize == ((alignment == 0) ? s2u(usize) : sa2u(usize, alignment,
NULL)));
if (alignment != 0) if (alignment != 0)
return (ipalloc(size, alignment, zero)); return (ipalloc(usize, alignment, zero));
else if (zero) else if (zero)
return (icalloc(size)); return (icalloc(usize));
else else
return (imalloc(size)); return (imalloc(usize));
} }
JEMALLOC_ATTR(nonnull(1)) JEMALLOC_ATTR(nonnull(1))
@ -1562,20 +1566,27 @@ JEMALLOC_P(allocm)(void **ptr, size_t *rsize, size_t size, int flags)
if (malloc_init()) if (malloc_init())
goto OOM; goto OOM;
usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment,
NULL);
if (usize == 0)
goto OOM;
#ifdef JEMALLOC_PROF #ifdef JEMALLOC_PROF
if (opt_prof) { if (opt_prof) {
usize = (alignment == 0) ? s2u(size) : sa2u(size, alignment,
NULL);
if ((cnt = prof_alloc_prep(usize)) == NULL) if ((cnt = prof_alloc_prep(usize)) == NULL)
goto OOM; goto OOM;
if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U && usize <= if (prof_promote && (uintptr_t)cnt != (uintptr_t)1U && usize <=
small_maxclass) { small_maxclass) {
p = iallocm(small_maxclass+1, alignment, zero); size_t usize_promoted = (alignment == 0) ?
s2u(small_maxclass+1) : sa2u(small_maxclass+1,
alignment, NULL);
assert(usize_promoted != 0);
p = iallocm(usize_promoted, alignment, zero);
if (p == NULL) if (p == NULL)
goto OOM; goto OOM;
arena_prof_promoted(p, usize); arena_prof_promoted(p, usize);
} else { } else {
p = iallocm(size, alignment, zero); p = iallocm(usize, alignment, zero);
if (p == NULL) if (p == NULL)
goto OOM; goto OOM;
} }
@ -1585,15 +1596,13 @@ JEMALLOC_P(allocm)(void **ptr, size_t *rsize, size_t size, int flags)
} else } else
#endif #endif
{ {
p = iallocm(size, alignment, zero); p = iallocm(usize, alignment, zero);
if (p == NULL) if (p == NULL)
goto OOM; goto OOM;
#ifndef JEMALLOC_STATS #ifndef JEMALLOC_STATS
if (rsize != NULL) if (rsize != NULL)
#endif #endif
{ {
usize = (alignment == 0) ? s2u(size) : sa2u(size,
alignment, NULL);
#ifdef JEMALLOC_STATS #ifdef JEMALLOC_STATS
if (rsize != NULL) if (rsize != NULL)
#endif #endif