diff --git a/ChangeLog b/ChangeLog
index 3371a9b670..b55a14a386 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,138 @@
+2018-06-29  DJ Delorie  <dj@redhat.com>
+	    Carlos O'Donell  <carlos@redhat.com>
+
+	[BZ #23328]
+	* Makeconfig (built-modules): Add libmalloc-extras.
+	* NEWS: Describe deprecation of hooks.
+	* catgets/Makefile (tst-catgets-ENV): Preload libmalloc-extras.so.
+	* elf/Makefile (tests-special): Remove tst-leaks1-static-mem.out.
+	(noload-ENV): Preload libmalloc-extras.so.
+	($(objpfx)tst-leaks1-static-mem.out): Remove.
+	(tst-leaks1-ENV): Likewise.
+	* iconvdata/Makefile (tst-loading-ENV): Likewise.
+	* include/stdlib.h: Remove __default_morecore prototype.
+	* intl/tst-gettext.sh: Preload libmalloc-extras.so.
+	* libio/Makefile (test-fmemopen-ENV): Likewise.
+	(tst-fopenloc-ENV): Likewise.
+	(tst-bz22415-ENV): Likewise.
+	* localedata/Makefile (tst-leaks-ENV): Likewise.
+	* malloc/Makefile (tests): Add tst-malloc-weak-usable.
+	(tests-static): Add tst-malloc-weak-usable-static.
+	Remove tst-malloc-usable-static.
+	[ifneq (no,$(have-tunables))] (tests-static): Remove
+	tst-malloc-usable-tunables-static.
+	(extra-libs): Add libmalloc-extras.
+	(libmalloc-extras-routines): Define.
+	(LDLIBS-libmalloc-extras.so): Define.
+	(LDFLAGS-malloc-extras.so): Define.
+	($(objpfx)libmalloc-extras.so): Define.
+	(tst-mtrace-ENV): Preload libmalloc-extras.so.
+	(tst-malloc-usable-ENV): Likewise.
+	(tst-malloc-usable-tunables-ENV): Likewise.
+	(tst-malloc-weak-usable-ENV): Define.
+	(tst-malloc-weak-usable-static-ENV): Define.
+	(tst-dynarray-ENV): Likewise.
+	(tst-dynarray-fail-ENV): Likewise.
+	* malloc/Versions (libc.GLIBC_PRIVATE): Add __glibc_free_hook,
+	__glibc_malloc_hook, __glibc_realloc_hook, __glibc_memalign_hook,
+	__glibc_malloc_check_request, __glibC_malloc_check_enable.
+	* malloc/hooks.c: Define declrations for malloc_check,
+	free_check, realloc_check, and memalign_check.
+	(malloc_hook_ini): Call interposable API and use local hooks.
+	(realloc_hook_ini): Likewise.
+	(memalign_hook_ini): Likewise.
+	(__glibc_malloc_check_request): New global data.
+	(__malloc_check_init): Install but don't enable hooks.
+	(__glibc_malloc_check_enable): New function.
+	(mem2mem_check): Adjust comment.
+	(mem2chunk_check): Adjust comment.
+	(malloc_set_state): Use local hooks.
+	* malloc/malloc-extras.c: New file.
+	* malloc/malloc-hooks.h: Add prototypes for __glibc_free_hook,
+	__glibc_malloc_hook, __glibc_realloc_hook, __glibc_memalign_hook,
+	__glibc_malloc_check_request, __glibc_malloc_check_enable.
+	* malloc/malloc-internal.h: Add prototypes for __malloc_check_init,
+	__glibc_morecore.
+	* malloc/malloc.c: Remove prototypes for __default_morecore,
+	mem2mem_check, top_check, malloc_check, free_check, realloc_check, and
+	memalign_check.
+	(MORECORE): Call __glibc_morecore directly.
+	(__morecore): Declare as compat symbol conditional on
+	SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+	(__free_hook): Rename to...
+	(__glibc_free_hook): ...this.  And declare as compat symbol
+	__free_hook conditional on
+	SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+	(__malloc_hook): Rename to...
+	(__glibc_malloc_hook): ...this.  And declare as compat symbol
+	__malloc_hook conditional on
+	SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+	(__realloc_hook): Rename to...
+	(__glibc_realloc_hook): ...this. And declare as compat symbol
+	__glibc_realloc_hook conditional on
+	SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+	(__memalign_hook): Rename to...
+	(__glibc_memalign_hook): ...this. And declare as compat symbol
+	__glibc_memalign_hook conditional on
+	SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+	(__after_morecore_hook): Declare as compat symbol conditional on
+	SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+	(sysmalloc): Do not call __after_morecore_hook.
+	(systrim): Likewise.
+	(__libc_malloc): Call ptmalloc_init() and remove hook calls.
+	(__libc_free): Likewise.
+	(__libc_realloc): Likewise.
+	(__libc_calloc): Likewise.
+	(_mid_memaligin): Don't call __memalign_hook.
+	* malloc/malloc.h: Remove public hook declarations for __free_hook,
+	__malloc_hook, __realloc_hook, __memalign_hook, and
+	__after_morecore_hook.  Remove delcaration of __default_morecore,
+	and __morecore.
+	* malloc/mcheck.c: Remove most code, leaving an empty implementation
+	of the APIs for mcheck_check_all, mcheck, mcheck_pedantic, and mprobe.
+	* malloc/morecore.c (__default_morecore): Rename to...
+	(__glibc_morecore): ...this. Define as compat symbol
+	__default_morecore conditional on
+	SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+	* malloc/mtrace.c: Remove most code, leaving an empty implementation
+	of the APIs for mallwatch, tr_break, mtrace, and muntrace.
+	* malloc/tst-malloc-usable-static-tunables.c: Remove file.
+	* malloc/tst-malloc-usable-static.c: Remove file.
+	* malloc/tst-malloc-weak-usable-static.c: New file.
+	* malloc/tst-malloc-weak-usable.c: New file.
+	* malloc/tst-mtrace.sh: Preload libmalloc-extras.so.
+	* manual/memory.texi (Summary of Malloc): Remove "Hooks for Malloc".
+	(Hooks for Malloc): Remove.
+	(mcheck): Remove @mtasuconst{:malloc_hooks} safety not.
+	(mprobe): Likewise.
+	(mtrace): Likewise.
+	(muntrace): Likewise.
+	(Heap Consistency Checking): Document need for libmalloc-extra.so.
+	(Allocation Debugging): Likewise.
+	* misc/Makefile (tst-error1-ENV): Likewise.
+	(tst-allocate_once-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.
+
 2018-06-29  DJ Delorie  <dj@redhat.com>
 	    Carlos O'Donell  <carlos@redhat.com>
 
diff --git a/Makeconfig b/Makeconfig
index 608ffe648c..ece6f13198 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/NEWS b/NEWS
index a27dd371a3..ef036c8791 100644
--- a/NEWS
+++ b/NEWS
@@ -58,6 +58,32 @@ Major new features:
 
 Deprecated and removed features, and other changes affecting compatibility:
 
+* The malloc function redirection hooks for __free_hook, __malloc_hook,
+  __realloc_hook and __memalign_hook and their functionality has been
+  deprecated and is no longer available to newly compiled applications.
+  In addition the __morecore, __default_morecore, and
+  __after_morecore_hook which allow overriding some of the basic
+  allocation mechanisms in malloc have also been deprected and are no
+  longer available to newly compiled applications.  Applications already
+  using these malloc hooks can continue to operate by prelodaing, via
+  LD_PRELOAD, the provided libmalloc-extras.so shared object.  This
+  shared object implements a malloc interposer that provides all the
+  features previously provided by the hooks (with the exception of
+  __morcore and __after_morecore_hook which are unused).  This includes
+  all of the functionality provided by mcheck, mcheck_check_pedantic,
+  mcheck_check_all, mprobe, MALLOC_CHECK_, mallopt's M_CHECK_ACTION set
+  to non-zero, mtrace and muntrace.  The malloc hooks are deprecated
+  because they are not thread safe, pose a security risk, and impose
+  restrictions on the malloc internals which impact maintenance and
+  future performance enhancements.  The entire malloc family of APIs
+  must be implemented by an interposing library, and partial
+  implementation using the hooks are no longer supported in libc.so.
+  Lastly, all of the functionality described here is no longer supported
+  for statically linked applications.  In statically linked
+  applications, just like in legacy applications that don't preload
+  libmalloc-extras.so, the impacted APIs will do nothing, or return
+  appropriate error codes depending on their semantics.
+
 * The nonstandard header files <libio.h> and <_G_config.h> are no longer
   installed.  Software that was using either header should be updated to
   use standard <stdio.h> interfaces instead.
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 41cc3681be..d61bbecab8 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -205,7 +205,7 @@ endif
 tests += $(tests-execstack-$(have-z-execstack))
 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
@@ -812,7 +812,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
@@ -1227,11 +1228,15 @@ $(objpfx)tst-leaks1-mem.out: $(objpfx)tst-leaks1.out
 	$(evaluate-test)
 
 $(objpfx)tst-leaks1-static: $(common-objpfx)dlfcn/libdl.a
-$(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-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
+# Static applications no longer support tracing.  All of the hooks used
+# for tracing have been removed.  However, we can still test that the
+# application runs using the existing API calls without crashing.
+# Note that there is no tst-leaks1-static-mem.out target which runs
+# mtrace in this case because no *.mtrace file would be generated, again
+# we are just testing that the application itself doesn't crash.
 tst-leaks1-static-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1-static.mtrace
 
 $(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/include/stdlib.h b/include/stdlib.h
index 114e12d255..bd3dcf4950 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -285,9 +285,6 @@ libc_hidden_proto (__qfcvt_r)
 #  define MB_CUR_MAX (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX))
 # endif
 
-extern void *__default_morecore (ptrdiff_t) __THROW;
-libc_hidden_proto (__default_morecore)
-
 struct abort_msg_s
 {
   unsigned int size;
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 64d283e512..6781f6f8b2 100644
--- a/libio/Makefile
+++ b/libio/Makefile
@@ -154,9 +154,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..98ca0c56fc 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -38,11 +38,12 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-malloc_info \
 	 tst-malloc-too-large \
 	 tst-malloc-stats-cancellation \
+	 tst-malloc-weak-usable
 
 tests-static := \
 	 tst-interpose-static-nothread \
 	 tst-interpose-static-thread \
-	 tst-malloc-usable-static \
+	 tst-malloc-weak-usable-static
 
 tests-internal := tst-mallocstate tst-scratch_buffer
 
@@ -54,7 +55,6 @@ tests-internal += \
 
 ifneq (no,$(have-tunables))
 tests += tst-malloc-usable-tunables
-tests-static += tst-malloc-usable-static-tunables
 endif
 
 tests += $(tests-static)
@@ -78,7 +78,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 +143,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,11 +194,14 @@ 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-static-ENV = $(tst-malloc-usable-ENV)
-tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
-tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
+tst-malloc-usable-ENV = MALLOC_CHECK_=3 LD_PRELOAD=$(objpfx)libmalloc-extras.so
+tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \
+	LD_PRELOAD=$(objpfx)libmalloc-extras.so
+# Do not preload libmalloc-extras.so for tst-malloc-weak-usable* tests.
+tst-malloc-weak-usable-ENV = MALLOC_CHECK_=3
+tst-malloc-weak-usable-static-ENV = MALLOC_CHECK_=3
 
 ifeq ($(experimental-malloc),yes)
 CPPFLAGS-malloc.c += -DUSE_TCACHE=1
@@ -239,12 +247,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..4a7967e790 100644
--- a/malloc/Versions
+++ b/malloc/Versions
@@ -92,5 +92,13 @@ libc {
     __libc_alloc_buffer_copy_bytes;
     __libc_alloc_buffer_copy_string;
     __libc_alloc_buffer_create_failure;
+
+    # Implementation of libmalloc-extras.so.
+    __glibc_free_hook;
+    __glibc_malloc_hook;
+    __glibc_realloc_hook;
+    __glibc_memalign_hook;
+    __glibc_malloc_check_request;
+    __glibc_malloc_check_enable;
   }
 }
diff --git a/malloc/hooks.c b/malloc/hooks.c
index ae7305b036..d854c0bbba 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -21,46 +21,82 @@
    corrupt pointer is detected: do nothing (0), print an error message
    (1), or call abort() (2). */
 
+/* Forward declarations of the check functions for use by the hooks.  */
+static void *malloc_check(size_t sz, const void *caller);
+static void free_check(void *mem, const void *caller);
+static void *realloc_check(void *oldmem, size_t bytes,
+			   const void *caller);
+static void *memalign_check(size_t alignment, size_t bytes,
+			    const void *caller);
+
 /* Hooks for debugging versions.  The initial hooks just call the
    initialization routine, then do the normal work. */
 
 static void *
 malloc_hook_ini (size_t sz, const void *caller)
 {
-  __malloc_hook = NULL;
+  __glibc_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 *
 realloc_hook_ini (void *ptr, size_t sz, const void *caller)
 {
-  __malloc_hook = NULL;
-  __realloc_hook = NULL;
+  __glibc_malloc_hook = NULL;
+  __glibc_realloc_hook = NULL;
   ptmalloc_init ();
-  return __libc_realloc (ptr, sz);
+  return realloc (ptr, sz);
 }
 
 static void *
 memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
 {
-  __memalign_hook = NULL;
+  __glibc_memalign_hook = NULL;
   ptmalloc_init ();
-  return __libc_memalign (alignment, sz);
+  return memalign (alignment, sz);
 }
 
 /* Whether we are using malloc checking.  */
 static int using_malloc_checking;
 
-/* Activate a standard set of debugging hooks. */
+/* In __malloc_check_init we do not enable checking, but we install
+   the hooks.  The hooks are no longer used unless libmalloc-extras.so
+   is preloaded.  Therefore we leave the hooks disabled until
+   the library tells us it has enabled them.  The value is a simple
+   protocol, it starts 0, we install the check hooks and set it to 1,
+   the interposing implementation calls __glibc_malloc_check_enable
+   when ready, and we set using_malloc_checking to 1 and
+   __glibc_malloc_check_request to zero.  That completes the transition
+   between libc.so and libmalloc-extras.so.  */
+int __glibc_malloc_check_request;
+
+/* Install a standard set of debugging hooks. */
 void
 __malloc_check_init (void)
+{
+  /* Don't enable checking yet...  */
+  using_malloc_checking = 0;
+  /* Request that libmalloc-extras.so enable checking once it has
+     been loaded.  */
+  __glibc_malloc_check_request = 1;
+  __glibc_malloc_hook = malloc_check;
+  __glibc_free_hook = free_check;
+  __glibc_realloc_hook = realloc_check;
+  __glibc_memalign_hook = memalign_check;
+}
+
+/* Enable the installed debugging hooks.
+   Called from libmalloc-extras.so.  */
+void
+__glibc_malloc_check_enable (void)
 {
   using_malloc_checking = 1;
-  __malloc_hook = malloc_check;
-  __free_hook = free_check;
-  __realloc_hook = realloc_check;
-  __memalign_hook = memalign_check;
+  __glibc_malloc_check_request = 0;
 }
 
 /* A simple, standard set of debugging hooks.  Overhead is `only' one
@@ -109,8 +145,7 @@ malloc_check_get_size (mchunkptr p)
 }
 
 /* Instrument a chunk with overrun detector byte(s) and convert it
-   into a user pointer with requested size req_sz. */
-
+   into a user pointer with requested size req_sz.  */
 static void *
 mem2mem_check (void *ptr, size_t req_sz)
 {
@@ -142,8 +177,7 @@ mem2mem_check (void *ptr, size_t req_sz)
 }
 
 /* Convert a pointer to be free()d or realloc()ed to a valid chunk
-   pointer.  If the provided pointer is not valid, return NULL. */
-
+   pointer.  If the provided pointer is not valid, return NULL.  */
 static mchunkptr
 mem2chunk_check (void *mem, unsigned char **magic_p)
 {
@@ -453,10 +487,10 @@ malloc_set_state (void *msptr)
      cannot be more than one thread when we reach this point.  */
 
   /* Disable the malloc hooks (and malloc checking).  */
-  __malloc_hook = NULL;
-  __realloc_hook = NULL;
-  __free_hook = NULL;
-  __memalign_hook = NULL;
+  __glibc_malloc_hook = NULL;
+  __glibc_realloc_hook = NULL;
+  __glibc_free_hook = NULL;
+  __glibc_memalign_hook = NULL;
   using_malloc_checking = 0;
 
   /* Patch the dumped heap.  We no longer try to integrate into the
diff --git a/malloc/malloc-extras.c b/malloc/malloc-extras.c
new file mode 100644
index 0000000000..38735d2a56
--- /dev/null
+++ b/malloc/malloc-extras.c
@@ -0,0 +1,792 @@
+/* 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 <stdarg.h>
+
+#include <libc-internal.h>
+
+#include "malloc-internal.h"
+#include "malloc-hooks.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;
+
+static void
+flood (void *ptr, int val, size_t size)
+{
+  char *cp = ptr;
+  while (size--)
+    *cp++ = val;
+}
+
+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;
+}
+
+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;
+    }
+  fprintf (stderr, "mcheck: %s", msg);
+  fflush (stderr);
+  abort ();
+}
+
+/* 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;
+}
+
+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 ("");
+}
+
+static int recursing = 0;
+
+/* Call a hook function FUNC, and if recusion is detected return
+   with value ERV.  In addition we check for
+   __glibc_malloc_check_requested to see if the runtime is waiting
+   to know if the hooks are active and if malloc_usable_size can
+   use the more accurate checking sizes for chunks.  */
+#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);	\
+      if (__glibc_malloc_check_request)				\
+	__glibc_malloc_check_enable ();				\
+    }
+
+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 (__glibc_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 (__glibc_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 (__glibc_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 (__glibc_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 (__glibc_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 ();
+}
+
+void
+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);
+    }
+}
+
+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;
+
+  fprintf (f, "= End\n");
+  fclose (f);
+}
+
+/*======================================================================*/
+/* user interface */
+
+void __attribute__ ((constructor))
+mtrace_extras_ctor (void)
+{
+  /* Enable checking if it was requested early.  */
+  if (__glibc_malloc_check_request)
+    __glibc_malloc_check_enable ();
+}
+
+void __attribute__ ((destructor))
+mtrace_extras_dtor (void)
+{
+  if (mallstream)
+    {
+      __libc_freeres ();
+      fprintf (mallstream, "= Unload?\n");
+    }
+}
diff --git a/malloc/malloc-hooks.h b/malloc/malloc-hooks.h
index f09d2318f4..4abb9c2824 100644
--- a/malloc/malloc-hooks.h
+++ b/malloc/malloc-hooks.h
@@ -20,5 +20,13 @@
 #define _MALLOC_HOOKS_H
 
 void (*__malloc_initialize_hook) (void);
+extern void (* __glibc_free_hook) (void *__ptr, const void *);
+extern void *(* __glibc_malloc_hook)(size_t __size, const void *);
+extern void *(* __glibc_realloc_hook)(void *__ptr, size_t __size, const void *);
+extern void *(* __glibc_memalign_hook)(size_t __alignment, size_t __size, const void *);
+
+/* Private APIs for libmalloc-extras.so interaction with hooks.  */
+extern int __glibc_malloc_check_request;
+void __glibc_malloc_check_enable (void);
 
 #endif  /* _MALLOC_HOOKS_H */
diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h
index 9cee0fb2d7..5e2e610cd3 100644
--- a/malloc/malloc-internal.h
+++ b/malloc/malloc-internal.h
@@ -94,4 +94,8 @@ check_mul_overflow_size_t (size_t left, size_t right, size_t *result)
 #endif
 }
 
+void __malloc_check_init (void) __THROW attribute_hidden;
+
+void *__glibc_morecore (ptrdiff_t increment) attribute_hidden;
+
 #endif /* _MALLOC_INTERNAL_H */
diff --git a/malloc/malloc.c b/malloc/malloc.c
index e247c77b7d..b642971e4e 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -357,11 +357,12 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
 
 
 /* Definition for getting more memory from the OS.  */
-#define MORECORE         (*__morecore)
+#define MORECORE         (__glibc_morecore)
 #define MORECORE_FAILURE 0
-void * __default_morecore (ptrdiff_t);
-void *(*__morecore)(ptrdiff_t) = __default_morecore;
-
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+void *(*__morecore)(ptrdiff_t) = __glibc_morecore;
+compat_symbol (libc, __morecore, __morecore, GLIBC_2_0);
+#endif
 
 #include <string.h>
 
@@ -998,20 +999,11 @@ 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);
 #endif
 
-static void*   malloc_check(size_t sz, const void *caller);
-static void      free_check(void* mem, const void *caller);
-static void*   realloc_check(void* oldmem, size_t bytes,
-			       const void *caller);
-static void*   memalign_check(size_t alignment, size_t bytes,
-				const void *caller);
-
 /* ------------------ MMAP support ------------------  */
 
 
@@ -1831,6 +1823,13 @@ 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;
@@ -1839,24 +1838,33 @@ 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,
+void weak_variable (*__glibc_free_hook) (void *__ptr,
                                    const void *) = NULL;
-void *weak_variable (*__malloc_hook)
+void *weak_variable (*__glibc_malloc_hook)
   (size_t __size, const void *) = malloc_hook_ini;
-void *weak_variable (*__realloc_hook)
+void *weak_variable (*__glibc_realloc_hook)
   (void *__ptr, size_t __size, const void *)
   = realloc_hook_ini;
-void *weak_variable (*__memalign_hook)
+void *weak_variable (*__glibc_memalign_hook)
   (size_t __alignment, size_t __size, const void *)
   = memalign_hook_ini;
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 void weak_variable (*__after_morecore_hook) (void) = NULL;
 
+/* When building the shared library we include compat symbols for the
+   hooks.  When building a static application we don't, but we also
+   don't define the hooks in any public header, so static applications
+   should not compile.  */
+compat_symbol (libc, __glibc_free_hook, __free_hook, GLIBC_2_0);
+compat_symbol (libc, __glibc_malloc_hook, __malloc_hook, GLIBC_2_0);
+compat_symbol (libc, __glibc_realloc_hook, __realloc_hook, GLIBC_2_0);
+compat_symbol (libc, __glibc_memalign_hook, __memalign_hook, GLIBC_2_0);
+compat_symbol (libc, __after_morecore_hook, __after_morecore_hook, GLIBC_2_0);
+#endif
+
+
 /* This function is called from the arena shutdown hook, to free the
    thread cache (if it exists).  */
 static void tcache_thread_shutdown (void);
@@ -2474,14 +2482,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
@@ -2618,13 +2619,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 */
@@ -2782,10 +2776,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);
@@ -3013,10 +3003,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;
@@ -3071,13 +3059,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;
@@ -3117,10 +3100,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)
@@ -3246,11 +3227,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);
@@ -3369,17 +3345,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/malloc.h b/malloc/malloc.h
index 3e7c447be1..b8234cf90b 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -71,14 +71,6 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__ __wur;
    __size to nearest pagesize. */
 extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur;
 
