]> git.ipfire.org Git - thirdparty/glibc.git/blobdiff - malloc/mcheck.c
Move malloc hooks into a compat DSO
[thirdparty/glibc.git] / malloc / mcheck.c
index c67636c2893d36f3a9ad8865bbf537d846ae99c0..1e68cedbf58e03abcf14c0c711eb41220f7d3315 100644 (file)
@@ -1,5 +1,5 @@
 /* Standard debugging hooks for `malloc'.
-   Copyright (C) 1990-1997,99,2000,01,02 Free Software Foundation, Inc.
+   Copyright (C) 1990-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written May 1989 by Mike Haertel.
 
    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, write to the Free
-   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-   02111-1307 USA.  */
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
 
-#ifndef        _MALLOC_INTERNAL
+#ifndef _MALLOC_INTERNAL
 # define _MALLOC_INTERNAL
 # include <malloc.h>
+# include <malloc-size.h>
 # include <mcheck.h>
 # include <stdint.h>
 # include <stdio.h>
 # include <libintl.h>
+# include <errno.h>
+# include <malloc-internal.h>
 #endif
 
 /* Old hook values.  */
-static void (*old_free_hook) __P ((__ptr_t ptr, __const __ptr_t));
-static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size, const __ptr_t));
-static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size,
-                                        __const __ptr_t));
+static void (*old_free_hook)(void *ptr, const void *);
+static void *(*old_malloc_hook) (size_t size, const void *);
+static void *(*old_memalign_hook) (size_t alignment, size_t size,
+                                  const void *);
+static void *(*old_realloc_hook) (void *ptr, size_t size,
+                                 const void *);
 
 /* Function to call when something awful happens.  */
-static void (*abortfunc) __P ((enum mcheck_status));
+static void (*abortfunc) (enum mcheck_status);
 
 /* Arbitrary magical numbers.  */
-#define MAGICWORD      0xfedabeeb
-#define MAGICFREE      0xd8675309
-#define MAGICBYTE      ((char) 0xd7)
-#define MALLOCFLOOD    ((char) 0x93)
-#define FREEFLOOD      ((char) 0x95)
+#define MAGICWORD       0xfedabeeb
+#define MAGICFREE       0xd8675309
+#define MAGICBYTE       ((char) 0xd7)
+#define MALLOCFLOOD     ((char) 0x93)
+#define FREEFLOOD       ((char) 0x95)
 
 struct hdr
-  {
-    __malloc_size_t size;      /* Exact size requested by user.  */
-    unsigned long int magic;   /* Magic number to check header integrity.  */
-    struct hdr *prev;
-    struct hdr *next;
-  };
+{
+  size_t size;                  /* Exact size requested by user.  */
+  unsigned long int magic;      /* Magic number to check header integrity.  */
+  struct hdr *prev;
+  struct hdr *next;
+  void *block;                  /* Real block allocated, for memalign.  */
+  unsigned long int magic2;     /* Extra, keeps us doubleword aligned.  */
+} __attribute__ ((aligned (MALLOC_ALIGNMENT)));
 
 /* This is the beginning of the list of all memory blocks allocated.
    It is only constructed if the pedantic testing is requested.  */
@@ -64,12 +70,9 @@ static int pedantic;
 # include <string.h>
 # define flood memset
 #else
-static void flood __P ((__ptr_t, int, __malloc_size_t));
+static void flood (void *, int, size_t);
 static void
-flood (ptr, val, size)
-     __ptr_t ptr;
-     int val;
-     __malloc_size_t size;
+flood (void *ptr, int val, size_t size)
 {
   char *cp = ptr;
   while (size--)
@@ -77,10 +80,8 @@ flood (ptr, val, size)
 }
 #endif
 
-static enum mcheck_status checkhdr __P ((const struct hdr *));
 static enum mcheck_status
-checkhdr (hdr)
-     const struct hdr *hdr;
+checkhdr (const struct hdr *hdr)
 {
   enum mcheck_status status;
 
@@ -99,9 +100,11 @@ checkhdr (hdr)
       break;
     case MAGICWORD:
       if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
-       status = MCHECK_TAIL;
+        status = MCHECK_TAIL;
+      else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
+        status = MCHECK_HEAD;
       else
-       status = MCHECK_OK;
+        status = MCHECK_OK;
       break;
     }
   if (status != MCHECK_OK)
@@ -114,9 +117,9 @@ checkhdr (hdr)
 }
 
 void
-mcheck_check_all ()
+mcheck_check_all (void)
 {
-  /* Walk through all the active blocks and test whether they were tempered
+  /* Walk through all the active blocks and test whether they were tampered
      with.  */
   struct hdr *runp = root;
 
@@ -137,31 +140,27 @@ mcheck_check_all ()
 libc_hidden_def (mcheck_check_all)
 #endif
 
-static void unlink_blk __P ((struct hdr *ptr));
 static void
-unlink_blk (ptr)
-     struct hdr *ptr;
+unlink_blk (struct hdr *ptr)
 {
   if (ptr->next != NULL)
     {
       ptr->next->prev = ptr->prev;
       ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
-                                     + (uintptr_t) ptr->next->next);
+                                      + (uintptr_t) ptr->next->next);
     }
   if (ptr->prev != NULL)
     {
       ptr->prev->next = ptr->next;
       ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
-                                     + (uintptr_t) ptr->prev->next);
+                                      + (uintptr_t) ptr->prev->next);
     }
   else
     root = ptr->next;
 }
 
-static void link_blk  __P ((struct hdr *ptr));
 static void
-link_blk (hdr)
-     struct hdr *hdr;
+link_blk (struct hdr *hdr)
 {
   hdr->prev = NULL;
   hdr->next = root;
@@ -173,15 +172,11 @@ link_blk (hdr)
     {
       hdr->next->prev = hdr;
       hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
-                                     + (uintptr_t) hdr->next->next);
+                                      + (uintptr_t) hdr->next->next);
     }
 }
-
-static void freehook __P ((__ptr_t, const __ptr_t));
 static void
-freehook (ptr, caller)
-     __ptr_t ptr;
-     const __ptr_t caller;
+freehook (void *ptr, const void *caller)
 {
   if (pedantic)
     mcheck_check_all ();
@@ -190,34 +185,38 @@ freehook (ptr, caller)
       struct hdr *hdr = ((struct hdr *) ptr) - 1;
       checkhdr (hdr);
       hdr->magic = MAGICFREE;
+      hdr->magic2 = MAGICFREE;
       unlink_blk (hdr);
       hdr->prev = hdr->next = NULL;
       flood (ptr, FREEFLOOD, hdr->size);
-      ptr = (__ptr_t) hdr;
+      ptr = hdr->block;
     }
   __free_hook = old_free_hook;
   if (old_free_hook != NULL)
-    (*old_free_hook) (ptr, caller);
+    (*old_free_hook)(ptr, caller);
   else
     free (ptr);
   __free_hook = freehook;
 }
 
-static __ptr_t mallochook __P ((__malloc_size_t, const __ptr_t));
-static __ptr_t
-mallochook (size, caller)
-     __malloc_size_t size;
-     const __ptr_t caller;
+static void *
+mallochook (size_t size, const void *caller)
 {
   struct hdr *hdr;
 
   if (pedantic)
     mcheck_check_all ();
 
+  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
   __malloc_hook = old_malloc_hook;
   if (old_malloc_hook != NULL)
-    hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
-                                            caller);
+    hdr = (struct hdr *) (*old_malloc_hook)(sizeof (struct hdr) + size + 1,
+                                            caller);
   else
     hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
   __malloc_hook = mallochook;
@@ -226,24 +225,73 @@ mallochook (size, caller)
 
   hdr->size = size;
   link_blk (hdr);
+  hdr->block = hdr;
+  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
   ((char *) &hdr[1])[size] = MAGICBYTE;
-  flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
-  return (__ptr_t) (hdr + 1);
+  flood ((void *) (hdr + 1), MALLOCFLOOD, size);
+  return (void *) (hdr + 1);
 }
 
-static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
-static __ptr_t
-reallochook (ptr, size, caller)
-     __ptr_t ptr;
-     __malloc_size_t size;
-     const __ptr_t caller;
+static void *
+memalignhook (size_t alignment, size_t size,
+              const void *caller)
 {
   struct hdr *hdr;
-  __malloc_size_t osize;
+  size_t slop;
+  char *block;
 
   if (pedantic)
     mcheck_check_all ();
 
+  slop = (sizeof *hdr + alignment - 1) & - alignment;
+
+  if (size > ~((size_t) 0) - (slop + 1))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
+  __memalign_hook = old_memalign_hook;
+  if (old_memalign_hook != NULL)
+    block = (*old_memalign_hook)(alignment, slop + size + 1, caller);
+  else
+    block = memalign (alignment, slop + size + 1);
+  __memalign_hook = memalignhook;
+  if (block == NULL)
+    return NULL;
+
+  hdr = ((struct hdr *) (block + slop)) - 1;
+
+  hdr->size = size;
+  link_blk (hdr);
+  hdr->block = (void *) block;
+  hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
+  ((char *) &hdr[1])[size] = MAGICBYTE;
+  flood ((void *) (hdr + 1), MALLOCFLOOD, size);
+  return (void *) (hdr + 1);
+}
+
+static void *
+reallochook (void *ptr, size_t size, const void *caller)
+{
+  if (size == 0)
+    {
+      freehook (ptr, caller);
+      return NULL;
+    }
+
+  struct hdr *hdr;
+  size_t osize;
+
+  if (pedantic)
+    mcheck_check_all ();
+
+  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
   if (ptr)
     {
       hdr = ((struct hdr *) ptr) - 1;
@@ -252,7 +300,7 @@ reallochook (ptr, size, caller)
       checkhdr (hdr);
       unlink_blk (hdr);
       if (size < osize)
-       flood ((char *) ptr + size, FREEFLOOD, osize - size);
+        flood ((char *) ptr + size, FREEFLOOD, osize - size);
     }
   else
     {
@@ -261,51 +309,53 @@ reallochook (ptr, size, caller)
     }
   __free_hook = old_free_hook;
   __malloc_hook = old_malloc_hook;
+  __memalign_hook = old_memalign_hook;
   __realloc_hook = old_realloc_hook;
   if (old_realloc_hook != NULL)
-    hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
-                                             sizeof (struct hdr) + size + 1,
-                                             caller);
+    hdr = (struct hdr *) (*old_realloc_hook)((void *) hdr,
+                                             sizeof (struct hdr) + size + 1,
+                                             caller);
   else
