diff mbox series

RFC: Removing malloc hooks

Message ID xnbmeyjlho.fsf@greed.delorie.com
State New
Headers show
Series RFC: Removing malloc hooks | expand

Commit Message

DJ Delorie April 5, 2018, 5 a.m. UTC
This fairly large and intrusive patch has the goal of removing the
malloc hook infrastructure from libc.so.  Removing these should
improve the security, performance, and maintainability of glibc's
malloc.

For users who require these hooks, or the services behind them (mcheck
& mtrace), the hooks are re-implemented in a separate .so that can be
prelinked via LD_PRELOAD.  This new .so interposes the malloc API and
implements the hook functionality.  Most of the intrusiveness of this
patch involves preloading this .so for relevent tests.

One drawback of this change is that statically linked programs can no
longer use the hooks, or the hook-based functions like mcheck and
mtrace.  The intrusiveness of this patch includes disabling those
tests throughout glibc that test for leaks when statically linked.  I
think the benefits outweigh this drawback, but I'm open for debate on
it :-) (I think a statically-linked interposer is possible, but
probably not worth the effort)

This patch also demonstrates some of the nuances of interposing
malloc, esp how to call dlfcn (which calls calloc) to interpose calloc
itself.

Tested on x86-64.

	* Makeconfig (built-modules): Add libmalloc-extras.
	* catgets/Makefile (tst-catgets-ENV): Preload libmalloc-extras.so.
	* elf/Makefile (tst-leaks1-static-mem): Skip, we can't interpose
	malloc when statically linking.
	(noload-ENV): Preload libmalloc-extras.so.
	(tst-leaks1-ENV): Likewise.
	* iconvdata/Makefile (tst-loading-ENV): Likewise.
	* intl/tst-gettext.sh: Likewise.
	* libio/Makefile (test-fmemopen-ENV): Likewise.
	(tst-fopenloc-ENV): Likewise.
	(tst-bz22415-ENV): Likewise.
	* localedata/Makefile (tst-leaks-ENV): Likewise.
	* misc/Makefile (tst-error1-ENV): Likewise.
	* nptl/Makefile (tst-atfork2-ENV): Likewise.
	(tst-stack3-ENV): Likewise.
	* posix/Makefile (tst-fnmatch-ENV): Likewise.
	(bug-regex2-ENV): Likewise.
	(bug-regex14-ENV): Likewise.
	(bug-regex21-ENV): Likewise.
	(bug-regex31-ENV): Likewise.
	(bug-regex36-ENV): Likewise.
	(tst-vfork3-ENV): Likewise.
	(tst-rxspencer-no-utf8-ENV): Likewise.
	(tst-pcre-ENV): Likewise.
	(tst-boost-ENV): Likewise.
	(bug-ga2-ENV): Likewise.
	(bug-glob2-ENV): Likewise.
	(tst-glob-tilde-ENV): Likewise.
	* posix/tst-vfork3.c (do_prepare): Unset LD_PRELOAD.
	* resolv/Makefile (tst-leaks-ENV): Preload libmalloc-extras.so.
	(tst-leaks2-ENV): Likewise.
	(tst-resolv-res_ninit-ENV): Likewise.
	* stdio-common/Makefile (tst-printf-bz18872-ENV): Likewise.
	(tst-vfprintf-width-prec-ENV): Likewise.

	* malloc/Makefile (tests-static): Remove tst-malloc-usable-static,
	we can't interpose malloc when static linking.
	(tst-malloc-usable-tunables): Likewise.
	(tst-malloc-usable-tunables-static): Likewise.
	(extra-libs): Add libmalloc-extras.
	(libmalloc-extras-routines): New.
	(LDLIBS-libmalloc-extras.so): New.
	(LDFLAGS-malloc-extras.so): New.
	($(objpfx)libmalloc-extras.so): New.
	(tst-mtrace-ENV): Preload libmalloc-extras.so.
	(tst-malloc-usable-ENV): Likewise.
	(tst-malloc-usable-tunables-ENV): Likewise.
	(tst-dynarray-ENV): Likewise.
	(tst-dynarray-fail-ENV): Likewise.
	* malloc/Versions (__glibc_mtrace_hook): New.
	(__glibc_mtrace_hook_enabled): New.
	* malloc/hooks.c (malloc_hook_ini): Call interposable malloc.
	(realloc_hook_ini): Call interposable realloc.
	(memalign_hook_ini): Call interposable memalign.
	* malloc/malloc-extras.c: New.
	* malloc/malloc.c: Remove all hook-related code.
	(__libc_malloc): Call ptmalloc_init().
	(__libc_free): Likewise.
	(__libc_realloc): Likewise.
	(__libc_calloc): Likewise.
	* malloc/mcheck.c: Remove most code, leaving an empty ABI.
	* malloc/mtrace.c: Likewise.
	* malloc/tst-mtrace.sh: Preload libmalloc-extras.so.

Comments

Joseph Myers April 17, 2018, 7:54 p.m. UTC | #1
On Thu, 5 Apr 2018, DJ Delorie wrote:

> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_24)
> +# define HAVE_MALLOC_HOOKS 1
> +#else
> +# define HAVE_MALLOC_HOOKS 0
> +#endif

I don't see where this 2.24 version comes from (but I also don't see 
anything using this macro).
diff mbox series

Patch

diff --git a/Makeconfig b/Makeconfig
index 1afe86475c..2c83ee252b 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -929,7 +929,7 @@  libio-include = -I$(..)libio
 built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \
 		libSegFault libpcprofile librpcsvc locale-programs \
 		memusagestat nonlib nscd extramodules libnldbl libsupport \
-		testsuite
+		testsuite libmalloc-extras
 
 in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \
 				    $(libof-$(<F)) \
diff --git a/catgets/Makefile b/catgets/Makefile
index 36f6a226c3..941e5cb4ea 100644
--- a/catgets/Makefile
+++ b/catgets/Makefile
@@ -56,7 +56,8 @@  generated += tst-catgets.mtrace tst-catgets-mem.out
 
 generated-dirs += de
 
-tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de MALLOC_TRACE=$(objpfx)tst-catgets.mtrace
+tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de MALLOC_TRACE=$(objpfx)tst-catgets.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 ifeq ($(run-built-tests),yes)
 # This test just checks whether the program produces any error or not.
diff --git a/elf/Makefile b/elf/Makefile
index 9bdb9220c7..f29f2b1e11 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -204,7 +204,7 @@  endif
 endif
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)tst-leaks1-mem.out \
-		 $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
+		 $(objpfx)noload-mem.out \
 		 $(objpfx)tst-ldconfig-X.out
 endif
 tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
@@ -802,7 +802,8 @@  $(objpfx)noload.out: $(objpfx)testobj5.so
 $(objpfx)noload-mem.out: $(objpfx)noload.out
 	$(common-objpfx)malloc/mtrace $(objpfx)noload.mtrace > $@; \
 	$(evaluate-test)