-/* Underlying allocation function; successive calls should return
-   contiguous pieces of memory.  */
-extern void *(*__morecore) (ptrdiff_t __size);
-
-/* Default value of `__morecore'.  */
-extern void *__default_morecore (ptrdiff_t __size)
-__THROW __attribute_malloc__;
-
 /* SVID2/XPG mallinfo structure */
 
 struct mallinfo
@@ -139,23 +131,6 @@ extern void malloc_stats (void) __THROW;
 /* Output information about state of allocator to stream FP.  */
 extern int malloc_info (int __options, FILE *__fp) __THROW;
 
-/* Hooks for debugging and user-defined versions. */
-extern void (*__MALLOC_HOOK_VOLATILE __free_hook) (void *__ptr,
-                                                   const void *)
-__MALLOC_DEPRECATED;
-extern void *(*__MALLOC_HOOK_VOLATILE __malloc_hook)(size_t __size,
-                                                     const void *)
-__MALLOC_DEPRECATED;
-extern void *(*__MALLOC_HOOK_VOLATILE __realloc_hook)(void *__ptr,
-                                                      size_t __size,
-                                                      const void *)
-__MALLOC_DEPRECATED;
-extern void *(*__MALLOC_HOOK_VOLATILE __memalign_hook)(size_t __alignment,
-                                                       size_t __size,
-                                                       const void *)
-__MALLOC_DEPRECATED;
-extern void (*__MALLOC_HOOK_VOLATILE __after_morecore_hook) (void);
-
 /* Activate a standard set of debugging hooks. */
 extern void __malloc_check_init (void) __THROW __MALLOC_DEPRECATED;
 
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/morecore.c b/malloc/morecore.c
index 165de7e386..b8242ceaff 100644
--- a/malloc/morecore.c
+++ b/malloc/morecore.c
@@ -42,7 +42,7 @@ libc_hidden_proto (__sbrk)
    and return the start of data space, or NULL on errors.
    If INCREMENT is negative, shrink data space.  */
 void *
