9 Commits
1.0.1 ... 1.0.3

Author SHA1 Message Date
Jason Evans
e139ab8b4f Merge branch 'dev' 2010-08-12 12:11:58 -07:00
Jason Evans
dcd15098a8 Move assert() calls up in arena_run_reg_alloc().
Move assert() calls up in arena_run_reg_alloc(), so that a corrupt
pointer will likely be caught by an assertion *before* it is
dereferenced.
2010-08-05 12:13:42 -07:00
Jason Evans
2541e1b083 Add a missing mutex unlock in malloc_init_hard().
If multiple threads race to initialize malloc, the loser(s) busy-wait
until initialization is complete.  Add a missing mutex lock so that the
loser(s) properly release the initialization mutex.  Under some
race conditions, this flaw could have caused one or more threads to
become permanently blocked.

Reported by Terrell Magee.
2010-07-22 11:35:59 -07:00
Jason Evans
b43b7750a6 Fix the libunwind version of prof_backtrace().
Fix the libunwind version of prof_backtrace() to set the backtrace depth
for all possible code paths.  This fixes the zero-length backtrace
problem when using libunwind.
2010-06-04 15:10:43 -07:00
Jason Evans
e13243eb63 Merge branch 'dev' 2010-05-11 18:24:19 -07:00
Jason Evans
7013d10a9e Avoid unnecessary isalloc() calls.
When heap profiling is enabled but deactivated, there is no need to call
isalloc(ptr) in prof_{malloc,realloc}().  Avoid these calls, so that
profiling overhead under such conditions is negligible.
2010-05-11 18:17:02 -07:00
Jason Evans
ed3d152ea0 Fix next_arena initialization.
If there is more than one arena, initialize next_arena so that the
first and second threads to allocate memory use arenas 0 and 1, rather
than both using arena 0.
2010-05-11 12:00:22 -07:00
Jordan DeLong
2206e1acc1 Add MAP_NORESERVE support.
Add MAP_NORESERVE to the chunk_mmap() case being used by
chunk_swap_enable(), if the system supports it.
2010-05-11 11:46:53 -07:00
Jason Evans
ecea0f6125 Fix junk filling of cached large objects.
Use the size argument to tcache_dalloc_large() to control the number of
bytes set to 0x5a when junk filling is enabled, rather than accessing a
non-existent arena bin.  This bug was capable of corrupting an
arbitrarily large memory region, depending on what followed the arena
data structure in memory (typically zeroed memory, another arena_t, or a
red-black tree node for a huge object).
2010-04-28 12:00:59 -07:00
7 changed files with 58 additions and 34 deletions

View File

@@ -10,6 +10,7 @@
#ifdef JEMALLOC_H_EXTERNS #ifdef JEMALLOC_H_EXTERNS
void *chunk_alloc_mmap(size_t size); void *chunk_alloc_mmap(size_t size);
void *chunk_alloc_mmap_noreserve(size_t size);
void chunk_dealloc_mmap(void *chunk, size_t size); void chunk_dealloc_mmap(void *chunk, size_t size);
#endif /* JEMALLOC_H_EXTERNS */ #endif /* JEMALLOC_H_EXTERNS */

View File

@@ -353,7 +353,7 @@ tcache_dalloc_large(tcache_t *tcache, void *ptr, size_t size)
#ifdef JEMALLOC_FILL #ifdef JEMALLOC_FILL
if (opt_junk) if (opt_junk)
memset(ptr, 0x5a, arena->bins[binind].reg_size); memset(ptr, 0x5a, size);
#endif #endif
tbin = &tcache->tbins[binind]; tbin = &tcache->tbins[binind];

View File

@@ -254,7 +254,6 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
run->nfree--; run->nfree--;
ret = run->avail; ret = run->avail;
if (ret != NULL) { if (ret != NULL) {
run->avail = *(void **)ret;
/* Double free can cause assertion failure.*/ /* Double free can cause assertion failure.*/
assert(ret != NULL); assert(ret != NULL);
/* Write-after free can cause assertion failure. */ /* Write-after free can cause assertion failure. */
@@ -264,6 +263,7 @@ arena_run_reg_alloc(arena_run_t *run, arena_bin_t *bin)
assert(((uintptr_t)ret - ((uintptr_t)run + assert(((uintptr_t)ret - ((uintptr_t)run +
(uintptr_t)bin->reg0_offset)) % (uintptr_t)bin->reg_size == (uintptr_t)bin->reg0_offset)) % (uintptr_t)bin->reg_size ==
0); 0);
run->avail = *(void **)ret;
return (ret); return (ret);
} }
ret = run->next; ret = run->next;

View File

