From 508f51f5f41e1e7af50f5f215688ad77daec0f1a Mon Sep 17 00:00:00 2001
From: Eli Zaretskii <eliz@gnu.org>
Date: Mon, 5 Nov 2012 19:23:25 +0200
Subject: [PATCH] Fix bug #12774 with crashes in ralloc.c.

 src/ralloc.c (relinquish): If real_morecore fails to return memory
 to the system, don't crash; instead, leave the last heap
 unchanged and return.
---
 src/ChangeLog |  6 ++++++
 src/ralloc.c  | 34 +++++++++++++++++-----------------
 2 files changed, 23 insertions(+), 17 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 3ae755f3d20..c49039a3cf9 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,9 @@
+2012-11-05  Eli Zaretskii  <eliz@gnu.org>
+
+	* ralloc.c (relinquish): If real_morecore fails to return memory
+	to the system, don't crash; instead, leave the last heap
+	unchanged and return.  (Bug#12774)
+
 2012-11-03  Eli Zaretskii  <eliz@gnu.org>
 
 	* lisp.mk: Adjust comments to the fact that term/internal is now
diff --git a/src/ralloc.c b/src/ralloc.c
index 11897411930..e5bf76b0e6d 100644
--- a/src/ralloc.c
+++ b/src/ralloc.c
@@ -327,6 +327,8 @@ relinquish (void)
 
       if ((char *)last_heap->end - (char *)last_heap->bloc_start <= excess)
 	{
+	  heap_ptr lh_prev;
+
 	  /* This heap should have no blocs in it.  If it does, we
 	     cannot return it to the system.  */
 	  if (last_heap->first_bloc != NIL_BLOC
@@ -335,28 +337,26 @@ relinquish (void)
 
 	  /* Return the last heap, with its header, to the system.  */
 	  excess = (char *)last_heap->end - (char *)last_heap->start;
-	  last_heap = last_heap->prev;
-	  last_heap->next = NIL_HEAP;
+	  lh_prev = last_heap->prev;
+	  /* If the system doesn't want that much memory back, leave
+	     last_heap unaltered to reflect that.  This can occur if
+	     break_value is still within the original data segment.  */
+	  if ((*real_morecore) (- excess) != 0)
+	    {
+	      last_heap = lh_prev;
+	      last_heap->next = NIL_HEAP;
+	    }
 	}
       else
 	{
 	  excess = (char *) last_heap->end
 			- (char *) ROUNDUP ((char *)last_heap->end - excess);
-	  last_heap->end = (char *) last_heap->end - excess;
-	}
-
-      if ((*real_morecore) (- excess) == 0)
-	{
-	  /* If the system didn't want that much memory back, adjust
-             the end of the last heap to reflect that.  This can occur
-             if break_value is still within the original data segment.  */
-	  last_heap->end = (char *) last_heap->end + excess;
-	  /* Make sure that the result of the adjustment is accurate.
-             It should be, for the else clause above; the other case,
-             which returns the entire last heap to the system, seems
-             unlikely to trigger this mode of failure.  */
-	  if (last_heap->end != (*real_morecore) (0))
-	    emacs_abort ();
+	  /* If the system doesn't want that much memory back, leave
+	     the end of the last heap unchanged to reflect that.  This
+	     can occur if break_value is still within the original
+	     data segment.  */
+	  if ((*real_morecore) (- excess) != 0)
+	    last_heap->end = (char *) last_heap->end - excess;
 	}
     }
 }
-- 
2.39.5