-__default_morecore (ptrdiff_t increment)
+__glibc_morecore (ptrdiff_t increment)
 {
   void *result = (void *) __sbrk (increment);
   if (result == (void *) -1)
@@ -50,4 +50,6 @@ __default_morecore (ptrdiff_t increment)
 
   return result;
 }
-libc_hidden_def (__default_morecore)
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+compat_symbol (libc, __glibc_morecore, __default_morecore, GLIBC_2_0);
+#endif
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index 9064f209ec..dd92e3f92d 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,20 @@ 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!  */
+   don't forget to set a breakpoint on tr_break!  In all of these cases
+   we call mtrace() and that is interposed by libmalloc-extras.so.  */
 
 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);
-    }
+  return;
 }
 
 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);
+  return;
 }
diff --git a/malloc/tst-malloc-usable-static-tunables.c b/malloc/tst-malloc-usable-static-tunables.c
deleted file mode 100644
index 8907db01a5..0000000000
--- a/malloc/tst-malloc-usable-static-tunables.c
+++ /dev/null
@@ -1 +0,0 @@
-#include <malloc/tst-malloc-usable.c>
diff --git a/malloc/tst-malloc-usable-static.c b/malloc/tst-malloc-usable-static.c
deleted file mode 100644
index 8907db01a5..0000000000
--- a/malloc/tst-malloc-usable-static.c
+++ /dev/null
@@ -1 +0,0 @@
-#include <malloc/tst-malloc-usable.c>
diff --git a/malloc/tst-malloc-weak-usable-static.c b/malloc/tst-malloc-weak-usable-static.c
new file mode 100644
index 0000000000..a8b9a6652f
--- /dev/null
+++ b/malloc/tst-malloc-weak-usable-static.c
@@ -0,0 +1 @@
+#include <malloc/tst-malloc-weak-usable.c>
diff --git a/malloc/tst-malloc-weak-usable.c b/malloc/tst-malloc-weak-usable.c
new file mode 100644
index 0000000000..70f939851b
--- /dev/null
+++ b/malloc/tst-malloc-weak-usable.c
@@ -0,0 +1,60 @@
+/* Ensure that malloc_usable_size returns the request size with
+   MALLOC_CHECK_ exported to a positive value and no preloaded
+   libmalloc-extras.so.
+
+   Copyright (C) 2012-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 <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+/* In this test we are purposely not loading libmalloc-extras.so
+   to test that the malloc_usable_size() correctly falls back to
+   the chunk size, and does not try to parse the check data which
+   is not present.  */
+
+static int
+do_test (void)
+{
+  size_t usable_size;
+  void *p = malloc (5);
+  if (!p)
+    {
+      printf ("memory allocation failed\n");
+      return 1;
+    }
+
+  usable_size = malloc_usable_size (p);
+
+  /* Set a reasonably wide test check here.  The point is that
+     without the checking code we are going to get the chunk
+     size back, and that might vary by architecture in theory.
+     On a 64-bit arch it should be no larger than 32-bytes given
+     the present struct layout, and likely 24 bytes.  */
+  if (usable_size < 5 || usable_size > 32)
+    {
+      printf ("malloc_usable_size: expected > 5 || < 32 but got %zu\n", usable_size);
+      return 1;
+    }
+
+  memset (p, 0, usable_size);
+  free (p);
+  return 0;
+}
+
+#include <support/test-driver.c>
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/manual/memory.texi b/manual/memory.texi
index a1435aad1a..0997412dd7 100644
--- a/manual/memory.texi
+++ b/manual/memory.texi
@@ -328,8 +328,6 @@ any time (or never).
 * Malloc Tunable Parameters::   Use @code{mallopt} to adjust allocation
                                  parameters.
 * Heap Consistency Checking::   Automatic checking for errors.
