]> code.delx.au - gnu-emacs/blobdiff - src/ralloc.c
Port documentation to Texinfo 5.0.
[gnu-emacs] / src / ralloc.c
index 19d15664eec28c493b28784ad50ffe6273ed0fec..ec1ac40414ccef537c093e8ea97cecbdf8de33cf 100644 (file)
@@ -1,5 +1,5 @@
 /* Block-relocating memory allocator.
-   Copyright (C) 1993, 1995, 2000-201 Free Software Foundation, Inc.
+   Copyright (C) 1993, 1995, 2000-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -25,7 +25,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #ifdef emacs
 
 #include <config.h>
-#include <setjmp.h>
+
 #include "lisp.h"              /* Needed for VALBITS.  */
 #include "blockinput.h"
 
@@ -72,7 +72,7 @@ static void r_alloc_init (void);
 /* Declarations for working with the malloc, ralloc, and system breaks.  */
 
 /* Function to set the real break value.  */
-POINTER (*real_morecore) (long int);
+POINTER (*real_morecore) (ptrdiff_t);
 
 /* The break value, as seen by malloc.  */
 static POINTER virtual_break_value;
@@ -91,18 +91,18 @@ static int extra_bytes;
 /* Macros for rounding.  Note that rounding to any value is possible
    by changing the definition of PAGE.  */
 #define PAGE (getpagesize ())
-#define ROUNDUP(size) (((unsigned long int) (size) + page_size - 1) \
-                      & ~(page_size - 1))
+#define ROUNDUP(size) (((size_t) (size) + page_size - 1) \
+                      & ~((size_t)(page_size - 1)))
 
 #define MEM_ALIGN sizeof (double)
-#define MEM_ROUNDUP(addr) (((unsigned long int)(addr) + MEM_ALIGN - 1) \
-                                  & ~(MEM_ALIGN - 1))
+#define MEM_ROUNDUP(addr) (((size_t)(addr) + MEM_ALIGN - 1) \
+                          & ~(MEM_ALIGN - 1))
 
 /* The hook `malloc' uses for the function which gets more space
    from the system.  */
 
 #ifndef SYSTEM_MALLOC
-extern POINTER (*__morecore) (long int);
+extern POINTER (*__morecore) (ptrdiff_t);
 #endif
 
 
@@ -237,7 +237,7 @@ obtain (POINTER address, SIZE size)
     }
 
   if (! heap)
-    abort ();
+    emacs_abort ();
 
   /* If we can't fit SIZE bytes in that heap,
      try successive later heaps.  */
