Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libc/stdlib Fix race condition on reallocation of huge c...



details:   https://anonhg.NetBSD.org/src/rev/e9ca329add94
branches:  trunk
changeset: 752720:e9ca329add94
user:      enami <enami%NetBSD.org@localhost>
date:      Thu Mar 04 22:48:31 2010 +0000

description:
Fix race condition on reallocation of huge category.

We need to remove the old region before mremap() since if it relesae the
old region, other thread may map it for the same huge category allocation
and insert it to the tree before we acquire a lock after mremap().

Fixes PR/42876.

diffstat:

 lib/libc/stdlib/jemalloc.c |  47 +++++++++++++++++++++++++++++----------------
 1 files changed, 30 insertions(+), 17 deletions(-)

diffs (72 lines):

diff -r 97371056c41e -r e9ca329add94 lib/libc/stdlib/jemalloc.c
--- a/lib/libc/stdlib/jemalloc.c        Thu Mar 04 22:42:22 2010 +0000
+++ b/lib/libc/stdlib/jemalloc.c        Thu Mar 04 22:48:31 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: jemalloc.c,v 1.20 2009/02/12 03:11:01 lukem Exp $      */
+/*     $NetBSD: jemalloc.c,v 1.21 2010/03/04 22:48:31 enami Exp $      */
 
 /*-
  * Copyright (C) 2006,2007 Jason Evans <jasone%FreeBSD.org@localhost>.
@@ -118,7 +118,7 @@
 
 #include <sys/cdefs.h>
 /* __FBSDID("$FreeBSD: src/lib/libc/stdlib/malloc.c,v 1.147 2007/06/15 22:00:16 jasone Exp $"); */ 
-__RCSID("$NetBSD: jemalloc.c,v 1.20 2009/02/12 03:11:01 lukem Exp $");
+__RCSID("$NetBSD: jemalloc.c,v 1.21 2010/03/04 22:48:31 enami Exp $");
 
 #ifdef __FreeBSD__
 #include "libc_private.h"
@@ -2856,25 +2856,38 @@
                        /* size_t wrap-around */
                        return (NULL);
                }
+
+               /*
+                * Remove the old region from the tree now.  If mremap()
+                * returns the region to the system, other thread may
+                * map it for same huge allocation and insert it to the
+                * tree before we acquire the mutex lock again.
+                */
+               malloc_mutex_lock(&chunks_mtx);
+               key.chunk = __DECONST(void *, ptr);
+               /* LINTED */
+               node = RB_FIND(chunk_tree_s, &huge, &key);
+               assert(node != NULL);
+               assert(node->chunk == ptr);
+               assert(node->size == oldcsize);
+               RB_REMOVE(chunk_tree_s, &huge, node);
+               malloc_mutex_unlock(&chunks_mtx);
+
                newptr = mremap(ptr, oldcsize, NULL, newcsize,
                    MAP_ALIGNED(chunksize_2pow));
-               if (newptr != MAP_FAILED) {
-                       assert(CHUNK_ADDR2BASE(newptr) == newptr);
-
-                       /* update tree */
+               if (newptr == MAP_FAILED) {
+                       /* We still own the old region. */
                        malloc_mutex_lock(&chunks_mtx);
-                       key.chunk = __DECONST(void *, ptr);
-                       /* LINTED */
-                       node = RB_FIND(chunk_tree_s, &huge, &key);
-                       assert(node != NULL);
-                       assert(node->chunk == ptr);
-                       assert(node->size == oldcsize);
+                       RB_INSERT(chunk_tree_s, &huge, node);
+                       malloc_mutex_unlock(&chunks_mtx);
+               } else {
+                       assert(CHUNK_ADDR2BASE(newptr) == newptr);
+
+                       /* Insert new or resized old region. */
+                       malloc_mutex_lock(&chunks_mtx);
                        node->size = newcsize;
-                       if (ptr != newptr) {
-                               RB_REMOVE(chunk_tree_s, &huge, node);
-                               node->chunk = newptr;
-                               RB_INSERT(chunk_tree_s, &huge, node);
-                       }
+                       node->chunk = newptr;
+                       RB_INSERT(chunk_tree_s, &huge, node);
 #ifdef MALLOC_STATS
                        huge_nralloc++;
                        huge_allocated += newcsize - oldcsize;



Home | Main Index | Thread Index | Old Index