-* Hooks for Malloc::            You can use these hooks for debugging
-				 programs that use @code{malloc}.
 * Statistics of Malloc::        Getting information about how much
 				 memory your program is using.
 * Summary of Malloc::           Summary of @code{malloc} and related functions.
@@ -347,21 +345,21 @@ this function is in @file{stdlib.h}.
 @standards{ISO, malloc.h}
 @standards{ISO, stdlib.h}
 @safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}}
-@c Malloc hooks and __morecore pointers, as well as such parameters as
-@c max_n_mmaps and max_mmapped_mem, are accessed without guards, so they
-@c could pose a thread safety issue; in order to not declare malloc
-@c MT-unsafe, it's modifying the hooks and parameters while multiple
-@c threads are active that is regarded as unsafe.  An arena's next field
-@c is initialized and never changed again, except for main_arena's,
-@c that's protected by list_lock; next_free is only modified while
-@c list_lock is held too.  All other data members of an arena, as well
-@c as the metadata of the memory areas assigned to it, are only modified
-@c while holding the arena's mutex (fastbin pointers use catomic ops
-@c because they may be modified by free without taking the arena's
-@c lock).  Some reassurance was needed for fastbins, for it wasn't clear
-@c how they were initialized.  It turns out they are always
-@c zero-initialized: main_arena's, for being static data, and other
-@c arena's, for being just-mmapped memory.
+
+@c Malloc parameters such as max_n_mmaps and max_mmapped_mem, are
+@c accessed without guards, so they could pose a thread safety issue; in
+@c order to not declare malloc MT-unsafe, it's modifying the hooks and
+@c parameters while multiple threads are active that is regarded as
+@c unsafe.  An arena's next field is initialized and never changed
+@c again, except for main_arena's, that's protected by list_lock;
+@c next_free is only modified while list_lock is held too.  All other
+@c data members of an arena, as well as the metadata of the memory areas
+@c assigned to it, are only modified while holding the arena's mutex
+@c (fastbin pointers use catomic ops because they may be modified by
+@c free without taking the arena's lock).  Some reassurance was needed
+@c for fastbins, for it wasn't clear how they were initialized.  It
+@c turns out they are always zero-initialized: main_arena's, for being
+@c static data, and other arena's, for being just-mmapped memory.
 
 @c Leaking file descriptors and memory in case of cancellation is
 @c unavoidable without disabling cancellation, but the lock situation is
@@ -375,7 +373,6 @@ this function is in @file{stdlib.h}.
 
 @c __libc_malloc @asulock @aculock @acsfd @acsmem
 @c  force_reg ok
-@c  *malloc_hook unguarded
 @c  arena_lock @asulock @aculock @acsfd @acsmem
 @c   mutex_lock @asulock @aculock
 @c   arena_get2 @asulock @aculock @acsfd @acsmem
@@ -506,11 +503,8 @@ this function is in @file{stdlib.h}.
 @c    set_foot dup ok
 @c    contiguous ok
 @c    MORECORE ok
-@c     *__morecore ok unguarded
-@c      __default_morecore
 @c       sbrk ok
 @c    force_reg dup ok
-@c    *__after_morecore_hook unguarded
 @c    set_noncontiguous ok
 @c    malloc_printerr dup ok
 @c    _int_free (have_lock) @acsfd @acsmem [@asulock @aculock]
@@ -543,7 +537,6 @@ this function is in @file{stdlib.h}.
 @c     malloc_consolidate dup ok
 @c     systrim ok
 @c      MORECORE dup ok
-@c      *__after_morecore_hook dup unguarded
 @c      set_head dup ok
 @c      check_malloc_state ok/disabled
 @c     top dup ok
@@ -695,7 +688,6 @@ The prototype for this function is in @file{stdlib.h}.
 @c   each gets a signal whose handler free()s large (non-fastbin-able)
 @c   blocks from each other's arena, we deadlock; this is a more general
 @c   case of @asulock.
-@c  *__free_hook unguarded
 @c  mem2chunk ok
 @c  chunk_is_mmapped ok, chunk bits not modified after allocation
 @c  chunksize ok
@@ -764,7 +756,6 @@ You can make the block longer by calling @code{realloc} or
 @c issues arise, plus the realloc hook, also accessed without guards.
 
 @c __libc_realloc @asulock @aculock @acsfd @acsmem
-@c  *__realloc_hook unguarded
 @c  __libc_free dup @asulock @aculock @acsfd @acsmem
 @c  __libc_malloc dup @asulock @aculock @acsfd @acsmem
 @c  mem2chunk dup ok
@@ -885,7 +876,6 @@ is declared in @file{stdlib.h}.
 @c Same caveats as malloc.
 
 @c __libc_calloc @asulock @aculock @acsfd @acsmem
-@c  *__malloc_hook dup unguarded
 @c  memset dup ok
 @c  arena_get @asulock @aculock @acsfd @acsmem
 @c   arena_lock dup @asulock @aculock @acsfd @acsmem
@@ -967,7 +957,6 @@ portability to modern non-POSIX systems than @code{posix_memalign}.
 @c _int_memalign, with the arena still locked.
 
 @c __libc_memalign @asulock @aculock @acsfd @acsmem
-@c  *__memalign_hook dup unguarded
 @c  __libc_malloc dup @asulock @aculock @acsfd @acsmem
 @c  arena_get dup @asulock @aculock @acsfd @acsmem
 @c  _int_memalign @acsfd @acsmem
@@ -1056,9 +1045,7 @@ systems that do not support @w{ISO C11}.
 @c   next_env_entry ok
 @c   strcspn dup ok
 @c   __libc_mallopt dup @mtasuconst:mallopt [setting mp_]
-@c   __malloc_check_init @mtasuconst:malloc_hooks [setting hooks]
 @c   *__malloc_initialize_hook unguarded, ok
-@c  *__memalign_hook dup ok, unguarded
 @c  arena_get dup @asulock @aculock @acsfd @acsmem
 @c  _int_valloc @acsfd @acsmem
 @c   malloc_consolidate dup ok
@@ -1206,9 +1193,13 @@ using the @code{mcheck} function.  This function is a GNU extension,
 declared in @file{mcheck.h}.
 @pindex mcheck.h
 
+The functionality associated with @code{MALLOC_CHECK_} or @code{mcheck}
+is disabled by default.  To enable the functionality you must preload
+the @code{libmalloc-extras.so} library.
+
 @deftypefun int mcheck (void (*@var{abortfn}) (enum mcheck_status @var{status}))
 @standards{GNU, mcheck.h}
-@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck} @mtasuconst{:malloc_hooks}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
+@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
 @c The hooks must be set up before malloc is first used, which sort of
 @c implies @mtuinit/@asuinit but since the function is a no-op if malloc
 @c was already used, that doesn't pose any safety issues.  The actual
