This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch master updated. glibc-2.21-363-gfff94fa


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  fff94fa2245612191123a8015eac94eb04f001e2 (commit)
       via  99db95db37b4fd95986fadb263e4180b7381d10d (commit)
       via  920d70128baa41ce6ce3b1b4771fe912f8d1691a (commit)
      from  46f894d8c60afcc06056a376340df2f378694551 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=fff94fa2245612191123a8015eac94eb04f001e2

commit fff94fa2245612191123a8015eac94eb04f001e2
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Tue May 19 06:40:37 2015 +0530

    Avoid deadlock in malloc on backtrace (BZ #16159)
    
    When the malloc subsystem detects some kind of memory corruption,
    depending on the configuration it prints the error, a backtrace, a
    memory map and then aborts the process.  In this process, the
    backtrace() call may result in a call to malloc, resulting in
    various kinds of problematic behavior.
    
    In one case, the malloc it calls may detect a corruption and call
    backtrace again, and a stack overflow may result due to the infinite
    recursion.  In another case, the malloc it calls may deadlock on an
    arena lock with the malloc (or free, realloc, etc.) that detected the
    corruption.  In yet another case, if the program is linked with
    pthreads, backtrace may do a pthread_once initialization, which
    deadlocks on itself.
    
    In all these cases, the program exit is not as intended.  This is
    avoidable by marking the arena that malloc detected a corruption on,
    as unusable.  The following patch does that.  Features of this patch
    are as follows:
    
    - A flag is added to the mstate struct of the arena to indicate if the
      arena is corrupt.
    
    - The flag is checked whenever malloc functions try to get a lock on
      an arena.  If the arena is unusable, a NULL is returned, causing the
      malloc to use mmap or try the next arena.
    
    - malloc_printerr sets the corrupt flag on the arena when it detects a
      corruption
    
    - free does not concern itself with the flag at all.  It is not
      important since the backtrace workflow does not need free.  A free
      in a parallel thread may cause another corruption, but that's not
      new
    
    - The flag check and set are not atomic and may race.  This is fine
      since we don't care about contention during the flag check.  We want
      to make sure that the malloc call in the backtrace does not trip on
      itself and all that action happens in the same thread and not across
      threads.
    
    I verified that the test case does not show any regressions due to
    this patch.  I also ran the malloc benchmarks and found an
    insignificant difference in timings (< 2%).
    
    	* malloc/Makefile (tests): New test case tst-malloc-backtrace.
    	* malloc/arena.c (arena_lock): Check if arena is corrupt.
    	(reused_arena): Find a non-corrupt arena.
    	(heap_trim): Pass arena to unlink.
    	* malloc/hooks.c (malloc_check_get_size): Pass arena to
    	malloc_printerr.
    	(top_check): Likewise.
    	(free_check): Likewise.
    	(realloc_check): Likewise.
    	* malloc/malloc.c (malloc_printerr): Add arena argument.
    	(unlink): Likewise.
    	(munmap_chunk): Adjust.
    	(ARENA_CORRUPTION_BIT): New macro.
    	(arena_is_corrupt): Likewise.
    	(set_arena_corrupt): Likewise.
    	(sysmalloc): Use mmap if there are no usable arenas.
    	(_int_malloc): Likewise.
    	(__libc_malloc): Don't fail if arena_get returns NULL.
    	(_mid_memalign): Likewise.
    	(__libc_calloc): Likewise.
    	(__libc_realloc): Adjust for additional argument to
    	malloc_printerr.
    	(_int_free): Likewise.
    	(malloc_consolidate): Likewise.
    	(_int_realloc): Likewise.
    	(_int_memalign): Don't touch corrupt arenas.
    	* malloc/tst-malloc-backtrace.c: New test case.

diff --git a/ChangeLog b/ChangeLog
index 1ec13ba..82a52c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,34 @@
 2015-05-19  Siddhesh Poyarekar  <siddhesh@redhat.com>
 
+	[BZ #16159]
+	* malloc/Makefile (tests): New test case tst-malloc-backtrace.
+	* malloc/arena.c (arena_lock): Check if arena is corrupt.
+	(reused_arena): Find a non-corrupt arena.
+	(heap_trim): Pass arena to unlink.
+	* malloc/hooks.c (malloc_check_get_size): Pass arena to
+	malloc_printerr.
+	(top_check): Likewise.
+	(free_check): Likewise.
+	(realloc_check): Likewise.
+	* malloc/malloc.c (malloc_printerr): Add arena argument.
+	(unlink): Likewise.
+	(munmap_chunk): Adjust.
+	(ARENA_CORRUPTION_BIT): New macro.
+	(arena_is_corrupt): Likewise.
+	(set_arena_corrupt): Likewise.
+	(sysmalloc): Use mmap if there are no usable arenas.
+	(_int_malloc): Likewise.
+	(__libc_malloc): Don't fail if arena_get returns NULL.
+	(_mid_memalign): Likewise.
+	(__libc_calloc): Likewise.
+	(__libc_realloc): Adjust for additional argument to
+	malloc_printerr.
+	(_int_free): Likewise.
+	(malloc_consolidate): Likewise.
+	(_int_realloc): Likewise.
+	(_int_memalign): Don't touch corrupt arenas.
+	* malloc/tst-malloc-backtrace.c: New test case.
+
 	* Makefile (summarize-tests): Fix return value on success.
 
 	* manual/string.texi (Envz Functions): Add envz_remove.
diff --git a/NEWS b/NEWS
index bfeb3a7..877ea34 100644
--- a/NEWS
+++ b/NEWS
@@ -9,16 +9,16 @@ Version 2.22
 
 * The following bugs are resolved with this release:
 
-  4719, 6792, 13064, 14094, 14841, 14906, 15319, 15467, 15790, 15969, 16339,
-  16351, 16352, 16512, 16560, 16704, 16783, 16850, 17090, 17195, 17269,
-  17523, 17542, 17569, 17588, 17596, 17620, 17621, 17628, 17631, 17692,
-  17711, 17715, 17776, 17779, 17792, 17836, 17912, 17916, 17930, 17932,
-  17944, 17949, 17964, 17965, 17967, 17969, 17978, 17987, 17991, 17996,
-  17998, 17999, 18007, 18019, 18020, 18029, 18030, 18032, 18036, 18038,
-  18039, 18042, 18043, 18046, 18047, 18068, 18080, 18093, 18100, 18104,
-  18110, 18111, 18125, 18128, 18138, 18185, 18196, 18197, 18206, 18210,
-  18211, 18217, 18220, 18221, 18247, 18287, 18319, 18333, 18346, 18397,
-  18409, 18418.
+  4719, 6792, 13064, 14094, 14841, 14906, 15319, 15467, 15790, 15969, 16159,
+  16339, 16351, 16352, 16512, 16560, 16704, 16783, 16850, 17090, 17195,
+  17269, 17523, 17542, 17569, 17588, 17596, 17620, 17621, 17628, 17631,
+  17692, 17711, 17715, 17776, 17779, 17792, 17836, 17912, 17916, 17930,
+  17932, 17944, 17949, 17964, 17965, 17967, 17969, 17978, 17987, 17991,
+  17996, 17998, 17999, 18007, 18019, 18020, 18029, 18030, 18032, 18036,
+  18038, 18039, 18042, 18043, 18046, 18047, 18068, 18080, 18093, 18100,
+  18104, 18110, 18111, 18125, 18128, 18138, 18185, 18196, 18197, 18206,
+  18210, 18211, 18217, 18220, 18221, 18247, 18287, 18319, 18333, 18346,
+  18397, 18409, 18418.
 
 * Cache information can be queried via sysconf() function on s390 e.g. with
   _SC_LEVEL1_ICACHE_SIZE as argument.
diff --git a/malloc/Makefile b/malloc/Makefile
index 9e7112a..67ed293 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -27,7 +27,8 @@ headers := $(dist-headers) obstack.h mcheck.h
 tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 \
 	 tst-malloc-usable tst-realloc tst-posix_memalign \
-	 tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer
+	 tst-pvalloc tst-memalign tst-mallopt tst-scratch_buffer \
+	 tst-malloc-backtrace
 test-srcs = tst-mtrace
 
 routines = malloc morecore mcheck mtrace obstack \
@@ -44,6 +45,9 @@ extra-libs-others = $(extra-libs)
 libmemusage-routines = memusage
 libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
 
+$(objpfx)tst-malloc-backtrace: $(common-objpfx)nptl/libpthread.so \
+			       $(common-objpfx)nptl/libpthread_nonshared.a
+
 # These should be removed by `make clean'.
 extra-objs = mcheck-init.o libmcheck.a
 
diff --git a/malloc/arena.c b/malloc/arena.c
index d85f371..2466697 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -99,7 +99,7 @@ int __malloc_initialized = -1;
   } while (0)
 
 #define arena_lock(ptr, size) do {					      \
-      if (ptr)								      \
+      if (ptr && !arena_is_corrupt (ptr))				      \
         (void) mutex_lock (&ptr->mutex);				      \
       else								      \
         ptr = arena_get2 (ptr, (size), NULL);				      \
@@ -686,7 +686,7 @@ heap_trim (heap_info *heap, size_t pad)
       if (!prev_inuse (p)) /* consolidate backward */
         {
           p = prev_chunk (p);
-          unlink (p, bck, fwd);
+          unlink (ar_ptr, p, bck, fwd);
         }
       assert (((unsigned long) ((char *) p + new_size) & (pagesz - 1)) == 0);
       assert (((char *) p + new_size) == ((char *) heap + heap->size));
@@ -809,7 +809,7 @@ reused_arena (mstate avoid_arena)
   result = next_to_use;
   do
     {
-      if (!mutex_trylock (&result->mutex))
+      if (!arena_is_corrupt (result) && !mutex_trylock (&result->mutex))
         goto out;
 
       result = result->next;
@@ -821,7 +821,21 @@ reused_arena (mstate avoid_arena)
   if (result == avoid_arena)
     result = result->next;
 
-  /* No arena available.  Wait for the next in line.  */
+  /* Make sure that the arena we get is not corrupted.  */
+  mstate begin = result;
+  while (arena_is_corrupt (result) || result == avoid_arena)
+    {
+      result = result->next;
+      if (result == begin)
+	break;
+    }
+
+  /* We could not find any arena that was either not corrupted or not the one
+     we wanted to avoid.  */
+  if (result == begin || result == avoid_arena)
+    return NULL;
+
+  /* No arena available without contention.  Wait for the next in line.  */
   LIBC_PROBE (memory_arena_reuse_wait, 3, &result->mutex, result, avoid_arena);
   (void) mutex_lock (&result->mutex);
 
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 0c4816f..9303fe5 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -112,7 +112,8 @@ malloc_check_get_size (mchunkptr p)
       if (c <= 0 || size < (c + 2 * SIZE_SZ))
         {
           malloc_printerr (check_action, "malloc_check_get_size: memory corruption",
-                           chunk2mem (p));
+                           chunk2mem (p),
+			   chunk_is_mmapped (p) ? NULL : arena_for_chunk (p));
           return 0;
         }
     }