@@ -23,14 +23,15 @@ static
/******************************************************************************/ /******************************************************************************/
/* Function prototypes for non-inline static functions. */ /* Function prototypes for non-inline static functions. */
static void *pages_map(void *addr, size_t size); static void *pages_map(void *addr, size_t size, bool noreserve);
static void pages_unmap(void *addr, size_t size); static void pages_unmap(void *addr, size_t size);
static void *chunk_alloc_mmap_slow(size_t size, bool unaligned); static void *chunk_alloc_mmap_slow(size_t size, bool unaligned, bool noreserve);
static void *chunk_alloc_mmap_internal(size_t size, bool noreserve);
/******************************************************************************/ /******************************************************************************/
static void * static void *
pages_map(void *addr, size_t size) pages_map(void *addr, size_t size, bool noreserve)
{ {
void *ret; void *ret;
@@ -38,8 +39,12 @@ pages_map(void *addr, size_t size)
* We don't use MAP_FIXED here, because it can cause the *replacement* * We don't use MAP_FIXED here, because it can cause the *replacement*
* of existing mappings, and we only want to create new mappings. * of existing mappings, and we only want to create new mappings.
*/ */
ret = mmap(addr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, int flags = MAP_PRIVATE | MAP_ANON;
-1, 0); #ifdef MAP_NORESERVE
if (noreserve)
flags |= MAP_NORESERVE;
#endif
ret = mmap(addr, size, PROT_READ | PROT_WRITE, flags, -1, 0);
assert(ret != NULL); assert(ret != NULL);
if (ret == MAP_FAILED) if (ret == MAP_FAILED)
@@ -83,7 +88,7 @@ pages_unmap(void *addr, size_t size)
} }
static void * static void *
chunk_alloc_mmap_slow(size_t size, bool unaligned) chunk_alloc_mmap_slow(size_t size, bool unaligned, bool noreserve)
{ {
void *ret; void *ret;
size_t offset; size_t offset;
@@ -92,7 +97,7 @@ chunk_alloc_mmap_slow(size_t size, bool unaligned)
if (size + chunksize <= size) if (size + chunksize <= size)
return (NULL); return (NULL);
ret = pages_map(NULL, size + chunksize); ret = pages_map(NULL, size + chunksize, noreserve);
if (ret == NULL) if (ret == NULL)
return (NULL); return (NULL);
@@ -128,8 +133,8 @@ chunk_alloc_mmap_slow(size_t size, bool unaligned)
return (ret); return (ret);
} }
void * static void *
chunk_alloc_mmap(size_t size) chunk_alloc_mmap_internal(size_t size, bool noreserve)
{ {
void *ret; void *ret;
@@ -164,7 +169,7 @@ chunk_alloc_mmap(size_t size)
if (mmap_unaligned == false) { if (mmap_unaligned == false) {
size_t offset; size_t offset;
ret = pages_map(NULL, size); ret = pages_map(NULL, size, noreserve);
if (ret == NULL) if (ret == NULL)
return (NULL); return (NULL);
@@ -173,13 +178,13 @@ chunk_alloc_mmap(size_t size)
mmap_unaligned = true; mmap_unaligned = true;
/* Try to extend chunk boundary. */ /* Try to extend chunk boundary. */
if (pages_map((void *)((uintptr_t)ret + size), if (pages_map((void *)((uintptr_t)ret + size),
chunksize - offset) == NULL) { chunksize - offset, noreserve) == NULL) {
/* /*
* Extension failed. Clean up, then revert to * Extension failed. Clean up, then revert to
* the reliable-but-expensive method. * the reliable-but-expensive method.
*/ */
pages_unmap(ret, size); pages_unmap(ret, size);
ret = chunk_alloc_mmap_slow(size, true); ret = chunk_alloc_mmap_slow(size, true, noreserve);
} else { } else {
/* Clean up unneeded leading space. */ /* Clean up unneeded leading space. */
pages_unmap(ret, chunksize - offset); pages_unmap(ret, chunksize - offset);
@@ -188,11 +193,23 @@ chunk_alloc_mmap(size_t size)
} }
} }
} else } else
ret = chunk_alloc_mmap_slow(size, false); ret = chunk_alloc_mmap_slow(size, false, noreserve);
return (ret); return (ret);
} }
void *
chunk_alloc_mmap(size_t size)
{
return chunk_alloc_mmap_internal(size, false);
}
void *
chunk_alloc_mmap_noreserve(size_t size)
{
return chunk_alloc_mmap_internal(size, true);
}
void void
chunk_dealloc_mmap(void *chunk, size_t size) chunk_dealloc_mmap(void *chunk, size_t size)
{ {

View File

@@ -283,7 +283,7 @@ chunk_swap_enable(const int *fds, unsigned nfds, bool prezeroed)
* Allocate a chunk-aligned region of anonymous memory, which will * Allocate a chunk-aligned region of anonymous memory, which will
* be the final location for the memory-mapped files. * be the final location for the memory-mapped files.
*/ */
vaddr = chunk_alloc_mmap(cumsize); vaddr = chunk_alloc_mmap_noreserve(cumsize);
if (vaddr == NULL) { if (vaddr == NULL) {
ret = true; ret = true;
goto RETURN; goto RETURN;

View File

@@ -324,6 +324,7 @@ malloc_init_hard(void)
CPU_SPINWAIT; CPU_SPINWAIT;
malloc_mutex_lock(&init_lock); malloc_mutex_lock(&init_lock);
} while (malloc_initialized == false); } while (malloc_initialized == false);
malloc_mutex_unlock(&init_lock);
return (false); return (false);
} }
@@ -775,7 +776,7 @@ MALLOC_OUT:
#endif #endif
#ifndef NO_TLS #ifndef NO_TLS
next_arena = 0; next_arena = (narenas > 0) ? 1 : 0;
#endif #endif
/* Allocate and initialize arenas. */ /* Allocate and initialize arenas. */