-noload-ENV = MALLOC_TRACE=$(objpfx)noload.mtrace
+noload-ENV = MALLOC_TRACE=$(objpfx)noload.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 LDFLAGS-nodelete = -rdynamic
 LDFLAGS-nodelmod1.so = -Wl,--enable-new-dtags,-z,nodelete
@@ -1206,8 +1207,10 @@  $(objpfx)tst-leaks1-static-mem.out: $(objpfx)tst-leaks1-static.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1-static.mtrace > $@; \
 	$(evaluate-test)
 
-tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace
-tst-leaks1-static-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1-static.mtrace
+tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
+tst-leaks1-static-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1-static.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)tst-addr1: $(libdl)
 
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 06e161d9b8..3930890903 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -292,7 +292,8 @@  cpp-srcs-left := $(modules) $(generated-modules) $(libJIS-routines) \
 lib := iconvdata
 include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
 
-tst-loading-ENV = MALLOC_TRACE=$(objpfx)tst-loading.mtrace
+tst-loading-ENV = MALLOC_TRACE=$(objpfx)tst-loading.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)mtrace-tst-loading.out: $(objpfx)tst-loading.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-loading.mtrace > $@; \
 	$(evaluate-test)
diff --git a/intl/tst-gettext.sh b/intl/tst-gettext.sh
index 0c65583149..c49f61586c 100755
--- a/intl/tst-gettext.sh
+++ b/intl/tst-gettext.sh
@@ -50,6 +50,7 @@  msgfmt -o ${objpfx}domaindir/existing-locale/LC_TIME/existing-time-domain.mo \
 ${test_program_prefix_before_env} \
 ${run_program_env} \
 MALLOC_TRACE=$malloc_trace \
+LD_PRELOAD=${common_objpfx}/malloc/libmalloc-extras.so \
 LOCPATH=${objpfx}localedir:${common_objpfx}localedata \
 ${test_program_prefix_after_env} \
 ${objpfx}tst-gettext > ${objpfx}tst-gettext.out ${objpfx}domaindir
diff --git a/libio/Makefile b/libio/Makefile
index cbe14a8e25..f99138dd48 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -152,9 +152,12 @@  CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
 
 tst_wprintf2-ARGS = "Some Text"
 
-test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
-tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
-tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
+test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
+tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
+tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 generated += test-fmemopen.mtrace test-fmemopen.check
 generated += tst-fopenloc.mtrace tst-fopenloc.check
diff --git a/localedata/Makefile b/localedata/Makefile
index d51064adec..71e87c88d6 100644
--- a/localedata/Makefile
+++ b/localedata/Makefile
@@ -385,7 +385,8 @@  $(INSTALL-SUPPORTED-LOCALES): install-locales-dir
 tst-setlocale-ENV = LC_ALL=ja_JP.EUC-JP
 tst-wctype-ENV = LC_ALL=ja_JP.EUC-JP
 
-tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace
+tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace \
+	LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
 $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks.mtrace > $@; \
 	$(evaluate-test)
diff --git a/malloc/Makefile b/malloc/Makefile
index 7d54bad866..dc5dd40815 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -41,8 +41,7 @@  tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 
 tests-static := \
 	 tst-interpose-static-nothread \
-	 tst-interpose-static-thread \
-	 tst-malloc-usable-static \
+	 tst-interpose-static-thread
 
 tests-internal := tst-mallocstate tst-scratch_buffer
 
@@ -53,8 +52,8 @@  tests-internal += \
 	 tst-dynarray-at-fail \
 
 ifneq (no,$(have-tunables))
-tests += tst-malloc-usable-tunables
-tests-static += tst-malloc-usable-static-tunables
+# tests += tst-malloc-usable-tunables
+# tests-static += tst-malloc-usable-static-tunables
 endif
 
 tests += $(tests-static)
@@ -78,7 +77,7 @@  install-lib := libmcheck.a
 non-lib.a := libmcheck.a
 
 # Additional library.
-extra-libs = libmemusage
+extra-libs = libmemusage libmalloc-extras
 extra-libs-others = $(extra-libs)
 
 # Helper objects for some tests.
@@ -143,6 +142,11 @@  $(objpfx)memusagestat.o: sysincludes = # nothing
 endif
 endif
 
+libmalloc-extras-routines = malloc-extras
+LDLIBS-libmalloc-extras.so = $(shared-thread-library)
+LDFLAGS-malloc-extras.so = -Wl,-z,nodelete
+$(objpfx)libmalloc-extras.so: $(libdl)
+
 # Another goal which can be used to override the configure decision.
 .PHONY: do-memusagestat
 do-memusagestat: $(objpfx)memusagestat
@@ -189,10 +193,12 @@  endif
 endif
 endif
 
+tst-mtrace-ENV = LD_PRELOAD=$(objpfx)libmalloc-extras.so
 tst-mcheck-ENV = MALLOC_CHECK_=3
-tst-malloc-usable-ENV = MALLOC_CHECK_=3
+tst-malloc-usable-ENV = MALLOC_CHECK_=3 LD_PRELOAD=$(objpfx)libmalloc-extras.so
 tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV)
-tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
+tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \
+	LD_PRELOAD=$(objdir)libmalloc-extras.so
 tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
 
 ifeq ($(experimental-malloc),yes)
@@ -239,12 +245,14 @@  $(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o
 $(objpfx)tst-interpose-static-thread: \
   $(objpfx)tst-interpose-aux-thread.o $(static-thread-library)
 
-tst-dynarray-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray.mtrace
+tst-dynarray-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)tst-dynarray-mem.out: $(objpfx)tst-dynarray.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray.mtrace > $@; \
 	$(evaluate-test)
 
-tst-dynarray-fail-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray-fail.mtrace
+tst-dynarray-fail-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray-fail.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)tst-dynarray-fail-mem.out: $(objpfx)tst-dynarray-fail.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray-fail.mtrace > $@; \
 	$(evaluate-test)
diff --git a/malloc/Versions b/malloc/Versions
index 2357cff3da..883a6a56b8 100644
--- a/malloc/Versions
+++ b/malloc/Versions
@@ -92,5 +92,8 @@  libc {
     __libc_alloc_buffer_copy_bytes;
     __libc_alloc_buffer_copy_string;
     __libc_alloc_buffer_create_failure;
+
+    __glibc_mtrace_hook;
+    __glibc_mtrace_hook_enabled;
   }
 }
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 95aefd0bfc..b35f5bf9cf 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -29,7 +29,11 @@  malloc_hook_ini (size_t sz, const void *caller)
 {
   __malloc_hook = NULL;
   ptmalloc_init ();
-  return __libc_malloc (sz);
+  /* We can't call __libc_malloc because it doesn't support hooks; we
+     have to re-call the interposed malloc which does, if it's present
+     (which it should be, else we wouldn't get here in the first
+     place.  */
+  return malloc (sz);
 }
 
 static void *
@@ -38,7 +42,7 @@  realloc_hook_ini (void *ptr, size_t sz, const void *caller)
   __malloc_hook = NULL;
   __realloc_hook = NULL;
   ptmalloc_init ();
