diff options
author | jasone <jasone@FreeBSD.org> | 2008-02-17 18:34:17 +0000 |
---|---|---|
committer | jasone <jasone@FreeBSD.org> | 2008-02-17 18:34:17 +0000 |
commit | 2bc29a153085cdb6c0bff364cf46b376668f0c46 (patch) | |
tree | 0040f394d41847427fc23ae9c854b42a5c45f6fc /lib/libc/stdlib | |
parent | b08b976e68b5fc68d63f1f00accb6b34ea2307d9 (diff) | |
download | FreeBSD-src-2bc29a153085cdb6c0bff364cf46b376668f0c46.zip FreeBSD-src-2bc29a153085cdb6c0bff364cf46b376668f0c46.tar.gz |
Fix a race condition in arena_ralloc() for shrinking in-place large
reallocation, when junk filling is enabled. Junk filling must occur
prior to shrinking, since any deallocated trailing pages are immediately
available for use by other threads.
Reported by: Mats Palmgren <mats.palmgren@bredband.net>
Diffstat (limited to 'lib/libc/stdlib')
-rw-r--r-- | lib/libc/stdlib/malloc.c | 66 |
1 files changed, 41 insertions, 25 deletions
diff --git a/lib/libc/stdlib/malloc.c b/lib/libc/stdlib/malloc.c index 6d31b7d..1e85a34 100644 --- a/lib/libc/stdlib/malloc.c +++ b/lib/libc/stdlib/malloc.c @@ -894,11 +894,11 @@ static void *arena_palloc(arena_t *arena, size_t alignment, size_t size, static size_t arena_salloc(const void *ptr); 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, +static void arena_ralloc_large_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, +static bool arena_ralloc_large_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 bool arena_ralloc_large(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); @@ -3345,7 +3345,7 @@ idalloc(void *ptr) } static void -arena_ralloc_resize_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, +arena_ralloc_large_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t size, size_t oldsize) { extent_node_t *node, key; @@ -3373,7 +3373,7 @@ arena_ralloc_resize_shrink(arena_t *arena, arena_chunk_t *chunk, void *ptr, } static bool -arena_ralloc_resize_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, +arena_ralloc_large_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, size_t size, size_t oldsize) { extent_node_t *nodeC, key; @@ -3431,21 +3431,44 @@ arena_ralloc_resize_grow(arena_t *arena, arena_chunk_t *chunk, void *ptr, * 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_ralloc_large(void *ptr, size_t size, size_t oldsize) { - arena_chunk_t *chunk; - arena_t *arena; + size_t psize; - 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); + psize = PAGE_CEILING(size); + if (psize == oldsize) { + /* Same size class. */ + if (opt_junk && size < oldsize) { + memset((void *)((uintptr_t)ptr + size), 0x5a, oldsize - + size); + } return (false); } else { - return (arena_ralloc_resize_grow(arena, chunk, ptr, size, - oldsize)); + arena_chunk_t *chunk; + arena_t *arena; + + chunk = (arena_chunk_t *)CHUNK_ADDR2BASE(ptr); + arena = chunk->arena; + assert(arena->magic == ARENA_MAGIC); + + if (psize < oldsize) { + /* Fill before shrinking in order avoid a race. */ + if (opt_junk) { + memset((void *)((uintptr_t)ptr + size), 0x5a, + oldsize - size); + } + arena_ralloc_large_shrink(arena, chunk, ptr, psize, + oldsize); + return (false); + } else { + bool ret = arena_ralloc_large_grow(arena, chunk, ptr, + psize, oldsize); + if (ret == false && opt_zero) { + memset((void *)((uintptr_t)ptr + oldsize), 0, + size - oldsize); + } + return (ret); + } } } @@ -3471,16 +3494,9 @@ arena_ralloc(void *ptr, size_t size, size_t oldsize) 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 (arena_ralloc_large(ptr, size, oldsize) == false) + return (ptr); } /* |