]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix crashes in lisp_align_free in a build with GC_MCHECK.
authorEli Zaretskii <eliz@gnu.org>
Mon, 3 Mar 2014 16:46:36 +0000 (18:46 +0200)
committerEli Zaretskii <eliz@gnu.org>
Mon, 3 Mar 2014 16:46:36 +0000 (18:46 +0200)
 src/gmalloc.c (aligned_alloc): Fix adjustment of size of the
 allocated buffer due to alignment.
 (freehook): If the block to be freed was allocated by
 'aligned_alloc', find its real pointer before calling 'free'.
 (mabort) [emacs]: Call 'emacs_abort', not 'abort', to provide a
 backtrace.

Fixes: debbugs:16901
src/ChangeLog
src/gmalloc.c

index 7bc69b2894e765e722ae94221aa537efc0767985..ecf8503117c35468aa25d81450afdfe39dbe98fc 100644 (file)
@@ -1,3 +1,13 @@
+2014-03-03  Eli Zaretskii  <eliz@gnu.org>
+
+       * gmalloc.c (aligned_alloc): Fix adjustment of size of the
+       allocated buffer due to alignment.
+       (freehook): If the block to be freed was allocated by
+       'aligned_alloc', find its real pointer before calling 'free'.
+       (Bug#16901)
+       (mabort) [emacs]: Call 'emacs_abort', not 'abort', to provide a
+       backtrace.
+
 2014-03-03  Dmitry Antipov  <dmantipov@yandex.ru>
 
        * font.c (toplevel): Adjust comment about font cache layout.
index 12c2357de7719779d8ad05b489a779bf6e2cd701..f8d0cfdc30a47cacf18f85d208711f8bdf6a069c 100644 (file)
@@ -68,6 +68,10 @@ extern int posix_memalign (void **, size_t, size_t);
 extern void malloc_enable_thread (void);
 #endif
 
+#ifdef emacs
+extern void emacs_abort (void);
+#endif
+
 /* The allocator divides the heap into blocks of fixed size; large
    requests receive one or more whole blocks, and small requests
    receive a fragment of a block.  Fragment sizes are powers of two,
@@ -1595,7 +1599,7 @@ aligned_alloc (size_t alignment, size_t size)
     {
       /* Reallocate the block with only as much excess as it needs.  */
       free (result);
-      result = malloc (adj + size);
+      result = malloc (size + alignment - adj);
       if (result == NULL)      /* Impossible unless interrupted.  */
        return NULL;
 
@@ -1605,7 +1609,7 @@ aligned_alloc (size_t alignment, size_t size)
         different block with weaker alignment.  If so, this block is too
         short to contain SIZE after alignment correction.  So we must
         try again and get another block, slightly larger.  */
-    } while (adj > lastadj);
+    } while (adj < lastadj);
 
   if (adj != 0)
     {
@@ -1787,6 +1791,22 @@ freehook (void *ptr)
 
   if (ptr)
     {
+      struct alignlist *l;
+
+      /* If the block was allocated by aligned_alloc, its real pointer
+        to free is recorded in _aligned_blocks; find that.  */
+      PROTECT_MALLOC_STATE (0);
+      LOCK_ALIGNED_BLOCKS ();
+      for (l = _aligned_blocks; l != NULL; l = l->next)
+       if (l->aligned == ptr)
+         {
+           l->aligned = NULL;  /* Mark the slot in the list as free.  */
+           ptr = l->exact;
+           break;
+         }
+      UNLOCK_ALIGNED_BLOCKS ();
+      PROTECT_MALLOC_STATE (1);
+
       hdr = ((struct hdr *) ptr) - 1;
       checkhdr (hdr);
       hdr->magic = MAGICFREE;
@@ -1878,7 +1898,11 @@ mabort (enum mcheck_status status)
 #else
   fprintf (stderr, "mcheck: %s\n", msg);
   fflush (stderr);
+# ifdef emacs
+  emacs_abort ();
+# else
   abort ();
+# endif
 #endif
 }