@@ -308,7 +308,7 @@ static void
 relinquish (void)
 {
   register heap_ptr h;
-  long excess = 0;
+  ptrdiff_t excess = 0;
 
   /* Add the amount of space beyond break_value
      in all heaps which have extend beyond break_value at all.  */
@@ -327,35 +327,36 @@ relinquish (void)
 
       if ((char *)last_heap->end - (char *)last_heap->bloc_start <= excess)
        {
-         /* This heap should have no blocs in it.  */
+         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
              || last_heap->last_bloc != NIL_BLOC)
-           abort ();
+           return;
 
          /* 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))
-           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;
        }
     }
 }
@@ -396,7 +397,7 @@ get_bloc (SIZE size)
   register bloc_ptr new_bloc;
   register heap_ptr heap;
 
-  if (! (new_bloc = (bloc_ptr) malloc (BLOC_PTR_SIZE))
+  if (! (new_bloc = malloc (BLOC_PTR_SIZE))
       || ! (new_bloc->data = obtain (break_value, size)))
     {
       free (new_bloc);
@@ -452,7 +453,7 @@ relocate_blocs (bloc_ptr bloc, heap_ptr heap, POINTER address)
 
   /* No need to ever call this if arena is frozen, bug somewhere!  */
   if (r_alloc_freeze_level)
-    abort ();
+    emacs_abort ();
 
   while (b)
     {
@@ -576,7 +577,7 @@ resize_bloc (bloc_ptr bloc, SIZE size)
 
   /* No need to ever call this if arena is frozen, bug somewhere!  */
   if (r_alloc_freeze_level)
-    abort ();
+    emacs_abort ();
 
   if (bloc == NIL_BLOC || size == bloc->size)
     return 1;
@@ -588,7 +589,7 @@ resize_bloc (bloc_ptr bloc, SIZE size)
     }
 
   if (heap == NIL_HEAP)
-    abort ();
+    emacs_abort ();
 
   old_size = bloc->size;
   bloc->size = size;
@@ -670,6 +671,7 @@ static void
 free_bloc (bloc_ptr bloc)
 {
   heap_ptr heap = bloc->heap;
+  heap_ptr h;
 
   if (r_alloc_freeze_level)
     {
@@ -699,20 +701,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)
-    {
-      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)
+  /* 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->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 ();
@@ -733,7 +753,7 @@ free_bloc (bloc_ptr bloc)
    GNU malloc package.  */
 
 static POINTER
-r_alloc_sbrk (long int size)
+r_alloc_sbrk (ptrdiff_t size)
 {
   register bloc_ptr b;
   POINTER address;
@@ -741,7 +761,7 @@ r_alloc_sbrk (long int size)
   if (! r_alloc_initialized)
     r_alloc_init ();
 
-  if (! use_relocatable_buffers)
+  if (use_relocatable_buffers <= 0)
     return (*real_morecore) (size);
 
   if (size == 0)
@@ -918,7 +938,7 @@ r_alloc_free (register POINTER *ptr)
 
   dead_bloc = find_bloc (ptr);
   if (dead_bloc == NIL_BLOC)
-    abort (); /* Double free? PTR not originally used to allocate?  */
+    emacs_abort (); /* Double free? PTR not originally used to allocate?  */
 
   free_bloc (dead_bloc);
   *ptr = 0;
@@ -960,7 +980,7 @@ r_re_alloc (POINTER *ptr, SIZE size)
 
   bloc = find_bloc (ptr);
   if (bloc == NIL_BLOC)
-    abort (); /* Already freed? PTR not originally used to allocate?  */
+    emacs_abort (); /* Already freed? PTR not originally used to allocate?  */
 
   if (size < bloc->size)
     {
@@ -1133,7 +1153,7 @@ r_alloc_reset_variable (POINTER *old, POINTER *new)
     }
 
   if (bloc == NIL_BLOC || bloc->variable != old)
-    abort (); /* Already freed? OLD not originally used to allocate?  */
+    emacs_abort (); /* Already freed? OLD not originally used to allocate?  */
 
   /* Update variable to point to the new location.  */
   bloc->variable = new;
@@ -1142,12 +1162,12 @@ r_alloc_reset_variable (POINTER *old, POINTER *new)
 void
 r_alloc_inhibit_buffer_relocation (int inhibit)
 {
-  if (use_relocatable_buffers < 0)
-    use_relocatable_buffers = 0;
+  if (use_relocatable_buffers > 1)
+    use_relocatable_buffers = 1;
   if (inhibit)
-    use_relocatable_buffers++;
-  else if (use_relocatable_buffers > 0)
     use_relocatable_buffers--;
+  else if (use_relocatable_buffers < 1)
+    use_relocatable_buffers++;
 }
 
 \f
@@ -1174,20 +1194,26 @@ r_alloc_init (void)
   first_heap->start = first_heap->bloc_start
     = virtual_break_value = break_value = (*real_morecore) (0);
   if (break_value == NIL)
-    abort ();
+    emacs_abort ();
 
   extra_bytes = ROUNDUP (50000);
 #endif
 
 #ifdef DOUG_LEA_MALLOC
-  BLOCK_INPUT;
+  block_input ();
   mallopt (M_TOP_PAD, 64 * 4096);
-  UNBLOCK_INPUT;
+  unblock_input ();
 #else
 #ifndef SYSTEM_MALLOC
-  /* Give GNU malloc's morecore some hysteresis
-     so that we move all the relocatable blocks much less often.  */
-  __malloc_extra_blocks = 64;
+  /* Give GNU malloc's morecore some hysteresis so that we move all
+     the relocatable blocks much less often.  The number used to be
+     64, but alloc.c would override that with 32 in code that was
+     removed when SYNC_INPUT became the only input handling mode.
+     That code was conditioned on !DOUG_LEA_MALLOC, so the call to
+     mallopt above is left unchanged.  (Actually, I think there's no
+     system nowadays that uses DOUG_LEA_MALLOC and also uses
+     REL_ALLOC.)  */
+  __malloc_extra_blocks = 32;
 #endif
 #endif