-  return __libc_realloc (ptr, sz);
+  return realloc (ptr, sz);
 }
 
 static void *
@@ -46,7 +50,7 @@  memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
 {
   __memalign_hook = NULL;
   ptmalloc_init ();
-  return __libc_memalign (alignment, sz);
+  return memalign (alignment, sz);
 }
 
 /* Whether we are using malloc checking.  */
diff --git a/malloc/malloc-extras.c b/malloc/malloc-extras.c
new file mode 100644
index 0000000000..ccffaaac97
--- /dev/null
+++ b/malloc/malloc-extras.c
@@ -0,0 +1,814 @@ 
+/* Provide malloc hook functionality outside of libc.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <atomic.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <malloc.h>
+#include <errno.h>
+#include <libintl.h>
+#include <shlib-compat.h>
+#include <libc-internal.h>
+#include <stdarg.h>
+
+#include "malloc-internal.h"
+#include "mcheck.h"
+
+static void *(*next_malloc) (size_t) = NULL;
+static void (*next_free) (void *) = NULL;
+static void *(*next_realloc) (void *, size_t) = NULL;
+static void *(*next_calloc) (size_t, size_t) = NULL;
+static void *(*next_memalign) (size_t, size_t) = NULL;
+static size_t (*next_malloc_usable_size) (void *) = NULL;
+
+#define TRACE_BUFFER_SIZE 512
+
+static FILE *mallstream;
+static const char mallenv[] = "MALLOC_TRACE";
+static char *malloc_trace_buffer;
+
+__libc_lock_define_initialized (static, lock);
+
+#define TRACE_LOCK(caller, info)		\
+  caller = RETURN_ADDRESS (0);			\
+  dladdr (caller, &info);			\
+  __libc_lock_lock (lock);
+
+#define TRACE_LOCK_N(caller, info)		\
+  dladdr (caller, &info);			\
+  __libc_lock_lock (lock);
+
+#define TRACE_UNLOCK() \
+  __libc_lock_unlock (lock);
+
+
+/*======================================================================*/
+/* mtrace support.  */
+
+static void
+tr_where (const void *caller, Dl_info *info)
+{
+  if (caller != NULL)
+    {
+      if (info != NULL)
+        {
+	  fprintf (mallstream, "@ %s%s",
+		   info->dli_fname ? : "", info->dli_fname ? ":" : "");
+
+          if (info->dli_sname != NULL)
+            {
+	      if (caller > (const void *) info->dli_saddr)
+		fprintf (mallstream, "(%s+0x%lx)", info->dli_sname,
+			 (long unsigned)(caller - (const void *) info->dli_saddr));
+	      else
+		fprintf (mallstream, "(%s-0x%lx)", info->dli_sname,
+			 (long unsigned)((const void *) info->dli_saddr - caller));
+            }
+
+          fprintf (mallstream, "[%p] ", caller);
+        }
+      else
+        fprintf (mallstream, "@ [%p] ", caller);
+    }
+}
+
+
+/*======================================================================*/
+/* mcheck support. */
+
+/* Function to call when something awful happens.  */
+static void (*abortfunc) (enum mcheck_status);
+
+static int __malloc_extras_initialized = 0;
+
+/* 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
+//#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;
+
+  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)
+#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);
+    }
+}
+
+__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;
+  setbuf (stdout, NULL);
+
+  /* These hooks may not be safely inserted if malloc is already in use.  */
+  if (__malloc_extras_initialized <= 0 && !mcheck_used)
+    {
+      /* We call malloc () once here to ensure it is initialized.  */
+      void *p = malloc (0);
+      p = realloc (p, 16);
+      void *p2 = memalign (4, 0);
+      /* GCC might optimize out the malloc/free pair without a barrier.  */
+      p = malloc_opt_barrier (p);
+      p2 = malloc_opt_barrier (p2);
+      free (p);
+      free (p2);
+
+      mcheck_used = 1;
+    }
+
+  return mcheck_used ? 0 : -1;
+}
+#ifdef _LIBC
+libc_hidden_def (mcheck)
+#endif
+
+int
+mcheck_pedantic (void (*func) (enum mcheck_status))
+{
+  int res = mcheck (func);
+  if (res == 0)
+    pedantic = 1;
+  return res;
+}
+
+enum mcheck_status
+mprobe (void *ptr)
+{
+  return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+}
+
+/* For these, a round/align of zero means "don't".  */
+
+#define cfa() __builtin_return_address (0)
+
+#define MCHECK_PRE(size, align_ptr_to)			\
+  if (mcheck_used)							\
+    {									\
+      if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1) - align_ptr_to) \
+	{								\
+	  __set_errno (ENOMEM);						\
+	  return NULL;							\
+	}								\
+      size += align_ptr_to;						\
+      size += sizeof (struct hdr) + 1;					\
+    }
+
+
+#define MCHECK_POST_NOFLOOD(ptr, original_size, align_to)	\
+  if (mcheck_used)						\
+    {								\
+      void *block = (void *) ptr;				\
+      struct hdr *hdr = (struct hdr *) block;			\
+      ptr = (void *) (hdr + 1);					\
+      if (align_to)						\
+        {							\
+          ptr = PTR_ALIGN_UP (ptr, align_to);			\
+          hdr = (struct hdr *)ptr - 1;				\
+        }							\
+      hdr->size = original_size;				\
+      link_blk (hdr);						\
+      hdr->block = (void *) block;				\
+      hdr->magic2 = (uintptr_t) block ^ MAGICWORD;		\
+      ((char *) &hdr[1])[original_size] = MAGICBYTE;		\
+    }
+    
+
+#define MCHECK_POST(ptr, original_size, align_to)		\
+  if (mcheck_used)						\
+    {								\
+      MCHECK_POST_NOFLOOD (ptr, original_size, align_to);	\
+      flood (ptr, MALLOCFLOOD, original_size);			\
+    }
+
+#define MCHECK_PREFREE(ptr)			  \
+  if (mcheck_used && ptr != NULL)		  \
+    {						  \
+      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;				  \
+    }
+
+/*======================================================================*/
+/* mallwatch, hooks */
+
+/* Address to breakpoint on accesses to... */
+void *mallwatch = (void *) (-1);
+
+/* This function is called when the block being alloc'd, realloc'd, or
+   freed has an address matching the variable "mallwatch".  In a debugger,
+   set "mallwatch" to the address of interest, then put a breakpoint on
+   tr_break.  */
+
+extern void tr_break (void) __THROW;
+libc_hidden_proto (tr_break)
+void __attribute__ ((noinline))
+tr_break (void)
+{
+  /* Never optimize it away either.  */
+  asm ("");
+}
+libc_hidden_def (tr_break)
+
+static int recursing = 0;
+
+#define HOOK(func, erv)						\
+  if (next_##func == NULL)					\
+    {								\
+      int r;							\
+      r = atomic_load_acquire (&recursing);			\
+      if (r)							\
+	return erv;						\
+      __typeof__ (next_##func) tmp;				\
+      atomic_add (&recursing, 1);				\
+      tmp = dlsym (RTLD_NEXT, #func);				\
+      atomic_store_relaxed (&next_##func, tmp);			\
+      if (tmp == NULL)						\
+	abort ();						\
+      atomic_add (&recursing, -1);				\
+      atomic_store_relaxed (&__malloc_extras_initialized, 1);	\
+    }
+
+void *
+malloc (size_t sz)
+{
+  void *rv;
+  size_t original_size = sz;
+  void *caller;
+  Dl_info info;
+
+  void *(*hook) (size_t, const void *)
+    = atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook) (sz, RETURN_ADDRESS (0));
+
+  HOOK (malloc, NULL);
+
+  MCHECK_PRE (sz, 0);
+
+  rv =  next_malloc (sz);
+
+  MCHECK_POST (rv, original_size, 0);
+
+  if (mallstream)
+    {
+      TRACE_LOCK (caller, info);
+      tr_where (caller, &info);
+      /* We could be printing a NULL here; that's OK.  */
+      fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+      TRACE_UNLOCK ();
+   }
+
+  if (rv == mallwatch)
+    tr_break ();
+
+  return rv;
+}
+
+void 
+free (void *ptr)
+{
+  void *caller;
+  Dl_info info;
+
+  if (ptr == NULL)
+    return;
+
+  void (*hook) (void *, const void *)
+    = atomic_forced_read (__free_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      (*hook)(ptr, RETURN_ADDRESS (0));
+      return;
+    }
+
+  HOOK (free, );
+
+  if (mallstream && ptr)
+    {
+      TRACE_LOCK (caller, info);
+      tr_where (caller, &info);
+      /* We could be printing a NULL here; that's OK.  */
+      fprintf (mallstream, "- %p\n", ptr);
+      TRACE_UNLOCK ();
+   }
+
+  if (ptr == mallwatch)
+    tr_break ();
+
+  MCHECK_PREFREE (ptr);
+
+  next_free (ptr);
+
+  return;
+}
+
+void *
+realloc (void *ptr, size_t sz)
+{
+  void *rv;
+  size_t original_size = sz;
+  void *caller;
+  Dl_info info;
+
+  void *(*hook) (void *, size_t, const void *) =
+    atomic_forced_read (__realloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook)(ptr, sz, RETURN_ADDRESS (0));
+
+  HOOK (realloc, NULL);
+
+  if (ptr == mallwatch)
+    tr_break ();
+
+  MCHECK_PREFREE (ptr);
+  MCHECK_PRE (sz, 0);
+
+  rv = next_realloc (ptr, sz);
+
+  MCHECK_POST (ptr, original_size, 0);
+
+  if (mallstream)
+    {
+      TRACE_LOCK (caller, info);
+      tr_where (caller, &info);
+
+      if (rv == NULL)
+	{
+	  if (original_size != 0)
+	    /* Failed realloc.  */
+	    fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) original_size);
+	  else
+	    fprintf (mallstream, "- %p\n", ptr);
+	}
+      else if (ptr == NULL)
+	fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+      else
+	{
+	  fprintf (mallstream, "< %p\n", ptr);
+	  tr_where (caller, &info);
+	  fprintf (mallstream, "> %p %#lx\n", rv, (unsigned long int) original_size);
+	}
+
+      TRACE_UNLOCK ();
+    }
+
+  if (rv == mallwatch)
+    tr_break ();
+
+  return rv;
+}
+
+void *
+calloc (size_t sz1, size_t sz2)
+{
+  void *rv;
+  size_t original_size;
+  size_t sz = sz1 * sz2;
+  void *caller;
+  Dl_info info;
+
+#define HALF_INTERNAL_SIZE_T \
+  (((size_t) 1) << (8 * sizeof (size_t) / 2))
+  if (__builtin_expect ((sz1 | sz2) >= HALF_INTERNAL_SIZE_T, 0))
+    {
+      if (sz1 != 0 && sz / sz1 != sz2)
+        {
+          __set_errno (ENOMEM);
+          return 0;
+        }
+    }
+
+  original_size = sz;
+
+  void *(*hook) (size_t, const void *) =
+    atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      rv = (*hook)(sz, RETURN_ADDRESS (0));
+      if (rv == 0)
+	return 0;
+
+      memset (rv, 0, sz);
+
+      if (rv == mallwatch)
+	tr_break ();
+
+      return rv;
+    }
+
+  HOOK (calloc, NULL);
+
+  MCHECK_PRE (sz, 0);
+
+  rv = next_calloc (sz, 1);
+
+  MCHECK_POST_NOFLOOD (rv, sz, 0);
+
+  if (mallstream)
+    {
+      TRACE_LOCK (caller, info);
+      tr_where (caller, &info);
+      /* We could be printing a NULL here; that's OK.  */
+      fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+      TRACE_UNLOCK ();
+   }
+
+  if (rv == mallwatch)
+    tr_break ();
+
+  return rv;
+}
+
+static void *
+memalign_common (size_t sz1, size_t sz2, void *caller)
+{
+  void *rv;
+  size_t original_size = sz2;
+  Dl_info info;
+
+  void *(*hook) (size_t, size_t, const void *) =
+    atomic_forced_read (__memalign_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook)(sz1, sz2, RETURN_ADDRESS (0));
+
+  HOOK (memalign, NULL);
+
+  MCHECK_PRE (sz2, sz1);
+
+  rv =  next_memalign (sz1, sz2);
+
+  MCHECK_POST (rv, original_size, sz1);
+
+  if (mallstream)
+    {
+      TRACE_LOCK_N (caller, info);
+      tr_where (caller, &info);
+      /* We could be printing a NULL here; that's OK.  */
+      fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+      TRACE_UNLOCK ();
+   }
+
+  if (rv == mallwatch)
+    tr_break ();
+
+  return rv;
+}
+
+void *
+memalign (size_t sz1, size_t sz2)
+{
+  return memalign_common (sz1, sz2, RETURN_ADDRESS (0));
+}
+
+int
+posix_memalign (void **memptr, size_t alignment, size_t size)
+{
+  void *rvptr;
+
+  /* Test whether the SIZE argument is valid.  It must be a power of
+     two multiple of sizeof (void *).  */
+  if (alignment % sizeof (void *) != 0
+      || !powerof2 (alignment / sizeof (void *))
+      || alignment == 0)
+    return EINVAL;
+
+  rvptr = memalign_common (alignment, size, RETURN_ADDRESS (0));
+
+  if (rvptr)
+    {
+      *memptr = rvptr;
+      return 0;
+    }
+
+  return ENOMEM;
+}
+
+static size_t remembered_pagesize = 0;
+
+static inline size_t
+pagesize (void)
+{
+  size_t rv = atomic_load_relaxed (&remembered_pagesize);
+  if (remembered_pagesize == 0)
+    {
+      rv = sysconf (_SC_PAGESIZE);
+      atomic_store_relaxed (&remembered_pagesize, rv);
+    }
+  return rv;
+}
+
+void *
+valloc (size_t sz)
+{
+  return memalign_common (sysconf (_SC_PAGESIZE), sz, RETURN_ADDRESS (0));
+}
+
+void *
+pvalloc (size_t sz)
+{
+  size_t rounded_bytes = ALIGN_UP (sz, pagesize ());
+  return memalign_common (pagesize (), rounded_bytes, RETURN_ADDRESS (0));
+}
+
+size_t
+malloc_usable_size (void *ptr)
+{
+  size_t rv;
+
+  HOOK (malloc_usable_size, 0);
+
+  if (!mcheck_used)
+    rv = next_malloc_usable_size (ptr);
+  else
+    {
+      struct hdr *hdr = (struct hdr *) ptr;
+      -- hdr;
+      rv = hdr->size;
+    }
+
+  return rv;
+}
+
+/*======================================================================*/
+
+/* This function gets called to make sure all memory the library
+   allocates get freed and so does not irritate the user when studying
+   the mtrace output.  */
+static void
+release_libc_mem (void)
+{
+  /* Only call the free function if we still are running in mtrace mode.  */
+  if (mallstream != NULL)
+    __libc_freeres ();
+}
+
+
+static void
+local_mtrace (void)
+{
+  char *mallfile;
+  static int added_atexit_handler = 0;
+
+  /* Don't panic if we're called more than once.  */
+  if (mallstream != NULL)
+    {
+      fprintf (mallstream, "= Restart?\n");
+      return;
+    }
+
+  mallfile = getenv (mallenv);
+  if (mallfile != NULL || mallwatch != NULL)
+    {
+      char *mtb = malloc (TRACE_BUFFER_SIZE);
+      if (mtb == NULL)
+        return;
+
+      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
+      if (mallstream != NULL)
+        {
+          /* Be sure it doesn't malloc its buffer!  */
+          malloc_trace_buffer = mtb;
+          setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
+          fprintf (mallstream, "= Start\n");
+
+	  if (!added_atexit_handler)
+            {
+              added_atexit_handler = 1;
+              atexit ((void (*)(void))release_libc_mem);
+            }
+
+        }
+      else
+        free (mtb);
+    }
+}
+
+static void
+local_muntrace (void)
+{
+  if (mallstream == NULL)
+    return;
+
+  /* Do the reverse of what done in mtrace: first reset the hooks and
+     MALLSTREAM, and only after that write the trailer and close the
+     file.  */
+  FILE *f = mallstream;
+  mallstream = NULL;
+
+  fprintf (f, "= End\n");
+  fclose (f);
+}
+
+/*======================================================================*/
+/* user interface */
+
+extern void (*__glibc_mtrace_hook)(int);
+extern int __glibc_mtrace_hook_enabled;
+
+void
+__glibc_mtrace_hook_func (int enable_it)
+{
+  if (enable_it)
+    local_mtrace ();
+  else
+    local_muntrace ();
+}
+
+void __attribute__ ((constructor))
+mtrace_extras_ctor (void)
+{
+  __glibc_mtrace_hook = __glibc_mtrace_hook_func;
+  if (__glibc_mtrace_hook_enabled)
+    __glibc_mtrace_hook (1);
+}
+
+void __attribute__ ((destructor))
+mtrace_extras_dtor (void)
+{
+  if (mallstream)
+    {
+      __libc_freeres ();
+      fprintf (mallstream, "= Unload?\n");
+    }
+}
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 9614954975..e01703681f 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -463,6 +463,12 @@  void *(*__morecore)(ptrdiff_t) = __default_morecore;
 # define HAVE_MALLOC_INIT_HOOK 0
 #endif
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_24)
+# define HAVE_MALLOC_HOOKS 1
+#else
+# define HAVE_MALLOC_HOOKS 0
+#endif
+
 
 /*
   This version of malloc supports the standard SVID/XPG mallinfo
@@ -1014,8 +1020,6 @@  static void*  _mid_memalign(size_t, size_t, void *);
 
 static void malloc_printerr(const char *str) __attribute__ ((noreturn));
 
-static void* mem2mem_check(void *p, size_t sz);
-static void top_check(void);
 static void munmap_chunk(mchunkptr p);
 #if HAVE_MREMAP
 static mchunkptr mremap_chunk(mchunkptr p, size_t new_size);
@@ -1847,6 +1851,12 @@  static void     malloc_consolidate (mstate);
 # define weak_variable weak_function
 #endif
 
+#if HAVE_MALLOC_INIT_HOOK
+void weak_variable (*__malloc_initialize_hook) (void) = NULL;
+compat_symbol (libc, __malloc_initialize_hook,
+	       __malloc_initialize_hook, GLIBC_2_0);
+#endif
+
 /* Forward declarations.  */
 static void *malloc_hook_ini (size_t sz,
                               const void *caller) __THROW;