View File

@@ -239,16 +239,15 @@ prof_backtrace(prof_bt_t *bt, unsigned nignore, unsigned max)
} }
/* /*
* Iterate over stack frames until there are no more. Heap-allocate * Iterate over stack frames until there are no more, or until no space
* and iteratively grow a larger bt if necessary. * remains in bt.
*/ */
for (i = 0; i < max; i++) { for (i = 0; i < max; i++) {
unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)&bt->vec[i]); unw_get_reg(&cursor, UNW_REG_IP, (unw_word_t *)&bt->vec[i]);
bt->len++;
err = unw_step(&cursor); err = unw_step(&cursor);
if (err <= 0) { if (err <= 0)
bt->len = i;
break; break;
}
} }
} }
#else #else
@@ -623,13 +622,8 @@ static inline void
prof_sample_accum_update(size_t size) prof_sample_accum_update(size_t size)
{ {
if (opt_lg_prof_sample == 0) { /* Sampling logic is unnecessary if the interval is 1. */
/* assert(opt_lg_prof_sample != 0);
* Don't bother with sampling logic, since sampling interval is
* 1.
*/
return;
}
/* Take care to avoid integer overflow. */ /* Take care to avoid integer overflow. */
if (size >= prof_sample_threshold - prof_sample_accum) { if (size >= prof_sample_threshold - prof_sample_accum) {
@@ -647,11 +641,15 @@ prof_sample_accum_update(size_t size)
void void
prof_malloc(const void *ptr, prof_thr_cnt_t *cnt) prof_malloc(const void *ptr, prof_thr_cnt_t *cnt)
{ {
size_t size = isalloc(ptr); size_t size;
assert(ptr != NULL); assert(ptr != NULL);
prof_sample_accum_update(size); if (opt_lg_prof_sample != 0) {
size = isalloc(ptr);
prof_sample_accum_update(size);
} else if ((uintptr_t)cnt > (uintptr_t)1U)
size = isalloc(ptr);
if ((uintptr_t)cnt > (uintptr_t)1U) { if ((uintptr_t)cnt > (uintptr_t)1U) {
prof_ctx_set(ptr, cnt->ctx); prof_ctx_set(ptr, cnt->ctx);
@@ -679,11 +677,18 @@ void
prof_realloc(const void *ptr, prof_thr_cnt_t *cnt, const void *old_ptr, prof_realloc(const void *ptr, prof_thr_cnt_t *cnt, const void *old_ptr,
size_t old_size, prof_ctx_t *old_ctx) size_t old_size, prof_ctx_t *old_ctx)
{ {
size_t size = isalloc(ptr); size_t size;
prof_thr_cnt_t *told_cnt; prof_thr_cnt_t *told_cnt;
if (ptr != NULL) assert(ptr != NULL || (uintptr_t)cnt <= (uintptr_t)1U);
prof_sample_accum_update(size);
if (ptr != NULL) {
if (opt_lg_prof_sample != 0) {
size = isalloc(ptr);
prof_sample_accum_update(size);
} else if ((uintptr_t)cnt > (uintptr_t)1U)
size = isalloc(ptr);
}
if ((uintptr_t)old_ctx > (uintptr_t)1U) { if ((uintptr_t)old_ctx > (uintptr_t)1U) {
told_cnt = prof_lookup(old_ctx->bt); told_cnt = prof_lookup(old_ctx->bt);