-    hdr = (struct hdr *) realloc ((__ptr_t) hdr,
-                                 sizeof (struct hdr) + size + 1);
+    hdr = (struct hdr *) realloc ((void *) hdr,
+                                  sizeof (struct hdr) + size + 1);
   __free_hook = freehook;
   __malloc_hook = mallochook;
+  __memalign_hook = memalignhook;
   __realloc_hook = reallochook;
   if (hdr == NULL)
     return NULL;
 
   hdr->size = size;
   link_blk (hdr);
+  hdr->block = hdr;
+  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
   ((char *) &hdr[1])[size] = MAGICBYTE;
   if (size > osize)
     flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
-  return (__ptr_t) (hdr + 1);
+  return (void *) (hdr + 1);
 }
 
-static void mabort __P ((enum mcheck_status status))
-     __attribute__ ((noreturn));
+__attribute__ ((noreturn))
 static void
-mabort (status)
-     enum mcheck_status status;
+mabort (enum mcheck_status status)
 {
   const char *msg;
   switch (status)
     {
     case MCHECK_OK:
-      msg = _("memory is consistent, library is buggy\n");
+      msg = _ ("memory is consistent, library is buggy\n");
       break;
     case MCHECK_HEAD:
-      msg = _("memory clobbered before allocated block\n");
+      msg = _ ("memory clobbered before allocated block\n");
       break;
     case MCHECK_TAIL:
-      msg = _("memory clobbered past end of allocated block\n");
+      msg = _ ("memory clobbered past end of allocated block\n");
       break;
     case MCHECK_FREE:
-      msg = _("block freed twice\n");
+      msg = _ ("block freed twice\n");
       break;
     default:
-      msg = _("bogus mcheck_status, library is buggy\n");
+      msg = _ ("bogus mcheck_status, library is buggy\n");
       break;
     }
 #ifdef _LIBC
@@ -317,9 +367,12 @@ mabort (status)
 #endif
 }
 
+/* Memory barrier so that GCC does not optimize out the argument.  */
+#define malloc_opt_barrier(x) \
+  ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
+
 int
-mcheck (func)
-     void (*func) __P ((enum mcheck_status));
+mcheck (void (*func) (enum mcheck_status))
 {
   abortfunc = (func != NULL) ? func : &mabort;
 
@@ -328,12 +381,16 @@ mcheck (func)
     {
       /* We call malloc() once here to ensure it is initialized.  */
       void *p = malloc (0);
+      /* GCC might optimize out the malloc/free pair without a barrier.  */
+      p = malloc_opt_barrier (p);
       free (p);
 
       old_free_hook = __free_hook;
       __free_hook = freehook;
       old_malloc_hook = __malloc_hook;
       __malloc_hook = mallochook;
+      old_memalign_hook = __memalign_hook;
+      __memalign_hook = memalignhook;
       old_realloc_hook = __realloc_hook;
       __realloc_hook = reallochook;
       mcheck_used = 1;
@@ -346,8 +403,7 @@ libc_hidden_def (mcheck)
 #endif
 
 int
-mcheck_pedantic (func)
-      void (*func) __P ((enum mcheck_status));
+mcheck_pedantic (void (*func) (enum mcheck_status))
 {
   int res = mcheck (func);
   if (res == 0)
@@ -356,7 +412,7 @@ mcheck_pedantic (func)
 }
 
 enum mcheck_status
-mprobe (__ptr_t ptr)
+mprobe (void *ptr)
 {
   return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
 }