@@ -1855,11 +1865,6 @@  static void *realloc_hook_ini (void *ptr, size_t sz,
 static void *memalign_hook_ini (size_t alignment, size_t sz,
                                 const void *caller) __THROW;
 
-#if HAVE_MALLOC_INIT_HOOK
-void weak_variable (*__malloc_initialize_hook) (void) = NULL;
-compat_symbol (libc, __malloc_initialize_hook,
-	       __malloc_initialize_hook, GLIBC_2_0);
-#endif
 
 void weak_variable (*__free_hook) (void *__ptr,
                                    const void *) = NULL;
@@ -2490,14 +2495,7 @@  sysmalloc (INTERNAL_SIZE_T nb, mstate av)
           LIBC_PROBE (memory_sbrk_more, 2, brk, size);
         }
 
-      if (brk != (char *) (MORECORE_FAILURE))
-        {
-          /* Call the `morecore' hook if necessary.  */
-          void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
-          if (__builtin_expect (hook != NULL, 0))
-            (*hook)();
-        }
-      else
+      if (brk == (char *) (MORECORE_FAILURE))
         {
           /*
              If have mmap, try using it as a backup when MORECORE fails or
@@ -2634,13 +2632,6 @@  sysmalloc (INTERNAL_SIZE_T nb, mstate av)
                       correction = 0;
                       snd_brk = (char *) (MORECORE (0));
                     }
-                  else
-                    {
-                      /* Call the `morecore' hook if necessary.  */
-                      void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
-                      if (__builtin_expect (hook != NULL, 0))
-                        (*hook)();
-                    }
                 }
 
               /* handle non-contiguous cases */
