diff options
author | Jason Evans <jasone@canonware.com> | 2012-03-30 19:11:03 (GMT) |
---|---|---|
committer | Jason Evans <jasone@canonware.com> | 2012-03-30 19:11:03 (GMT) |
commit | 09a0769ba7a3d139168e606e4295f8002861355f (patch) | |
tree | a22c69f86af8d82868624009dc79af89579fabb9 /include | |
parent | 3c2ba0dcbc2f4896a892fad84d5dcf5bd4c30a81 (diff) | |
download | jemalloc-09a0769ba7a3d139168e606e4295f8002861355f.zip jemalloc-09a0769ba7a3d139168e606e4295f8002861355f.tar.gz jemalloc-09a0769ba7a3d139168e606e4295f8002861355f.tar.bz2 |
Work around TLS deallocation via free().
glibc uses memalign()/free() to allocate/deallocate TLS, which means
that it is unsafe to set TLS variables as a side effect of free() --
they may already be deallocated. Work around this by avoiding
tcache_create() within free().
Reported by Mike Hommey.
Diffstat (limited to 'include')
-rw-r--r-- | include/jemalloc/internal/arena.h | 7 | ||||
-rw-r--r-- | include/jemalloc/internal/tcache.h | 16 |
2 files changed, 18 insertions, 5 deletions
diff --git a/include/jemalloc/internal/arena.h b/include/jemalloc/internal/arena.h index c521489..2592e89 100644 --- a/include/jemalloc/internal/arena.h +++ b/include/jemalloc/internal/arena.h @@ -556,7 +556,7 @@ arena_malloc(size_t size, bool zero) assert(size <= arena_maxclass); if (size <= SMALL_MAXCLASS) { - if ((tcache = tcache_get()) != NULL) + if ((tcache = tcache_get(true)) != NULL) return (tcache_alloc_small(tcache, size, zero)); else return (arena_malloc_small(choose_arena(), size, zero)); @@ -565,7 +565,8 @@ arena_malloc(size_t size, bool zero) * Initialize tcache after checking size in order to avoid * infinite recursion during tcache initialization. */ - if (size <= tcache_maxclass && (tcache = tcache_get()) != NULL) + if (size <= tcache_maxclass && (tcache = tcache_get(true)) != + NULL) return (tcache_alloc_large(tcache, size, zero)); else return (arena_malloc_large(choose_arena(), size, zero)); @@ -590,7 +591,7 @@ arena_dalloc(arena_t *arena, arena_chunk_t *chunk, void *ptr) { size_t pageind; arena_chunk_map_t *mapelm; - tcache_t *tcache = tcache_get(); + tcache_t *tcache = tcache_get(false); assert(arena != NULL); assert(chunk->arena == arena); diff --git a/include/jemalloc/internal/tcache.h b/include/jemalloc/internal/tcache.h index 0d999f2..12552d8 100644 --- a/include/jemalloc/internal/tcache.h +++ b/include/jemalloc/internal/tcache.h @@ -126,7 +126,7 @@ malloc_tsd_protos(JEMALLOC_ATTR(unused), tcache_enabled, tcache_enabled_t) void tcache_event(tcache_t *tcache); void tcache_flush(void); bool tcache_enabled_get(void); -tcache_t *tcache_get(void); +tcache_t *tcache_get(bool create); void tcache_enabled_set(bool enabled); void *tcache_alloc_easy(tcache_bin_t *tbin); void *tcache_alloc_small(tcache_t *tcache, size_t size, bool zero); @@ -205,7 +205,7 @@ tcache_enabled_set(bool enabled) } JEMALLOC_INLINE tcache_t * -tcache_get(void) +tcache_get(bool create) { tcache_t *tcache; @@ -219,6 +219,18 @@ tcache_get(void) if (tcache == TCACHE_STATE_DISABLED) return (NULL); if (tcache == NULL) { + if (create == false) { + /* + * Creating a tcache here would cause + * allocation as a side effect of free(). + * Ordinarily that would be okay since + * tcache_create() failure is a soft failure + * that doesn't propagate. However, if TLS + * data are freed via free() as in glibc, + * subtle TLS corruption could result. + */ + return (NULL); + } if (tcache_enabled_get() == false) { tcache_enabled_set(false); /* Memoize. */ return (NULL); |