]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix bug #12242 with crashes in ralloc.c on OpenBSD.
authorEli Zaretskii <eliz@gnu.org>
Fri, 24 Aug 2012 08:26:46 +0000 (11:26 +0300)
committerEli Zaretskii <eliz@gnu.org>
Fri, 24 Aug 2012 08:26:46 +0000 (11:26 +0300)
 src/ralloc.c (free_bloc): Don't dereference a 'heap' structure if it
 is not one of the heaps we manage.

src/ChangeLog
src/ralloc.c

index 7da25a856e682f667b6d1ba92498e3f06bf67c86..e5adbedd567511a7cbf0828c9622fb0aac69a0c3 100644 (file)
@@ -1,3 +1,8 @@
+2012-08-24  Eli Zaretskii  <eliz@gnu.org>
+
+       * ralloc.c (free_bloc): Don't dereference a 'heap' structure if it
+       is not one of the heaps we manage.  (Bug#12242)
+
 2012-08-15  Chong Yidong  <cyd@gnu.org>
 
        * Version 24.2 released.
index b1a5982574f0e008ec09c7d4dbc914df0a334366..fdcee7c7ef47842a6f669a0dcc2dd8427dcde0f2 100644 (file)
@@ -686,6 +686,7 @@ static void
 free_bloc (bloc_ptr bloc)
 {
   heap_ptr heap = bloc->heap;
+  heap_ptr h;
 
   if (r_alloc_freeze_level)
     {
@@ -715,20 +716,38 @@ free_bloc (bloc_ptr bloc)
       bloc->prev->next = bloc->next;
     }
 
-  /* Update the records of which blocs are in HEAP.  */
-  if (heap->first_bloc == bloc)
+  /* Sometimes, 'heap' obtained from bloc->heap above is not really a
+     'heap' structure.  It can even be beyond the current break point,
+     which will cause crashes when we dereference it below (see
+     bug#12242).  Evidently, the reason is bloc allocations done while
+     use_relocatable_buffers was non-positive, because additional
+     memory we get then is not recorded in the heaps we manage.  If
+     bloc->heap records such a "heap", we cannot (and don't need to)
+     update its records.  So we validate the 'heap' value by making
+     sure it is one of the heaps we manage via the heaps linked list,
+     and don't touch a 'heap' that isn't found there.  This avoids
+     accessing memory we know nothing about.  */
+  for (h = first_heap; h != NIL_HEAP; h = h->next)
+    if (heap == h)
+      break;
+
+  if (h)
     {
-      if (bloc->next != 0 && bloc->next->heap == heap)
-       heap->first_bloc = bloc->next;
-      else
-       heap->first_bloc = heap->last_bloc = NIL_BLOC;
-    }
-  if (heap->last_bloc == bloc)
-    {
-      if (bloc->prev != 0 && bloc->prev->heap == heap)
-       heap->last_bloc = bloc->prev;
-      else
-       heap->first_bloc = heap->last_bloc = NIL_BLOC;
+      /* Update the records of which blocs are in HEAP.  */
+      if (heap->first_bloc == bloc)
+       {
+         if (bloc->next != 0 && bloc->next->heap == heap)
+           heap->first_bloc = bloc->next;
+         else
+           heap->first_bloc = heap->last_bloc = NIL_BLOC;
+       }
+      if (heap->last_bloc == bloc)
+       {
+         if (bloc->prev != 0 && bloc->prev->heap == heap)
+           heap->last_bloc = bloc->prev;
+         else
+           heap->first_bloc = heap->last_bloc = NIL_BLOC;
+       }
     }
 
   relinquish ();