@@ -237,7 +238,8 @@ top_check (void)
         (char *) t + chunksize (t) == mp_.sbrk_base + main_arena.system_mem)))
     return 0;
 
-  malloc_printerr (check_action, "malloc: top chunk is corrupt", t);
+  malloc_printerr (check_action, "malloc: top chunk is corrupt", t,
+		   &main_arena);
 
   /* Try to set up a new top chunk. */
   brk = MORECORE (0);
@@ -295,7 +297,8 @@ free_check (void *mem, const void *caller)
     {
       (void) mutex_unlock (&main_arena.mutex);
 
-      malloc_printerr (check_action, "free(): invalid pointer", mem);
+      malloc_printerr (check_action, "free(): invalid pointer", mem,
+		       &main_arena);
       return;
     }
   if (chunk_is_mmapped (p))
@@ -333,7 +336,8 @@ realloc_check (void *oldmem, size_t bytes, const void *caller)
   (void) mutex_unlock (&main_arena.mutex);
   if (!oldp)
     {
-      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem);
+      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem,
+		       &main_arena);
       return malloc_check (bytes, NULL);
     }
   const INTERNAL_SIZE_T oldsize = chunksize (oldp);
diff --git a/malloc/malloc.c b/malloc/malloc.c
index f361bad..452f036 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1059,7 +1059,7 @@ static void*  _int_realloc(mstate, mchunkptr, INTERNAL_SIZE_T,
 static void*  _int_memalign(mstate, size_t, size_t);
 static void*  _mid_memalign(size_t, size_t, void *);
 
-static void malloc_printerr(int action, const char *str, void *ptr);
+static void malloc_printerr(int action, const char *str, void *ptr, mstate av);
 
 static void* internal_function mem2mem_check(void *p, size_t sz);
 static int internal_function top_check(void);
@@ -1411,11 +1411,11 @@ typedef struct malloc_chunk *mbinptr;
 #define last(b)      ((b)->bk)
 
 /* Take a chunk off a bin list */
-#define unlink(P, BK, FD) {                                            \
+#define unlink(AV, P, BK, FD) {                                            \
     FD = P->fd;								      \
     BK = P->bk;								      \
     if (__builtin_expect (FD->bk != P || BK->fd != P, 0))		      \
-      malloc_printerr (check_action, "corrupted double-linked list", P);      \
+      malloc_printerr (check_action, "corrupted double-linked list", P, AV);  \
     else {								      \
         FD->bk = BK;							      \
         BK->fd = FD;							      \
@@ -1424,7 +1424,8 @@ typedef struct malloc_chunk *mbinptr;
 	    if (__builtin_expect (P->fd_nextsize->bk_nextsize != P, 0)	      \
 		|| __builtin_expect (P->bk_nextsize->fd_nextsize != P, 0))    \
 	      malloc_printerr (check_action,				      \
-			       "corrupted double-linked list (not small)", P);\
+			       "corrupted double-linked list (not small)",    \
+			       P, AV);					      \
             if (FD->fd_nextsize == NULL) {				      \
                 if (P->fd_nextsize == P)				      \
                   FD->fd_nextsize = FD->bk_nextsize = FD;		      \
@@ -1656,6 +1657,15 @@ typedef struct malloc_chunk *mfastbinptr;
 #define set_noncontiguous(M)   ((M)->flags |= NONCONTIGUOUS_BIT)
 #define set_contiguous(M)      ((M)->flags &= ~NONCONTIGUOUS_BIT)
 
+/* ARENA_CORRUPTION_BIT is set if a memory corruption was detected on the
+   arena.  Such an arena is no longer used to allocate chunks.  Chunks
+   allocated in that arena before detecting corruption are not freed.  */
+
+#define ARENA_CORRUPTION_BIT (4U)
+
+#define arena_is_corrupt(A)	(((A)->flags & ARENA_CORRUPTION_BIT))
+#define set_arena_corrupt(A)	((A)->flags |= ARENA_CORRUPTION_BIT)
+
 /*
    Set value of max_fast.
    Use impossibly small value if 0.
@@ -2280,8 +2290,9 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av)
      rather than expanding top.
    */
 
-  if ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold) &&
-      (mp_.n_mmaps < mp_.n_mmaps_max))
+  if (av == NULL
+      || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)
+	  && (mp_.n_mmaps < mp_.n_mmaps_max)))
     {
       char *mm;           /* return value from mmap call*/
 
@@ -2354,6 +2365,10 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av)
         }
     }
 
