summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--include/jemalloc/internal/chunk.h2
-rw-r--r--src/arena.c2
-rw-r--r--src/chunk.c16
-rw-r--r--src/huge.c21
-rw-r--r--src/stats.c2
6 files changed, 34 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index 61979683..326ee7a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,14 @@ found in the git revision history:
http://www.canonware.com/cgi-bin/gitweb.cgi?p=jemalloc.git
git://canonware.com/jemalloc.git
+* 2.2.5 (November 14, 2011)
+
+ Bug fixes:
+ - Fix huge_ralloc() race when using mremap(2). This is a serious bug that
+ could cause memory corruption and/or crashes.
+ - Fix huge_ralloc() to maintain chunk statistics.
+ - Fix malloc_stats_print(..., "a") output.
+
* 2.2.4 (November 5, 2011)
Bug fixes:
diff --git a/include/jemalloc/internal/chunk.h b/include/jemalloc/internal/chunk.h
index a60f0ad7..54b6a3ec 100644
--- a/include/jemalloc/internal/chunk.h
+++ b/include/jemalloc/internal/chunk.h
@@ -50,7 +50,7 @@ extern size_t map_bias; /* Number of arena chunk header pages. */
extern size_t arena_maxclass; /* Max size class for arenas. */
void *chunk_alloc(size_t size, bool base, bool *zero);
-void chunk_dealloc(void *chunk, size_t size);
+void chunk_dealloc(void *chunk, size_t size, bool unmap);
bool chunk_boot(void);
#endif /* JEMALLOC_H_EXTERNS */
diff --git a/src/arena.c b/src/arena.c
index e749c1d5..d166ca1e 100644
--- a/src/arena.c
+++ b/src/arena.c
@@ -569,7 +569,7 @@ arena_chunk_dealloc(arena_t *arena, arena_chunk_t *chunk)
arena->ndirty -= spare->ndirty;
}
malloc_mutex_unlock(&arena->lock);
- chunk_dealloc((void *)spare, chunksize);
+ chunk_dealloc((void *)spare, chunksize, true);
malloc_mutex_lock(&arena->lock);
#ifdef JEMALLOC_STATS
arena->stats.mapped -= chunksize;
diff --git a/src/chunk.c b/src/chunk.c
index 301519e8..d190c6f4 100644
--- a/src/chunk.c
+++ b/src/chunk.c
@@ -70,7 +70,7 @@ RETURN:
#ifdef JEMALLOC_IVSALLOC
if (base == false && ret != NULL) {
if (rtree_set(chunks_rtree, (uintptr_t)ret, ret)) {
- chunk_dealloc(ret, size);
+ chunk_dealloc(ret, size, true);
return (NULL);
}
}
@@ -108,7 +108,7 @@ RETURN:
}
void
-chunk_dealloc(void *chunk, size_t size)
+chunk_dealloc(void *chunk, size_t size, bool unmap)
{
assert(chunk != NULL);
@@ -125,15 +125,17 @@ chunk_dealloc(void *chunk, size_t size)
malloc_mutex_unlock(&chunks_mtx);
#endif
+ if (unmap) {
#ifdef JEMALLOC_SWAP
- if (swap_enabled && chunk_dealloc_swap(chunk, size) == false)
- return;
+ if (swap_enabled && chunk_dealloc_swap(chunk, size) == false)
+ return;
#endif
#ifdef JEMALLOC_DSS
- if (chunk_dealloc_dss(chunk, size) == false)
- return;
+ if (chunk_dealloc_dss(chunk, size) == false)
+ return;
#endif
- chunk_dealloc_mmap(chunk, size);
+ chunk_dealloc_mmap(chunk, size);
+ }
}
bool
diff --git a/src/huge.c b/src/huge.c
index ac3f3a0d..a4f9b054 100644
--- a/src/huge.c
+++ b/src/huge.c
@@ -110,12 +110,12 @@ huge_palloc(size_t size, size_t alignment, bool zero)
if (offset == 0) {
/* Trim trailing space. */
chunk_dealloc((void *)((uintptr_t)ret + chunk_size), alloc_size
- - chunk_size);
+ - chunk_size, true);
} else {
size_t trailsize;
/* Trim leading space. */
- chunk_dealloc(ret, alignment - offset);
+ chunk_dealloc(ret, alignment - offset, true);
ret = (void *)((uintptr_t)ret + (alignment - offset));
@@ -124,7 +124,7 @@ huge_palloc(size_t size, size_t alignment, bool zero)
/* Trim trailing space. */
assert(trailsize < alloc_size);
chunk_dealloc((void *)((uintptr_t)ret + chunk_size),
- trailsize);
+ trailsize, true);
}
}
@@ -234,6 +234,13 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
) {
size_t newsize = huge_salloc(ret);
+ /*
+ * Remove ptr from the tree of huge allocations before
+ * performing the remap operation, in order to avoid the
+ * possibility of another thread acquiring that mapping before
+ * this one removes it from the tree.
+ */
+ huge_dalloc(ptr, false);
if (mremap(ptr, oldsize, newsize, MREMAP_MAYMOVE|MREMAP_FIXED,
ret) == MAP_FAILED) {
/*
@@ -253,9 +260,8 @@ huge_ralloc(void *ptr, size_t oldsize, size_t size, size_t extra,
if (opt_abort)
abort();
memcpy(ret, ptr, copysize);
- idalloc(ptr);
- } else
- huge_dalloc(ptr, false);
+ chunk_dealloc_mmap(ptr, oldsize);
+ }
} else
#endif
{
@@ -295,9 +301,10 @@ huge_dalloc(void *ptr, bool unmap)
memset(node->addr, 0x5a, node->size);
#endif
#endif
- chunk_dealloc(node->addr, node->size);
}
+ chunk_dealloc(node->addr, node->size, unmap);
+
base_node_dealloc(node);
}
diff --git a/src/stats.c b/src/stats.c
index cbbbb5ba..dc172e42 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -748,7 +748,7 @@ stats_print(void (*write_cb)(void *, const char *), void *cbopaque,
ninitialized++;
}
- if (ninitialized > 1) {
+ if (ninitialized > 1 || unmerged == false) {
/* Print merged arena stats. */
malloc_cprintf(write_cb, cbopaque,
"\nMerged arenas stats:\n");