@@ -1261,7 +1252,7 @@ must be called before the first such function.
 @end deftypefun
 
 @deftypefun {enum mcheck_status} mprobe (void *@var{pointer})
-@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck} @mtasuconst{:malloc_hooks}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
+@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
 @c The linked list of headers may be modified concurrently by other
 @c threads, and it may find a partial update if called from a signal
 @c handler.  It's mostly read only, so cancelling it might be safe, but
@@ -1334,173 +1325,6 @@ compatibility.  Both @code{MALLOC_CHECK_} and @samp{-lmcheck} should
 uncover the same bugs - but using @code{MALLOC_CHECK_} you don't need to
 recompile your application.
 
-@node Hooks for Malloc
-@subsubsection Memory Allocation Hooks
-@cindex allocation hooks, for @code{malloc}
-
-@Theglibc{} lets you modify the behavior of @code{malloc},
-@code{realloc}, and @code{free} by specifying appropriate hook
-functions.  You can use these hooks to help you debug programs that use
-dynamic memory allocation, for example.
-
-The hook variables are declared in @file{malloc.h}.
-@pindex malloc.h
-
-@defvar __malloc_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to the function that
-@code{malloc} uses whenever it is called.  You should define this
-function to look like @code{malloc}; that is, like:
-
-@smallexample
-void *@var{function} (size_t @var{size}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{malloc} function was called.  This value allows you to trace
-the memory consumption of the program.
-@end defvar
-
-@defvar __realloc_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to function that @code{realloc}
-uses whenever it is called.  You should define this function to look
-like @code{realloc}; that is, like:
-
-@smallexample
-void *@var{function} (void *@var{ptr}, size_t @var{size}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{realloc} function was called.  This value allows you to trace the
-memory consumption of the program.
-@end defvar
-
-@defvar __free_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to function that @code{free}
-uses whenever it is called.  You should define this function to look
-like @code{free}; that is, like:
-
-@smallexample
-void @var{function} (void *@var{ptr}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{free} function was called.  This value allows you to trace the
-memory consumption of the program.
-@end defvar
-
-@defvar __memalign_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to function that @code{aligned_alloc},
-@code{memalign}, @code{posix_memalign} and @code{valloc} use whenever they
-are called.  You should define this function to look like @code{aligned_alloc};
-that is, like:
-
-@smallexample
-void *@var{function} (size_t @var{alignment}, size_t @var{size}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{aligned_alloc}, @code{memalign}, @code{posix_memalign} or
-@code{valloc} functions are called.  This value allows you to trace the
-memory consumption of the program.
-@end defvar
-
-You must make sure that the function you install as a hook for one of
-these functions does not call that function recursively without restoring
-the old value of the hook first!  Otherwise, your program will get stuck
-in an infinite recursion.  Before calling the function recursively, one
-should make sure to restore all the hooks to their previous value.  When
-coming back from the recursive call, all the hooks should be resaved
-since a hook might modify itself.
-
-An issue to look out for is the time at which the malloc hook functions
-can be safely installed.  If the hook functions call the malloc-related
-functions recursively, it is necessary that malloc has already properly
-initialized itself at the time when @code{__malloc_hook} etc. is
-assigned to.  On the other hand, if the hook functions provide a
-complete malloc implementation of their own, it is vital that the hooks
-are assigned to @emph{before} the very first @code{malloc} call has
-completed, because otherwise a chunk obtained from the ordinary,
-un-hooked malloc may later be handed to @code{__free_hook}, for example.
-
-Here is an example showing how to use @code{__malloc_hook} and
-@code{__free_hook} properly.  It installs a function that prints out
-information every time @code{malloc} or @code{free} is called.  We just
-assume here that @code{realloc} and @code{memalign} are not used in our
-program.
-
-@smallexample
-/* Prototypes for __malloc_hook, __free_hook */
-#include <malloc.h>
-
-/* Prototypes for our hooks.  */
-static void my_init_hook (void);
-static void *my_malloc_hook (size_t, const void *);
-static void my_free_hook (void*, const void *);
-
-static void
-my_init (void)
-@{
-  old_malloc_hook = __malloc_hook;
-  old_free_hook = __free_hook;
-  __malloc_hook = my_malloc_hook;
-  __free_hook = my_free_hook;
-@}
-
-static void *
-my_malloc_hook (size_t size, const void *caller)
-@{
-  void *result;
-  /* Restore all old hooks */
-  __malloc_hook = old_malloc_hook;
-  __free_hook = old_free_hook;
-  /* Call recursively */
-  result = malloc (size);
-  /* Save underlying hooks */
-  old_malloc_hook = __malloc_hook;
-  old_free_hook = __free_hook;
-  /* @r{@code{printf} might call @code{malloc}, so protect it too.} */
-  printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
-  /* Restore our own hooks */
-  __malloc_hook = my_malloc_hook;
-  __free_hook = my_free_hook;
-  return result;
-@}
-
-static void
-my_free_hook (void *ptr, const void *caller)
-@{
-  /* Restore all old hooks */
-  __malloc_hook = old_malloc_hook;
-  __free_hook = old_free_hook;
-  /* Call recursively */
-  free (ptr);
-  /* Save underlying hooks */
-  old_malloc_hook = __malloc_hook;
-  old_free_hook = __free_hook;
-  /* @r{@code{printf} might call @code{free}, so protect it too.} */
-  printf ("freed pointer %p\n", ptr);
-  /* Restore our own hooks */
-  __malloc_hook = my_malloc_hook;
-  __free_hook = my_free_hook;
-@}
-
-main ()
-@{
-  my_init ();
-  @dots{}
-@}
-@end smallexample
-
-The @code{mcheck} function (@pxref{Heap Consistency Checking}) works by
-installing such hooks.
-
-@c __morecore, __after_morecore_hook are undocumented
-@c It's not clear whether to document them.
-
 @node Statistics of Malloc
 @subsubsection Statistics for Memory Allocation with @code{malloc}
 
@@ -1632,19 +1456,6 @@ Tell @code{malloc} to perform occasional consistency checks on
 dynamically allocated memory, and to call @var{abortfn} when an
 inconsistency is found.  @xref{Heap Consistency Checking}.
 
-@item void *(*__malloc_hook) (size_t @var{size}, const void *@var{caller})
-A pointer to a function that @code{malloc} uses whenever it is called.
-
-@item void *(*__realloc_hook) (void *@var{ptr}, size_t @var{size}, const void *@var{caller})
-A pointer to a function that @code{realloc} uses whenever it is called.
-
-@item void (*__free_hook) (void *@var{ptr}, const void *@var{caller})
-A pointer to a function that @code{free} uses whenever it is called.
-
-@item void (*__memalign_hook) (size_t @var{size}, size_t @var{alignment}, const void *@var{caller})
-A pointer to a function that @code{aligned_alloc}, @code{memalign},
-@code{posix_memalign} and @code{valloc} use whenever they are called.
-
 @item struct mallinfo mallinfo (void)
 Return information about the current dynamic memory usage.
 @xref{Statistics of Malloc}.
@@ -1667,6 +1478,10 @@ the location.  To do this the application must be started in a special
 mode which is enabled by an environment variable.  There are no speed
 penalties for the program if the debugging mode is not enabled.
 
+The allocation debugging functionality is only safe for use in
+single-threaded programs and requires preloading
+@code{libmalloc-extras.so}.
+
 @menu
 * Tracing malloc::               How to install the tracing functionality.
 * Using the Memory Debugger::    Example programs excerpts.
@@ -1679,7 +1494,7 @@ penalties for the program if the debugging mode is not enabled.
 
 @deftypefun void mtrace (void)
 @standards{GNU, mcheck.h}
-@safety{@prelim{}@mtunsafe{@mtsenv{} @mtasurace{:mtrace} @mtasuconst{:malloc_hooks} @mtuinit{}}@asunsafe{@asuinit{} @ascuheap{} @asucorrupt{} @asulock{}}@acunsafe{@acuinit{} @acucorrupt{} @aculock{} @acsfd{} @acsmem{}}}
+@safety{@prelim{}@mtunsafe{@mtsenv{} @mtasurace{:mtrace} @mtuinit{}}@asunsafe{@asuinit{} @ascuheap{} @asucorrupt{} @asulock{}}@acunsafe{@acuinit{} @acucorrupt{} @aculock{} @acsfd{} @acsmem{}}}
 @c Like the mcheck hooks, these are not designed with thread safety in
 @c mind, because the hook pointers are temporarily modified without
 @c regard to other threads, signals or cancellation.
@@ -1715,7 +1530,7 @@ systems.  The prototype can be found in @file{mcheck.h}.
 
 @deftypefun void muntrace (void)
 @standards{GNU, mcheck.h}
-@safety{@prelim{}@mtunsafe{@mtasurace{:mtrace} @mtasuconst{:malloc_hooks} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{}}@acunsafe{@acucorrupt{} @acsmem{} @aculock{} @acsfd{}}}
+@safety{@prelim{}@mtunsafe{@mtasurace{:mtrace} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{}}@acunsafe{@acucorrupt{} @acsmem{} @aculock{} @acsfd{}}}
 
 @c muntrace @mtasurace:mtrace @mtslocale @asucorrupt @ascuheap @acucorrupt @acsmem @aculock @acsfd
 @c  fprintf (fputs) dup @mtslocale @asucorrupt @ascuheap @acsmem @aculock @acucorrupt
diff --git a/misc/Makefile b/misc/Makefile
index b7be2bc19a..901b287468 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -135,13 +135,15 @@ $(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 > $@; \
 	$(evaluate-test)
 
-tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace
+tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace \
+	LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
 $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
 	$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
 	$(evaluate-test)
diff --git a/nptl/Makefile b/nptl/Makefile
index 2f2bb0569d..4ee04ef620 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -529,10 +529,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 989e42e1f8..8efa11bc34 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -278,43 +278,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 > $@; \
@@ -323,18 +330,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)
@@ -347,15 +357,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..3ab6bdce49 100644
--- a/posix/tst-vfork3.c
+++ b/posix/tst-vfork3.c
@@ -147,6 +147,12 @@ do_prepare (void)
     FAIL_EXIT1 ("out of memory");
   strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX");
 
+  /* We have preloaded libmalloc-extras.so to implement mtrace().
+     We unset LD_PRELOAD since the children run via /bin/sh which
+     uses the system libc which may lack the integration required
+     by libmalloc-extras.so.  */
+  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 ea395ac3eb..2668ee1c54 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -152,17 +152,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 738a3cead0..bdb8578c40 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -91,9 +91,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)' > $@; \