@@ -2798,10 +2789,6 @@  systrim (size_t pad, mstate av)
        */
 
       MORECORE (-extra);
-      /* Call the `morecore' hook if necessary.  */
-      void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
-      if (__builtin_expect (hook != NULL, 0))
-        (*hook)();
       new_brk = (char *) (MORECORE (0));
 
       LIBC_PROBE (memory_sbrk_less, 2, new_brk, extra);
@@ -3029,10 +3016,8 @@  __libc_malloc (size_t bytes)
   mstate ar_ptr;
   void *victim;
 
-  void *(*hook) (size_t, const void *)
-    = atomic_forced_read (__malloc_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    return (*hook)(bytes, RETURN_ADDRESS (0));
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
 #if USE_TCACHE
   /* int_free also calls request2size, be careful to not pad twice.  */
   size_t tbytes;
@@ -3087,13 +3072,8 @@  __libc_free (void *mem)
   mstate ar_ptr;
   mchunkptr p;                          /* chunk corresponding to mem */
 
-  void (*hook) (void *, const void *)
-    = atomic_forced_read (__free_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      (*hook)(mem, RETURN_ADDRESS (0));
-      return;
-    }
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
 
   if (mem == 0)                              /* free(0) has no effect */
     return;
@@ -3133,10 +3113,8 @@  __libc_realloc (void *oldmem, size_t bytes)
 
   void *newp;             /* chunk to return */
 
-  void *(*hook) (void *, size_t, const void *) =
-    atomic_forced_read (__realloc_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
 
 #if REALLOC_ZERO_BYTES_FREES
   if (bytes == 0 && oldmem != NULL)
@@ -3262,11 +3240,6 @@  _mid_memalign (size_t alignment, size_t bytes, void *address)
   mstate ar_ptr;
   void *p;
 
-  void *(*hook) (size_t, size_t, const void *) =
-    atomic_forced_read (__memalign_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    return (*hook)(alignment, bytes, address);
-
   /* If we need less alignment than we give anyway, just relay to malloc.  */
   if (alignment <= MALLOC_ALIGNMENT)
     return __libc_malloc (bytes);
@@ -3385,17 +3358,8 @@  __libc_calloc (size_t n, size_t elem_size)
         }
     }
 
-  void *(*hook) (size_t, const void *) =
-    atomic_forced_read (__malloc_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      sz = bytes;
-      mem = (*hook)(sz, RETURN_ADDRESS (0));
-      if (mem == 0)
-        return 0;
-
-      return memset (mem, 0, sz);
-    }
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
 
   sz = bytes;
 
diff --git a/malloc/mcheck.c b/malloc/mcheck.c
index dc04a6391a..a0006c560a 100644
--- a/malloc/mcheck.c
+++ b/malloc/mcheck.c
@@ -27,374 +27,19 @@ 
 # include <errno.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
-#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;
-
-  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)
 #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;
