@@ -3,9 +3,5 @@
#include <malloc/mcheck.h>
# ifndef _ISOMAC
-
-libc_hidden_proto (mcheck)
-libc_hidden_proto (mcheck_check_all)
-
# endif /* !_ISOMAC */
#endif
@@ -90,9 +90,6 @@ tests-exclude-mcheck = tst-mallocstate \
tst-malloc-thread-fail \
tst-malloc-usable-tunables \
tst-malloc_info \
- tst-memalign \
- tst-posix_memalign \
- tst-posix-realloc \
tst-compathooks-off tst-compathooks-on
tests-mcheck = $(filter-out $(tests-exclude-mcheck), $(tests))
@@ -59,7 +59,6 @@ generic_hook_ini (void)
if (hook != NULL)
(*hook)();
#endif
- __malloc_initialized = 1;
}
static void *
@@ -43,6 +43,35 @@ DEBUG_FN(valloc);
DEBUG_FN(pvalloc);
DEBUG_FN(calloc);
+static bool malloc_called;
+
+enum malloc_debug_hooks
+{
+ MALLOC_NONE_HOOK = 0,
+ MALLOC_MCHECK_HOOK = 1 << 0, /* mcheck() */
+};
+static unsigned __malloc_debugging_hooks;
+
+static __always_inline bool
+__is_malloc_debug_enabled (enum malloc_debug_hooks flag)
+{
+ return __malloc_debugging_hooks & flag;
+}
+
+static __always_inline void
+__malloc_debug_enable (enum malloc_debug_hooks flag)
+{
+ __malloc_debugging_hooks |= flag;
+}
+
+static __always_inline void
+__malloc_debug_disable (enum malloc_debug_hooks flag)
+{
+ __malloc_debugging_hooks &= ~flag;
+}
+
+#include "mcheck.c"
+
extern void (*__free_hook) (void *, const void *);
compat_symbol_reference (libc, __free_hook, __free_hook, GLIBC_2_0);
extern void * (*__malloc_hook) (size_t, const void *);
@@ -63,7 +92,19 @@ __debug_malloc (size_t bytes)
if (__builtin_expect (hook != NULL, 0))
return (*hook)(bytes, RETURN_ADDRESS (0));
- return __libc_malloc (bytes);
+ malloc_called = true;
+
+ void *victim = NULL;
+ size_t orig_bytes = bytes;
+ if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ || !malloc_mcheck_before (&bytes, &victim))
+ {
+ victim = __libc_malloc (bytes);
+ }
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && victim != NULL)
+ victim = malloc_mcheck_after (victim, orig_bytes);
+
+ return victim;
}
strong_alias (__debug_malloc, malloc)
@@ -76,6 +117,10 @@ __debug_free (void *mem)
(*hook)(mem, RETURN_ADDRESS (0));
return;
}
+
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ mem = free_mcheck (mem);
+
__libc_free (mem);
}
strong_alias (__debug_free, free)
@@ -88,7 +133,21 @@ __debug_realloc (void *oldmem, size_t bytes)
if (__builtin_expect (hook != NULL, 0))
return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
- return __libc_realloc (oldmem, bytes);
+ malloc_called = true;
+
+ size_t orig_bytes = bytes, oldsize = 0;
+ void *victim = NULL;
+
+ if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ || !realloc_mcheck_before (&oldmem, &bytes, &oldsize, &victim))
+ {
+ victim = __libc_realloc (oldmem, bytes);
+ }
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && victim != NULL)
+ victim = realloc_mcheck_after (victim, oldmem, orig_bytes,
+ oldsize);
+
+ return victim;
}
strong_alias (__debug_realloc, realloc)
@@ -100,7 +159,20 @@ _mid_memalign (size_t alignment, size_t bytes, const void *address)
if (__builtin_expect (hook != NULL, 0))
return (*hook)(alignment, bytes, address);
- return __libc_memalign (alignment, bytes);
+ malloc_called = true;
+
+ void *victim = NULL;
+ size_t orig_bytes = bytes;
+
+ if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ || !memalign_mcheck_before (alignment, &bytes, &victim))
+ {
+ victim = __libc_memalign (alignment, bytes);
+ }
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && victim != NULL)
+ victim = memalign_mcheck_after (victim, alignment, orig_bytes);
+
+ return victim;
}
static void *
@@ -165,17 +237,17 @@ strong_alias (__debug_posix_memalign, posix_memalign)
static void *
__debug_calloc (size_t nmemb, size_t size)
{
+ size_t bytes;
+
+ if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes)))
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+
void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
{
- size_t bytes;
-
- if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes)))
- {
- errno = ENOMEM;
- return NULL;
- }
-
void *mem = (*hook)(bytes, RETURN_ADDRESS (0));
if (mem != NULL)
@@ -184,6 +256,22 @@ __debug_calloc (size_t nmemb, size_t size)
return mem;
}
- return __libc_calloc (nmemb, size);
+ malloc_called = true;
+
+ size_t orig_bytes = bytes;
+ void *victim = NULL;
+
+ if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ || !malloc_mcheck_before (&bytes, &victim))
+ {
+ victim = __libc_malloc (bytes);
+ }
+ if (victim != NULL)
+ {
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ victim = malloc_mcheck_after (victim, orig_bytes);
+ memset (victim, 0, orig_bytes);
+ }
+ return victim;
}
strong_alias (__debug_calloc, calloc)
new file mode 100644
@@ -0,0 +1,406 @@
+/* mcheck debugging hooks for malloc.
+ Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written May 1989 by Mike Haertel.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ 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, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <malloc-internal.h>
+#include <mcheck.h>
+#include <libintl.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/* Arbitrary magical numbers. */
+#define MAGICWORD 0xfedabeeb
+#define MAGICFREE 0xd8675309
+#define MAGICBYTE ((char) 0xd7)
+#define MALLOCFLOOD ((char) 0x93)
+#define FREEFLOOD ((char) 0x95)
+
+/* Function to call when something awful happens. */
+static void (*abortfunc) (enum mcheck_status);
+
+struct hdr
+{
+ 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. */
+};
+
+/* This is the beginning of the list of all memory blocks allocated.
+ It is only constructed if the pedantic testing is requested. */
+static struct hdr *__mcheck_root;
+
+/* Nonzero if pedentic checking of all blocks is requested. */
+static bool pedantic;
+
+#if defined _LIBC || defined STDC_HEADERS || defined USG
+# include <string.h>
+# define flood memset
+#else
+static void flood (void *, int, size_t);
+static void
+flood (void *ptr, int val, size_t size)
+{
+ char *cp = ptr;
+ while (size--)
+ *cp++ = val;
+}
+#endif
+
+static enum mcheck_status
+checkhdr (const struct hdr *hdr)
+{
+ enum mcheck_status status;
+ bool mcheck_used = __is_malloc_debug_enabled (MALLOC_MCHECK_HOOK);
+
+ if (!mcheck_used)
+ /* Maybe the mcheck used is disabled? This happens when we find
+ an error and report it. */
+ return MCHECK_OK;
+
+ switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
+ {
+ default:
+ status = MCHECK_HEAD;
+ break;
+ case MAGICFREE:
+ status = MCHECK_FREE;
+ break;
+ case MAGICWORD:
+ if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
+ status = MCHECK_TAIL;
+ else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
+ status = MCHECK_HEAD;
+ else
+ status = MCHECK_OK;
+ break;
+ }
+ if (status != MCHECK_OK)
+ {
+ mcheck_used = 0;
+ (*abortfunc) (status);
+ mcheck_used = 1;
+ }
+ return status;
+}
+
+static enum mcheck_status
+__mcheck_checkptr (const void *ptr)
+{
+ if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ return MCHECK_DISABLED;
+
+ if (ptr != NULL)
+ return checkhdr (((struct hdr *) ptr) - 1);
+
+ /* Walk through all the active blocks and test whether they were tampered
+ with. */
+ struct hdr *runp = __mcheck_root;
+
+ /* Temporarily turn off the checks. */
+ pedantic = false;
+
+ while (runp != NULL)
+ {
+ (void) checkhdr (runp);
+
+ runp = runp->next;
+ }
+
+ /* Turn checks on again. */
+ pedantic = true;
+
+ return MCHECK_OK;
+}
+
+static void
+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);
+ }
+ if (ptr->prev != NULL)
+ {
+ ptr->prev->next = ptr->next;
+ ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
+ + (uintptr_t) ptr->prev->next);
+ }
+ else
+ __mcheck_root = ptr->next;
+}
+
+static void
+link_blk (struct hdr *hdr)
+{
+ hdr->prev = NULL;
+ hdr->next = __mcheck_root;
+ __mcheck_root = hdr;
+ hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
+
+ /* And the next block. */
+ if (hdr->next != NULL)
+ {
+ hdr->next->prev = hdr;
+ hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
+ + (uintptr_t) hdr->next->next);
+ }
+}
+
+static void *
+free_mcheck (void *ptr)
+{
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+ if (ptr)
+ {
+ 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 = hdr->block;
+ }
+ return ptr;
+}
+
+static bool
+malloc_mcheck_before (size_t *sizep, void **victimp)
+{
+ size_t size = *sizep;
+
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+
+ if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+ {
+ __set_errno (ENOMEM);
+ *victimp = NULL;
+ return true;
+ }
+
+ *sizep = sizeof (struct hdr) + size + 1;
+ return false;
+}
+
+static void *
+malloc_mcheck_after (void *mem, size_t size)
+{
+ struct hdr *hdr = mem;
+
+ 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;
+ flood ((void *) (hdr + 1), MALLOCFLOOD, size);
+ return (void *) (hdr + 1);
+}
+
+static bool
+memalign_mcheck_before (size_t alignment, size_t *sizep, void **victimp)
+{
+ struct hdr *hdr;
+ size_t slop, size = *sizep;
+
+ /* Punt to malloc to avoid double headers. */
+ if (alignment <= MALLOC_ALIGNMENT)
+ {
+ *victimp = __debug_malloc (size);
+ return true;
+ }
+
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+
+ slop = (sizeof *hdr + alignment - 1) & - alignment;
+
+ if (size > ~((size_t) 0) - (slop + 1))
+ {
+ __set_errno (ENOMEM);
+ *victimp = NULL;
+ return true;
+ }
+
+ *sizep = slop + size + 1;
+ return false;
+}
+
+static void *
+memalign_mcheck_after (void *block, size_t alignment, size_t size)
+{
+ if (block == NULL)
+ return NULL;
+
+ /* This was served by __debug_malloc, so return as is. */
+ if (alignment <= MALLOC_ALIGNMENT)
+ return block;
+
+ size_t slop = (sizeof (struct hdr) + alignment - 1) & - alignment;
+ struct hdr *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 bool
+realloc_mcheck_before (void **ptrp, size_t *sizep, size_t *oldsize,
+ void **victimp)
+{
+ size_t size = *sizep;
+ void *ptr = *ptrp;
+
+ if (ptr == NULL)
+ {
+ *victimp = __debug_malloc (size);
+ *oldsize = 0;
+ return true;
+ }
+
+ if (size == 0)
+ {
+ __debug_free (ptr);
+ *victimp = NULL;
+ return true;
+ }
+
+ if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+ {
+ __set_errno (ENOMEM);
+ *victimp = NULL;
+ *oldsize = 0;
+ return true;
+ }
+
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+
+ struct hdr *hdr;
+ size_t osize;
+
+ /* Update the oldptr for glibc realloc. */
+ *ptrp = hdr = ((struct hdr *) ptr) - 1;
+
+ osize = hdr->size;
+
+ checkhdr (hdr);
+ unlink_blk (hdr);
+ if (size < osize)
+ flood ((char *) ptr + size, FREEFLOOD, osize - size);
+
+ *oldsize = osize;
+ *sizep = sizeof (struct hdr) + size + 1;
+ return false;
+}
+
+static void *
+realloc_mcheck_after (void *ptr, void *oldptr, size_t size, size_t osize)
+{
+ struct hdr *hdr = ptr;
+
+ if (hdr == NULL)
+ return NULL;
+
+ /* Malloc already added the header so don't tamper with it. */
+ if (oldptr == NULL)
+ return ptr;
+
+ 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 (void *) (hdr + 1);
+}
+
+__attribute__ ((noreturn))
+static void
+mabort (enum mcheck_status status)
+{
+ const char *msg;
+ switch (status)
+ {
+ case MCHECK_OK:
+ msg = _ ("memory is consistent, library is buggy\n");
+ break;
+ case MCHECK_HEAD:
+ msg = _ ("memory clobbered before allocated block\n");
+ break;
+ case MCHECK_TAIL:
+ msg = _ ("memory clobbered past end of allocated block\n");
+ break;
+ case MCHECK_FREE:
+ msg = _ ("block freed twice\n");
+ break;
+ default:
+ msg = _ ("bogus mcheck_status, library is buggy\n");
+ break;
+ }
+#ifdef _LIBC
+ __libc_fatal (msg);
+#else
+ fprintf (stderr, "mcheck: %s", msg);
+ fflush (stderr);
+ abort ();
+#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; })
+
+static int
+__mcheck_initialize (void (*func) (enum mcheck_status), bool in_pedantic)
+{
+ abortfunc = (func != NULL) ? func : &mabort;
+
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ goto out;
+
+ /* There was a call to malloc before this initializer was called. */
+ if (malloc_called)
+ return -1;
+
+ /* 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);
+ /* FALLTHROUGH */
+ __malloc_debug_enable (MALLOC_MCHECK_HOOK);
+
+out:
+ pedantic = in_pedantic;
+ return 0;
+}
@@ -1,4 +1,4 @@
-/* Standard debugging hooks for `malloc'.
+/* The mcheck() interface.
Copyright (C) 1990-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written May 1989 by Mike Haertel.
@@ -17,401 +17,46 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#ifndef _MALLOC_INTERNAL
-# define _MALLOC_INTERNAL
-# include <malloc.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)(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) (enum mcheck_status);
-
-/* Arbitrary magical numbers. */
-#define MAGICWORD 0xfedabeeb
-#define MAGICFREE 0xd8675309
-#define MAGICBYTE ((char) 0xd7)
-#define MALLOCFLOOD ((char) 0x93)
-#define FREEFLOOD ((char) 0x95)
-
-struct hdr
-{
- 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. */
-};
-
-/* This is the beginning of the list of all memory blocks allocated.
- It is only constructed if the pedantic testing is requested. */
-static struct hdr *root;
-
-static int mcheck_used;
-
-/* Nonzero if pedentic checking of all blocks is requested. */
-static int pedantic;
-
-#if defined _LIBC || defined STDC_HEADERS || defined USG
-# include <string.h>
-# define flood memset
+#if !IS_IN (libc)
+# include "mcheck-impl.c"
#else
-static void flood (void *, int, size_t);
-static void
-flood (void *ptr, int val, size_t size)
-{
- char *cp = ptr;
- while (size--)
- *cp++ = val;
-}
+# include <mcheck.h>
#endif
-static enum mcheck_status
-checkhdr (const struct hdr *hdr)
-{
- enum mcheck_status status;
-
- if (!mcheck_used)
- /* Maybe the mcheck used is disabled? This happens when we find
- an error and report it. */
- return MCHECK_OK;
-
- switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
- {
- default:
- status = MCHECK_HEAD;
- break;
- case MAGICFREE:
- status = MCHECK_FREE;
- break;
- case MAGICWORD:
- if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
- status = MCHECK_TAIL;
- else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
- status = MCHECK_HEAD;
- else
- status = MCHECK_OK;
- break;
- }
- if (status != MCHECK_OK)
- {
- mcheck_used = 0;
- (*abortfunc) (status);
- mcheck_used = 1;
- }
- return status;
-}
-
void
mcheck_check_all (void)
{
- /* Walk through all the active blocks and test whether they were tampered
- with. */
- struct hdr *runp = root;
-
- /* Temporarily turn off the checks. */
- pedantic = 0;
-
- while (runp != NULL)
- {
- (void) checkhdr (runp);
-
- runp = runp->next;
- }
-
- /* Turn checks on again. */
- pedantic = 1;
-}
-#ifdef _LIBC
-libc_hidden_def (mcheck_check_all)
+#if !IS_IN (libc)
+ __mcheck_checkptr (NULL);
#endif
-
-static void
-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);
- }
- if (ptr->prev != NULL)
- {
- ptr->prev->next = ptr->next;
- ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
- + (uintptr_t) ptr->prev->next);
- }
- else
- root = ptr->next;
-}
-
-static void
-link_blk (struct hdr *hdr)
-{
- hdr->prev = NULL;
- hdr->next = root;
- root = hdr;
- hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
-
- /* And the next block. */
- if (hdr->next != NULL)
- {
- hdr->next->prev = hdr;
- hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
- + (uintptr_t) hdr->next->next);
- }
}
-static void
-freehook (void *ptr, const void *caller)
-{
- if (pedantic)
- mcheck_check_all ();
- if (ptr)
- {
- 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 = hdr->block;
- }
- __free_hook = old_free_hook;
- if (old_free_hook != NULL)
- (*old_free_hook)(ptr, caller);
- else
- free (ptr);
- __free_hook = freehook;
-}
-
-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);
- else
- hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
- __malloc_hook = mallochook;
- 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;
- flood ((void *) (hdr + 1), MALLOCFLOOD, size);
- return (void *) (hdr + 1);
-}
-
-static void *
-memalignhook (size_t alignment, size_t size,
- const void *caller)
-{
- struct hdr *hdr;
- 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;
- osize = hdr->size;
-
- checkhdr (hdr);
- unlink_blk (hdr);
- if (size < osize)
- flood ((char *) ptr + size, FREEFLOOD, osize - size);
- }
- else
- {
- osize = 0;
- hdr = NULL;
- }
- __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)((void *) hdr,
- sizeof (struct hdr) + size + 1,
- caller);
- else
- 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 (void *) (hdr + 1);
-}
-
-__attribute__ ((noreturn))
-static void
-mabort (enum mcheck_status status)
-{
- const char *msg;
- switch (status)
- {
- case MCHECK_OK:
- msg = _ ("memory is consistent, library is buggy\n");
- break;
- case MCHECK_HEAD:
- msg = _ ("memory clobbered before allocated block\n");
- break;
- case MCHECK_TAIL:
- msg = _ ("memory clobbered past end of allocated block\n");
- break;
- case MCHECK_FREE:
- msg = _ ("block freed twice\n");
- break;
- default:
- msg = _ ("bogus mcheck_status, library is buggy\n");
- break;
- }
-#ifdef _LIBC
- __libc_fatal (msg);
-#else
- fprintf (stderr, "mcheck: %s", msg);
- fflush (stderr);
- abort ();
-#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 (void (*func) (enum mcheck_status))
{
- abortfunc = (func != NULL) ? func : &mabort;
-
- /* These hooks may not be safely inserted if malloc is already in use. */
- if (__malloc_initialized <= 0 && !mcheck_used)
- {
- /* 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;
- }
-
- return mcheck_used ? 0 : -1;
-}
-#ifdef _LIBC
-libc_hidden_def (mcheck)
+#if IS_IN (libc)
+ return -1;
+#else
+ return __mcheck_initialize (func, false);
#endif
+}
int
mcheck_pedantic (void (*func) (enum mcheck_status))
{
- int res = mcheck (func);
- if (res == 0)
- pedantic = 1;
- return res;
+#if IS_IN (libc)
+ return -1;
+#else
+ return __mcheck_initialize (func, true);
+#endif
}
enum mcheck_status
mprobe (void *ptr)
{
- return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+#if IS_IN (libc)
+ return MCHECK_DISABLED;
+#else
+ return __mcheck_checkptr (ptr);
+#endif
}