+  /* There are no usable arenas and mmap also failed.  */
+  if (av == NULL)
+    return 0;
+
   /* Record incoming configuration of top */
 
   old_top = av->top;
@@ -2528,7 +2543,8 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av)
           else if (contiguous (av) && old_size && brk < old_end)
             {
               /* Oops!  Someone else killed our space..  Can't touch anything.  */
-              malloc_printerr (3, "break adjusted to free malloc space", brk);
+              malloc_printerr (3, "break adjusted to free malloc space", brk,
+			       av);
             }
 
           /*
@@ -2818,7 +2834,7 @@ munmap_chunk (mchunkptr p)
   if (__builtin_expect (((block | total_size) & (GLRO (dl_pagesize) - 1)) != 0, 0))
     {
       malloc_printerr (check_action, "munmap_chunk(): invalid pointer",
-                       chunk2mem (p));
+                       chunk2mem (p), NULL);
       return;
     }
 
@@ -2888,22 +2904,19 @@ __libc_malloc (size_t bytes)
 
   arena_get (ar_ptr, bytes);
 
-  if (!ar_ptr)
-    return 0;
-
   victim = _int_malloc (ar_ptr, bytes);
-  if (!victim)
+  /* Retry with another arena only if we were able to find a usable arena
+     before.  */
+  if (!victim && ar_ptr != NULL)
     {
       LIBC_PROBE (memory_malloc_retry, 1, bytes);
       ar_ptr = arena_get_retry (ar_ptr, bytes);
-      if (__builtin_expect (ar_ptr != NULL, 1))
-        {
-          victim = _int_malloc (ar_ptr, bytes);
-          (void) mutex_unlock (&ar_ptr->mutex);
-        }
+      victim = _int_malloc (ar_ptr, bytes);
     }
-  else
+
+  if (ar_ptr != NULL)
     (void) mutex_unlock (&ar_ptr->mutex);
+
   assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
           ar_ptr == arena_for_chunk (mem2chunk (victim)));
   return victim;
@@ -2979,6 +2992,11 @@ __libc_realloc (void *oldmem, size_t bytes)
   /* its size */
   const INTERNAL_SIZE_T oldsize = chunksize (oldp);
 
+  if (chunk_is_mmapped (oldp))
+    ar_ptr = NULL;
+  else
+    ar_ptr = arena_for_chunk (oldp);
+
   /* Little security check which won't hurt performance: the
      allocator never wrapps around at the end of the address space.
      Therefore we can exclude some size values which might appear
@@ -2986,7 +3004,8 @@ __libc_realloc (void *oldmem, size_t bytes)
   if (__builtin_expect ((uintptr_t) oldp > (uintptr_t) -oldsize, 0)
       || __builtin_expect (misaligned_chunk (oldp), 0))
     {
-      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem);
+      malloc_printerr (check_action, "realloc(): invalid pointer", oldmem,
+		       ar_ptr);
       return NULL;
     }
 
@@ -3015,10 +3034,8 @@ __libc_realloc (void *oldmem, size_t bytes)
       return newmem;
     }
 
-  ar_ptr = arena_for_chunk (oldp);
   (void) mutex_lock (&ar_ptr->mutex);
 
-
   newp = _int_realloc (ar_ptr, oldp, oldsize, nb);
 
   (void) mutex_unlock (&ar_ptr->mutex);
@@ -3093,22 +3110,18 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
     }
 
   arena_get (ar_ptr, bytes + alignment + MINSIZE);
-  if (!ar_ptr)
-    return 0;
 
   p = _int_memalign (ar_ptr, alignment, bytes);
-  if (!p)
+  if (!p && ar_ptr != NULL)
     {
       LIBC_PROBE (memory_memalign_retry, 2, bytes, alignment);
       ar_ptr = arena_get_retry (ar_ptr, bytes);
-      if (__builtin_expect (ar_ptr != NULL, 1))
-        {
-          p = _int_memalign (ar_ptr, alignment, bytes);
-          (void) mutex_unlock (&ar_ptr->mutex);
-        }
+      p = _int_memalign (ar_ptr, alignment, bytes);
     }
-  else
+
+  if (ar_ptr != NULL)
     (void) mutex_unlock (&ar_ptr->mutex);
+
   assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
           ar_ptr == arena_for_chunk (mem2chunk (p)));
   return p;
@@ -3187,47 +3200,53 @@ __libc_calloc (size_t n, size_t elem_size)
   sz = bytes;
 
   arena_get (av, sz);
-  if (!av)
-    return 0;
-
-  /* Check if we hand out the top chunk, in which case there may be no
-     need to clear. */
+  if (av)
+    {
+      /* Check if we hand out the top chunk, in which case there may be no
+	 need to clear. */
 #if MORECORE_CLEARS
-  oldtop = top (av);
-  oldtopsize = chunksize (top (av));
+      oldtop = top (av);
+      oldtopsize = chunksize (top (av));
 # if MORECORE_CLEARS < 2
-  /* Only newly allocated memory is guaranteed to be cleared.  */
-  if (av == &main_arena &&
-      oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *) oldtop)
-    oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *) oldtop);
+      /* Only newly allocated memory is guaranteed to be cleared.  */
+      if (av == &main_arena &&
+	  oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *) oldtop)
+	oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *) oldtop);
 # endif