+  return 0;
 }
 #ifdef _LIBC
 libc_hidden_def (mcheck)
@@ -403,14 +48,11 @@  libc_hidden_def (mcheck)
 int
 mcheck_pedantic (void (*func) (enum mcheck_status))
 {
-  int res = mcheck (func);
-  if (res == 0)
-    pedantic = 1;
-  return res;
+  return 0;
 }
 
 enum mcheck_status
 mprobe (void *ptr)
 {
-  return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+  return MCHECK_DISABLED;
 }
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index 9064f209ec..2e3ac66d9c 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -37,30 +37,12 @@ 
 #include <dso_handle.h>
 
 #include <libio/iolibio.h>
-#define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
-#define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
 
 #include <kernel-features.h>
 
-#define TRACE_BUFFER_SIZE 512
-
-static FILE *mallstream;
-static const char mallenv[] = "MALLOC_TRACE";
-static char *malloc_trace_buffer;
-
-__libc_lock_define_initialized (static, lock);
-
 /* Address to breakpoint on accesses to... */
 void *mallwatch;
 
-/* Old hook values.  */
-static void (*tr_old_free_hook) (void *ptr, const void *);
-static void *(*tr_old_malloc_hook) (size_t size, const void *);
-static void *(*tr_old_realloc_hook) (void *ptr, size_t size,
-				     const void *);
-static void *(*tr_old_memalign_hook) (size_t __alignment, size_t __size,
-				      const void *);
-
 /* This function is called when the block being alloc'd, realloc'd, or
    freed has an address matching the variable "mallwatch".  In a debugger,
    set "mallwatch" to the address of interest, then put a breakpoint on
@@ -74,275 +56,26 @@  tr_break (void)
 }
 libc_hidden_def (tr_break)
 
-static void
-tr_where (const void *caller, Dl_info *info)
-{
-  if (caller != NULL)
-    {
-      if (info != NULL)
-        {
-          char *buf = (char *) "";
-          if (info->dli_sname != NULL)
-            {
-              size_t len = strlen (info->dli_sname);
-              buf = alloca (len + 6 + 2 * sizeof (void *));
-
-              buf[0] = '(';
-              __stpcpy (_fitoa (caller >= (const void *) info->dli_saddr
-                                ? caller - (const void *) info->dli_saddr
-                                : (const void *) info->dli_saddr - caller,
-                                __stpcpy (__mempcpy (buf + 1, info->dli_sname,
-                                                     len),
-                                          caller >= (void *) info->dli_saddr
-                                          ? "+0x" : "-0x"),
-                                16, 0),
-                        ")");
-            }
-
-          fprintf (mallstream, "@ %s%s%s[%p] ",
-                   info->dli_fname ? : "", info->dli_fname ? ":" : "",
-                   buf, caller);
-        }
-      else
-        fprintf (mallstream, "@ [%p] ", caller);
-    }
-}
-
-static Dl_info *
-lock_and_info (const void *caller, Dl_info *mem)
-{
-  if (caller == NULL)
-    return NULL;
-
-  Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
-
-  __libc_lock_lock (lock);
-
-  return res;
-}
-
-static void
-tr_freehook (void *ptr, const void *caller)
-{
-  if (ptr == NULL)
-    return;
-
-  Dl_info mem;
-  Dl_info *info = lock_and_info (caller, &mem);
-  tr_where (caller, info);
-  /* Be sure to print it first.  */
-  fprintf (mallstream, "- %p\n", ptr);
-  if (ptr == mallwatch)
-    {
-      __libc_lock_unlock (lock);
-      tr_break ();
-      __libc_lock_lock (lock);
-    }
-  __free_hook = tr_old_free_hook;
-  if (tr_old_free_hook != NULL)
-    (*tr_old_free_hook)(ptr, caller);
-  else
-    free (ptr);
-  __free_hook = tr_freehook;
-  __libc_lock_unlock (lock);
-}
-
-static void *
-tr_mallochook (size_t size, const void *caller)
-{
-  void *hdr;
-
-  Dl_info mem;
-  Dl_info *info = lock_and_info (caller, &mem);
-
-  __malloc_hook = tr_old_malloc_hook;
-  if (tr_old_malloc_hook != NULL)
-    hdr = (void *) (*tr_old_malloc_hook)(size, caller);
-  else
-    hdr = (void *) malloc (size);
-  __malloc_hook = tr_mallochook;
-
-  tr_where (caller, info);
-  /* We could be printing a NULL here; that's OK.  */
-  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
-
-  __libc_lock_unlock (lock);
-
-  if (hdr == mallwatch)
-    tr_break ();
-
-  return hdr;
-}
-
-static void *
-tr_reallochook (void *ptr, size_t size, const void *caller)
-{
-  void *hdr;
-
-  if (ptr == mallwatch)
-    tr_break ();
-
-  Dl_info mem;
-  Dl_info *info = lock_and_info (caller, &mem);
-
-  __free_hook = tr_old_free_hook;
-  __malloc_hook = tr_old_malloc_hook;
-  __realloc_hook = tr_old_realloc_hook;
-  if (tr_old_realloc_hook != NULL)
-    hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
-  else
-    hdr = (void *) realloc (ptr, size);
-  __free_hook = tr_freehook;
-  __malloc_hook = tr_mallochook;
-  __realloc_hook = tr_reallochook;
-
-  tr_where (caller, info);
-  if (hdr == NULL)
-    {
-      if (size != 0)
-        /* Failed realloc.  */
-        fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
-      else
-        fprintf (mallstream, "- %p\n", ptr);
-    }
-  else if (ptr == NULL)
-    fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
-  else
-    {
-      fprintf (mallstream, "< %p\n", ptr);
-      tr_where (caller, info);
-      fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
-    }
-
-  __libc_lock_unlock (lock);
-
-  if (hdr == mallwatch)
-    tr_break ();
-
-  return hdr;
-}
-
-static void *
-tr_memalignhook (size_t alignment, size_t size, const void *caller)
-{
-  void *hdr;
-
-  Dl_info mem;
-  Dl_info *info = lock_and_info (caller, &mem);
-
-  __memalign_hook = tr_old_memalign_hook;
-  __malloc_hook = tr_old_malloc_hook;
-  if (tr_old_memalign_hook != NULL)
-    hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
-  else
-    hdr = (void *) memalign (alignment, size);
-  __memalign_hook = tr_memalignhook;
-  __malloc_hook = tr_mallochook;
-
-  tr_where (caller, info);
-  /* We could be printing a NULL here; that's OK.  */
-  fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
-
-  __libc_lock_unlock (lock);
-
-  if (hdr == mallwatch)
-    tr_break ();
-
-  return hdr;
-}
-
-
-#ifdef _LIBC
-
-/* This function gets called to make sure all memory the library
-   allocates get freed and so does not irritate the user when studying
-   the mtrace output.  */
-static void __libc_freeres_fn_section
-release_libc_mem (void)
-{
-  /* Only call the free function if we still are running in mtrace mode.  */
-  if (mallstream != NULL)
-    __libc_freeres ();
-}
-#endif
-
-
 /* We enable tracing if either the environment variable MALLOC_TRACE
    is set, or if the variable mallwatch has been patched to an address
    that the debugging user wants us to stop on.  When patching mallwatch,
    don't forget to set a breakpoint on tr_break!  */
 
