summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJason Evans <jasone@canonware.com>2012-03-30 19:11:03 (GMT)
committerJason Evans <jasone@canonware.com>2012-03-30 19:11:03 (GMT)
commit09a0769ba7a3d139168e606e4295f8002861355f (patch)
treea22c69f86af8d82868624009dc79af89579fabb9 /include
parent3c2ba0dcbc2f4896a892fad84d5dcf5bd4c30a81 (diff)
downloadjemalloc-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.h7
-rw-r--r--include/jemalloc/internal/tcache.h16
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);