-  if (av != &main_arena)
+      if (av != &main_arena)
+	{
+	  heap_info *heap = heap_for_ptr (oldtop);
+	  if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
+	    oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
+	}
+#endif
+    }
+  else
     {
-      heap_info *heap = heap_for_ptr (oldtop);
-      if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop)
-        oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop;
+      /* No usable arenas.  */
+      oldtop = 0;
+      oldtopsize = 0;
     }
-#endif
   mem = _int_malloc (av, sz);
 
 
   assert (!mem || chunk_is_mmapped (mem2chunk (mem)) ||
           av == arena_for_chunk (mem2chunk (mem)));
 
-  if (mem == 0)
+  if (mem == 0 && av != NULL)
     {
       LIBC_PROBE (memory_calloc_retry, 1, sz);
       av = arena_get_retry (av, sz);
-      if (__builtin_expect (av != NULL, 1))
-        {
-          mem = _int_malloc (av, sz);
-          (void) mutex_unlock (&av->mutex);
-        }
-      if (mem == 0)
-        return 0;
+      mem = _int_malloc (av, sz);
     }
-  else
+
+  if (av != NULL)
     (void) mutex_unlock (&av->mutex);
+
+  /* Allocation failed even after a retry.  */
+  if (mem == 0)
+    return 0;
+
   p = mem2chunk (mem);
 
   /* Two optional cases in which clearing not necessary */
@@ -3323,6 +3342,16 @@ _int_malloc (mstate av, size_t bytes)
 
   checked_request2size (bytes, nb);
 
+  /* There are no usable arenas.  Fall back to sysmalloc to get a chunk from
+     mmap.  */
+  if (__glibc_unlikely (av == NULL))
+    {
+      void *p = sysmalloc (nb, av);
+      if (p != NULL)
+	alloc_perturb (p, bytes);
+      return p;
+    }
+
   /*
      If the size qualifies as a fastbin, first check corresponding bin.
      This code is safe to execute even if av is not yet initialized, so we
@@ -3348,7 +3377,7 @@ _int_malloc (mstate av, size_t bytes)
             {
               errstr = "malloc(): memory corruption (fast)";
             errout:
-              malloc_printerr (check_action, errstr, chunk2mem (victim));
+              malloc_printerr (check_action, errstr, chunk2mem (victim), av);
               return NULL;
             }
           check_remalloced_chunk (av, victim, nb);
@@ -3437,7 +3466,7 @@ _int_malloc (mstate av, size_t bytes)
           if (__builtin_expect (victim->size <= 2 * SIZE_SZ, 0)
               || __builtin_expect (victim->size > av->system_mem, 0))
             malloc_printerr (check_action, "malloc(): memory corruption",
-                             chunk2mem (victim));
+                             chunk2mem (victim), av);
           size = chunksize (victim);
 
           /*
@@ -3584,7 +3613,7 @@ _int_malloc (mstate av, size_t bytes)
                 victim = victim->fd;
 
               remainder_size = size - nb;
-              unlink (victim, bck, fwd);
+              unlink (av, victim, bck, fwd);
 
               /* Exhaust */
               if (remainder_size < MINSIZE)
@@ -3689,7 +3718,7 @@ _int_malloc (mstate av, size_t bytes)
               remainder_size = size - nb;
 
               /* unlink */
-              unlink (victim, bck, fwd);
+              unlink (av, victim, bck, fwd);
 
               /* Exhaust */
               if (remainder_size < MINSIZE)
@@ -3829,7 +3858,7 @@ _int_free (mstate av, mchunkptr p, int have_lock)
     errout:
       if (!have_lock && locked)
         (void) mutex_unlock (&av->mutex);
-      malloc_printerr (check_action, errstr, chunk2mem (p));
+      malloc_printerr (check_action, errstr, chunk2mem (p), av);
       return;
     }
   /* We know that each chunk is at least MINSIZE bytes in size or a
@@ -3967,7 +3996,7 @@ _int_free (mstate av, mchunkptr p, int have_lock)
       prevsize = p->prev_size;
       size += prevsize;
       p = chunk_at_offset(p, -((long) prevsize));
-      unlink(p, bck, fwd);
+      unlink(av, p, bck, fwd);
     }
 
     if (nextchunk != av->top) {
@@ -3976,7 +4005,7 @@ _int_free (mstate av, mchunkptr p, int have_lock)
 
       /* consolidate forward */
       if (!nextinuse) {
-	unlink(nextchunk, bck, fwd);
+	unlink(av, nextchunk, bck, fwd);
 	size += nextsize;
       } else
 	clear_inuse_bit_at_offset(nextchunk, 0);
@@ -4137,7 +4166,7 @@ static void malloc_consolidate(mstate av)
 	    prevsize = p->prev_size;
 	    size += prevsize;
 	    p = chunk_at_offset(p, -((long) prevsize));
-	    unlink(p, bck, fwd);
+	    unlink(av, p, bck, fwd);
 	  }
 
 	  if (nextchunk != av->top) {
@@ -4145,7 +4174,7 @@ static void malloc_consolidate(mstate av)
 
 	    if (!nextinuse) {
 	      size += nextsize;
-	      unlink(nextchunk, bck, fwd);
+	      unlink(av, nextchunk, bck, fwd);
 	    } else
 	      clear_inuse_bit_at_offset(nextchunk, 0);
 
@@ -4214,7 +4243,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
     {
       errstr = "realloc(): invalid old size";
     errout:
-      malloc_printerr (check_action, errstr, chunk2mem (oldp));
+      malloc_printerr (check_action, errstr, chunk2mem (oldp), av);
       return NULL;
     }
 
@@ -4260,7 +4289,7 @@ _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
                (unsigned long) (nb))
         {
           newp = oldp;
-          unlink (next, bck, fwd);
+          unlink (av, next, bck, fwd);
         }
 
       /* allocate, copy, free */
@@ -4455,6 +4484,10 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
 static int
 mtrim (mstate av, size_t pad)
 {
+  /* Don't touch corrupt arenas.  */
+  if (arena_is_corrupt (av))
+    return 0;
+
   /* Ensure initialization/consolidation */
   malloc_consolidate (av);
 
@@ -4945,8 +4978,14 @@ libc_hidden_def (__libc_mallopt)
 extern char **__libc_argv attribute_hidden;
 
 static void
-malloc_printerr (int action, const char *str, void *ptr)
+malloc_printerr (int action, const char *str, void *ptr, mstate ar_ptr)
 {
+  /* Avoid using this arena in future.  We do not attempt to synchronize this
+     with anything else because we minimally want to ensure that __libc_message
+     gets its resources safely without stumbling on the current corruption.  */
+  if (ar_ptr)
+    set_arena_corrupt (ar_ptr);
+
   if ((action & 5) == 5)
     __libc_message (action & 2, "%s\n", str);
   else if (action & 1)
diff --git a/malloc/tst-malloc-backtrace.c b/malloc/tst-malloc-backtrace.c
new file mode 100644
index 0000000..2e24157
--- /dev/null
+++ b/malloc/tst-malloc-backtrace.c
@@ -0,0 +1,50 @@
+/* Verify that backtrace does not deadlock on itself on memory corruption.
+   Copyright (C) 2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#include <stdlib.h>
+
+#define SIZE 4096
+
+/* Wrap free with a function to prevent gcc from optimizing it out.  */
+static void
+__attribute__((noinline))
+call_free (void *ptr)
+{
+  free (ptr);
+  *(size_t *)(ptr - sizeof (size_t)) = 1;
+}
+
+int
+do_test (void)
+{
+  void *ptr1 = malloc (SIZE);
+  void *ptr2 = malloc (SIZE);
+
+  call_free (ptr1);
+  ptr1 = malloc (SIZE);
+
+  /* Not reached.  The return statement is to put ptr2 into use so that gcc
+     doesn't optimize out that malloc call.  */
+  return (ptr1 == ptr2);
+}
+
+#define TEST_FUNCTION do_test ()
+#define EXPECTED_SIGNAL SIGABRT
+
+#include "../test-skeleton.c"

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=99db95db37b4fd95986fadb263e4180b7381d10d

commit 99db95db37b4fd95986fadb263e4180b7381d10d
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Tue May 19 06:36:29 2015 +0530

    Succeed if make check does not report any errors
    
    The conditional that evaluates if there are any FAILed test cases
    currently always fails, since we ensure it fails if we find any
    unexpected results in tests.sum and it would obviously fail if it does
    not find failed results in tests.sum.  This patch fixes this by simply
    inverting the result of the egrep, i.e. succeed if egrep fails (to
    find failed results) and fail if it succeeds.
    
    Tested with 'make subdirs=localedata check' and 'make subdirs=locale
    check' where all tests succeed and with 'make subdirs=elf check' where
    a couple of tests fail for me.
    
    	 * Makefile (summarize-tests): Fix return value on success.

diff --git a/ChangeLog b/ChangeLog
index 68254a9..1ec13ba 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2015-05-19  Siddhesh Poyarekar  <siddhesh@redhat.com>
 
+	* Makefile (summarize-tests): Fix return value on success.
+
 	* manual/string.texi (Envz Functions): Add envz_remove.
 
 2015-05-18  Roland McGrath  <roland@hack.frob.com>
diff --git a/Makefile b/Makefile
index 7edf517..658ccfa 100644
--- a/Makefile
+++ b/Makefile
@@ -320,7 +320,7 @@ define summarize-tests
 @egrep -v '^(PASS|XFAIL):' $(objpfx)$1 || true
 @echo "Summary of test results$2:"
 @sed 's/:.*//' < $(objpfx)$1 | sort | uniq -c
-@egrep -q -v '^(X?PASS|XFAIL|UNSUPPORTED):' $(objpfx)$1 && false
+@! egrep -q -v '^(X?PASS|XFAIL|UNSUPPORTED):' $(objpfx)$1
 endef
 
 tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=920d70128baa41ce6ce3b1b4771fe912f8d1691a

commit 920d70128baa41ce6ce3b1b4771fe912f8d1691a
Author: Siddhesh Poyarekar <siddhesh@redhat.com>
Date:   Tue May 19 06:35:37 2015 +0530

    Add envz_remove to the libc manual
    
    I was told that Ma Shimao submitted a patch to add envz_remove to the
    libc manual, but the patch could not be accepted since he does not
    have a copyright assignment in place.  I have been woefully behind on
    libc-alpha recently and have not seen the patch or the discussion
    thread.  I have also not read the man page for envz_remove, so
    Alexandre Oliva asked me if I could write this independently and post
    a patch.  The patch below is the result of the same - I have written
    it based on the implementation in string/envz.c and Alex told me via
    email that the function is AS, AC and MT-safe like envz_strip.
    
    I assume Alex and Carlos cannot review this since they have been
    tainted by the original patch (I haven't even tried to look for a link
    to it since I don't want to be tainted) so someone else will have to
    review this.  If there are no reviewers till the end of the week, I
    will commit this since I believe there is a chance that there are no
    other reviewers who haven't read that thread.
    
    	* manual/string.texi (Envz Functions): Add envz_remove.

diff --git a/ChangeLog b/ChangeLog
index 1c4f896..68254a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2015-05-19  Siddhesh Poyarekar  <siddhesh@redhat.com>
+
+	* manual/string.texi (Envz Functions): Add envz_remove.
+
 2015-05-18  Roland McGrath  <roland@hack.frob.com>
 
 	* sysdeps/posix/opendir.c: Include <stdbool.h>.
diff --git a/manual/string.texi b/manual/string.texi
index 397c181..c53e73a 100644
--- a/manual/string.texi
+++ b/manual/string.texi
@@ -2788,5 +2788,13 @@ The @code{envz_strip} function removes any null entries from @var{envz},
 updating @code{*@var{envz}} and @code{*@var{envz_len}}.
 @end deftypefun
 
+@comment envz.h
+@comment GNU
+@deftypefun {void} envz_remove (char **@var{envz}, size_t *@var{envz_len}, const char *@var{name})
+@safety{@prelim{}@mtsafe{}@asunsafe{@acsuheap{}}@acunsafe{@acsmem{}}}
+The @code{envz_remove} function removes an entry named @var{name} from
+@var{envz}, updating @code{*@var{envz}} and @code{*@var{envz_len}}.
+@end deftypefun
+
 @c FIXME this are undocumented:
 @c strcasecmp_l @safety{@mtsafe{}@assafe{}@acsafe{}} see strcasecmp

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                          |   35 ++++
 Makefile                                           |    2 +-
 NEWS                                               |   20 +-
 malloc/Makefile                                    |    6 +-
 malloc/arena.c                                     |   22 ++-
 malloc/hooks.c                                     |   12 +-
 malloc/malloc.c                                    |  173 ++++++++++++--------
 .../tst-detach1.c => malloc/tst-malloc-backtrace.c |   49 +++---
 manual/string.texi                                 |    8 +
 9 files changed, 213 insertions(+), 114 deletions(-)
 copy nptl/tst-detach1.c => malloc/tst-malloc-backtrace.c (57%)


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]