+void (*__glibc_mtrace_hook)(int) = NULL;
+int __glibc_mtrace_hook_enabled = 0;
+
 void
 mtrace (void)
 {
-#ifdef _LIBC
-  static int added_atexit_handler;
-#endif
-  char *mallfile;
-
-  /* Don't panic if we're called more than once.  */
-  if (mallstream != NULL)
-    return;
-
-#ifdef _LIBC
-  /* When compiling the GNU libc we use the secure getenv function
-     which prevents the misuse in case of SUID or SGID enabled
-     programs.  */
-  mallfile = __libc_secure_getenv (mallenv);
-#else
-  mallfile = getenv (mallenv);
-#endif
-  if (mallfile != NULL || mallwatch != NULL)
-    {
-      char *mtb = malloc (TRACE_BUFFER_SIZE);
-      if (mtb == NULL)
-        return;
-
-      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
-      if (mallstream != NULL)
-        {
-          /* Be sure it doesn't malloc its buffer!  */
-          malloc_trace_buffer = mtb;
-          setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
-          fprintf (mallstream, "= Start\n");
-          tr_old_free_hook = __free_hook;
-          __free_hook = tr_freehook;
-          tr_old_malloc_hook = __malloc_hook;
-          __malloc_hook = tr_mallochook;
-          tr_old_realloc_hook = __realloc_hook;
-          __realloc_hook = tr_reallochook;
-          tr_old_memalign_hook = __memalign_hook;
-          __memalign_hook = tr_memalignhook;
-#ifdef _LIBC
-          if (!added_atexit_handler)
-            {
-              added_atexit_handler = 1;
-              __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
-			    __dso_handle);
-            }
-#endif
-        }
-      else
-        free (mtb);
-    }
+  if (__glibc_mtrace_hook)
+    __glibc_mtrace_hook(1);
+  __glibc_mtrace_hook_enabled = 1;
 }
 
 void
 muntrace (void)
 {
-  if (mallstream == NULL)
-    return;
-
-  /* Do the reverse of what done in mtrace: first reset the hooks and
-     MALLSTREAM, and only after that write the trailer and close the
-     file.  */
-  FILE *f = mallstream;
-  mallstream = NULL;
-  __free_hook = tr_old_free_hook;
-  __malloc_hook = tr_old_malloc_hook;
-  __realloc_hook = tr_old_realloc_hook;
-  __memalign_hook = tr_old_memalign_hook;
-
-  fprintf (f, "= End\n");
-  fclose (f);
+  if (__glibc_mtrace_hook)
+    __glibc_mtrace_hook(0);
+  __glibc_mtrace_hook_enabled = 0;
 }
diff --git a/malloc/tst-mtrace.sh b/malloc/tst-mtrace.sh
index 9c50c0675d..926c96e3bb 100755
--- a/malloc/tst-mtrace.sh
+++ b/malloc/tst-mtrace.sh
@@ -30,6 +30,7 @@  trap "rm -f ${common_objpfx}malloc/tst-mtrace.leak; exit 1" 1 2 15
 ${test_program_prefix_before_env} \
 ${run_program_env} \
 MALLOC_TRACE=${common_objpfx}malloc/tst-mtrace.leak \
+LD_PRELOAD=${common_objpfx}/malloc/libmalloc-extras.so \
 ${test_program_prefix_after_env} \
   ${common_objpfx}malloc/tst-mtrace || status=1
 
diff --git a/misc/Makefile b/misc/Makefile
index a5076b3672..81fe068b64 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -132,7 +132,8 @@  $(objpfx)libg.a: $(dep-dummy-lib); $(make-dummy-lib)
 
 $(objpfx)tst-tsearch: $(libm)
 
-tst-error1-ENV = MALLOC_TRACE=$(objpfx)tst-error1.mtrace
+tst-error1-ENV = MALLOC_TRACE=$(objpfx)tst-error1.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 tst-error1-ARGS = $(objpfx)tst-error1.out
 $(objpfx)tst-error1-mem.out: $(objpfx)tst-error1.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-error1.mtrace > $@; \
diff --git a/nptl/Makefile b/nptl/Makefile
index 94be92c789..7d014be36a 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -528,10 +528,12 @@  tst-umask1-ARGS = $(objpfx)tst-umask1.temp
 
 $(objpfx)tst-atfork2: $(libdl) $(shared-thread-library)
 LDFLAGS-tst-atfork2 = -rdynamic
-tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace
+tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)tst-atfork2mod.so: $(shared-thread-library)
 
-tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace
+tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace \
+	LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
 $(objpfx)tst-stack3-mem.out: $(objpfx)tst-stack3.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@; \
 	$(evaluate-test)
diff --git a/posix/Makefile b/posix/Makefile
index 51dcf129ec..3a902a284c 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -277,43 +277,50 @@  annexc-CFLAGS = -O
 $(objpfx)annexc: annexc.c
 	$(native-compile)
 
-tst-fnmatch-ENV += MALLOC_TRACE=$(objpfx)tst-fnmatch.mtrace
+tst-fnmatch-ENV += MALLOC_TRACE=$(objpfx)tst-fnmatch.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)tst-fnmatch-mem.out: $(objpfx)tst-fnmatch.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-fnmatch.mtrace > $@; \
 	$(evaluate-test)
 
-bug-regex2-ENV = MALLOC_TRACE=$(objpfx)bug-regex2.mtrace
+bug-regex2-ENV = MALLOC_TRACE=$(objpfx)bug-regex2.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)bug-regex2-mem.out: $(objpfx)bug-regex2.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-regex2.mtrace > $@; \
 	$(evaluate-test)
 
-bug-regex14-ENV = MALLOC_TRACE=$(objpfx)bug-regex14.mtrace
+bug-regex14-ENV = MALLOC_TRACE=$(objpfx)bug-regex14.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)bug-regex14-mem.out: $(objpfx)bug-regex14.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-regex14.mtrace > $@; \
 	$(evaluate-test)
 
-bug-regex21-ENV = MALLOC_TRACE=$(objpfx)bug-regex21.mtrace
+bug-regex21-ENV = MALLOC_TRACE=$(objpfx)bug-regex21.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)bug-regex21-mem.out: $(objpfx)bug-regex21.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-regex21.mtrace > $@; \
 	$(evaluate-test)
 
-bug-regex31-ENV = MALLOC_TRACE=$(objpfx)bug-regex31.mtrace
+bug-regex31-ENV = MALLOC_TRACE=$(objpfx)bug-regex31.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)bug-regex31-mem.out: $(objpfx)bug-regex31.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-regex31.mtrace > $@; \
 	$(evaluate-test)
 
-bug-regex36-ENV = MALLOC_TRACE=$(objpfx)bug-regex36.mtrace
+bug-regex36-ENV = MALLOC_TRACE=$(objpfx)bug-regex36.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)bug-regex36-mem.out: $(objpfx)bug-regex36.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-regex36.mtrace > $@; \
 	$(evaluate-test)
 
-tst-vfork3-ENV = MALLOC_TRACE=$(objpfx)tst-vfork3.mtrace
+tst-vfork3-ENV = MALLOC_TRACE=$(objpfx)tst-vfork3.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)tst-vfork3-mem.out: $(objpfx)tst-vfork3.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-vfork3.mtrace > $@; \
@@ -322,18 +329,21 @@  $(objpfx)tst-vfork3-mem.out: $(objpfx)tst-vfork3.out
 # tst-rxspencer.mtrace is not generated, only
 # tst-rxspencer-no-utf8.mtrace, since otherwise the file has almost
 # 100M and takes very long time to process.
-tst-rxspencer-no-utf8-ENV += MALLOC_TRACE=$(objpfx)tst-rxspencer-no-utf8.mtrace
+tst-rxspencer-no-utf8-ENV += MALLOC_TRACE=$(objpfx)tst-rxspencer-no-utf8.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)tst-rxspencer-no-utf8-mem.out: $(objpfx)tst-rxspencer-no-utf8.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-rxspencer-no-utf8.mtrace \
 				      > $@; \
 	$(evaluate-test)
 
-tst-pcre-ENV = MALLOC_TRACE=$(objpfx)tst-pcre.mtrace
+tst-pcre-ENV = MALLOC_TRACE=$(objpfx)tst-pcre.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)tst-pcre-mem.out: $(objpfx)tst-pcre.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-pcre.mtrace > $@; \
 	$(evaluate-test)
 
-tst-boost-ENV = MALLOC_TRACE=$(objpfx)tst-boost.mtrace
+tst-boost-ENV = MALLOC_TRACE=$(objpfx)tst-boost.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)tst-boost-mem.out: $(objpfx)tst-boost.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-boost.mtrace > $@; \
 	$(evaluate-test)
@@ -346,15 +356,18 @@  $(objpfx)bug-ga2-mem.out: $(objpfx)bug-ga2.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-ga2.mtrace > $@; \
 	$(evaluate-test)
 
-bug-ga2-ENV = MALLOC_TRACE=$(objpfx)bug-ga2.mtrace
+bug-ga2-ENV = MALLOC_TRACE=$(objpfx)bug-ga2.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
-bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bug-glob2.mtrace
+bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bug-glob2.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out
 	$(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \
 	$(evaluate-test)
 
-tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace
+tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \
diff --git a/posix/tst-vfork3.c b/posix/tst-vfork3.c
index 0449b2486a..199eaf1c0f 100644
--- a/posix/tst-vfork3.c
+++ b/posix/tst-vfork3.c
@@ -147,6 +147,8 @@  do_prepare (void)
     FAIL_EXIT1 ("out of memory");
   strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX");
 
+  unsetenv("LD_PRELOAD");
+
   tmpdirname = mkdtemp (tmpdirname);
   if (tmpdirname == NULL)
     FAIL_EXIT1 ("could not create temporary directory");
diff --git a/resolv/Makefile b/resolv/Makefile
index 6e70ae9f6b..6791a22de2 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -140,17 +140,20 @@  $(objpfx)tst-res_hconf_reorder: $(libdl) $(shared-thread-library)
 tst-res_hconf_reorder-ENV = RESOLV_REORDER=on
 
 $(objpfx)tst-leaks: $(objpfx)libresolv.so
-tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace
+tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace \
+	LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
 $(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks.mtrace > $@; \
 	$(evaluate-test)
 
-tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace
+tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace \
+	LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
 $(objpfx)mtrace-tst-leaks2.out: $(objpfx)tst-leaks2.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks2.mtrace > $@; \
 	$(evaluate-test)
 
-tst-resolv-res_ninit-ENV = MALLOC_TRACE=$(objpfx)tst-resolv-res_ninit.mtrace
+tst-resolv-res_ninit-ENV = MALLOC_TRACE=$(objpfx)tst-resolv-res_ninit.mtrace \
+	LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
 $(objpfx)mtrace-tst-resolv-res_ninit.out: $(objpfx)tst-resolv-res_ninit.out
 	$(common-objpfx)malloc/mtrace \
 	  $(objpfx)tst-resolv-res_ninit.mtrace > $@; \
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 9dfc115313..10da17ff6e 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -90,9 +90,11 @@  $(objpfx)tst-swprintf.out: $(gen-locales)
 $(objpfx)tst-vfprintf-mbs-prec.out: $(gen-locales)
 endif
 
-tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace
+tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 tst-vfprintf-width-prec-ENV = \
-  MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace
+  MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 
 $(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
 	$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \