ce426f
commit 362b47fe09ca9a928d444c7e2f7992f7f61bfc3e
ce426f
Author: Maxim Kuvyrkov <maxim@kugelworks.com>
ce426f
Date:   Tue Dec 24 09:44:50 2013 +1300
ce426f
ce426f
    Fix race in free() of fastbin chunk: BZ #15073
ce426f
    
ce426f
    Perform sanity check only if we have_lock.  Due to lockless nature of fastbins
ce426f
    we need to be careful derefencing pointers to fastbin entries (chunksize(old)
ce426f
    in this case) in multithreaded environments.
ce426f
    
ce426f
    The fix is to add have_lock to the if-condition checks.  The rest of the patch
ce426f
    only makes code more readable.
ce426f
    
ce426f
    	* malloc/malloc.c (_int_free): Perform sanity check only if we
ce426f
    	have_lock.
ce426f
ce426f
Index: b/malloc/malloc.c
ce426f
===================================================================
ce426f
--- a/malloc/malloc.c
ce426f
+++ b/malloc/malloc.c
ce426f
@@ -3909,25 +3909,29 @@ _int_free(mstate av, mchunkptr p, int ha
ce426f
     unsigned int idx = fastbin_index(size);
ce426f
     fb = &fastbin (av, idx);
ce426f
 
ce426f
-    mchunkptr fd;
ce426f
-    mchunkptr old = *fb;
ce426f
+    /* Atomically link P to its fastbin: P->FD = *FB; *FB = P;  */
ce426f
+    mchunkptr old = *fb, old2;
ce426f
     unsigned int old_idx = ~0u;
ce426f
     do
ce426f
       {
ce426f
-	/* Another simple check: make sure the top of the bin is not the
ce426f
-	   record we are going to add (i.e., double free).  */
ce426f
+	/* Check that the top of the bin is not the record we are going to add
ce426f
+	   (i.e., double free).  */
ce426f
 	if (__builtin_expect (old == p, 0))
ce426f
 	  {
ce426f
 	    errstr = "double free or corruption (fasttop)";
ce426f
 	    goto errout;
ce426f
 	  }
ce426f
-	if (old != NULL)
ce426f
+	/* Check that size of fastbin chunk at the top is the same as
ce426f
+	   size of the chunk that we are adding.  We can dereference OLD
ce426f
+	   only if we have the lock, otherwise it might have already been
ce426f
+	   deallocated.  See use of OLD_IDX below for the actual check.  */
ce426f
+	if (have_lock && old != NULL)
ce426f
 	  old_idx = fastbin_index(chunksize(old));
ce426f
-	p->fd = fd = old;
ce426f
+	p->fd = old2 = old;
ce426f
       }
ce426f
-    while ((old = catomic_compare_and_exchange_val_rel (fb, p, fd)) != fd);
ce426f
+    while ((old = catomic_compare_and_exchange_val_rel (fb, p, old2)) != old2);
ce426f
 
ce426f
-    if (fd != NULL && __builtin_expect (old_idx != idx, 0))
ce426f
+    if (have_lock && old != NULL && __builtin_expect (old_idx != idx, 0))
ce426f
       {
ce426f
 	errstr = "invalid fastbin entry (free)";
ce426f
 	goto errout;