public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH v4 00/10] Remove malloc hooks
@ 2021-07-02 11:38 Siddhesh Poyarekar
  2021-07-02 11:38 ` [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c Siddhesh Poyarekar
                   ` (10 more replies)
  0 siblings, 11 replies; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

This patchset removes the malloc hooks __malloc_hook, __free_hook,
__realloc_hook and __memalign_hook from the API and leaves compatibility
symbols so that existing applications can continue to link to them.  The
reading and execution of the hooks has been moved to a DSO
libmalloc_compathooks.so, which can be preloaded for applications that
need it.  By default these hooks no longer have any effect in the
library.

Further, the __morecore, __morecore_after_hook and __default_morecore
hooks have also been moved to compat symbols and removed from the API.
Existing applications will continue to link to them but they won't have
any effect on malloc behaviour.

To enable this, the MALLOC_CHECK_, mcheck() and mtrace() hooks have been
weaned away from hooks.  In the process, some mcheck() failures have
been fixed and the overall behaviour is now simpler to follow.  Finally,
tr_break and mallwatch symbols have been deprecated and are not used
anywhere.  Users are advised to use gdb watchpoints and conditional
breakpoints to debug malloc internals since they ought to provide
equivalent functionality.

Changes from v3:
- Remove source file dependencies
- Commit mcheck tests

Changes from v2:
- Move hooks dependencies to malloc.o{,sS}

Changes from v1:

- Added makefile dependencies for the new hooks files
- Fixed memset call in calloc debugging hooks
- Added the tr_break deprecation patch and mcheck test patch to this
  series

Siddhesh Poyarekar (10):
  Drop source dependencies on hooks.c and arena.c
  mtrace: Deprecate mallwatch and tr_break
  Move glibc.malloc.check implementation into its own file
  malloc: Move malloc hook references to hooks.c
  glibc.malloc.check: Wean away from malloc hooks
  mcheck: Wean away from malloc hooks
  mtrace: Wean away from malloc hooks
  Remove malloc hooks
  Remove __after_morecore_hook
  Remove __morecore and __default_morecore

 Makeconfig                                    |   2 +-
 NEWS                                          |  18 +
 include/malloc.h                              |  11 +-
 include/stdlib.h                              |   3 -
 malloc/Makefile                               |  23 +-
 malloc/Versions                               |   3 +
 malloc/arena.c                                |  26 +-
 malloc/hooks.c                                | 545 +++++++-----------
 malloc/malloc-check.c                         | 376 ++++++++++++
 malloc/malloc-compathooks.c                   | 166 ++++++
 malloc/malloc-internal.h                      |   6 +
 malloc/malloc.c                               | 235 ++++----
 malloc/malloc.h                               |  27 -
 malloc/mcheck-hooks.c                         | 411 +++++++++++++
 malloc/mcheck-init.c                          |  14 +-
 malloc/mcheck.c                               | 369 +-----------
 malloc/morecore.c                             |  15 +-
 malloc/mtrace-hooks.c                         | 137 +++++
 malloc/mtrace.c                               | 276 +--------
 manual/memory.texi                            | 191 +-----
 sysdeps/mach/hurd/i386/libc.abilist           |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |   1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 53 files changed, 1547 insertions(+), 1340 deletions(-)
 create mode 100644 malloc/malloc-check.c
 create mode 100644 malloc/malloc-compathooks.c
 create mode 100644 malloc/mcheck-hooks.c
 create mode 100644 malloc/mtrace-hooks.c

-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 12:12   ` Andreas Schwab
  2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Siddhesh Poyarekar
                   ` (9 subsequent siblings)
  10 siblings, 2 replies; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Dependencies on hooks.c and arena.c get auto-computed when generating
malloc.o{,s}.d so there is no need to add them manually.
---
 malloc/Makefile | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/malloc/Makefile b/malloc/Makefile
index c8256abbbf..2f9b3d596d 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -269,10 +269,6 @@ $(objpfx)memusage: memusage.sh
 	    -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|' $^ > $@.new \
 	&& rm -f $@ && mv $@.new $@ && chmod +x $@
 
-
-# Extra dependencies
-$(foreach o,$(all-object-suffixes),$(objpfx)malloc$(o)): arena.c hooks.c
-
 # Compile the tests with a flag which suppresses the mallopt call in
 # the test skeleton.
 $(tests:%=$(objpfx)%.o): CPPFLAGS += -DTEST_NO_MALLOPT
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
  2021-07-02 11:38 ` [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 20:37   ` Tulio Magno Quites Machado Filho
  2021-07-02 11:38 ` [PATCH v4 03/10] Move glibc.malloc.check implementation into its own file Siddhesh Poyarekar
                   ` (8 subsequent siblings)
  10 siblings, 2 replies; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

The variable and function pair appear to provide a way for users to
set conditional breakpoints in mtrace when a specific address is
returned by the allocator.  This can be achieved by using conditional
breakpoints in gdb so it is redundant.  There is no documentation of
this interface in the manual either, so it appears to have been a hack
that got added to debug malloc.  Deprecate these symbols and do not
call tr_break anymore.

Reviewed-by: DJ Delorie <dj@redhat.com>
---
 NEWS            |  4 ++++
 malloc/mtrace.c | 57 +++++++++++++++++--------------------------------
 2 files changed, 24 insertions(+), 37 deletions(-)

diff --git a/NEWS b/NEWS
index 60933bd975..8e72946c3f 100644
--- a/NEWS
+++ b/NEWS
@@ -93,6 +93,10 @@ Deprecated and removed features, and other changes affecting compatibility:
   package managers that delete removed files late during the package
   upgrade or downgrade process.
 
+* The symbols mallwatch and tr_break are now deprecated and no longer used in
+  mtrace.  Similar functionality can be achieved by using conditional
+  breakpoints within mtrace functions from within gdb.
+
 Changes to build and runtime requirements:
 
 * On Linux, the shm_open, sem_open, and related functions now expect the
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index b65b21a933..6c2c58b706 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -50,8 +50,25 @@ static char *malloc_trace_buffer;
 
 __libc_lock_define_initialized (static, lock);
 
-/* Address to breakpoint on accesses to... */
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+/* Compatibility symbols that were introduced to help break at allocation sites
+   for specific memory allocations.  This is unusable with ASLR, although gdb
+   may allow predictable allocation addresses.  Even then, gdb has watchpoint
+   and conditional breakpoint support which should provide the same
+   functionality without having this kludge.  These symbols are preserved in
+   case some applications ended up linking against them but they don't actually
+   do anything anymore; not that they did much before anyway.  */
+
 void *mallwatch;
+compat_symbol (libc, mallwatch, mallwatch, GLIBC_2_0);
+
+void
+tr_break (void)
+{
+}
+compat_symbol (libc, tr_break, tr_break, GLIBC_2_0);
+#endif
+
 
 /* Old hook values.  */
 static void (*tr_old_free_hook) (void *ptr, const void *);
@@ -61,19 +78,6 @@ static void *(*tr_old_realloc_hook) (void *ptr, size_t size,
 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
-   tr_break.  */
-
-extern void tr_break (void) __THROW;
-libc_hidden_proto (tr_break)
-void
-tr_break (void)
-{
-}
-libc_hidden_def (tr_break)
-
 static void
 tr_where (const void *caller, Dl_info *info)
 {
@@ -167,12 +171,6 @@ tr_freehook (void *ptr, const void *caller)
   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);
-    }
   set_default_hooks ();
   if (tr_old_free_hook != NULL)
     (*tr_old_free_hook)(ptr, caller);
@@ -203,9 +201,6 @@ tr_mallochook (size_t size, const void *caller)
 
   __libc_lock_unlock (lock);
 
-  if (hdr == mallwatch)
-    tr_break ();
-
   return hdr;
 }
 
@@ -214,9 +209,6 @@ 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);
 
@@ -247,9 +239,6 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
 
   __libc_lock_unlock (lock);
 
-  if (hdr == mallwatch)
-    tr_break ();
-
   return hdr;
 }
 
@@ -274,9 +263,6 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
 
   __libc_lock_unlock (lock);
 
-  if (hdr == mallwatch)
-    tr_break ();
-
   return hdr;
 }
 
@@ -296,10 +282,7 @@ release_libc_mem (void)
 #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!  */
+/* We enable tracing if the environment variable MALLOC_TRACE is set.  */
 
 void
 mtrace (void)
@@ -321,7 +304,7 @@ mtrace (void)
 #else
   mallfile = getenv (mallenv);
 #endif
-  if (mallfile != NULL || mallwatch != NULL)
+  if (mallfile != NULL)
     {
       char *mtb = malloc (TRACE_BUFFER_SIZE);
       if (mtb == NULL)
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 03/10] Move glibc.malloc.check implementation into its own file
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
  2021-07-02 11:38 ` [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c Siddhesh Poyarekar
  2021-07-02 11:38 ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 04/10] malloc: Move malloc hook references to hooks.c Siddhesh Poyarekar
                   ` (7 subsequent siblings)
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Separate the malloc check implementation from the malloc hooks.  They
still use the hooks but are now maintained in a separate file.
---
 malloc/hooks.c        | 371 +---------------------------------------
 malloc/malloc-check.c | 390 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 391 insertions(+), 370 deletions(-)
 create mode 100644 malloc/malloc-check.c

diff --git a/malloc/hooks.c b/malloc/hooks.c
index 8080c3f40e..57a9b55788 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -49,376 +49,7 @@ memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
   return __libc_memalign (alignment, sz);
 }
 
-/* Whether we are using malloc checking.  */
-static int using_malloc_checking;
-
-/* Activate a standard set of debugging hooks. */
-void
-__malloc_check_init (void)
-{
-  using_malloc_checking = 1;
-  __malloc_hook = malloc_check;
-  __free_hook = free_check;
-  __realloc_hook = realloc_check;
-  __memalign_hook = memalign_check;
-}
-
-/* When memory is tagged, the checking data is stored in the user part
-   of the chunk.  We can't rely on the user not having modified the
-   tags, so fetch the tag at each location before dereferencing
-   it.  */
-#define SAFE_CHAR_OFFSET(p,offset) \
-  ((unsigned char *) tag_at (((unsigned char *) p) + offset))
-
-/* A simple, standard set of debugging hooks.  Overhead is `only' one
-   byte per chunk; still this will catch most cases of double frees or
-   overruns.  The goal here is to avoid obscure crashes due to invalid
-   usage, unlike in the MALLOC_DEBUG code. */
-
-static unsigned char
-magicbyte (const void *p)
-{
-  unsigned char magic;
-
-  magic = (((uintptr_t) p >> 3) ^ ((uintptr_t) p >> 11)) & 0xFF;
-  /* Do not return 1.  See the comment in mem2mem_check().  */
-  if (magic == 1)
-    ++magic;
-  return magic;
-}
-
-/* Visualize the chunk as being partitioned into blocks of 255 bytes from the
-   highest address of the chunk, downwards.  The end of each block tells
-   us the size of that block, up to the actual size of the requested
-   memory.  Our magic byte is right at the end of the requested size, so we
-   must reach it with this iteration, otherwise we have witnessed a memory
-   corruption.  */
-static size_t
-malloc_check_get_size (mchunkptr p)
-{
-  size_t size;
-  unsigned char c;
-  unsigned char magic = magicbyte (p);
-
-  assert (using_malloc_checking == 1);
-
-  for (size = CHUNK_HDR_SZ + memsize (p) - 1;
-       (c = *SAFE_CHAR_OFFSET (p, size)) != magic;
-       size -= c)
-    {
-      if (c <= 0 || size < (c + CHUNK_HDR_SZ))
-	malloc_printerr ("malloc_check_get_size: memory corruption");
-    }
-
-  /* chunk2mem size.  */
-  return size - CHUNK_HDR_SZ;
-}
-
-/* Instrument a chunk with overrun detector byte(s) and convert it
-   into a user pointer with requested size req_sz. */
-
-static void *
-mem2mem_check (void *ptr, size_t req_sz)
-{
-  mchunkptr p;
-  unsigned char *m_ptr = ptr;
-  size_t max_sz, block_sz, i;
-  unsigned char magic;
-
-  if (!ptr)
-    return ptr;
-
-  p = mem2chunk (ptr);
-  magic = magicbyte (p);
-  max_sz = memsize (p);
-
-  for (i = max_sz - 1; i > req_sz; i -= block_sz)
-    {
-      block_sz = MIN (i - req_sz, 0xff);
-      /* Don't allow the magic byte to appear in the chain of length bytes.
-         For the following to work, magicbyte cannot return 0x01.  */
-      if (block_sz == magic)
-        --block_sz;
-
-      *SAFE_CHAR_OFFSET (m_ptr, i) = block_sz;
-    }
-  *SAFE_CHAR_OFFSET (m_ptr, req_sz) = magic;
-  return (void *) m_ptr;
-}
-
-/* Convert a pointer to be free()d or realloc()ed to a valid chunk
-   pointer.  If the provided pointer is not valid, return NULL. */
-
-static mchunkptr
-mem2chunk_check (void *mem, unsigned char **magic_p)
-{
-  mchunkptr p;
-  INTERNAL_SIZE_T sz, c;
-  unsigned char magic;
-
-  if (!aligned_OK (mem))
-    return NULL;
-
-  p = mem2chunk (mem);
-  sz = chunksize (p);
-  magic = magicbyte (p);
-  if (!chunk_is_mmapped (p))
-    {
-      /* Must be a chunk in conventional heap memory. */
-      int contig = contiguous (&main_arena);
-      if ((contig &&
-           ((char *) p < mp_.sbrk_base ||
-            ((char *) p + sz) >= (mp_.sbrk_base + main_arena.system_mem))) ||
-          sz < MINSIZE || sz & MALLOC_ALIGN_MASK || !inuse (p) ||
-          (!prev_inuse (p) && ((prev_size (p) & MALLOC_ALIGN_MASK) != 0 ||
-                               (contig && (char *) prev_chunk (p) < mp_.sbrk_base) ||
-                               next_chunk (prev_chunk (p)) != p)))
-        return NULL;
-
-      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
-	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
-	   sz -= c)
-        {
-          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
-            return NULL;
-        }
-    }
-  else
-    {
-      unsigned long offset, page_mask = GLRO (dl_pagesize) - 1;
-
-      /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
-         alignment relative to the beginning of a page.  Check this
-         first. */
-      offset = (unsigned long) mem & page_mask;
-      if ((offset != MALLOC_ALIGNMENT && offset != 0 && offset != 0x10 &&
-           offset != 0x20 && offset != 0x40 && offset != 0x80 && offset != 0x100 &&
-           offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
-           offset < 0x2000) ||
-          !chunk_is_mmapped (p) || prev_inuse (p) ||
-          ((((unsigned long) p - prev_size (p)) & page_mask) != 0) ||
-          ((prev_size (p) + sz) & page_mask) != 0)
-        return NULL;
-
-      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
-	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
-	   sz -= c)
-        {
-          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
-            return NULL;
-        }
-    }
-
-  unsigned char* safe_p = SAFE_CHAR_OFFSET (p, sz);
-  *safe_p ^= 0xFF;
-  if (magic_p)
-    *magic_p = safe_p;
-  return p;
-}
-
-/* Check for corruption of the top chunk.  */
-static void
-top_check (void)
-{
-  mchunkptr t = top (&main_arena);
-
-  if (t == initial_top (&main_arena) ||
-      (!chunk_is_mmapped (t) &&
-       chunksize (t) >= MINSIZE &&
-       prev_inuse (t) &&
-       (!contiguous (&main_arena) ||
-        (char *) t + chunksize (t) == mp_.sbrk_base + main_arena.system_mem)))
-    return;
-
-  malloc_printerr ("malloc: top chunk is corrupt");
-}
-
-static void *
-malloc_check (size_t sz, const void *caller)
-{
-  void *victim;
-  size_t nb;
-
-  if (__builtin_add_overflow (sz, 1, &nb))
-    {
-      __set_errno (ENOMEM);
-      return NULL;
-    }
-
-  __libc_lock_lock (main_arena.mutex);
-  top_check ();
-  victim = _int_malloc (&main_arena, nb);
-  __libc_lock_unlock (main_arena.mutex);
-  return mem2mem_check (tag_new_usable (victim), sz);
-}
-
-static void
-free_check (void *mem, const void *caller)
-{
-  mchunkptr p;
-
-  if (!mem)
-    return;
-
-  int err = errno;
-
-  /* Quickly check that the freed pointer matches the tag for the memory.
-     This gives a useful double-free detection.  */
-  if (__glibc_unlikely (mtag_enabled))
-    *(volatile char *)mem;
-
-  __libc_lock_lock (main_arena.mutex);
-  p = mem2chunk_check (mem, NULL);
-  if (!p)
-    malloc_printerr ("free(): invalid pointer");
-  if (chunk_is_mmapped (p))
-    {
-      __libc_lock_unlock (main_arena.mutex);
-      munmap_chunk (p);
-    }
-  else
-    {
-      /* Mark the chunk as belonging to the library again.  */
-      (void)tag_region (chunk2mem (p), memsize (p));
-      _int_free (&main_arena, p, 1);
-      __libc_lock_unlock (main_arena.mutex);
-    }
-  __set_errno (err);
-}
-
-static void *
-realloc_check (void *oldmem, size_t bytes, const void *caller)
-{
-  INTERNAL_SIZE_T chnb;
-  void *newmem = 0;
-  unsigned char *magic_p;
-  size_t rb;
-
-  if (__builtin_add_overflow (bytes, 1, &rb))
-    {
-      __set_errno (ENOMEM);
-      return NULL;
-    }
-  if (oldmem == 0)
-    return malloc_check (bytes, NULL);
-
-  if (bytes == 0)
-    {
-      free_check (oldmem, NULL);
-      return NULL;
-    }
-
-  /* Quickly check that the freed pointer matches the tag for the memory.
-     This gives a useful double-free detection.  */
-  if (__glibc_unlikely (mtag_enabled))
-    *(volatile char *)oldmem;
-
-  __libc_lock_lock (main_arena.mutex);
-  const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p);
-  __libc_lock_unlock (main_arena.mutex);
-  if (!oldp)
-    malloc_printerr ("realloc(): invalid pointer");
-  const INTERNAL_SIZE_T oldsize = chunksize (oldp);
-
-  if (!checked_request2size (rb, &chnb))
-    {
-      __set_errno (ENOMEM);
-      goto invert;
-    }
-
-  __libc_lock_lock (main_arena.mutex);
-
-  if (chunk_is_mmapped (oldp))
-    {
-#if HAVE_MREMAP
-      mchunkptr newp = mremap_chunk (oldp, chnb);
-      if (newp)
-        newmem = chunk2mem_tag (newp);
-      else
-#endif
-      {
-	/* Note the extra SIZE_SZ overhead. */
-        if (oldsize - SIZE_SZ >= chnb)
-          newmem = oldmem; /* do nothing */
-        else
-          {
-            /* Must alloc, copy, free. */
-	    top_check ();
-	    newmem = _int_malloc (&main_arena, rb);
-            if (newmem)
-              {
-                memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
-                munmap_chunk (oldp);
-              }
-          }
-      }
-    }
-  else
-    {
-      top_check ();
-      newmem = _int_realloc (&main_arena, oldp, oldsize, chnb);
-    }
-
-  DIAG_PUSH_NEEDS_COMMENT;
-#if __GNUC_PREREQ (7, 0)
-  /* GCC 7 warns about magic_p may be used uninitialized.  But we never
-     reach here if magic_p is uninitialized.  */
-  DIAG_IGNORE_NEEDS_COMMENT (7, "-Wmaybe-uninitialized");
-#endif
-  /* mem2chunk_check changed the magic byte in the old chunk.
-     If newmem is NULL, then the old chunk will still be used though,
-     so we need to invert that change here.  */
-invert:
-  if (newmem == NULL)
-    *magic_p ^= 0xFF;
-  DIAG_POP_NEEDS_COMMENT;
-
-  __libc_lock_unlock (main_arena.mutex);
-
-  return mem2mem_check (tag_new_usable (newmem), bytes);
-}
-
-static void *
-memalign_check (size_t alignment, size_t bytes, const void *caller)
-{
-  void *mem;
-
-  if (alignment <= MALLOC_ALIGNMENT)
-    return malloc_check (bytes, NULL);
-
-  if (alignment < MINSIZE)
-    alignment = MINSIZE;
-
-  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
-     power of 2 and will cause overflow in the check below.  */
-  if (alignment > SIZE_MAX / 2 + 1)
-    {
-      __set_errno (EINVAL);
-      return 0;
-    }
-
-  /* Check for overflow.  */
-  if (bytes > SIZE_MAX - alignment - MINSIZE)
-    {
-      __set_errno (ENOMEM);
-      return 0;
-    }
-
-  /* Make sure alignment is power of 2.  */
-  if (!powerof2 (alignment))
-    {
-      size_t a = MALLOC_ALIGNMENT * 2;
-      while (a < alignment)
-        a <<= 1;
-      alignment = a;
-    }
-
-  __libc_lock_lock (main_arena.mutex);
-  top_check ();
-  mem = _int_memalign (&main_arena, alignment, bytes + 1);
-  __libc_lock_unlock (main_arena.mutex);
-  return mem2mem_check (tag_new_usable (mem), bytes);
-}
+#include "malloc-check.c"
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
 
diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
new file mode 100644
index 0000000000..dcab880510
--- /dev/null
+++ b/malloc/malloc-check.c
@@ -0,0 +1,390 @@
+/* glibc.malloc.check implementation.
+   Copyright (C) 2001-2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
+
+   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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+
+/* Whether we are using malloc checking.  */
+static int using_malloc_checking;
+
+/* Activate a standard set of debugging hooks. */
+void
+__malloc_check_init (void)
+{
+  using_malloc_checking = 1;
+  __malloc_hook = malloc_check;
+  __free_hook = free_check;
+  __realloc_hook = realloc_check;
+  __memalign_hook = memalign_check;
+}
+
+/* When memory is tagged, the checking data is stored in the user part
+   of the chunk.  We can't rely on the user not having modified the
+   tags, so fetch the tag at each location before dereferencing
+   it.  */
+#define SAFE_CHAR_OFFSET(p,offset) \
+  ((unsigned char *) tag_at (((unsigned char *) p) + offset))
+
+/* A simple, standard set of debugging hooks.  Overhead is `only' one
+   byte per chunk; still this will catch most cases of double frees or
+   overruns.  The goal here is to avoid obscure crashes due to invalid
+   usage, unlike in the MALLOC_DEBUG code. */
+
+static unsigned char
+magicbyte (const void *p)
+{
+  unsigned char magic;
+
+  magic = (((uintptr_t) p >> 3) ^ ((uintptr_t) p >> 11)) & 0xFF;
+  /* Do not return 1.  See the comment in mem2mem_check().  */
+  if (magic == 1)
+    ++magic;
+  return magic;
+}
+
+/* Visualize the chunk as being partitioned into blocks of 255 bytes from the
+   highest address of the chunk, downwards.  The end of each block tells
+   us the size of that block, up to the actual size of the requested
+   memory.  Our magic byte is right at the end of the requested size, so we
+   must reach it with this iteration, otherwise we have witnessed a memory
+   corruption.  */
+static size_t
+malloc_check_get_size (mchunkptr p)
+{
+  size_t size;
+  unsigned char c;
+  unsigned char magic = magicbyte (p);
+
+  assert (using_malloc_checking == 1);
+
+  for (size = CHUNK_HDR_SZ + memsize (p) - 1;
+       (c = *SAFE_CHAR_OFFSET (p, size)) != magic;
+       size -= c)
+    {
+      if (c <= 0 || size < (c + CHUNK_HDR_SZ))
+	malloc_printerr ("malloc_check_get_size: memory corruption");
+    }
+
+  /* chunk2mem size.  */
+  return size - CHUNK_HDR_SZ;
+}
+
+/* Instrument a chunk with overrun detector byte(s) and convert it
+   into a user pointer with requested size req_sz. */
+
+static void *
+mem2mem_check (void *ptr, size_t req_sz)
+{
+  mchunkptr p;
+  unsigned char *m_ptr = ptr;
+  size_t max_sz, block_sz, i;
+  unsigned char magic;
+
+  if (!ptr)
+    return ptr;
+
+  p = mem2chunk (ptr);
+  magic = magicbyte (p);
+  max_sz = memsize (p);
+
+  for (i = max_sz - 1; i > req_sz; i -= block_sz)
+    {
+      block_sz = MIN (i - req_sz, 0xff);
+      /* Don't allow the magic byte to appear in the chain of length bytes.
+         For the following to work, magicbyte cannot return 0x01.  */
+      if (block_sz == magic)
+        --block_sz;
+
+      *SAFE_CHAR_OFFSET (m_ptr, i) = block_sz;
+    }
+  *SAFE_CHAR_OFFSET (m_ptr, req_sz) = magic;
+  return (void *) m_ptr;
+}
+
+/* Convert a pointer to be free()d or realloc()ed to a valid chunk
+   pointer.  If the provided pointer is not valid, return NULL. */
+
+static mchunkptr
+mem2chunk_check (void *mem, unsigned char **magic_p)
+{
+  mchunkptr p;
+  INTERNAL_SIZE_T sz, c;
+  unsigned char magic;
+
+  if (!aligned_OK (mem))
+    return NULL;
+
+  p = mem2chunk (mem);
+  sz = chunksize (p);
+  magic = magicbyte (p);
+  if (!chunk_is_mmapped (p))
+    {
+      /* Must be a chunk in conventional heap memory. */
+      int contig = contiguous (&main_arena);
+      if ((contig &&
+           ((char *) p < mp_.sbrk_base ||
+            ((char *) p + sz) >= (mp_.sbrk_base + main_arena.system_mem))) ||
+          sz < MINSIZE || sz & MALLOC_ALIGN_MASK || !inuse (p) ||
+          (!prev_inuse (p) && ((prev_size (p) & MALLOC_ALIGN_MASK) != 0 ||
+                               (contig && (char *) prev_chunk (p) < mp_.sbrk_base) ||
+                               next_chunk (prev_chunk (p)) != p)))
+        return NULL;
+
+      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
+	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
+	   sz -= c)
+        {
+          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
+            return NULL;
+        }
+    }
+  else
+    {
+      unsigned long offset, page_mask = GLRO (dl_pagesize) - 1;
+
+      /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
+         alignment relative to the beginning of a page.  Check this
+         first. */
+      offset = (unsigned long) mem & page_mask;
+      if ((offset != MALLOC_ALIGNMENT && offset != 0 && offset != 0x10 &&
+           offset != 0x20 && offset != 0x40 && offset != 0x80 && offset != 0x100 &&
+           offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
+           offset < 0x2000) ||
+          !chunk_is_mmapped (p) || prev_inuse (p) ||
+          ((((unsigned long) p - prev_size (p)) & page_mask) != 0) ||
+          ((prev_size (p) + sz) & page_mask) != 0)
+        return NULL;
+
+      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
+	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
+	   sz -= c)
+        {
+          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
+            return NULL;
+        }
+    }
+
+  unsigned char* safe_p = SAFE_CHAR_OFFSET (p, sz);
+  *safe_p ^= 0xFF;
+  if (magic_p)
+    *magic_p = safe_p;
+  return p;
+}
+
+/* Check for corruption of the top chunk.  */
+static void
+top_check (void)
+{
+  mchunkptr t = top (&main_arena);
+
+  if (t == initial_top (&main_arena) ||
+      (!chunk_is_mmapped (t) &&
+       chunksize (t) >= MINSIZE &&
+       prev_inuse (t) &&
+       (!contiguous (&main_arena) ||
+        (char *) t + chunksize (t) == mp_.sbrk_base + main_arena.system_mem)))
+    return;
+
+  malloc_printerr ("malloc: top chunk is corrupt");
+}
+
+static void *
+malloc_check (size_t sz, const void *caller)
+{
+  void *victim;
+  size_t nb;
+
+  if (__builtin_add_overflow (sz, 1, &nb))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+
+  __libc_lock_lock (main_arena.mutex);
+  top_check ();
+  victim = _int_malloc (&main_arena, nb);
+  __libc_lock_unlock (main_arena.mutex);
+  return mem2mem_check (tag_new_usable (victim), sz);
+}
+
+static void
+free_check (void *mem, const void *caller)
+{
+  mchunkptr p;
+
+  if (!mem)
+    return;
+
+  int err = errno;
+
+  /* Quickly check that the freed pointer matches the tag for the memory.
+     This gives a useful double-free detection.  */
+  if (__glibc_unlikely (mtag_enabled))
+    *(volatile char *)mem;
+
+  __libc_lock_lock (main_arena.mutex);
+  p = mem2chunk_check (mem, NULL);
+  if (!p)
+    malloc_printerr ("free(): invalid pointer");
+  if (chunk_is_mmapped (p))
+    {
+      __libc_lock_unlock (main_arena.mutex);
+      munmap_chunk (p);
+    }
+  else
+    {
+      /* Mark the chunk as belonging to the library again.  */
+      (void)tag_region (chunk2mem (p), memsize (p));
+      _int_free (&main_arena, p, 1);
+      __libc_lock_unlock (main_arena.mutex);
+    }
+  __set_errno (err);
+}
+
+static void *
+realloc_check (void *oldmem, size_t bytes, const void *caller)
+{
+  INTERNAL_SIZE_T chnb;
+  void *newmem = 0;
+  unsigned char *magic_p;
+  size_t rb;
+
+  if (__builtin_add_overflow (bytes, 1, &rb))
+    {
+      __set_errno (ENOMEM);
+      return NULL;
+    }
+  if (oldmem == 0)
+    return malloc_check (bytes, NULL);
+
+  if (bytes == 0)
+    {
+      free_check (oldmem, NULL);
+      return NULL;
+    }
+
+  /* Quickly check that the freed pointer matches the tag for the memory.
+     This gives a useful double-free detection.  */
+  if (__glibc_unlikely (mtag_enabled))
+    *(volatile char *)oldmem;
+
+  __libc_lock_lock (main_arena.mutex);
+  const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p);
+  __libc_lock_unlock (main_arena.mutex);
+  if (!oldp)
+    malloc_printerr ("realloc(): invalid pointer");
+  const INTERNAL_SIZE_T oldsize = chunksize (oldp);
+
+  if (!checked_request2size (rb, &chnb))
+    {
+      __set_errno (ENOMEM);
+      goto invert;
+    }
+
+  __libc_lock_lock (main_arena.mutex);
+
+  if (chunk_is_mmapped (oldp))
+    {
+#if HAVE_MREMAP
+      mchunkptr newp = mremap_chunk (oldp, chnb);
+      if (newp)
+        newmem = chunk2mem_tag (newp);
+      else
+#endif
+      {
+	/* Note the extra SIZE_SZ overhead. */
+        if (oldsize - SIZE_SZ >= chnb)
+          newmem = oldmem; /* do nothing */
+        else
+          {
+            /* Must alloc, copy, free. */
+	    top_check ();
+	    newmem = _int_malloc (&main_arena, rb);
+            if (newmem)
+              {
+                memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
+                munmap_chunk (oldp);
+              }
+          }
+      }
+    }
+  else
+    {
+      top_check ();
+      newmem = _int_realloc (&main_arena, oldp, oldsize, chnb);
+    }
+
+  DIAG_PUSH_NEEDS_COMMENT;
+#if __GNUC_PREREQ (7, 0)
+  /* GCC 7 warns about magic_p may be used uninitialized.  But we never
+     reach here if magic_p is uninitialized.  */
+  DIAG_IGNORE_NEEDS_COMMENT (7, "-Wmaybe-uninitialized");
+#endif
+  /* mem2chunk_check changed the magic byte in the old chunk.
+     If newmem is NULL, then the old chunk will still be used though,
+     so we need to invert that change here.  */
+invert:
+  if (newmem == NULL)
+    *magic_p ^= 0xFF;
+  DIAG_POP_NEEDS_COMMENT;
+
+  __libc_lock_unlock (main_arena.mutex);
+
+  return mem2mem_check (tag_new_usable (newmem), bytes);
+}
+
+static void *
+memalign_check (size_t alignment, size_t bytes, const void *caller)
+{
+  void *mem;
+
+  if (alignment <= MALLOC_ALIGNMENT)
+    return malloc_check (bytes, NULL);
+
+  if (alignment < MINSIZE)
+    alignment = MINSIZE;
+
+  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
+     power of 2 and will cause overflow in the check below.  */
+  if (alignment > SIZE_MAX / 2 + 1)
+    {
+      __set_errno (EINVAL);
+      return 0;
+    }
+
+  /* Check for overflow.  */
+  if (bytes > SIZE_MAX - alignment - MINSIZE)
+    {
+      __set_errno (ENOMEM);
+      return 0;
+    }
+
+  /* Make sure alignment is power of 2.  */
+  if (!powerof2 (alignment))
+    {
+      size_t a = MALLOC_ALIGNMENT * 2;
+      while (a < alignment)
+        a <<= 1;
+      alignment = a;
+    }
+
+  __libc_lock_lock (main_arena.mutex);
+  top_check ();
+  mem = _int_memalign (&main_arena, alignment, bytes + 1);
+  __libc_lock_unlock (main_arena.mutex);
+  return mem2mem_check (tag_new_usable (mem), bytes);
+}
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 04/10] malloc: Move malloc hook references to hooks.c
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (2 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 03/10] Move glibc.malloc.check implementation into its own file Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 19:07   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 05/10] glibc.malloc.check: Wean away from malloc hooks Siddhesh Poyarekar
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Make the core malloc code hooks free and instead only have entry
points for _*_debug_before inline functions.

This also introduces the first (albeit very constrained) breakage for
malloc hooks behaviour.  The hook variables no longer call
ptmalloc_init, it is called directly on first invocation of an
allocator function.  This breaks debugging hooks that may depend on
overriding the hook symbols with their own implementations due to
which ptmalloc_init is never called.  In other words, it breaks hooks
users that use the malloc hooks to have their own implementation of
malloc that is conflicting with glibc malloc, which is not the
intended use of the hooks as documented.

None of the three debugging hooks in glibc depend on this behaviour
and hence continue to work as before.  In any case, future patches
that move the hooks out into their own layer ought to bring back this
functionality.  As a result, the breakage will not be visible to the
user in the end.

Reviewed-by: DJ Delorie <dj@redhat.com>
---
 malloc/arena.c           |   2 -
 malloc/hooks.c           | 110 ++++++++++++++++++++++++++++++++-------
 malloc/malloc-internal.h |   1 +
 malloc/malloc.c          |  85 ++++++++++--------------------
 4 files changed, 119 insertions(+), 79 deletions(-)

diff --git a/malloc/arena.c b/malloc/arena.c
index 7eb110445e..1861d20006 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -44,8 +44,6 @@
 
 /***************************************************************************/
 
-#define top(ar_ptr) ((ar_ptr)->top)
-
 /* A heap is a single contiguous memory region holding (coalesceable)
    malloc_chunks.  It is allocated with mmap() and always starts at an
    address aligned to HEAP_MAX_SIZE.  */
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 57a9b55788..4960aafd08 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -21,35 +21,107 @@
    corrupt pointer is detected: do nothing (0), print an error message
    (1), or call abort() (2). */
 
-/* Hooks for debugging versions.  The initial hooks just call the
-   initialization routine, then do the normal work. */
+/* Define and initialize the hook variables.  These weak definitions must
+   appear before any use of the variables in a function (arena.c uses one).  */
+#ifndef weak_variable
+/* In GNU libc we want the hook variables to be weak definitions to
+   avoid a problem with Emacs.  */
+# define weak_variable weak_function
+#endif
+
+/* Forward declarations.  */
+
+#if HAVE_MALLOC_INIT_HOOK
+void (*__malloc_initialize_hook) (void) __attribute__ ((nocommon));
+compat_symbol (libc, __malloc_initialize_hook,
+	       __malloc_initialize_hook, GLIBC_2_0);
+#endif
+
+void weak_variable (*__free_hook) (void *__ptr,
+                                   const void *) = NULL;
+void *weak_variable (*__malloc_hook)
+  (size_t __size, const void *) = NULL;
+void *weak_variable (*__realloc_hook)
+  (void *__ptr, size_t __size, const void *) = NULL;
+void *weak_variable (*__memalign_hook)
+  (size_t __alignment, size_t __size, const void *) = NULL;
+
+static void ptmalloc_init (void);
 
-static void *
-malloc_hook_ini (size_t sz, const void *caller)
+#include "malloc-check.c"
+
+static __always_inline bool
+_malloc_debug_before (size_t bytes, void **victimp, const void *address)
 {
-  __malloc_hook = NULL;
-  ptmalloc_init ();
-  return __libc_malloc (sz);
+  _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
+                  "PTRDIFF_MAX is not more than half of SIZE_MAX");
+
+  void *(*hook) (size_t, const void *)
+    = atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      *victimp = (*hook)(bytes, address);
+      return true;
+    }
+  return false;
 }
 
-static void *
-realloc_hook_ini (void *ptr, size_t sz, const void *caller)
+static __always_inline bool
+_free_debug_before (void *mem, const void *address)
 {
-  __malloc_hook = NULL;
-  __realloc_hook = NULL;
-  ptmalloc_init ();
-  return __libc_realloc (ptr, sz);
+  void (*hook) (void *, const void *)
+    = atomic_forced_read (__free_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      (*hook)(mem, address);
+      return true;
+    }
+  return false;
 }
 
-static void *
-memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
+static __always_inline bool
+_realloc_debug_before (void *oldmem, size_t bytes, void **victimp,
+			const void *address)
 {
-  __memalign_hook = NULL;
-  ptmalloc_init ();
-  return __libc_memalign (alignment, sz);
+  void *(*hook) (void *, size_t, const void *) =
+    atomic_forced_read (__realloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      *victimp = (*hook)(oldmem, bytes, address);
+      return true;
+    }
+
+  return false;
 }
 
-#include "malloc-check.c"
+static __always_inline bool
+_memalign_debug_before (size_t alignment, size_t bytes, void **victimp,
+			 const void *address)
+{
+  void *(*hook) (size_t, size_t, const void *) =
+    atomic_forced_read (__memalign_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      *victimp = (*hook)(alignment, bytes, address);
+      return true;
+    }
+  return false;
+}
+
+static __always_inline bool
+_calloc_debug_before (size_t bytes, void **victimp, const void *address)
+{
+  void *(*hook) (size_t, const void *) =
+    atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      *victimp = (*hook)(bytes, address);
+      if (*victimp != NULL)
+	memset (*victimp, 0, bytes);
+      return true;
+    }
+  return false;
+}
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
 
diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h
index 258f29584e..ee0f5697af 100644
--- a/malloc/malloc-internal.h
+++ b/malloc/malloc-internal.h
@@ -61,6 +61,7 @@
 /* The corresponding bit mask value.  */
 #define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
 
+#define top(ar_ptr) ((ar_ptr)->top)
 
 /* Called in the parent process before a fork.  */
 void __malloc_fork_lock_parent (void) attribute_hidden;
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 0e2e1747e0..75ca6ec3f0 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -2013,30 +2013,6 @@ static void     malloc_consolidate (mstate);
 # define weak_variable weak_function
 #endif
 
-/* Forward declarations.  */
-static void *malloc_hook_ini (size_t sz,
-                              const void *caller) __THROW;
-static void *realloc_hook_ini (void *ptr, size_t sz,
-                               const void *caller) __THROW;
-static void *memalign_hook_ini (size_t alignment, size_t sz,
-                                const void *caller) __THROW;
-
-#if HAVE_MALLOC_INIT_HOOK
-void (*__malloc_initialize_hook) (void) __attribute__ ((nocommon));
-compat_symbol (libc, __malloc_initialize_hook,
-	       __malloc_initialize_hook, GLIBC_2_0);
-#endif
-
-void weak_variable (*__free_hook) (void *__ptr,
-                                   const void *) = NULL;
-void *weak_variable (*__malloc_hook)
-  (size_t __size, const void *) = malloc_hook_ini;
-void *weak_variable (*__realloc_hook)
-  (void *__ptr, size_t __size, const void *)
-  = realloc_hook_ini;
-void *weak_variable (*__memalign_hook)
-  (size_t __alignment, size_t __size, const void *)
-  = memalign_hook_ini;
 void weak_variable (*__after_morecore_hook) (void) = NULL;
 
 /* This function is called from the arena shutdown hook, to free the
@@ -2065,6 +2041,9 @@ free_perturb (char *p, size_t n)
 
 #include <stap-probe.h>
 
+/* ----------------- Support for debugging hooks -------------------- */
+#include "hooks.c"
+
 /* ------------------- Support for multiple arenas -------------------- */
 #include "arena.c"
 
@@ -2425,10 +2404,6 @@ do_check_malloc_state (mstate av)
 #endif
 
 
-/* ----------------- Support for debugging hooks -------------------- */
-#include "hooks.c"
-
-
 /* ----------- Routines dealing with system allocation -------------- */
 
 /*
@@ -3225,13 +3200,12 @@ __libc_malloc (size_t bytes)
   mstate ar_ptr;
   void *victim;
 
-  _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
-                  "PTRDIFF_MAX is not more than half of SIZE_MAX");
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+
+  if (_malloc_debug_before (bytes, &victim, RETURN_ADDRESS (0)))
+    return 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 USE_TCACHE
   /* int_free also calls request2size, be careful to not pad twice.  */
   size_t tbytes;
@@ -3292,13 +3266,11 @@ __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 (_free_debug_before (mem, RETURN_ADDRESS (0)))
+    return;
 
   if (mem == 0)                              /* free(0) has no effect */
     return;
@@ -3351,10 +3323,11 @@ __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_debug_before (oldmem, bytes, &newp, RETURN_ADDRESS (0)))
+    return newp;
 
 #if REALLOC_ZERO_BYTES_FREES
   if (bytes == 0 && oldmem != NULL)
@@ -3490,6 +3463,9 @@ void *
 __libc_memalign (size_t alignment, size_t bytes)
 {
   void *address = RETURN_ADDRESS (0);
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
+
   return _mid_memalign (alignment, bytes, address);
 }
 
@@ -3499,10 +3475,8 @@ _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 (_memalign_debug_before (alignment, bytes, &p, address))
+    return p;
 
   /* If we need less alignment than we give anyway, just relay to malloc.  */
   if (alignment <= MALLOC_ALIGNMENT)
@@ -3612,16 +3586,11 @@ __libc_calloc (size_t n, size_t elem_size)
 
   sz = bytes;
 
-  void *(*hook) (size_t, const void *) =
-    atomic_forced_read (__malloc_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      mem = (*hook)(sz, RETURN_ADDRESS (0));
-      if (mem == 0)
-        return 0;
+  if (__malloc_initialized < 0)
+    ptmalloc_init ();
 
-      return memset (mem, 0, sz);
-    }
+  if (_calloc_debug_before (sz, &mem, RETURN_ADDRESS (0)))
+    return mem;
 
   MAYBE_INIT_TCACHE ();
 
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 05/10] glibc.malloc.check: Wean away from malloc hooks
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (3 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 04/10] malloc: Move malloc hook references to hooks.c Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 06/10] mcheck: " Siddhesh Poyarekar
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Set up a new internal debugging hooks flag variable and migrate
glibc.malloc.check to it so that it no longer uses the malloc hooks.

Reviewed-by: DJ Delorie <dj@redhat.com>
---
 malloc/arena.c        |  4 +--
 malloc/hooks.c        | 63 ++++++++++++++++++++++++++++++++++++++++++-
 malloc/malloc-check.c | 30 ++++++---------------
 malloc/malloc.c       |  9 +------
 4 files changed, 73 insertions(+), 33 deletions(-)

diff --git a/malloc/arena.c b/malloc/arena.c
index 1861d20006..357a3b0b30 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -210,7 +210,7 @@ TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp)
 {
   int32_t value = (int32_t) valp->numval;
   if (value != 0)
-    __malloc_check_init ();
+    __malloc_debug_enable (MALLOC_CHECK_HOOK);
 }
 
 # define TUNABLE_CALLBACK_FNDECL(__name, __type) \
@@ -400,7 +400,7 @@ ptmalloc_init (void)
         }
     }
   if (s && s[0] != '\0' && s[0] != '0')
-    __malloc_check_init ();
+    __malloc_debug_enable (MALLOC_CHECK_HOOK);
 #endif
 
 #if HAVE_MALLOC_INIT_HOOK
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 4960aafd08..77855801c8 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -21,6 +21,8 @@
    corrupt pointer is detected: do nothing (0), print an error message
    (1), or call abort() (2). */
 
+#  include <stdbool.h>
+
 /* Define and initialize the hook variables.  These weak definitions must
    appear before any use of the variables in a function (arena.c uses one).  */
 #ifndef weak_variable
@@ -29,6 +31,14 @@
 # define weak_variable weak_function
 #endif
 
+/* The internal malloc debugging hooks.  */
+enum malloc_debug_hooks
+{
+  MALLOC_NONE_HOOK = 0,
+  MALLOC_CHECK_HOOK = 1 << 0,	/* MALLOC_CHECK_ or glibc.malloc.check.  */
+};
+static unsigned __malloc_debugging_hooks;
+
 /* Forward declarations.  */
 
 #if HAVE_MALLOC_INIT_HOOK
@@ -48,6 +58,24 @@ void *weak_variable (*__memalign_hook)
 
 static void ptmalloc_init (void);
 
+static __always_inline bool
+__is_malloc_debug_enabled (enum malloc_debug_hooks flag)
+{
+  return __malloc_debugging_hooks & flag;
+}
+
+static __always_inline void
+__malloc_debug_enable (enum malloc_debug_hooks flag)
+{
+  __malloc_debugging_hooks |= flag;
+}
+
+static __always_inline void
+__malloc_debug_disable (enum malloc_debug_hooks flag)
+{
+  __malloc_debugging_hooks &= ~flag;
+}
+
 #include "malloc-check.c"
 
 static __always_inline bool
@@ -63,6 +91,12 @@ _malloc_debug_before (size_t bytes, void **victimp, const void *address)
       *victimp = (*hook)(bytes, address);
       return true;
     }
+
+  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+    {
+      *victimp = malloc_check (bytes);
+      return true;
+    }
   return false;
 }
 
@@ -76,6 +110,12 @@ _free_debug_before (void *mem, const void *address)
       (*hook)(mem, address);
       return true;
     }
+
+  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+    {
+      free_check (mem);
+      return true;
+    }
   return false;
 }
 
@@ -91,6 +131,12 @@ _realloc_debug_before (void *oldmem, size_t bytes, void **victimp,
       return true;
     }
 
+  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+    {
+      *victimp = realloc_check (oldmem, bytes);
+      return true;
+    }
+
   return false;
 }
 
@@ -105,6 +151,13 @@ _memalign_debug_before (size_t alignment, size_t bytes, void **victimp,
       *victimp = (*hook)(alignment, bytes, address);
       return true;
     }
+
+  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+    {
+      *victimp = memalign_check (alignment, bytes);
+      return true;
+    }
+
   return false;
 }
 
@@ -120,6 +173,14 @@ _calloc_debug_before (size_t bytes, void **victimp, const void *address)
 	memset (*victimp, 0, bytes);
       return true;
     }
+
+  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+    {
+      *victimp = malloc_check (bytes);
+      if (*victimp != NULL)
+	memset (*victimp, 0, bytes);
+      return true;
+    }
   return false;
 }
 
@@ -195,7 +256,7 @@ malloc_set_state (void *msptr)
   __realloc_hook = NULL;
   __free_hook = NULL;
   __memalign_hook = NULL;
-  using_malloc_checking = 0;
+  __malloc_debug_disable (MALLOC_CHECK_HOOK);
 
   /* Patch the dumped heap.  We no longer try to integrate into the
      existing heap.  Instead, we mark the existing chunks as mmapped.
diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
index dcab880510..a85e519498 100644
--- a/malloc/malloc-check.c
+++ b/malloc/malloc-check.c
@@ -18,20 +18,6 @@
    not, see <https://www.gnu.org/licenses/>.  */
 
 
-/* Whether we are using malloc checking.  */
-static int using_malloc_checking;
-
-/* Activate a standard set of debugging hooks. */
-void
-__malloc_check_init (void)
-{
-  using_malloc_checking = 1;
-  __malloc_hook = malloc_check;
-  __free_hook = free_check;
-  __realloc_hook = realloc_check;
-  __memalign_hook = memalign_check;
-}
-
 /* When memory is tagged, the checking data is stored in the user part
    of the chunk.  We can't rely on the user not having modified the
    tags, so fetch the tag at each location before dereferencing
@@ -69,7 +55,7 @@ malloc_check_get_size (mchunkptr p)
   unsigned char c;
   unsigned char magic = magicbyte (p);
 
-  assert (using_malloc_checking == 1);
+  assert (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK));
 
   for (size = CHUNK_HDR_SZ + memsize (p) - 1;
        (c = *SAFE_CHAR_OFFSET (p, size)) != magic;
@@ -203,7 +189,7 @@ top_check (void)
 }
 
 static void *
-malloc_check (size_t sz, const void *caller)
+malloc_check (size_t sz)
 {
   void *victim;
   size_t nb;
@@ -222,7 +208,7 @@ malloc_check (size_t sz, const void *caller)
 }
 
 static void
-free_check (void *mem, const void *caller)
+free_check (void *mem)
 {
   mchunkptr p;
 
@@ -256,7 +242,7 @@ free_check (void *mem, const void *caller)
 }
 
 static void *
-realloc_check (void *oldmem, size_t bytes, const void *caller)
+realloc_check (void *oldmem, size_t bytes)
 {
   INTERNAL_SIZE_T chnb;
   void *newmem = 0;
@@ -269,11 +255,11 @@ realloc_check (void *oldmem, size_t bytes, const void *caller)
       return NULL;
     }
   if (oldmem == 0)
-    return malloc_check (bytes, NULL);
+    return malloc_check (bytes);
 
   if (bytes == 0)
     {
-      free_check (oldmem, NULL);
+      free_check (oldmem);
       return NULL;
     }
 
@@ -348,12 +334,12 @@ invert:
 }
 
 static void *
-memalign_check (size_t alignment, size_t bytes, const void *caller)
+memalign_check (size_t alignment, size_t bytes)
 {
   void *mem;
 
   if (alignment <= MALLOC_ALIGNMENT)
-    return malloc_check (bytes, NULL);
+    return malloc_check (bytes);
 
   if (alignment < MINSIZE)
     alignment = MINSIZE;
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 75ca6ec3f0..60753446a1 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1124,13 +1124,6 @@ static void munmap_chunk(mchunkptr p);
 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 ------------------  */
 
 
@@ -5078,7 +5071,7 @@ musable (void *mem)
 
       p = mem2chunk (mem);
 
-      if (__builtin_expect (using_malloc_checking == 1, 0))
+      if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
 	return malloc_check_get_size (p);
 
       if (chunk_is_mmapped (p))
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 06/10] mcheck: Wean away from malloc hooks
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (4 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 05/10] glibc.malloc.check: Wean away from malloc hooks Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 18:34   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 07/10] mtrace: " Siddhesh Poyarekar
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Split the mcheck implementation into the debugging hooks and the user
visible implementation so that the debugging hooks (in mcheck-hooks.c)
can be embedded like malloc-check.c.

Further, add *_debug_after debugging hooks into malloc so that mcheck
can then be adapted to using the debugging hooks instead of fiddling
with hooks variables.  This adds an extra conditional branch at the
end of the allocator functions but it should have minimal effect in
the default use case.

Initialization using -lmcheck now depends on a new exported variable
__libc_lmcheck which is a const flag that mcheck-init can override.

While this simplifies the mcheck implementation, it still does not
make the interface thread safe as access to its internal structures is
still unprotected.
---
 include/malloc.h                              |  10 +-
 malloc/Makefile                               |   4 +-
 malloc/Versions                               |   3 +
 malloc/arena.c                                |   5 +
 malloc/hooks.c                                | 133 ++++--
 malloc/malloc.c                               | 115 +++--
 malloc/mcheck-hooks.c                         | 411 ++++++++++++++++++
 malloc/mcheck-init.c                          |  14 +-
 malloc/mcheck.c                               | 369 +---------------
 sysdeps/mach/hurd/i386/libc.abilist           |   1 +
 sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
 sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
 sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
 sysdeps/unix/sysv/linux/ia64/libc.abilist     |   1 +
 .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
 .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
 .../sysv/linux/microblaze/be/libc.abilist     |   1 +
 .../sysv/linux/microblaze/le/libc.abilist     |   1 +
 .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
 .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
 .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
 .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
 sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
 .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
 .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
 .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
 .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
 .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
 .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
 .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
 sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
 sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
 .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
 .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
 .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
 .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
 42 files changed, 649 insertions(+), 448 deletions(-)
 create mode 100644 malloc/mcheck-hooks.c

diff --git a/include/malloc.h b/include/malloc.h
index b77761f74d..bb1123d9d3 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -4,6 +4,11 @@
 
 # ifndef _ISOMAC
 #  include <rtld-malloc.h>
+#  include <stdbool.h>
+#  include <mcheck.h>
+
+struct malloc_state;
+typedef struct malloc_state *mstate;
 
 /* In the GNU libc we rename the global variable
    `__malloc_initialized' to `__libc_malloc_initialized'.  */
@@ -11,8 +16,9 @@
 /* Nonzero if the malloc is already initialized.  */
 extern int __malloc_initialized attribute_hidden;
 
-struct malloc_state;
-typedef struct malloc_state *mstate;
+enum mcheck_status __mcheck_checkptr (const void *) attribute_hidden;
+extern int __mcheck_initialize (void (*) (enum mcheck_status), bool)
+     attribute_hidden;
 
 # endif /* !_ISOMAC */
 
diff --git a/malloc/Makefile b/malloc/Makefile
index 2f9b3d596d..328e0be1fd 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -91,9 +91,7 @@ tests-exclude-mcheck = tst-mallocstate \
 	tst-malloc-usable-static \
 	tst-malloc-usable-static-tunables \
 	tst-malloc-usable-tunables \
-	tst-malloc_info \
-	tst-memalign \
-	tst-posix_memalign
+	tst-malloc_info
 
 tests-mcheck = $(filter-out $(tests-exclude-mcheck), $(tests))
 
diff --git a/malloc/Versions b/malloc/Versions
index 62e4698a08..e138eaa24b 100644
--- a/malloc/Versions
+++ b/malloc/Versions
@@ -67,6 +67,9 @@ libc {
   GLIBC_2.33 {
     mallinfo2;
   }
+  GLIBC_2.34 {
+    __libc_lmcheck;
+  }
   GLIBC_PRIVATE {
     # Internal startup hook for libpthread.
     __libc_malloc_pthread_startup;
diff --git a/malloc/arena.c b/malloc/arena.c
index 357a3b0b30..a8500a25c9 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -403,6 +403,11 @@ ptmalloc_init (void)
     __malloc_debug_enable (MALLOC_CHECK_HOOK);
 #endif
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+  if (__libc_lmcheck)
+    __mcheck_initialize (NULL, false);
+#endif
+
 #if HAVE_MALLOC_INIT_HOOK
   void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
   if (hook != NULL)
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 77855801c8..7b500e5671 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -36,6 +36,7 @@ enum malloc_debug_hooks
 {
   MALLOC_NONE_HOOK = 0,
   MALLOC_CHECK_HOOK = 1 << 0,	/* MALLOC_CHECK_ or glibc.malloc.check.  */
+  MALLOC_MCHECK_HOOK = 1 << 1,	/* mcheck()  */
 };
 static unsigned __malloc_debugging_hooks;
 
@@ -77,113 +78,181 @@ __malloc_debug_disable (enum malloc_debug_hooks flag)
 }
 
 #include "malloc-check.c"
+#include "mcheck-hooks.c"
 
 static __always_inline bool
-_malloc_debug_before (size_t bytes, void **victimp, const void *address)
+_malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
 {
   _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
-                  "PTRDIFF_MAX is not more than half of SIZE_MAX");
+		  "PTRDIFF_MAX is not more than half of SIZE_MAX");
 
   void *(*hook) (size_t, const void *)
     = atomic_forced_read (__malloc_hook);
   if (__builtin_expect (hook != NULL, 0))
     {
-      *victimp = (*hook)(bytes, address);
+      *victimp = (*hook)(*bytesp, address);
       return true;
     }
 
-  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+  if (__glibc_unlikely (__malloc_debugging_hooks))
     {
-      *victimp = malloc_check (bytes);
-      return true;
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+	  && malloc_mcheck_before (bytesp, victimp))
+	return true;
+      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+	{
+	  *victimp = malloc_check (*bytesp);
+	  return true;
+	}
     }
   return false;
 }
 
+static __always_inline void *
+_malloc_debug_after (void *mem, size_t bytes, const void *address)
+{
+  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+    mem = malloc_mcheck_after (mem, bytes);
+  return mem;
+}
+
 static __always_inline bool
-_free_debug_before (void *mem, const void *address)
+_free_debug_before (void **mem, const void *address)
 {
   void (*hook) (void *, const void *)
     = atomic_forced_read (__free_hook);
   if (__builtin_expect (hook != NULL, 0))
     {
-      (*hook)(mem, address);
+      (*hook)(*mem, address);
       return true;
     }
 
-  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+  if (__glibc_unlikely (__malloc_debugging_hooks))
     {
-      free_check (mem);
-      return true;
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+	*mem = free_mcheck (*mem);
+      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+	{
+	  free_check (*mem);
+	  return true;
+	}
     }
   return false;
 }
 
 static __always_inline bool
-_realloc_debug_before (void *oldmem, size_t bytes, void **victimp,
-			const void *address)
+_realloc_debug_before (void **oldmem, size_t *bytesp, size_t *oldsize,
+		       void **victimp, const void *address)
 {
   void *(*hook) (void *, size_t, const void *) =
     atomic_forced_read (__realloc_hook);
   if (__builtin_expect (hook != NULL, 0))
     {
-      *victimp = (*hook)(oldmem, bytes, address);
+      *victimp = (*hook)(*oldmem, *bytesp, address);
       return true;
     }
 
-  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+  if (__glibc_unlikely (__malloc_debugging_hooks))
     {
-      *victimp = realloc_check (oldmem, bytes);
-      return true;
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+	  && realloc_mcheck_before (oldmem, bytesp, oldsize, victimp))
+	return true;
+      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+	{
+	  *victimp = realloc_check (*oldmem, *bytesp);
+	  return true;
+	}
     }
 
   return false;
 }
 
+static __always_inline void *
+_realloc_debug_after (void *mem, void *oldmem, size_t bytes, size_t oldsize,
+		      const void *address)
+{
+  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+    mem = realloc_mcheck_after (mem, oldmem, bytes, oldsize);
+  return mem;
+}
+
 static __always_inline bool
-_memalign_debug_before (size_t alignment, size_t bytes, void **victimp,
-			 const void *address)
+_memalign_debug_before (size_t alignment, size_t *bytesp, void **victimp,
+			const void *address)
 {
   void *(*hook) (size_t, size_t, const void *) =
     atomic_forced_read (__memalign_hook);
   if (__builtin_expect (hook != NULL, 0))
     {
-      *victimp = (*hook)(alignment, bytes, address);
+      *victimp = (*hook)(alignment, *bytesp, address);
       return true;
     }
-
-  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+  if (__glibc_unlikely (__malloc_debugging_hooks))
     {
-      *victimp = memalign_check (alignment, bytes);
-      return true;
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+	  && memalign_mcheck_before (alignment, bytesp, victimp))
+	return true;
+      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+	{
+	  *victimp = memalign_check (alignment, *bytesp);
+	  return true;
+	}
     }
 
   return false;
 }
 
+static __always_inline void *
+_memalign_debug_after (void *mem, size_t alignment, size_t bytes,
+		       const void *address)
+{
+  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+    mem = memalign_mcheck_after (mem, alignment, bytes);
+  return mem;
+}
+
 static __always_inline bool
-_calloc_debug_before (size_t bytes, void **victimp, const void *address)
+_calloc_debug_before (size_t *bytesp, void **victimp, const void *address)
 {
   void *(*hook) (size_t, const void *) =
     atomic_forced_read (__malloc_hook);
   if (__builtin_expect (hook != NULL, 0))
     {
-      *victimp = (*hook)(bytes, address);
+      *victimp = (*hook)(*bytesp, address);
+
       if (*victimp != NULL)
-	memset (*victimp, 0, bytes);
+	memset (*victimp, 0, *bytesp);
+
       return true;
     }
 
-  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+  /* Memory is zeroed out in the AFTER hook.  */
+  if (__glibc_unlikely (__malloc_debugging_hooks))
     {
-      *victimp = malloc_check (bytes);
-      if (*victimp != NULL)
-	memset (*victimp, 0, bytes);
-      return true;
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+	  && malloc_mcheck_before (bytesp, victimp))
+	return true;
+      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+	{
+	  *victimp = malloc_check (*bytesp);
+	  return true;
+	}
     }
   return false;
 }
 
+static __always_inline void *
+_calloc_debug_after (void *mem, size_t bytes, const void *address)
+{
+  if (__glibc_unlikely (__malloc_debugging_hooks) && mem != NULL)
+    {
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+	mem = malloc_mcheck_after (mem, bytes);
+      memset (mem, 0, bytes);
+    }
+  return mem;
+}
+
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
 
 /* Support for restoring dumped heaps contained in historic Emacs
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 60753446a1..c899619e50 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3191,13 +3191,14 @@ void *
 __libc_malloc (size_t bytes)
 {
   mstate ar_ptr;
-  void *victim;
+  void *victim = NULL;
+  size_t orig_bytes = bytes;
 
   if (__malloc_initialized < 0)
     ptmalloc_init ();
 
-  if (_malloc_debug_before (bytes, &victim, RETURN_ADDRESS (0)))
-    return victim;
+  if (_malloc_debug_before (&bytes, &victim, RETURN_ADDRESS (0)))
+    goto out;
 
 #if USE_TCACHE
   /* int_free also calls request2size, be careful to not pad twice.  */
@@ -3205,7 +3206,8 @@ __libc_malloc (size_t bytes)
   if (!checked_request2size (bytes, &tbytes))
     {
       __set_errno (ENOMEM);
-      return NULL;
+      victim = NULL;
+      goto out;
     }
   size_t tc_idx = csize2tidx (tbytes);
 
@@ -3217,7 +3219,8 @@ __libc_malloc (size_t bytes)
       && tcache->counts[tc_idx] > 0)
     {
       victim = tcache_get (tc_idx);
-      return tag_new_usable (victim);
+      victim = tag_new_usable (victim);
+      goto out;
     }
   DIAG_POP_NEEDS_COMMENT;
 #endif
@@ -3227,7 +3230,7 @@ __libc_malloc (size_t bytes)
       victim = tag_new_usable (_int_malloc (&main_arena, bytes));
       assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
 	      &main_arena == arena_for_chunk (mem2chunk (victim)));
-      return victim;
+      goto out;
     }
 
   arena_get (ar_ptr, bytes);
@@ -3249,7 +3252,9 @@ __libc_malloc (size_t bytes)
 
   assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
           ar_ptr == arena_for_chunk (mem2chunk (victim)));
-  return victim;
+
+out:
+  return _malloc_debug_after (victim, orig_bytes, RETURN_ADDRESS (0));
 }
 libc_hidden_def (__libc_malloc)
 
@@ -3262,7 +3267,7 @@ __libc_free (void *mem)
   if (__malloc_initialized < 0)
     ptmalloc_init ();
 
-  if (_free_debug_before (mem, RETURN_ADDRESS (0)))
+  if (_free_debug_before (&mem, RETURN_ADDRESS (0)))
     return;
 
   if (mem == 0)                              /* free(0) has no effect */
@@ -3315,23 +3320,30 @@ __libc_realloc (void *oldmem, size_t bytes)
   INTERNAL_SIZE_T nb;         /* padded request size */
 
   void *newp;             /* chunk to return */
+  size_t orig_bytes = bytes, debug_osize = 0;
 
   if (__malloc_initialized < 0)
     ptmalloc_init ();
 
-  if (_realloc_debug_before (oldmem, bytes, &newp, RETURN_ADDRESS (0)))
-    return newp;
+  if (_realloc_debug_before (&oldmem, &bytes, &debug_osize, &newp,
+			     RETURN_ADDRESS (0)))
+    goto out;
 
 #if REALLOC_ZERO_BYTES_FREES
   if (bytes == 0 && oldmem != NULL)
     {
-      __libc_free (oldmem); return 0;
+      __libc_free (oldmem);
+      newp = NULL;
+      goto out;
     }
 #endif
 
   /* realloc of null is supposed to be same as malloc */
   if (oldmem == 0)
-    return __libc_malloc (bytes);
+    {
+      newp = __libc_malloc (bytes);
+      goto out;
+    }
 
   /* Perform a quick check to ensure that the pointer's tag matches the
      memory's tag.  */
@@ -3365,7 +3377,8 @@ __libc_realloc (void *oldmem, size_t bytes)
   if (!checked_request2size (bytes, &nb))
     {
       __set_errno (ENOMEM);
-      return NULL;
+      newp = NULL;
+      goto out;
     }
 
   if (chunk_is_mmapped (oldp))
@@ -3377,7 +3390,10 @@ __libc_realloc (void *oldmem, size_t bytes)
 	  /* Must alloc, copy, free. */
 	  void *newmem = __libc_malloc (bytes);
 	  if (newmem == 0)
-	    return NULL;
+	    {
+	      newp = NULL;
+	      goto out;
+	    }
 	  /* Copy as many bytes as are available from the old chunk
 	     and fit into the new size.  NB: The overhead for faked
 	     mmapped chunks is only SIZE_SZ, not CHUNK_HDR_SZ as for
@@ -3385,7 +3401,8 @@ __libc_realloc (void *oldmem, size_t bytes)
 	  if (bytes > oldsize - SIZE_SZ)
 	    bytes = oldsize - SIZE_SZ;
 	  memcpy (newmem, oldmem, bytes);
-	  return newmem;
+	  newp = newmem;
+	  goto out;
 	}
 
       void *newmem;
@@ -3400,21 +3417,29 @@ __libc_realloc (void *oldmem, size_t bytes)
 	     reused.  There's a performance hit for both us and the
 	     caller for doing this, so we might want to
 	     reconsider.  */
-	  return tag_new_usable (newmem);
+	  newp = tag_new_usable (newmem);
+	  goto out;
 	}
 #endif
       /* Note the extra SIZE_SZ overhead. */
       if (oldsize - SIZE_SZ >= nb)
-        return oldmem;                         /* do nothing */
+	{
+	  newp = oldmem;                         /* do nothing */
+	  goto out;
+	}
 
       /* Must alloc, copy, free. */
       newmem = __libc_malloc (bytes);
       if (newmem == 0)
-        return 0;              /* propagate failure */
+	{
+	  newp = NULL;              /* propagate failure */
+	  goto out;
+	}
 
       memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
       munmap_chunk (oldp);
-      return newmem;
+      newp = newmem;
+      goto out;
     }
 
   if (SINGLE_THREAD_P)
@@ -3423,7 +3448,7 @@ __libc_realloc (void *oldmem, size_t bytes)
       assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
 	      ar_ptr == arena_for_chunk (mem2chunk (newp)));
 
-      return newp;
+      goto out;
     }
 
   __libc_lock_lock (ar_ptr->mutex);
@@ -3448,7 +3473,9 @@ __libc_realloc (void *oldmem, size_t bytes)
         }
     }
 
-  return newp;
+out:
+  return _realloc_debug_after (newp, oldmem, orig_bytes, debug_osize,
+			       RETURN_ADDRESS (0));
 }
 libc_hidden_def (__libc_realloc)
 
@@ -3467,13 +3494,17 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
 {
   mstate ar_ptr;
   void *p;
+  size_t orig_bytes = bytes;
 
-  if (_memalign_debug_before (alignment, bytes, &p, address))
-    return p;
+  if (_memalign_debug_before (alignment, &bytes, &p, address))
+    goto out;
 
   /* If we need less alignment than we give anyway, just relay to malloc.  */
   if (alignment <= MALLOC_ALIGNMENT)
-    return __libc_malloc (bytes);
+    {
+      p = __libc_malloc (bytes);
+      goto out;
+    }
 
   /* Otherwise, ensure that it is at least a minimum chunk size */
   if (alignment < MINSIZE)
@@ -3484,7 +3515,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
   if (alignment > SIZE_MAX / 2 + 1)
     {
       __set_errno (EINVAL);
-      return 0;
+      p = NULL;
+      goto out;
     }
 
 
@@ -3502,7 +3534,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
       p = _int_memalign (&main_arena, alignment, bytes);
       assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
 	      &main_arena == arena_for_chunk (mem2chunk (p)));
-      return tag_new_usable (p);
+      p = tag_new_usable (p);
+      goto out;
     }
 
   arena_get (ar_ptr, bytes + alignment + MINSIZE);
@@ -3520,7 +3553,9 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
 
   assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
           ar_ptr == arena_for_chunk (mem2chunk (p)));
-  return tag_new_usable (p);
+  p = tag_new_usable (p);
+out:
+  return _memalign_debug_after (p, alignment, orig_bytes, RETURN_ADDRESS (0));
 }
 /* For ISO C11.  */
 weak_alias (__libc_memalign, aligned_alloc)
@@ -3582,8 +3617,8 @@ __libc_calloc (size_t n, size_t elem_size)
   if (__malloc_initialized < 0)
     ptmalloc_init ();
 
-  if (_calloc_debug_before (sz, &mem, RETURN_ADDRESS (0)))
-    return mem;
+  if (_calloc_debug_before (&sz, &mem, RETURN_ADDRESS (0)))
+    goto out;
 
   MAYBE_INIT_TCACHE ();
 
@@ -3639,7 +3674,10 @@ __libc_calloc (size_t n, size_t elem_size)
 
   /* Allocation failed even after a retry.  */
   if (mem == 0)
-    return 0;
+    {
+      mem = NULL;
+      goto out;
+    }
 
   mchunkptr p = mem2chunk (mem);
 
@@ -3647,7 +3685,10 @@ __libc_calloc (size_t n, size_t elem_size)
      regardless of MORECORE_CLEARS, so we zero the whole block while
      doing so.  */
   if (__glibc_unlikely (mtag_enabled))
-    return tag_new_zero_region (mem, memsize (p));
+    {
+      mem = tag_new_zero_region (mem, memsize (p));
+      goto out;
+    }
 
   INTERNAL_SIZE_T csz = chunksize (p);
 
@@ -3655,9 +3696,9 @@ __libc_calloc (size_t n, size_t elem_size)
   if (chunk_is_mmapped (p))
     {
       if (__builtin_expect (perturb_byte, 0))
-        return memset (mem, 0, sz);
+        memset (mem, 0, sz);
 
-      return mem;
+      goto out;
     }
 
 #if MORECORE_CLEARS
@@ -3677,7 +3718,10 @@ __libc_calloc (size_t n, size_t elem_size)
   assert (nclears >= 3);
 
   if (nclears > 9)
-    return memset (d, 0, clearsize);
+    {
+      memset (d, 0, clearsize);
+      goto out;
+    }
 
   else
     {
@@ -3701,7 +3745,8 @@ __libc_calloc (size_t n, size_t elem_size)
         }
     }
 
-  return mem;
+out:
+  return _calloc_debug_after (mem, bytes, RETURN_ADDRESS (0));
 }
 
 /*
diff --git a/malloc/mcheck-hooks.c b/malloc/mcheck-hooks.c
new file mode 100644
index 0000000000..f3520c7659
--- /dev/null
+++ b/malloc/mcheck-hooks.c
@@ -0,0 +1,411 @@
+/* mcheck debugging hooks for malloc.
+   Copyright (C) 1990-2021 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Written May 1989 by Mike Haertel.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <mcheck.h>
+#include <libintl.h>
+
+/* Arbitrary magical numbers.  */
+#define MAGICWORD       0xfedabeeb
+#define MAGICFREE       0xd8675309
+#define MAGICBYTE       ((char) 0xd7)
+#define MALLOCFLOOD     ((char) 0x93)
+#define FREEFLOOD       ((char) 0x95)
+
+/* Function to call when something awful happens.  */
+static void (*abortfunc) (enum mcheck_status);
+
+struct hdr
+{
+  size_t size;                  /* Exact size requested by user.  */
+  unsigned long int magic;      /* Magic number to check header integrity.  */
+  struct hdr *prev;
+  struct hdr *next;
+  void *block;                  /* Real block allocated, for memalign.  */
+  unsigned long int magic2;     /* Extra, keeps us doubleword aligned.  */
+};
+
+/* This is the beginning of the list of all memory blocks allocated.
+   It is only constructed if the pedantic testing is requested.  */
+struct hdr *__mcheck_root;
+
+/* Nonzero if pedentic checking of all blocks is requested.  */
+static bool pedantic;
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+/* Flag to initialize mcheck on first malloc invocation through -lmcheck.
+   libmcheck.a overrides this with a strong symbol initialized to 1.  The
+   symbol cannot be linked against directly during build.  */
+const int __libc_lmcheck __attribute__ ((weak));
+compat_symbol (libc, __libc_lmcheck, __libc_lmcheck, GLIBC_2_34);
+#endif
+
+#if defined _LIBC || defined STDC_HEADERS || defined USG
+# include <string.h>
+# define flood memset
+#else
+static void flood (void *, int, size_t);
+static void
+flood (void *ptr, int val, size_t size)
+{
+  char *cp = ptr;
+  while (size--)
+    *cp++ = val;
+}
+#endif
+
+static enum mcheck_status
+checkhdr (const struct hdr *hdr)
+{
+  enum mcheck_status status;
+  bool mcheck_used = __is_malloc_debug_enabled (MALLOC_MCHECK_HOOK);
+
+  if (!mcheck_used)
+    /* Maybe the mcheck used is disabled?  This happens when we find
+       an error and report it.  */
+    return MCHECK_OK;
+
+  switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
+    {
+    default:
+      status = MCHECK_HEAD;
+      break;
+    case MAGICFREE:
+      status = MCHECK_FREE;
+      break;
+    case MAGICWORD:
+      if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
+	status = MCHECK_TAIL;
+      else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
+	status = MCHECK_HEAD;
+      else
+	status = MCHECK_OK;
+      break;
+    }
+  if (status != MCHECK_OK)
+    {
+      mcheck_used = 0;
+      (*abortfunc) (status);
+      mcheck_used = 1;
+    }
+  return status;
+}
+
+enum mcheck_status
+__mcheck_checkptr (const void *ptr)
+{
+  if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+      return MCHECK_DISABLED;
+
+  if (ptr != NULL)
+    return checkhdr (((struct hdr *) ptr) - 1);
+
+  /* Walk through all the active blocks and test whether they were tampered
+     with.  */
+  struct hdr *runp = __mcheck_root;
+
+  /* Temporarily turn off the checks.  */
+  pedantic = false;
+
+  while (runp != NULL)
+    {
+      (void) checkhdr (runp);
+
+      runp = runp->next;
+    }
+
+  /* Turn checks on again.  */
+  pedantic = true;
+
+  return MCHECK_OK;
+}
+
+static void
+unlink_blk (struct hdr *ptr)
+{
+  if (ptr->next != NULL)
+    {
+      ptr->next->prev = ptr->prev;
+      ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
+                                      + (uintptr_t) ptr->next->next);
+    }
+  if (ptr->prev != NULL)
+    {
+      ptr->prev->next = ptr->next;
+      ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
+                                      + (uintptr_t) ptr->prev->next);
+    }
+  else
+    __mcheck_root = ptr->next;
+}
+
+static void
+link_blk (struct hdr *hdr)
+{
+  hdr->prev = NULL;
+  hdr->next = __mcheck_root;
+  __mcheck_root = hdr;
+  hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
+
+  /* And the next block.  */
+  if (hdr->next != NULL)
+    {
+      hdr->next->prev = hdr;
+      hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
+                                      + (uintptr_t) hdr->next->next);
+    }
+}
+
+static void *
+free_mcheck (void *ptr)
+{
+  if (pedantic)
+    __mcheck_checkptr (NULL);
+  if (ptr)
+    {
+      struct hdr *hdr = ((struct hdr *) ptr) - 1;
+      checkhdr (hdr);
+      hdr->magic = MAGICFREE;
+      hdr->magic2 = MAGICFREE;
+      unlink_blk (hdr);
+      hdr->prev = hdr->next = NULL;
+      flood (ptr, FREEFLOOD, hdr->size);
+      ptr = hdr->block;
+    }
+  return ptr;
+}
+
+static bool
+malloc_mcheck_before (size_t *sizep, void **victimp)
+{
+  size_t size = *sizep;
+
+  if (pedantic)
+    __mcheck_checkptr (NULL);
+
+  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+    {
+      __set_errno (ENOMEM);
+      *victimp = NULL;
+      return true;
+    }
+
+  *sizep = sizeof (struct hdr) + size + 1;
+  return false;
+}
+
+static void *
+malloc_mcheck_after (void *mem, size_t size)
+{
+  struct hdr *hdr = mem;
+
+  if (hdr == NULL)
+    return NULL;
+
+  hdr->size = size;
+  link_blk (hdr);
+  hdr->block = hdr;
+  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
+  ((char *) &hdr[1])[size] = MAGICBYTE;
+  flood ((void *) (hdr + 1), MALLOCFLOOD, size);
+  return (void *) (hdr + 1);
+}
+
+static bool
+memalign_mcheck_before (size_t alignment, size_t *sizep, void **victimp)
+{
+  struct hdr *hdr;
+  size_t slop, size = *sizep;
+
+  /* Punt to malloc to avoid double headers.  */
+  if (alignment <= MALLOC_ALIGNMENT)
+    {
+      *victimp = __libc_malloc (size);
+      return true;
+    }
+
+  if (pedantic)
+    __mcheck_checkptr (NULL);
+
+  slop = (sizeof *hdr + alignment - 1) & - alignment;
+
+  if (size > ~((size_t) 0) - (slop + 1))
+    {
+      __set_errno (ENOMEM);
+      *victimp = NULL;
+      return true;
+    }
+
+  *sizep = slop + size + 1;
+  return false;
+}
+
+static void *
+memalign_mcheck_after (void *block, size_t alignment, size_t size)
+{
+  if (block == NULL)
+    return NULL;
+
+  /* This was served by __libc_malloc, so return as is.  */
+  if (alignment <= MALLOC_ALIGNMENT)
+    return block;
+
+  size_t slop = (sizeof (struct hdr) + alignment - 1) & - alignment;
+  struct hdr *hdr = ((struct hdr *) (block + slop)) - 1;
+
+  hdr->size = size;
+  link_blk (hdr);
+  hdr->block = (void *) block;
+  hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
+  ((char *) &hdr[1])[size] = MAGICBYTE;
+  flood ((void *) (hdr + 1), MALLOCFLOOD, size);
+  return (void *) (hdr + 1);
+}
+
+static bool
+realloc_mcheck_before (void **ptrp, size_t *sizep, size_t *oldsize,
+		       void **victimp)
+{
+  size_t size = *sizep;
+  void *ptr = *ptrp;
+
+  /* Handle special cases to avoid adding multiple headers.  */
+  if (size == 0)
+    {
+      __libc_free (ptr);
+      *victimp = NULL;
+      return true;
+    }
+
+  if (ptr == NULL)
+    {
+      *victimp = __libc_malloc (size);
+      *oldsize = 0;
+      return true;
+    }
+
+  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+    {
+      __set_errno (ENOMEM);
+      *victimp = NULL;
+      *oldsize = 0;
+      return true;
+    }
+
+  if (pedantic)
+    __mcheck_checkptr (NULL);
+
+  struct hdr *hdr;
+  size_t osize;
+
+  /* Update the oldptr for glibc realloc.  */
+  *ptrp = hdr = ((struct hdr *) ptr) - 1;
+
+  osize = hdr->size;
+
+  checkhdr (hdr);
+  unlink_blk (hdr);
+  if (size < osize)
+    flood ((char *) ptr + size, FREEFLOOD, osize - size);
+
+  *oldsize = osize;
+  *sizep = sizeof (struct hdr) + size + 1;
+  return false;
+}
+
+static void *
+realloc_mcheck_after (void *ptr, void *oldptr, size_t size, size_t osize)
+{
+  struct hdr *hdr = ptr;
+
+  if (hdr == NULL)
+    return NULL;
+
+  /* Malloc already added the header so don't tamper with it.  */
+  if (oldptr == NULL)
+    return ptr;
+
+  hdr->size = size;
+  link_blk (hdr);
+  hdr->block = hdr;
+  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
+  ((char *) &hdr[1])[size] = MAGICBYTE;
+  if (size > osize)
+    flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
+  return (void *) (hdr + 1);
+}
+
+__attribute__ ((noreturn))
+static void
+mabort (enum mcheck_status status)
+{
+  const char *msg;
+  switch (status)
+    {
+    case MCHECK_OK:
+      msg = _ ("memory is consistent, library is buggy\n");
+      break;
+    case MCHECK_HEAD:
+      msg = _ ("memory clobbered before allocated block\n");
+      break;
+    case MCHECK_TAIL:
+      msg = _ ("memory clobbered past end of allocated block\n");
+      break;
+    case MCHECK_FREE:
+      msg = _ ("block freed twice\n");
+      break;
+    default:
+      msg = _ ("bogus mcheck_status, library is buggy\n");
+      break;
+    }
+#ifdef _LIBC
+  __libc_fatal (msg);
+#else
+  fprintf (stderr, "mcheck: %s", msg);
+  fflush (stderr);
+  abort ();
+#endif
+}
+
+int
+__mcheck_initialize (void (*func) (enum mcheck_status), bool in_pedantic)
+{
+  abortfunc = (func != NULL) ? func : &mabort;
+
+  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+    goto out;
+
+  switch (__malloc_initialized)
+    {
+    case -1:
+      ptmalloc_init ();
+      /* FALLTHROUGH */
+    case 0:
+      __malloc_debug_enable (MALLOC_MCHECK_HOOK);
+      break;
+    default:
+      break;
+    }
+
+  if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+    return -1;
+
+out:
+  pedantic = in_pedantic;
+  return 0;
+}
diff --git a/malloc/mcheck-init.c b/malloc/mcheck-init.c
index 9ee69ee5f8..e3d08ae05f 100644
--- a/malloc/mcheck-init.c
+++ b/malloc/mcheck-init.c
@@ -17,17 +17,7 @@
 
 /* The object of this file should be installed as libmcheck.a,
    so one can do -lmcheck to turn on mcheck.  */
-
-#include <malloc.h>
-#include <mcheck.h>
 #include <shlib-compat.h>
 
-static void
-turn_on_mcheck (void)
-{
-  mcheck (NULL);
-}
-
-void (*__malloc_initialize_hook) (void) = turn_on_mcheck;
-compat_symbol_reference (libc, __malloc_initialize_hook,
-                         __malloc_initialize_hook, GLIBC_2_0);
+const int __libc_lmcheck = 1;
+compat_symbol_reference (libc, __libc_lmcheck, __libc_lmcheck, GLIBC_2_34);
diff --git a/malloc/mcheck.c b/malloc/mcheck.c
index 2a1fc645d4..f60766eded 100644
--- a/malloc/mcheck.c
+++ b/malloc/mcheck.c
@@ -1,4 +1,4 @@
-/* Standard debugging hooks for `malloc'.
+/* The mcheck() interface.
    Copyright (C) 1990-2021 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Written May 1989 by Mike Haertel.
@@ -23,378 +23,22 @@
 # include <mcheck.h>
 # include <stdint.h>
 # include <stdio.h>
-# include <libintl.h>
 # 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;
+  __mcheck_checkptr (NULL);
 }
 #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 __mcheck_initialize (func, false);
 }
 #ifdef _LIBC
 libc_hidden_def (mcheck)
@@ -403,14 +47,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 __mcheck_initialize (func, true);
 }
 
 enum mcheck_status
 mprobe (void *ptr)
 {
-  return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+  return __mcheck_checkptr (ptr);
 }
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index fcfe64f26b..27e8f14bb5 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2223,6 +2223,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
 GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 _hurd_libc_proc_init F
 GLIBC_2.34 dladdr F
diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 6730cbdd6b..5c24c5e77f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2380,6 +2380,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 63de4fadc3..bf75524649 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2479,6 +2479,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
index 2f13701fd7..3bf0c17629 100644
--- a/sysdeps/unix/sysv/linux/arc/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
@@ -2139,6 +2139,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
index 9b824f1605..59b64ceebc 100644
--- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
@@ -222,6 +222,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
index 443a81b8f7..406108f9ea 100644
--- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
@@ -219,6 +219,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 243de3cf93..af5c560d27 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2354,6 +2354,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 24ae58bb6f..920a9c0bc0 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2307,6 +2307,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 09bebcd5a1..3eea983bd0 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2491,6 +2491,7 @@ GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
 GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 0bafe09253..1a776e945f 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2317,6 +2317,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
 GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index c1fcde4c24..8a7244731d 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -223,6 +223,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 407651cfd7..c4724c9565 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2434,6 +2434,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
index 7da722a734..ef637690d2 100644
--- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
@@ -2405,6 +2405,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
index c374607b81..9fde5778c4 100644
--- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
@@ -2402,6 +2402,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index b1f426e053..a9ba4ef442 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2399,6 +2399,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index 066ceb2258..9c0ea27436 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2397,6 +2397,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 51c563ebbe..46f8d03699 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2405,6 +2405,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 28db715d8a..2ae9770ec6 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2368,6 +2368,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index ab9f2bd42c..6c4c684a93 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2444,6 +2444,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 83f8513e17..cbb02febac 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2461,6 +2461,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index 0fad357bf6..8426990a9b 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2494,6 +2494,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 424ec8d953..977feb5695 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2281,6 +2281,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 9909fd0e9a..00b74fe710 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2576,6 +2576,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
 GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
index 7085989b16..eac837a1ce 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
@@ -2141,6 +2141,7 @@ GLIBC_2.33 write F
 GLIBC_2.33 writev F
 GLIBC_2.33 wscanf F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index a855997957..73bf738b97 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2341,6 +2341,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 12aeb82520..167a715820 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2459,6 +2459,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index e2d746ad5f..cd22ad1a97 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2318,6 +2318,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
index 1ce4b54bf2..b2d5d40e1f 100644
--- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
@@ -2314,6 +2314,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
index 7d01add713..18f402719b 100644
--- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
@@ -2311,6 +2311,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index b5ef3247d7..a71416c70d 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2454,6 +2454,7 @@ GLIBC_2.34 __glob64_time64 F
 GLIBC_2.34 __globfree64_time64 F
 GLIBC_2.34 __gmtime64 F
 GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __localtime64 F
 GLIBC_2.34 __localtime64_r F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 14ae7c8417..254a6746a2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2340,6 +2340,7 @@ GLIBC_2.33 mknodat F
 GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 57c4f28d17..c0e6463916 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2296,6 +2296,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
 GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 47211abe4e..b1512a6339 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2395,6 +2395,7 @@ GLIBC_2.33 stat F
 GLIBC_2.33 stat64 F
 GLIBC_2.34 _Fork F
 GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
 GLIBC_2.34 __libc_start_main F
 GLIBC_2.34 __mq_open_2 F
 GLIBC_2.34 __pthread_cleanup_routine F
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 07/10] mtrace: Wean away from malloc hooks
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (5 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 06/10] mcheck: " Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 08/10] Remove " Siddhesh Poyarekar
                   ` (3 subsequent siblings)
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Split mtrace hooks into before and after and adapt to the new internal
debugging hooks infrastructure.  With this, the malloc hooks are
unused internally and can be removed from the main library.

This also eliminates the only use of memalign through a PLT in the
library, so checklocalplt data needs to be updated to reflect that.
---
 include/malloc.h                              |   1 +
 malloc/hooks.c                                |  40 ++-
 malloc/mtrace-hooks.c                         | 137 ++++++++++
 malloc/mtrace.c                               | 233 +-----------------
 sysdeps/generic/localplt.data                 |   1 -
 sysdeps/mach/hurd/i386/localplt.data          |   1 -
 sysdeps/unix/sysv/linux/aarch64/localplt.data |   1 -
 sysdeps/unix/sysv/linux/alpha/localplt.data   |   1 -
 sysdeps/unix/sysv/linux/arc/localplt.data     |   1 -
 sysdeps/unix/sysv/linux/arm/localplt.data     |   1 -
 sysdeps/unix/sysv/linux/csky/localplt.data    |   1 -
 sysdeps/unix/sysv/linux/hppa/localplt.data    |   1 -
 sysdeps/unix/sysv/linux/i386/localplt.data    |   1 -
 sysdeps/unix/sysv/linux/ia64/localplt.data    |   1 -
 .../sysv/linux/m68k/coldfire/localplt.data    |   1 -
 .../unix/sysv/linux/m68k/m680x0/localplt.data |   1 -
 .../unix/sysv/linux/microblaze/localplt.data  |   1 -
 sysdeps/unix/sysv/linux/nios2/localplt.data   |   1 -
 .../linux/powerpc/powerpc32/fpu/localplt.data |   1 -
 .../powerpc/powerpc32/nofpu/localplt.data     |   1 -
 .../linux/powerpc/powerpc64/localplt.data     |   1 -
 sysdeps/unix/sysv/linux/riscv/localplt.data   |   1 -
 sysdeps/unix/sysv/linux/s390/localplt.data    |   1 -
 sysdeps/unix/sysv/linux/sh/localplt.data      |   1 -
 .../sysv/linux/sparc/sparc32/localplt.data    |   1 -
 .../sysv/linux/sparc/sparc64/localplt.data    |   1 -
 sysdeps/x86_64/localplt.data                  |   1 -
 27 files changed, 182 insertions(+), 252 deletions(-)
 create mode 100644 malloc/mtrace-hooks.c

diff --git a/include/malloc.h b/include/malloc.h
index bb1123d9d3..6169d486f5 100644
--- a/include/malloc.h
+++ b/include/malloc.h
@@ -15,6 +15,7 @@ typedef struct malloc_state *mstate;
 #define __malloc_initialized __libc_malloc_initialized
 /* Nonzero if the malloc is already initialized.  */
 extern int __malloc_initialized attribute_hidden;
+extern FILE *__mtrace_mallstream attribute_hidden;
 
 enum mcheck_status __mcheck_checkptr (const void *) attribute_hidden;
 extern int __mcheck_initialize (void (*) (enum mcheck_status), bool)
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 7b500e5671..7f3b07ca44 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -37,6 +37,7 @@ enum malloc_debug_hooks
   MALLOC_NONE_HOOK = 0,
   MALLOC_CHECK_HOOK = 1 << 0,	/* MALLOC_CHECK_ or glibc.malloc.check.  */
   MALLOC_MCHECK_HOOK = 1 << 1,	/* mcheck()  */
+  MALLOC_MTRACE_HOOK = 1 << 2,	/* mtrace()  */
 };
 static unsigned __malloc_debugging_hooks;
 
@@ -79,6 +80,7 @@ __malloc_debug_disable (enum malloc_debug_hooks flag)
 
 #include "malloc-check.c"
 #include "mcheck-hooks.c"
+#include "mtrace-hooks.c"
 
 static __always_inline bool
 _malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
@@ -111,8 +113,13 @@ _malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
 static __always_inline void *
 _malloc_debug_after (void *mem, size_t bytes, const void *address)
 {
-  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
-    mem = malloc_mcheck_after (mem, bytes);
+  if (__glibc_unlikely (__malloc_debugging_hooks))
+    {
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+	mem = malloc_mcheck_after (mem, bytes);
+      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
+	mem = malloc_mtrace_after (mem, bytes, address);
+    }
   return mem;
 }
 
@@ -129,6 +136,8 @@ _free_debug_before (void **mem, const void *address)
 
   if (__glibc_unlikely (__malloc_debugging_hooks))
     {
+      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
+	free_mtrace (mem, address);
       if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
 	*mem = free_mcheck (*mem);
       if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
@@ -171,8 +180,13 @@ static __always_inline void *
 _realloc_debug_after (void *mem, void *oldmem, size_t bytes, size_t oldsize,
 		      const void *address)
 {
-  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
-    mem = realloc_mcheck_after (mem, oldmem, bytes, oldsize);
+  if (__glibc_unlikely (__malloc_debugging_hooks))
+    {
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+	mem = realloc_mcheck_after (mem, oldmem, bytes, oldsize);
+      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
+	mem = realloc_mtrace_after (mem, oldmem, bytes, address);
+    }
   return mem;
 }
 
@@ -206,8 +220,13 @@ static __always_inline void *
 _memalign_debug_after (void *mem, size_t alignment, size_t bytes,
 		       const void *address)
 {
-  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
-    mem = memalign_mcheck_after (mem, alignment, bytes);
+  if (__glibc_unlikely (__malloc_debugging_hooks))
+    {
+      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+	mem = memalign_mcheck_after (mem, alignment, bytes);
+      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
+	mem = memalign_mtrace_after (mem, bytes, address);
+    }
   return mem;
 }
 
@@ -244,11 +263,16 @@ _calloc_debug_before (size_t *bytesp, void **victimp, const void *address)
 static __always_inline void *
 _calloc_debug_after (void *mem, size_t bytes, const void *address)
 {
-  if (__glibc_unlikely (__malloc_debugging_hooks) && mem != NULL)
+  if (__glibc_unlikely (__malloc_debugging_hooks))
     {
       if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
 	mem = malloc_mcheck_after (mem, bytes);
-      memset (mem, 0, bytes);
+      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
+	mem = malloc_mtrace_after (mem, bytes, address);
+      /* mtrace uses __libc_calloc to do the zeroing.  */
+      if (mem != NULL && __is_malloc_debug_enabled (MALLOC_CHECK_HOOK
+						    | MALLOC_MCHECK_HOOK))
+	memset (mem, 0, bytes);
     }
   return mem;
 }
diff --git a/malloc/mtrace-hooks.c b/malloc/mtrace-hooks.c
new file mode 100644
index 0000000000..c1c6d6a6e9
--- /dev/null
+++ b/malloc/mtrace-hooks.c
@@ -0,0 +1,137 @@
+
+# include <libc-lock.h>
+
+#include <kernel-features.h>
+
+FILE *__mtrace_mallstream;
+
+__libc_lock_define_initialized (static, lock);
+
+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 (__mtrace_mallstream, "@ %s%s%s[%p] ",
+                   info->dli_fname ? : "", info->dli_fname ? ":" : "",
+                   buf, caller);
+        }
+      else
+        fprintf (__mtrace_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 bool
+free_mtrace (void *ptr, const void *caller)
+{
+  if (ptr == NULL)
+    return true;
+
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+  tr_where (caller, info);
+  /* Be sure to print it first.  */
+  fprintf (__mtrace_mallstream, "- %p\n", ptr);
+  __libc_lock_unlock (lock);
+
+  /* Continue on to free.  */
+  return false;
+}
+
+static void *
+malloc_mtrace_after (void *block, size_t size, const void *caller)
+{
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+
+  tr_where (caller, info);
+  /* We could be printing a NULL here; that's OK.  */
+  fprintf (__mtrace_mallstream, "+ %p %#lx\n", block,
+	   (unsigned long int) size);
+
+  __libc_lock_unlock (lock);
+
+  return block;
+}
+
+static void *
+realloc_mtrace_after (void *block, const void *oldptr, size_t size,
+		      const void *caller)
+{
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+
+  tr_where (caller, info);
+  if (block == NULL)
+    {
+      if (size != 0)
+        /* Failed realloc.  */
+        fprintf (__mtrace_mallstream, "! %p %#lx\n", oldptr,
+		 (unsigned long int) size);
+      else
+        fprintf (__mtrace_mallstream, "- %p\n", oldptr);
+    }
+  else if (oldptr == NULL)
+    fprintf (__mtrace_mallstream, "+ %p %#lx\n", block,
+	     (unsigned long int) size);
+  else
+    {
+      fprintf (__mtrace_mallstream, "< %p\n", oldptr);
+      tr_where (caller, info);
+      fprintf (__mtrace_mallstream, "> %p %#lx\n", block,
+	       (unsigned long int) size);
+    }
+
+  __libc_lock_unlock (lock);
+
+  return block;
+}
+
+static void *
+memalign_mtrace_after (void *block, size_t size, const void *caller)
+{
+  Dl_info mem;
+  Dl_info *info = lock_and_info (caller, &mem);
+
+  tr_where (caller, info);
+  /* We could be printing a NULL here; that's OK.  */
+  fprintf (__mtrace_mallstream, "+ %p %#lx\n", block,
+	   (unsigned long int) size);
+
+  __libc_lock_unlock (lock);
+
+  return block;
+}
diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index 6c2c58b706..2cc4507e25 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -22,7 +22,6 @@
 # define _MALLOC_INTERNAL
 # include <malloc.h>
 # include <mcheck.h>
-# include <libc-lock.h>
 #endif
 
 #include <dlfcn.h>
@@ -35,20 +34,14 @@
 
 #include <libc-internal.h>
 #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);
+static const char mallenv[] = "MALLOC_TRACE";
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
 /* Compatibility symbols that were introduced to help break at allocation sites
@@ -69,204 +62,6 @@ tr_break (void)
 compat_symbol (libc, tr_break, tr_break, GLIBC_2_0);
 #endif
 
-
-/* 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 *);
-
-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 *, const void *);
-static void * tr_mallochook (size_t, const void *);
-static void * tr_reallochook (void *, size_t, const void *);
-static void * tr_memalignhook (size_t, size_t, const void *);
-
-/* Set all the default non-trace hooks.  */
-static __always_inline void
-set_default_hooks (void)
-{
-  __free_hook = tr_old_free_hook;
-  __malloc_hook = tr_old_malloc_hook;
-  __realloc_hook = tr_old_realloc_hook;
-  __memalign_hook = tr_old_memalign_hook;
-}
-
-/* Set all of the tracing hooks used for mtrace.  */
-static __always_inline void
-set_trace_hooks (void)
-{
-  __free_hook = tr_freehook;
-  __malloc_hook = tr_mallochook;
-  __realloc_hook = tr_reallochook;
-  __memalign_hook = tr_memalignhook;
-}
-
-/* Save the current set of hooks as the default hooks.  */
-static __always_inline void
-save_default_hooks (void)
-{
-  tr_old_free_hook = __free_hook;
-  tr_old_malloc_hook = __malloc_hook;
-  tr_old_realloc_hook = __realloc_hook;
-  tr_old_memalign_hook = __memalign_hook;
-}
-
-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);
-  set_default_hooks ();
-  if (tr_old_free_hook != NULL)
-    (*tr_old_free_hook)(ptr, caller);
-  else
-    free (ptr);
-  set_trace_hooks ();
-  __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);
-
-  set_default_hooks ();
-  if (tr_old_malloc_hook != NULL)
-    hdr = (void *) (*tr_old_malloc_hook)(size, caller);
-  else
-    hdr = (void *) malloc (size);
-  set_trace_hooks ();
-
-  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);
-
-  return hdr;
-}
-
-static void *
-tr_reallochook (void *ptr, size_t size, const void *caller)
-{
-  void *hdr;
-
-  Dl_info mem;
-  Dl_info *info = lock_and_info (caller, &mem);
-
-  set_default_hooks ();
-  if (tr_old_realloc_hook != NULL)
-    hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
-  else
-    hdr = (void *) realloc (ptr, size);
-  set_trace_hooks ();
-
-  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);
-
-  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);
-
-  set_default_hooks ();
-  if (tr_old_memalign_hook != NULL)
-    hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
-  else
-    hdr = (void *) memalign (alignment, size);
-  set_trace_hooks ();
-
-  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);
-
-  return hdr;
-}
-
-
 #ifdef _LIBC
 
 /* This function gets called to make sure all memory the library
@@ -276,7 +71,7 @@ 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)
+  if (__mtrace_mallstream != NULL)
     __libc_freeres ();
 }
 #endif
@@ -293,7 +88,7 @@ mtrace (void)
   char *mallfile;
 
   /* Don't panic if we're called more than once.  */
-  if (mallstream != NULL)
+  if (__mtrace_mallstream != NULL)
     return;
 
 #ifdef _LIBC
@@ -310,15 +105,15 @@ mtrace (void)
       if (mtb == NULL)
         return;
 
-      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
-      if (mallstream != NULL)
+      __mtrace_mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null",
+				   "wce");
+      if (__mtrace_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");
-	  save_default_hooks ();
-	  set_trace_hooks ();
+          setvbuf (__mtrace_mallstream, malloc_trace_buffer, _IOFBF,
+		   TRACE_BUFFER_SIZE);
+          fprintf (__mtrace_mallstream, "= Start\n");
 #ifdef _LIBC
           if (!added_atexit_handler)
             {
@@ -336,15 +131,11 @@ mtrace (void)
 void
 muntrace (void)
 {
-  if (mallstream == NULL)
+  if (__mtrace_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;
-  set_default_hooks ();
+  FILE *f = __mtrace_mallstream;
+  __mtrace_mallstream = NULL;
 
   fprintf (f, "= End\n");
   fclose (f);
diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data
index e2083c0ce6..9b4f35786a 100644
--- a/sysdeps/generic/localplt.data
+++ b/sysdeps/generic/localplt.data
@@ -4,7 +4,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data
index 94064ecbc5..47fbe1e2a7 100644
--- a/sysdeps/mach/hurd/i386/localplt.data
+++ b/sysdeps/mach/hurd/i386/localplt.data
@@ -6,7 +6,6 @@
 libc.so: calloc + REL R_386_GLOB_DAT
 libc.so: free + REL R_386_GLOB_DAT
 libc.so: malloc + REL R_386_GLOB_DAT
-libc.so: memalign + REL R_386_GLOB_DAT
 libc.so: realloc + REL R_386_GLOB_DAT
 libm.so: matherr + REL R_386_GLOB_DAT
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data
index 2c14b652ef..348b3f3793 100644
--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data
+++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data
@@ -4,7 +4,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # If outline atomics are used, libgcc (built outside of glibc) may
diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
index 43f6fdaea1..44bf36f4f1 100644
--- a/sysdeps/unix/sysv/linux/alpha/localplt.data
+++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
@@ -18,7 +18,6 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc + RELA R_ALPHA_GLOB_DAT
 libc.so: free + RELA R_ALPHA_GLOB_DAT
 libc.so: malloc + RELA R_ALPHA_GLOB_DAT
-libc.so: memalign + RELA R_ALPHA_GLOB_DAT
 libc.so: realloc + RELA R_ALPHA_GLOB_DAT
 libm.so: matherr + RELA R_ALPHA_GLOB_DAT
 # We used to offer inline functions that used this, so it must be exported.
diff --git a/sysdeps/unix/sysv/linux/arc/localplt.data b/sysdeps/unix/sysv/linux/arc/localplt.data
index 4479e8ee8a..ac5332caf7 100644
--- a/sysdeps/unix/sysv/linux/arc/localplt.data
+++ b/sysdeps/unix/sysv/linux/arc/localplt.data
@@ -1,6 +1,5 @@
 libc.so: realloc
 libc.so: malloc
-libc.so: memalign
 libc.so: calloc
 libc.so: free
 # At -Os, a struct assignment in libgcc-static pulls this in
diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data
index eb315da2f1..78896444c6 100644
--- a/sysdeps/unix/sysv/linux/arm/localplt.data
+++ b/sysdeps/unix/sysv/linux/arm/localplt.data
@@ -1,7 +1,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: raise
 libc.so: realloc
 libm.so: matherr
diff --git a/sysdeps/unix/sysv/linux/csky/localplt.data b/sysdeps/unix/sysv/linux/csky/localplt.data
index 0ed8650b65..817ab2659a 100644
--- a/sysdeps/unix/sysv/linux/csky/localplt.data
+++ b/sysdeps/unix/sysv/linux/csky/localplt.data
@@ -4,7 +4,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 # The TLS-enabled version of these functions is interposed from libc.so.
 ld.so: _dl_signal_error
diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data
index 09893d4dcf..baf857a750 100644
--- a/sysdeps/unix/sysv/linux/hppa/localplt.data
+++ b/sysdeps/unix/sysv/linux/hppa/localplt.data
@@ -4,7 +4,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libc.so: __sigsetjmp
 libc.so: _IO_funlockfile
diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
index 5334875b4b..f9bf7fb410 100644
--- a/sysdeps/unix/sysv/linux/i386/localplt.data
+++ b/sysdeps/unix/sysv/linux/i386/localplt.data
@@ -4,7 +4,6 @@ libc.so: _Unwind_Find_FDE + REL R_386_GLOB_DAT
 libc.so: calloc + REL R_386_GLOB_DAT
 libc.so: free + REL R_386_GLOB_DAT
 libc.so: malloc + REL R_386_GLOB_DAT
-libc.so: memalign + REL R_386_GLOB_DAT
 libc.so: realloc + REL R_386_GLOB_DAT
 libm.so: matherr + REL R_386_GLOB_DAT
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data
index 1c566a503e..174fb88128 100644
--- a/sysdeps/unix/sysv/linux/ia64/localplt.data
+++ b/sysdeps/unix/sysv/linux/ia64/localplt.data
@@ -1,7 +1,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 libm.so: matherrf
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
index 3c5efb7204..42fa90508c 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
@@ -2,7 +2,6 @@ libc.so: __m68k_read_tp
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
index 843f4e25f2..34bd4c1aca 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
@@ -3,7 +3,6 @@ libc.so: __m68k_read_tp
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data
index 0e98d5251e..c3801314c9 100644
--- a/sysdeps/unix/sysv/linux/microblaze/localplt.data
+++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data
@@ -2,7 +2,6 @@ libc.so: __errno_location
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The dynamic loader needs __tls_get_addr for TLS.
diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data
index b37987c7c0..17fcfdd4db 100644
--- a/sysdeps/unix/sysv/linux/nios2/localplt.data
+++ b/sysdeps/unix/sysv/linux/nios2/localplt.data
@@ -6,7 +6,6 @@ libc.so: __gedf2
 libc.so: malloc
 libc.so: __gtsf2 ?
 libc.so: __nesf2
-libc.so: memalign
 libc.so: __mulsf3
 libc.so: __floatunsisf
 libc.so: __addsf3
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
index a02dd5cc24..c0af84eef7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
@@ -2,7 +2,6 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
index d8072597b7..581e54b95c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
@@ -30,7 +30,6 @@ libc.so: abort ?
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: memset ?
 libc.so: realloc
 libm.so: copysignl ?
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
index bb498fbe3a..d69b7ae646 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
@@ -1,7 +1,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data
index 0a235592c3..e6d5330d5b 100644
--- a/sysdeps/unix/sysv/linux/riscv/localplt.data
+++ b/sysdeps/unix/sysv/linux/riscv/localplt.data
@@ -4,7 +4,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: memset ?
 libc.so: realloc
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data
index a02dd5cc24..c0af84eef7 100644
--- a/sysdeps/unix/sysv/linux/s390/localplt.data
+++ b/sysdeps/unix/sysv/linux/s390/localplt.data
@@ -2,7 +2,6 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data
index 3225177c50..6491b9e37b 100644
--- a/sysdeps/unix/sysv/linux/sh/localplt.data
+++ b/sysdeps/unix/sysv/linux/sh/localplt.data
@@ -4,7 +4,6 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libc.so: _Unwind_Find_FDE
 libc.so: _exit
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
index be51efd566..38309a1393 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
@@ -16,7 +16,6 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
index 809062d46c..6a216f3a5a 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
@@ -15,7 +15,6 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
-libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
index 8f41e92870..d1f2e26612 100644
--- a/sysdeps/x86_64/localplt.data
+++ b/sysdeps/x86_64/localplt.data
@@ -6,7 +6,6 @@
 libc.so: calloc + RELA R_X86_64_GLOB_DAT
 libc.so: free + RELA R_X86_64_GLOB_DAT
 libc.so: malloc + RELA R_X86_64_GLOB_DAT
-libc.so: memalign + RELA R_X86_64_GLOB_DAT
 libc.so: realloc + RELA R_X86_64_GLOB_DAT
 libm.so: matherr + RELA R_X86_64_GLOB_DAT
 # The TLS-enabled version of these functions is interposed from libc.so.
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 08/10] Remove malloc hooks
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (6 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 07/10] mtrace: " Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 18:48   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 09/10] Remove __after_morecore_hook Siddhesh Poyarekar
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Make malloc hooks symbols compat-only so that new applications cannot
link against them and remove the declarations from the API.  The
existing hooks variables are not used in the library anymore.

Legacy applications that need hooks functionality need to preload a
new DSO libmalloc_compathooks.so, which interposes the libc malloc
functions to execute hooks if they exist.

Also remove all references to the malloc hooks in the manual.  Mention
the removal in NEWS and also warn that libmalloc_compathooks.so is a
temporary measure and may be removed in a future version of glibc.

memalign makes a comeback as a PLT reference since the initialization
hooks use them.  tst-mallocstate now needs libmalloc_compathooks.so
since it uses __malloc_initialize_hook to set up initial heap state to
emumate emacs.

Reviewed-by: DJ Delorie <dj@redhat.com>
---
 Makeconfig                                    |   2 +-
 NEWS                                          |   9 +
 malloc/Makefile                               |  15 +-
 malloc/arena.c                                |   5 -
 malloc/hooks.c                                | 114 ++++++-----
 malloc/malloc-compathooks.c                   | 166 +++++++++++++++
 malloc/malloc.c                               |  10 -
 malloc/malloc.h                               |  14 --
 manual/memory.texi                            | 191 +-----------------
 sysdeps/generic/localplt.data                 |   1 +
 sysdeps/mach/hurd/i386/localplt.data          |   1 +
 sysdeps/unix/sysv/linux/aarch64/localplt.data |   1 +
 sysdeps/unix/sysv/linux/alpha/localplt.data   |   1 +
 sysdeps/unix/sysv/linux/arc/localplt.data     |   1 +
 sysdeps/unix/sysv/linux/arm/localplt.data     |   1 +
 sysdeps/unix/sysv/linux/csky/localplt.data    |   1 +
 sysdeps/unix/sysv/linux/hppa/localplt.data    |   1 +
 sysdeps/unix/sysv/linux/i386/localplt.data    |   1 +
 sysdeps/unix/sysv/linux/ia64/localplt.data    |   1 +
 .../sysv/linux/m68k/coldfire/localplt.data    |   1 +
 .../unix/sysv/linux/m68k/m680x0/localplt.data |   1 +
 .../unix/sysv/linux/microblaze/localplt.data  |   1 +
 sysdeps/unix/sysv/linux/nios2/localplt.data   |   1 +
 .../linux/powerpc/powerpc32/fpu/localplt.data |   1 +
 .../powerpc/powerpc32/nofpu/localplt.data     |   1 +
 .../linux/powerpc/powerpc64/localplt.data     |   1 +
 sysdeps/unix/sysv/linux/riscv/localplt.data   |   1 +
 sysdeps/unix/sysv/linux/s390/localplt.data    |   1 +
 sysdeps/unix/sysv/linux/sh/localplt.data      |   1 +
 .../sysv/linux/sparc/sparc32/localplt.data    |   1 +
 .../sysv/linux/sparc/sparc64/localplt.data    |   1 +
 sysdeps/x86_64/localplt.data                  |   1 +
 32 files changed, 284 insertions(+), 265 deletions(-)
 create mode 100644 malloc/malloc-compathooks.c

diff --git a/Makeconfig b/Makeconfig
index efc7351d71..4a88cba647 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -951,7 +951,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_compathooks
 
 in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \
 				    $(libof-$(<F)) \
diff --git a/NEWS b/NEWS
index 8e72946c3f..cebe8384bf 100644
--- a/NEWS
+++ b/NEWS
@@ -97,6 +97,15 @@ Deprecated and removed features, and other changes affecting compatibility:
   mtrace.  Similar functionality can be achieved by using conditional
   breakpoints within mtrace functions from within gdb.
 
+* The deprecated memory allocation hooks __malloc_hook, __realloc_hook,
+  __memalign_hook and __free_hook are now removed from the API.  Compatibility
+  symbols are present to support legacy programs but new applications can no
+  longer link to these symbols.  Further, the hooks no longer have any effect
+  on glibc functionality.  A compatibility DSO libmalloc_compathooks.so has
+  been provided as a transitional measure to get hook functionality back for
+  legacy programs until they are updated to remove references to the memory
+  allocation hooks.
+
 Changes to build and runtime requirements:
 
 * On Linux, the shm_open, sem_open, and related functions now expect the
diff --git a/malloc/Makefile b/malloc/Makefile
index 328e0be1fd..50d6ad7b77 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -42,6 +42,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
 	 tst-malloc-stats-cancellation \
 	 tst-tcfree1 tst-tcfree2 tst-tcfree3 \
 	 tst-safe-linking \
+	 tst-compathooks-off tst-compathooks-on
 
 tests-static := \
 	 tst-interpose-static-nothread \
@@ -113,8 +114,8 @@ routines = malloc morecore mcheck mtrace obstack reallocarray \
 install-lib := libmcheck.a
 non-lib.a := libmcheck.a
 
-# Additional library.
-extra-libs = libmemusage
+# Additional libraries.
+extra-libs = libmemusage libmalloc_compathooks
 extra-libs-others = $(extra-libs)
 
 # Helper objects for some tests.
@@ -129,6 +130,9 @@ test-extras = \
 libmemusage-routines = memusage
 libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
 
+libmalloc_compathooks-routines = malloc-compathooks
+libmalloc_compathooks-inhibit-o = $(filter-out .os,$(object-suffixes))
+
 $(objpfx)tst-malloc-backtrace: $(shared-thread-library)
 $(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
 $(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
@@ -312,3 +316,10 @@ $(objpfx)tst-mallocfork2-mcheck: $(shared-thread-library)
 $(objpfx)tst-malloc-tcache-leak-malloc-check: $(shared-thread-library)
 $(objpfx)tst-malloc_info-malloc-check: $(shared-thread-library)
 $(objpfx)tst-mallocfork2-malloc-check: $(shared-thread-library)
+
+tst-compathooks-on-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
+tst-compathooks-on-mcheck-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
+tst-compathooks-on-malloc-check-ENV = \
+	LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
+tst-mallocstate-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
+tst-mallocstate-malloc-check-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
diff --git a/malloc/arena.c b/malloc/arena.c
index a8500a25c9..8591c8ea56 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -408,11 +408,6 @@ ptmalloc_init (void)
     __mcheck_initialize (NULL, false);
 #endif
 
-#if HAVE_MALLOC_INIT_HOOK
-  void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
-  if (hook != NULL)
-    (*hook)();
-#endif
   __malloc_initialized = 1;
 }
 
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 7f3b07ca44..397220aaba 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -42,23 +42,84 @@ enum malloc_debug_hooks
 static unsigned __malloc_debugging_hooks;
 
 /* Forward declarations.  */
+static void ptmalloc_init (void);
 
-#if HAVE_MALLOC_INIT_HOOK
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_24)
 void (*__malloc_initialize_hook) (void) __attribute__ ((nocommon));
 compat_symbol (libc, __malloc_initialize_hook,
 	       __malloc_initialize_hook, GLIBC_2_0);
+
+# define MALLOC_INIT_HOOK() ({ \
+  void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);	      \
+  if (hook != NULL)							      \
+    (*hook)();								      \
+})
+#else
+# define MALLOC_INIT_HOOK()
 #endif
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+
+static void *malloc_hook_ini (size_t, const void *) __THROW;
+static void *realloc_hook_ini (void *, size_t, const void *) __THROW;
+static void *memalign_hook_ini (size_t, size_t, const void *) __THROW;
+
 void weak_variable (*__free_hook) (void *__ptr,
                                    const void *) = NULL;
 void *weak_variable (*__malloc_hook)
-  (size_t __size, const void *) = NULL;
+  (size_t __size, const void *) = malloc_hook_ini;
 void *weak_variable (*__realloc_hook)
-  (void *__ptr, size_t __size, const void *) = NULL;
+  (void *__ptr, size_t __size, const void *) = realloc_hook_ini;
 void *weak_variable (*__memalign_hook)
-  (size_t __alignment, size_t __size, const void *) = NULL;
+  (size_t __alignment, size_t __size, const void *) = memalign_hook_ini;
 
-static void ptmalloc_init (void);
+compat_symbol (libc, __free_hook, __free_hook, GLIBC_2_0);
+compat_symbol (libc, __malloc_hook, __malloc_hook, GLIBC_2_0);
+compat_symbol (libc, __realloc_hook, __realloc_hook, GLIBC_2_0);
+compat_symbol (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
+
+/* These hooks will get executed only through the interposed allocator
+   functions in libmalloc_compathooks.  This means that the calls to malloc,
+   realloc, etc. will lead back into the interposed functions, which is what we
+   want.
+
+   These initial hooks are assumed to be called in a single-threaded context,
+   so it is safe to reset all hooks at once upon initialization.  */
+
+static void
+generic_hook_ini (void)
+{
+  __malloc_hook = NULL;
+  __realloc_hook = NULL;
+  __memalign_hook = NULL;
+  if (__malloc_initialized < 0)
+    {
+      ptmalloc_init ();
+      MALLOC_INIT_HOOK ();
+    }
+}
+
+static void *
+malloc_hook_ini (size_t sz, const void *caller)
+{
+  generic_hook_ini ();
+  return malloc (sz);
+}
+
+static void *
+realloc_hook_ini (void *ptr, size_t sz, const void *caller)
+{
+  generic_hook_ini ();
+  return realloc (ptr, sz);
+}
+
+static void *
+memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
+{
+  generic_hook_ini ();
+  return memalign (alignment, sz);
+}
+#endif
 
 static __always_inline bool
 __is_malloc_debug_enabled (enum malloc_debug_hooks flag)
@@ -88,14 +149,6 @@ _malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
   _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
 		  "PTRDIFF_MAX is not more than half of SIZE_MAX");
 
-  void *(*hook) (size_t, const void *)
-    = atomic_forced_read (__malloc_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      *victimp = (*hook)(*bytesp, address);
-      return true;
-    }
-
   if (__glibc_unlikely (__malloc_debugging_hooks))
     {
       if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
@@ -126,14 +179,6 @@ _malloc_debug_after (void *mem, size_t bytes, const void *address)
 static __always_inline bool
 _free_debug_before (void **mem, const void *address)
 {
-  void (*hook) (void *, const void *)
-    = atomic_forced_read (__free_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      (*hook)(*mem, address);
-      return true;
-    }
-
   if (__glibc_unlikely (__malloc_debugging_hooks))
     {
       if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
@@ -153,14 +198,6 @@ static __always_inline bool
 _realloc_debug_before (void **oldmem, size_t *bytesp, size_t *oldsize,
 		       void **victimp, const void *address)
 {
-  void *(*hook) (void *, size_t, const void *) =
-    atomic_forced_read (__realloc_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      *victimp = (*hook)(*oldmem, *bytesp, address);
-      return true;
-    }
-
   if (__glibc_unlikely (__malloc_debugging_hooks))
     {
       if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
@@ -194,13 +231,6 @@ static __always_inline bool
 _memalign_debug_before (size_t alignment, size_t *bytesp, void **victimp,
 			const void *address)
 {
-  void *(*hook) (size_t, size_t, const void *) =
-    atomic_forced_read (__memalign_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      *victimp = (*hook)(alignment, *bytesp, address);
-      return true;
-    }
   if (__glibc_unlikely (__malloc_debugging_hooks))
     {
       if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
@@ -233,18 +263,6 @@ _memalign_debug_after (void *mem, size_t alignment, size_t bytes,
 static __always_inline bool
 _calloc_debug_before (size_t *bytesp, void **victimp, const void *address)
 {
-  void *(*hook) (size_t, const void *) =
-    atomic_forced_read (__malloc_hook);
-  if (__builtin_expect (hook != NULL, 0))
-    {
-      *victimp = (*hook)(*bytesp, address);
-
-      if (*victimp != NULL)
-	memset (*victimp, 0, *bytesp);
-
-      return true;
-    }
-
   /* Memory is zeroed out in the AFTER hook.  */
   if (__glibc_unlikely (__malloc_debugging_hooks))
     {
diff --git a/malloc/malloc-compathooks.c b/malloc/malloc-compathooks.c
new file mode 100644
index 0000000000..6d1eaab774
--- /dev/null
+++ b/malloc/malloc-compathooks.c
@@ -0,0 +1,166 @@
+/* Malloc hooks compatibility DSO.
+   Copyright (C) 2021 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; see the file COPYING.LIB.  If
+   not, see <https://www.gnu.org/licenses/>.  */
+
+#include <atomic.h>
+#include <libc-symbols.h>
+#include <shlib-compat.h>
+#include <string.h>
+#include <unistd.h>
+
+extern void (*__free_hook) (void *__ptr, const void *);
+compat_symbol_reference (libc, __free_hook, __free_hook, GLIBC_2_0);
+extern void * (*__malloc_hook) (size_t __size, const void *);
+compat_symbol_reference (libc, __malloc_hook, __malloc_hook, GLIBC_2_0);
+extern void * (*__realloc_hook)
+     (void *__ptr, size_t __size, const void *);
+compat_symbol_reference (libc, __realloc_hook, __realloc_hook, GLIBC_2_0);
+extern void * (*__memalign_hook)
+  (size_t __alignment, size_t __size, const void *);
+compat_symbol_reference (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
+
+/* Support only the glibc allocators.  */
+extern void *__libc_malloc (size_t);
+extern void __libc_free (void *);
+extern void *__libc_realloc (void *, size_t);
+extern void *__libc_memalign (size_t, size_t);
+extern void *__libc_valloc (size_t);
+extern void *__libc_pvalloc (size_t);
+extern void *__libc_calloc (size_t, size_t);
+
+static size_t pagesize;
+
+/* The allocator functions.  */
+
+static void *
+__compathook_malloc (size_t bytes)
+{
+  void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook)(bytes, RETURN_ADDRESS (0));
+
+  return __libc_malloc (bytes);
+}
+strong_alias (__compathook_malloc, malloc)
+
+static void
+__compathook_free (void *mem)
+{
+  void (*hook) (void *, const void *) = atomic_forced_read (__free_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      (*hook)(mem, RETURN_ADDRESS (0));
+      return;
+    }
+  __libc_free (mem);
+}
+strong_alias (__compathook_free, free)
+
+static void *
+__compathook_realloc (void *oldmem, size_t bytes)
+{
+  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));
+
+  return __libc_realloc (oldmem, bytes);
+}
+strong_alias (__compathook_realloc, realloc)
+
+static void *
+__compathook_memalign (size_t alignment, size_t bytes)
+{
+  void *(*hook) (size_t, size_t, const void *) =
+    atomic_forced_read (__memalign_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    return (*hook)(alignment, bytes, RETURN_ADDRESS (0));
+
+  return __libc_memalign (alignment, bytes);
+}
+strong_alias (__compathook_memalign, memalign)
+
+static void *
+__compathook_pvalloc (size_t bytes)
+{
+  void *(*hook) (size_t, size_t, const void *) =
+    atomic_forced_read (__memalign_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      size_t rounded_bytes;
+
+      if (!pagesize)
+	pagesize = sysconf (_SC_PAGESIZE);
+
+      /* ALIGN_UP with overflow check.  */
+      if (__glibc_unlikely (__builtin_add_overflow (bytes,
+						    pagesize - 1,
+						    &rounded_bytes)))
+	{
+	  errno = ENOMEM;
+	  return NULL;
+	}
+      rounded_bytes = rounded_bytes & -(pagesize - 1);
+      return (*hook)(pagesize, rounded_bytes, RETURN_ADDRESS (0));
+    }
+
+  return __libc_pvalloc (bytes);
+}
+strong_alias (__compathook_pvalloc, pvalloc)
+
+static void *
+__compathook_valloc (size_t bytes)
+{
+  void *(*hook) (size_t, size_t, const void *) =
+    atomic_forced_read (__memalign_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      if (!pagesize)
+	pagesize = sysconf (_SC_PAGESIZE);
+
+      return (*hook)(pagesize, bytes, RETURN_ADDRESS (0));
+    }
+
+  return __libc_valloc (bytes);
+}
+strong_alias (__compathook_valloc, valloc)
+
+static void *
+__compathook_calloc (size_t nmemb, size_t size)
+{
+  void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook);
+  if (__builtin_expect (hook != NULL, 0))
+    {
+      size_t bytes;
+
+      if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes)))
+	{
+	  errno = ENOMEM;
+	  return NULL;
+	}
+
+      void *mem = (*hook)(bytes, RETURN_ADDRESS (0));
+
+      if (mem != NULL)
+	memset (mem, 0, bytes);
+
+      return mem;
+    }
+
+  return __libc_calloc (nmemb, size);
+}
+strong_alias (__compathook_calloc, calloc)
diff --git a/malloc/malloc.c b/malloc/malloc.c
index c899619e50..f6d7309721 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -570,16 +570,6 @@ tag_at (void *ptr)
 #define HAVE_MREMAP 0
 #endif
 
-/* We may need to support __malloc_initialize_hook for backwards
-   compatibility.  */
-
-#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_24)
-# define HAVE_MALLOC_INIT_HOOK 1
-#else
-# define HAVE_MALLOC_INIT_HOOK 0
-#endif
-
-
 /*
   This version of malloc supports the standard SVID/XPG mallinfo
   routine that returns a struct containing usage properties and
diff --git a/malloc/malloc.h b/malloc/malloc.h
index c1c0896d29..709fa454b5 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -165,20 +165,6 @@ extern void malloc_stats (void) __THROW;
 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)
   __MALLOC_DEPRECATED;
 
diff --git a/manual/memory.texi b/manual/memory.texi
index 28ec2e4e63..e66ecd582d 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.
@@ -1388,170 +1386,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 hook functions
-can be safely installed.  If the hook functions call the @code{malloc}-related
-functions recursively, it is necessary that @code{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 @code{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 @code{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.
 
@@ -1686,19 +1520,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 mallinfo2 mallinfo2 (void)
 Return information about the current dynamic memory usage.
 @xref{Statistics of Malloc}.
@@ -1733,7 +1554,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.
@@ -1758,10 +1579,10 @@ with the SUID or SGID bit set.
 
 If the named file is successfully opened, @code{mtrace} installs special
 handlers for the functions @code{malloc}, @code{realloc}, and
-@code{free} (@pxref{Hooks for Malloc}).  From then on, all uses of these
-functions are traced and protocolled into the file.  There is now of
-course a speed penalty for all calls to the traced functions so tracing
-should not be enabled during normal use.
+@code{free}.  From then on, all uses of these functions are traced and
+protocolled into the file.  There is now of course a speed penalty for all
+calls to the traced functions so tracing should not be enabled during normal
+use.
 
 This function is a GNU extension and generally not available on other
 systems.  The prototype can be found in @file{mcheck.h}.
@@ -1769,7 +1590,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/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data
index 9b4f35786a..e2083c0ce6 100644
--- a/sysdeps/generic/localplt.data
+++ b/sysdeps/generic/localplt.data
@@ -4,6 +4,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data
index 47fbe1e2a7..94064ecbc5 100644
--- a/sysdeps/mach/hurd/i386/localplt.data
+++ b/sysdeps/mach/hurd/i386/localplt.data
@@ -6,6 +6,7 @@
 libc.so: calloc + REL R_386_GLOB_DAT
 libc.so: free + REL R_386_GLOB_DAT
 libc.so: malloc + REL R_386_GLOB_DAT
+libc.so: memalign + REL R_386_GLOB_DAT
 libc.so: realloc + REL R_386_GLOB_DAT
 libm.so: matherr + REL R_386_GLOB_DAT
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data
index 348b3f3793..2c14b652ef 100644
--- a/sysdeps/unix/sysv/linux/aarch64/localplt.data
+++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data
@@ -4,6 +4,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # If outline atomics are used, libgcc (built outside of glibc) may
diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
index 44bf36f4f1..43f6fdaea1 100644
--- a/sysdeps/unix/sysv/linux/alpha/localplt.data
+++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
@@ -18,6 +18,7 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc + RELA R_ALPHA_GLOB_DAT
 libc.so: free + RELA R_ALPHA_GLOB_DAT
 libc.so: malloc + RELA R_ALPHA_GLOB_DAT
+libc.so: memalign + RELA R_ALPHA_GLOB_DAT
 libc.so: realloc + RELA R_ALPHA_GLOB_DAT
 libm.so: matherr + RELA R_ALPHA_GLOB_DAT
 # We used to offer inline functions that used this, so it must be exported.
diff --git a/sysdeps/unix/sysv/linux/arc/localplt.data b/sysdeps/unix/sysv/linux/arc/localplt.data
index ac5332caf7..4479e8ee8a 100644
--- a/sysdeps/unix/sysv/linux/arc/localplt.data
+++ b/sysdeps/unix/sysv/linux/arc/localplt.data
@@ -1,5 +1,6 @@
 libc.so: realloc
 libc.so: malloc
+libc.so: memalign
 libc.so: calloc
 libc.so: free
 # At -Os, a struct assignment in libgcc-static pulls this in
diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data
index 78896444c6..eb315da2f1 100644
--- a/sysdeps/unix/sysv/linux/arm/localplt.data
+++ b/sysdeps/unix/sysv/linux/arm/localplt.data
@@ -1,6 +1,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: raise
 libc.so: realloc
 libm.so: matherr
diff --git a/sysdeps/unix/sysv/linux/csky/localplt.data b/sysdeps/unix/sysv/linux/csky/localplt.data
index 817ab2659a..0ed8650b65 100644
--- a/sysdeps/unix/sysv/linux/csky/localplt.data
+++ b/sysdeps/unix/sysv/linux/csky/localplt.data
@@ -4,6 +4,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 # The TLS-enabled version of these functions is interposed from libc.so.
 ld.so: _dl_signal_error
diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data
index baf857a750..09893d4dcf 100644
--- a/sysdeps/unix/sysv/linux/hppa/localplt.data
+++ b/sysdeps/unix/sysv/linux/hppa/localplt.data
@@ -4,6 +4,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libc.so: __sigsetjmp
 libc.so: _IO_funlockfile
diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
index f9bf7fb410..5334875b4b 100644
--- a/sysdeps/unix/sysv/linux/i386/localplt.data
+++ b/sysdeps/unix/sysv/linux/i386/localplt.data
@@ -4,6 +4,7 @@ libc.so: _Unwind_Find_FDE + REL R_386_GLOB_DAT
 libc.so: calloc + REL R_386_GLOB_DAT
 libc.so: free + REL R_386_GLOB_DAT
 libc.so: malloc + REL R_386_GLOB_DAT
+libc.so: memalign + REL R_386_GLOB_DAT
 libc.so: realloc + REL R_386_GLOB_DAT
 libm.so: matherr + REL R_386_GLOB_DAT
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data
index 174fb88128..1c566a503e 100644
--- a/sysdeps/unix/sysv/linux/ia64/localplt.data
+++ b/sysdeps/unix/sysv/linux/ia64/localplt.data
@@ -1,6 +1,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 libm.so: matherrf
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
index 42fa90508c..3c5efb7204 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
@@ -2,6 +2,7 @@ libc.so: __m68k_read_tp
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
index 34bd4c1aca..843f4e25f2 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
@@ -3,6 +3,7 @@ libc.so: __m68k_read_tp
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data
index c3801314c9..0e98d5251e 100644
--- a/sysdeps/unix/sysv/linux/microblaze/localplt.data
+++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data
@@ -2,6 +2,7 @@ libc.so: __errno_location
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The dynamic loader needs __tls_get_addr for TLS.
diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data
index 17fcfdd4db..b37987c7c0 100644
--- a/sysdeps/unix/sysv/linux/nios2/localplt.data
+++ b/sysdeps/unix/sysv/linux/nios2/localplt.data
@@ -6,6 +6,7 @@ libc.so: __gedf2
 libc.so: malloc
 libc.so: __gtsf2 ?
 libc.so: __nesf2
+libc.so: memalign
 libc.so: __mulsf3
 libc.so: __floatunsisf
 libc.so: __addsf3
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
index c0af84eef7..a02dd5cc24 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
@@ -2,6 +2,7 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
index 581e54b95c..d8072597b7 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
@@ -30,6 +30,7 @@ libc.so: abort ?
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: memset ?
 libc.so: realloc
 libm.so: copysignl ?
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
index d69b7ae646..bb498fbe3a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
@@ -1,6 +1,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data
index e6d5330d5b..0a235592c3 100644
--- a/sysdeps/unix/sysv/linux/riscv/localplt.data
+++ b/sysdeps/unix/sysv/linux/riscv/localplt.data
@@ -4,6 +4,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: memset ?
 libc.so: realloc
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data
index c0af84eef7..a02dd5cc24 100644
--- a/sysdeps/unix/sysv/linux/s390/localplt.data
+++ b/sysdeps/unix/sysv/linux/s390/localplt.data
@@ -2,6 +2,7 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data
index 6491b9e37b..3225177c50 100644
--- a/sysdeps/unix/sysv/linux/sh/localplt.data
+++ b/sysdeps/unix/sysv/linux/sh/localplt.data
@@ -4,6 +4,7 @@
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libc.so: _Unwind_Find_FDE
 libc.so: _exit
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
index 38309a1393..be51efd566 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
@@ -16,6 +16,7 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
index 6a216f3a5a..809062d46c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
@@ -15,6 +15,7 @@ libc.so: _Unwind_Find_FDE
 libc.so: calloc
 libc.so: free
 libc.so: malloc
+libc.so: memalign
 libc.so: realloc
 libm.so: matherr
 # The TLS-enabled version of these functions is interposed from libc.so.
diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
index d1f2e26612..8f41e92870 100644
--- a/sysdeps/x86_64/localplt.data
+++ b/sysdeps/x86_64/localplt.data
@@ -6,6 +6,7 @@
 libc.so: calloc + RELA R_X86_64_GLOB_DAT
 libc.so: free + RELA R_X86_64_GLOB_DAT
 libc.so: malloc + RELA R_X86_64_GLOB_DAT
+libc.so: memalign + RELA R_X86_64_GLOB_DAT
 libc.so: realloc + RELA R_X86_64_GLOB_DAT
 libm.so: matherr + RELA R_X86_64_GLOB_DAT
 # The TLS-enabled version of these functions is interposed from libc.so.
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 09/10] Remove __after_morecore_hook
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (7 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 08/10] Remove " Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 11:38 ` [PATCH v4 10/10] Remove __morecore and __default_morecore Siddhesh Poyarekar
  2021-07-02 19:05 ` [PATCH v4 00/10] Remove malloc hooks Carlos O'Donell
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Remove __after_morecore_hook from the API and finalize the symbol so
that it can no longer be used in new applications.  Old applications
using __after_morecore_hook will find that their hook is no longer
called.

Reviewed-by: DJ Delorie <dj@redhat.com>
---
 malloc/hooks.c  |  3 +++
 malloc/malloc.c | 30 +-----------------------------
 malloc/malloc.h |  5 -----
 3 files changed, 4 insertions(+), 34 deletions(-)

diff --git a/malloc/hooks.c b/malloc/hooks.c
index 397220aaba..5e9355761a 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -78,6 +78,9 @@ compat_symbol (libc, __malloc_hook, __malloc_hook, GLIBC_2_0);
 compat_symbol (libc, __realloc_hook, __realloc_hook, GLIBC_2_0);
 compat_symbol (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
 
+void weak_variable (*__after_morecore_hook) (void) = NULL;
+compat_symbol (libc, __after_morecore_hook, __after_morecore_hook, GLIBC_2_0);
+
 /* These hooks will get executed only through the interposed allocator
    functions in libmalloc_compathooks.  This means that the calls to malloc,
    realloc, etc. will lead back into the interposed functions, which is what we
diff --git a/malloc/malloc.c b/malloc/malloc.c
index f6d7309721..296e4f9789 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -1988,16 +1988,6 @@ static void     malloc_consolidate (mstate);
 
 /* -------------- Early definitions for debugging hooks ---------------- */
 
-/* Define and initialize the hook variables.  These weak definitions must
-   appear before any use of the variables in a function (arena.c uses one).  */
-#ifndef weak_variable
-/* In GNU libc we want the hook variables to be weak definitions to
-   avoid a problem with Emacs.  */
-# define weak_variable weak_function
-#endif
-
-void weak_variable (*__after_morecore_hook) (void) = NULL;
-
 /* This function is called from the arena shutdown hook, to free the
    thread cache (if it exists).  */
 static void tcache_thread_shutdown (void);
@@ -2622,14 +2612,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
@@ -2768,13 +2751,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 */
@@ -2933,10 +2909,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);
diff --git a/malloc/malloc.h b/malloc/malloc.h
index 709fa454b5..d066a05d82 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -164,10 +164,5 @@ 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 __after_morecore_hook) (void)
-  __MALLOC_DEPRECATED;
-
-
 __END_DECLS
 #endif /* malloc.h */
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v4 10/10] Remove __morecore and __default_morecore
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (8 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 09/10] Remove __after_morecore_hook Siddhesh Poyarekar
@ 2021-07-02 11:38 ` Siddhesh Poyarekar
  2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 19:05 ` [PATCH v4 00/10] Remove malloc hooks Carlos O'Donell
  10 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 11:38 UTC (permalink / raw)
  To: libc-alpha; +Cc: dj, carlos, fweimer

Make the __morecore and __default_morecore symbols compat-only and
remove their declarations from the API.

Reviewed-by: DJ Delorie <dj@redhat.com>
---
 NEWS                     |  5 +++++
 include/stdlib.h         |  3 ---
 malloc/arena.c           | 12 ++----------
 malloc/hooks.c           |  3 +++
 malloc/malloc-internal.h |  5 +++++
 malloc/malloc.c          |  4 +---
 malloc/malloc.h          |  8 --------
 malloc/morecore.c        | 15 +++++++++++++--
 8 files changed, 29 insertions(+), 26 deletions(-)

diff --git a/NEWS b/NEWS
index cebe8384bf..2533919f75 100644
--- a/NEWS
+++ b/NEWS
@@ -106,6 +106,11 @@ Deprecated and removed features, and other changes affecting compatibility:
   legacy programs until they are updated to remove references to the memory
   allocation hooks.
 
+* The __morecore and __after_morecore_hook malloc hooks and the default
+  implementation __default_morecore have been removed from the API.  Existing
+  applications will continue to link against these symbols but the interfaces
+  no longer have any effect on malloc.
+
 Changes to build and runtime requirements:
 
 * On Linux, the shm_open, sem_open, and related functions now expect the
diff --git a/include/stdlib.h b/include/stdlib.h
index 1f6e1508e4..1c6f70b082 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -306,9 +306,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/malloc/arena.c b/malloc/arena.c
index 8591c8ea56..00e8b5a32f 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -272,14 +272,6 @@ next_env_entry (char ***position)
 #endif
 
 
-#if defined(SHARED) || defined(USE_MTAG)
-static void *
-__failing_morecore (ptrdiff_t d)
-{
-  return (void *) MORECORE_FAILURE;
-}
-#endif
-
 #ifdef SHARED
 extern struct dl_open_hook *_dl_open_hook;
 libc_hidden_proto (_dl_open_hook);
@@ -300,7 +292,7 @@ ptmalloc_init (void)
 	 and that morecore does not support tagged regions, then
 	 disable it.  */
       if (__MTAG_SBRK_UNTAGGED)
-	__morecore = __failing_morecore;
+	__always_fail_morecore = true;
 
       mtag_enabled = true;
       mtag_mmap_flags = __MTAG_MMAP_FLAGS;
@@ -313,7 +305,7 @@ ptmalloc_init (void)
      generic sbrk implementation also enforces this, but it is not
      used on Hurd.  */
   if (!__libc_initial)
-    __morecore = __failing_morecore;
+    __always_fail_morecore = true;
 #endif
 
   thread_arena = &main_arena;
diff --git a/malloc/hooks.c b/malloc/hooks.c
index 5e9355761a..b40696c8b7 100644
--- a/malloc/hooks.c
+++ b/malloc/hooks.c
@@ -81,6 +81,9 @@ compat_symbol (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
 void weak_variable (*__after_morecore_hook) (void) = NULL;
 compat_symbol (libc, __after_morecore_hook, __after_morecore_hook, GLIBC_2_0);
 
+void *(*__morecore)(ptrdiff_t);
+compat_symbol (libc, __morecore, __morecore, GLIBC_2_0);
+
 /* These hooks will get executed only through the interposed allocator
    functions in libmalloc_compathooks.  This means that the calls to malloc,
    realloc, etc. will lead back into the interposed functions, which is what we
diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h
index ee0f5697af..b104f7cdbf 100644
--- a/malloc/malloc-internal.h
+++ b/malloc/malloc-internal.h
@@ -21,6 +21,7 @@
 
 #include <malloc-machine.h>
 #include <malloc-sysdep.h>
+#include <stdbool.h>
 
 /* INTERNAL_SIZE_T is the word-size used for internal bookkeeping of
    chunk sizes.
@@ -63,6 +64,8 @@
 
 #define top(ar_ptr) ((ar_ptr)->top)
 
+extern bool __always_fail_morecore attribute_hidden;
+
 /* Called in the parent process before a fork.  */
 void __malloc_fork_lock_parent (void) attribute_hidden;
 
@@ -78,4 +81,6 @@ void __malloc_arena_thread_freeres (void) attribute_hidden;
 /* Activate a standard set of debugging hooks. */
 void __malloc_check_init (void) attribute_hidden;
 
+extern void *__glibc_morecore (ptrdiff_t) attribute_hidden;
+
 #endif /* _MALLOC_INTERNAL_H */
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 296e4f9789..79855e93ab 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -382,10 +382,8 @@ __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;
 
 /* Memory tagging.  */
 
diff --git a/malloc/malloc.h b/malloc/malloc.h
index d066a05d82..2df0b38050 100644
--- a/malloc/malloc.h
+++ b/malloc/malloc.h
@@ -76,14 +76,6 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__
 extern void *pvalloc (size_t __size) __THROW __attribute_malloc__
   __wur __attr_dealloc_free;
 
-/* Underlying allocation function; successive calls should return
-   contiguous pieces of memory.  */
-extern void *(*__morecore) (ptrdiff_t __size) __MALLOC_DEPRECATED;
-
-/* Default value of `__morecore'.  */
-extern void *__default_morecore (ptrdiff_t __size)
-__THROW __attribute_malloc__  __MALLOC_DEPRECATED;
-
 /* SVID2/XPG mallinfo structure */
 
 struct mallinfo
diff --git a/malloc/morecore.c b/malloc/morecore.c
index 047228779b..c85a85c0eb 100644
--- a/malloc/morecore.c
+++ b/malloc/morecore.c
@@ -38,16 +38,27 @@ libc_hidden_proto (__sbrk)
 # define NULL 0
 #endif
 
+#if defined(SHARED) || defined(USE_MTAG)
+bool __always_fail_morecore = false;
+#endif
+
 /* Allocate INCREMENT more bytes of data space,
    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)
 {
+#if defined(SHARED) || defined(USE_MTAG)
+  if (__always_fail_morecore)
+    return NULL;
+#endif
+
   void *result = (void *) __sbrk (increment);
   if (result == (void *) -1)
     return NULL;
 
   return result;
 }
-libc_hidden_def (__default_morecore)
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+compat_symbol (libc, __glibc_morecore, __default_morecore, GLIBC_2_0);
+#endif
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c
  2021-07-02 11:38 ` [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c Siddhesh Poyarekar
@ 2021-07-02 12:12   ` Andreas Schwab
  2021-07-02 19:06   ` Carlos O'Donell
  1 sibling, 0 replies; 35+ messages in thread
From: Andreas Schwab @ 2021-07-02 12:12 UTC (permalink / raw)
  To: Siddhesh Poyarekar via Libc-alpha; +Cc: Siddhesh Poyarekar, fweimer

On Jul 02 2021, Siddhesh Poyarekar via Libc-alpha wrote:

> Dependencies on hooks.c and arena.c get auto-computed when generating
> malloc.o{,s}.d so there is no need to add them manually.

Ok.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 06/10] mcheck: Wean away from malloc hooks
  2021-07-02 11:38 ` [PATCH v4 06/10] mcheck: " Siddhesh Poyarekar
@ 2021-07-02 18:34   ` Carlos O'Donell
  2021-07-02 18:46     ` Siddhesh Poyarekar
  0 siblings, 1 reply; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 18:34 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Split the mcheck implementation into the debugging hooks and the user
> visible implementation so that the debugging hooks (in mcheck-hooks.c)
> can be embedded like malloc-check.c.
> 
> Further, add *_debug_after debugging hooks into malloc so that mcheck
> can then be adapted to using the debugging hooks instead of fiddling
> with hooks variables.  This adds an extra conditional branch at the
> end of the allocator functions but it should have minimal effect in
> the default use case.
> 
> Initialization using -lmcheck now depends on a new exported variable
> __libc_lmcheck which is a const flag that mcheck-init can override.
> 
> While this simplifies the mcheck implementation, it still does not
> make the interface thread safe as access to its internal structures is
> still unprotected.

I do not like the addition of a new ABI for an interface whose functionality
is worse than valgrind which we have today, and will likely be removed
in the future.

We have put __libc_lmcheck into libmcheck.a, which is statically linked
into the application or a DSO, and so this creates an odd design where
the application, a DSO, and libc can all have the __libc_lmcheck variable.
This is not a good way forward for the -lmcheck support since this makes
the linkage slightly dependent on the executable, the DSOs etc.

I would rather you deprecate all the APIs and have the implemetnations do
nothing.

I don't think any of these functions are actually useful today.

Someone can provide an interposer malloc with all of this functionality,
and we can to, at some point in the future, and not be bound by compatibility
requirements (other than the malloc API requirements).

> ---
>  include/malloc.h                              |  10 +-
>  malloc/Makefile                               |   4 +-
>  malloc/Versions                               |   3 +
>  malloc/arena.c                                |   5 +
>  malloc/hooks.c                                | 133 ++++--
>  malloc/malloc.c                               | 115 +++--
>  malloc/mcheck-hooks.c                         | 411 ++++++++++++++++++
>  malloc/mcheck-init.c                          |  14 +-
>  malloc/mcheck.c                               | 369 +---------------
>  sysdeps/mach/hurd/i386/libc.abilist           |   1 +
>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/ia64/libc.abilist     |   1 +
>  .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
>  .../sysv/linux/microblaze/be/libc.abilist     |   1 +
>  .../sysv/linux/microblaze/le/libc.abilist     |   1 +
>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
>  .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
>  .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
>  .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
>  .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
>  .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
>  42 files changed, 649 insertions(+), 448 deletions(-)
>  create mode 100644 malloc/mcheck-hooks.c
> 
> diff --git a/include/malloc.h b/include/malloc.h
> index b77761f74d..bb1123d9d3 100644
> --- a/include/malloc.h
> +++ b/include/malloc.h
> @@ -4,6 +4,11 @@
>  
>  # ifndef _ISOMAC
>  #  include <rtld-malloc.h>
> +#  include <stdbool.h>
> +#  include <mcheck.h>
> +
> +struct malloc_state;
> +typedef struct malloc_state *mstate;
>  
>  /* In the GNU libc we rename the global variable
>     `__malloc_initialized' to `__libc_malloc_initialized'.  */
> @@ -11,8 +16,9 @@
>  /* Nonzero if the malloc is already initialized.  */
>  extern int __malloc_initialized attribute_hidden;
>  
> -struct malloc_state;
> -typedef struct malloc_state *mstate;
> +enum mcheck_status __mcheck_checkptr (const void *) attribute_hidden;
> +extern int __mcheck_initialize (void (*) (enum mcheck_status), bool)
> +     attribute_hidden;
>  
>  # endif /* !_ISOMAC */
>  
> diff --git a/malloc/Makefile b/malloc/Makefile
> index 2f9b3d596d..328e0be1fd 100644
> --- a/malloc/Makefile
> +++ b/malloc/Makefile
> @@ -91,9 +91,7 @@ tests-exclude-mcheck = tst-mallocstate \
>  	tst-malloc-usable-static \
>  	tst-malloc-usable-static-tunables \
>  	tst-malloc-usable-tunables \
> -	tst-malloc_info \
> -	tst-memalign \
> -	tst-posix_memalign
> +	tst-malloc_info
>  
>  tests-mcheck = $(filter-out $(tests-exclude-mcheck), $(tests))
>  
> diff --git a/malloc/Versions b/malloc/Versions
> index 62e4698a08..e138eaa24b 100644
> --- a/malloc/Versions
> +++ b/malloc/Versions
> @@ -67,6 +67,9 @@ libc {
>    GLIBC_2.33 {
>      mallinfo2;
>    }
> +  GLIBC_2.34 {
> +    __libc_lmcheck;

Should be removed or GLIBC_PRIVATE.

> +  }
>    GLIBC_PRIVATE {
>      # Internal startup hook for libpthread.
>      __libc_malloc_pthread_startup;
> diff --git a/malloc/arena.c b/malloc/arena.c
> index 357a3b0b30..a8500a25c9 100644
> --- a/malloc/arena.c
> +++ b/malloc/arena.c
> @@ -403,6 +403,11 @@ ptmalloc_init (void)
>      __malloc_debug_enable (MALLOC_CHECK_HOOK);
>  #endif
>  
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
> +  if (__libc_lmcheck)
> +    __mcheck_initialize (NULL, false);

So new architectures never support calling __mcheck_initialize?

> +#endif
> +
>  #if HAVE_MALLOC_INIT_HOOK
>    void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
>    if (hook != NULL)
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 77855801c8..7b500e5671 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -36,6 +36,7 @@ enum malloc_debug_hooks
>  {
>    MALLOC_NONE_HOOK = 0,
>    MALLOC_CHECK_HOOK = 1 << 0,	/* MALLOC_CHECK_ or glibc.malloc.check.  */
> +  MALLOC_MCHECK_HOOK = 1 << 1,	/* mcheck()  */
>  };
>  static unsigned __malloc_debugging_hooks;
>  
> @@ -77,113 +78,181 @@ __malloc_debug_disable (enum malloc_debug_hooks flag)
>  }
>  
>  #include "malloc-check.c"
> +#include "mcheck-hooks.c"
>  
>  static __always_inline bool
> -_malloc_debug_before (size_t bytes, void **victimp, const void *address)
> +_malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
>  {
>    _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
> -                  "PTRDIFF_MAX is not more than half of SIZE_MAX");
> +		  "PTRDIFF_MAX is not more than half of SIZE_MAX");
>  
>    void *(*hook) (size_t, const void *)
>      = atomic_forced_read (__malloc_hook);
>    if (__builtin_expect (hook != NULL, 0))
>      {
> -      *victimp = (*hook)(bytes, address);
> +      *victimp = (*hook)(*bytesp, address);
>        return true;
>      }
>  
> -  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
> -      *victimp = malloc_check (bytes);
> -      return true;
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
> +	  && malloc_mcheck_before (bytesp, victimp))
> +	return true;
> +      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
> +	{
> +	  *victimp = malloc_check (*bytesp);
> +	  return true;
> +	}
>      }
>    return false;
>  }
>  
> +static __always_inline void *
> +_malloc_debug_after (void *mem, size_t bytes, const void *address)
> +{
> +  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> +    mem = malloc_mcheck_after (mem, bytes);
> +  return mem;
> +}
> +
>  static __always_inline bool
> -_free_debug_before (void *mem, const void *address)
> +_free_debug_before (void **mem, const void *address)
>  {
>    void (*hook) (void *, const void *)
>      = atomic_forced_read (__free_hook);
>    if (__builtin_expect (hook != NULL, 0))
>      {
> -      (*hook)(mem, address);
> +      (*hook)(*mem, address);
>        return true;
>      }
>  
> -  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
> -      free_check (mem);
> -      return true;
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
> +	*mem = free_mcheck (*mem);
> +      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
> +	{
> +	  free_check (*mem);
> +	  return true;
> +	}
>      }
>    return false;
>  }
>  
>  static __always_inline bool
> -_realloc_debug_before (void *oldmem, size_t bytes, void **victimp,
> -			const void *address)
> +_realloc_debug_before (void **oldmem, size_t *bytesp, size_t *oldsize,
> +		       void **victimp, const void *address)
>  {
>    void *(*hook) (void *, size_t, const void *) =
>      atomic_forced_read (__realloc_hook);
>    if (__builtin_expect (hook != NULL, 0))
>      {
> -      *victimp = (*hook)(oldmem, bytes, address);
> +      *victimp = (*hook)(*oldmem, *bytesp, address);
>        return true;
>      }
>  
> -  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
> -      *victimp = realloc_check (oldmem, bytes);
> -      return true;
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
> +	  && realloc_mcheck_before (oldmem, bytesp, oldsize, victimp))
> +	return true;
> +      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
> +	{
> +	  *victimp = realloc_check (*oldmem, *bytesp);
> +	  return true;
> +	}
>      }
>  
>    return false;
>  }
>  
> +static __always_inline void *
> +_realloc_debug_after (void *mem, void *oldmem, size_t bytes, size_t oldsize,
> +		      const void *address)
> +{
> +  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> +    mem = realloc_mcheck_after (mem, oldmem, bytes, oldsize);
> +  return mem;
> +}
> +
>  static __always_inline bool
> -_memalign_debug_before (size_t alignment, size_t bytes, void **victimp,
> -			 const void *address)
> +_memalign_debug_before (size_t alignment, size_t *bytesp, void **victimp,
> +			const void *address)
>  {
>    void *(*hook) (size_t, size_t, const void *) =
>      atomic_forced_read (__memalign_hook);
>    if (__builtin_expect (hook != NULL, 0))
>      {
> -      *victimp = (*hook)(alignment, bytes, address);
> +      *victimp = (*hook)(alignment, *bytesp, address);
>        return true;
>      }
> -
> -  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
> -      *victimp = memalign_check (alignment, bytes);
> -      return true;
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
> +	  && memalign_mcheck_before (alignment, bytesp, victimp))
> +	return true;
> +      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
> +	{
> +	  *victimp = memalign_check (alignment, *bytesp);
> +	  return true;
> +	}
>      }
>  
>    return false;
>  }
>  
> +static __always_inline void *
> +_memalign_debug_after (void *mem, size_t alignment, size_t bytes,
> +		       const void *address)
> +{
> +  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> +    mem = memalign_mcheck_after (mem, alignment, bytes);
> +  return mem;
> +}
> +
>  static __always_inline bool
> -_calloc_debug_before (size_t bytes, void **victimp, const void *address)
> +_calloc_debug_before (size_t *bytesp, void **victimp, const void *address)
>  {
>    void *(*hook) (size_t, const void *) =
>      atomic_forced_read (__malloc_hook);
>    if (__builtin_expect (hook != NULL, 0))
>      {
> -      *victimp = (*hook)(bytes, address);
> +      *victimp = (*hook)(*bytesp, address);
> +
>        if (*victimp != NULL)
> -	memset (*victimp, 0, bytes);
> +	memset (*victimp, 0, *bytesp);
> +
>        return true;
>      }
>  
> -  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +  /* Memory is zeroed out in the AFTER hook.  */
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
> -      *victimp = malloc_check (bytes);
> -      if (*victimp != NULL)
> -	memset (*victimp, 0, bytes);
> -      return true;
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
> +	  && malloc_mcheck_before (bytesp, victimp))
> +	return true;
> +      if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
> +	{
> +	  *victimp = malloc_check (*bytesp);
> +	  return true;
> +	}
>      }
>    return false;
>  }
>  
> +static __always_inline void *
> +_calloc_debug_after (void *mem, size_t bytes, const void *address)
> +{
> +  if (__glibc_unlikely (__malloc_debugging_hooks) && mem != NULL)
> +    {
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
> +	mem = malloc_mcheck_after (mem, bytes);
> +      memset (mem, 0, bytes);
> +    }
> +  return mem;
> +}
> +
>  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
>  
>  /* Support for restoring dumped heaps contained in historic Emacs
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 60753446a1..c899619e50 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -3191,13 +3191,14 @@ void *
>  __libc_malloc (size_t bytes)
>  {
>    mstate ar_ptr;
> -  void *victim;
> +  void *victim = NULL;
> +  size_t orig_bytes = bytes;
>  
>    if (__malloc_initialized < 0)
>      ptmalloc_init ();
>  
> -  if (_malloc_debug_before (bytes, &victim, RETURN_ADDRESS (0)))
> -    return victim;
> +  if (_malloc_debug_before (&bytes, &victim, RETURN_ADDRESS (0)))
> +    goto out;
>  
>  #if USE_TCACHE
>    /* int_free also calls request2size, be careful to not pad twice.  */
> @@ -3205,7 +3206,8 @@ __libc_malloc (size_t bytes)
>    if (!checked_request2size (bytes, &tbytes))
>      {
>        __set_errno (ENOMEM);
> -      return NULL;
> +      victim = NULL;
> +      goto out;
>      }
>    size_t tc_idx = csize2tidx (tbytes);
>  
> @@ -3217,7 +3219,8 @@ __libc_malloc (size_t bytes)
>        && tcache->counts[tc_idx] > 0)
>      {
>        victim = tcache_get (tc_idx);
> -      return tag_new_usable (victim);
> +      victim = tag_new_usable (victim);
> +      goto out;
>      }
>    DIAG_POP_NEEDS_COMMENT;
>  #endif
> @@ -3227,7 +3230,7 @@ __libc_malloc (size_t bytes)
>        victim = tag_new_usable (_int_malloc (&main_arena, bytes));
>        assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
>  	      &main_arena == arena_for_chunk (mem2chunk (victim)));
> -      return victim;
> +      goto out;
>      }
>  
>    arena_get (ar_ptr, bytes);
> @@ -3249,7 +3252,9 @@ __libc_malloc (size_t bytes)
>  
>    assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
>            ar_ptr == arena_for_chunk (mem2chunk (victim)));
> -  return victim;
> +
> +out:
> +  return _malloc_debug_after (victim, orig_bytes, RETURN_ADDRESS (0));
>  }
>  libc_hidden_def (__libc_malloc)
>  
> @@ -3262,7 +3267,7 @@ __libc_free (void *mem)
>    if (__malloc_initialized < 0)
>      ptmalloc_init ();
>  
> -  if (_free_debug_before (mem, RETURN_ADDRESS (0)))
> +  if (_free_debug_before (&mem, RETURN_ADDRESS (0)))
>      return;
>  
>    if (mem == 0)                              /* free(0) has no effect */
> @@ -3315,23 +3320,30 @@ __libc_realloc (void *oldmem, size_t bytes)
>    INTERNAL_SIZE_T nb;         /* padded request size */
>  
>    void *newp;             /* chunk to return */
> +  size_t orig_bytes = bytes, debug_osize = 0;
>  
>    if (__malloc_initialized < 0)
>      ptmalloc_init ();
>  
> -  if (_realloc_debug_before (oldmem, bytes, &newp, RETURN_ADDRESS (0)))
> -    return newp;
> +  if (_realloc_debug_before (&oldmem, &bytes, &debug_osize, &newp,
> +			     RETURN_ADDRESS (0)))
> +    goto out;
>  
>  #if REALLOC_ZERO_BYTES_FREES
>    if (bytes == 0 && oldmem != NULL)
>      {
> -      __libc_free (oldmem); return 0;
> +      __libc_free (oldmem);
> +      newp = NULL;
> +      goto out;
>      }
>  #endif
>  
>    /* realloc of null is supposed to be same as malloc */
>    if (oldmem == 0)
> -    return __libc_malloc (bytes);
> +    {
> +      newp = __libc_malloc (bytes);
> +      goto out;
> +    }
>  
>    /* Perform a quick check to ensure that the pointer's tag matches the
>       memory's tag.  */
> @@ -3365,7 +3377,8 @@ __libc_realloc (void *oldmem, size_t bytes)
>    if (!checked_request2size (bytes, &nb))
>      {
>        __set_errno (ENOMEM);
> -      return NULL;
> +      newp = NULL;
> +      goto out;
>      }
>  
>    if (chunk_is_mmapped (oldp))
> @@ -3377,7 +3390,10 @@ __libc_realloc (void *oldmem, size_t bytes)
>  	  /* Must alloc, copy, free. */
>  	  void *newmem = __libc_malloc (bytes);
>  	  if (newmem == 0)
> -	    return NULL;
> +	    {
> +	      newp = NULL;
> +	      goto out;
> +	    }
>  	  /* Copy as many bytes as are available from the old chunk
>  	     and fit into the new size.  NB: The overhead for faked
>  	     mmapped chunks is only SIZE_SZ, not CHUNK_HDR_SZ as for
> @@ -3385,7 +3401,8 @@ __libc_realloc (void *oldmem, size_t bytes)
>  	  if (bytes > oldsize - SIZE_SZ)
>  	    bytes = oldsize - SIZE_SZ;
>  	  memcpy (newmem, oldmem, bytes);
> -	  return newmem;
> +	  newp = newmem;
> +	  goto out;
>  	}
>  
>        void *newmem;
> @@ -3400,21 +3417,29 @@ __libc_realloc (void *oldmem, size_t bytes)
>  	     reused.  There's a performance hit for both us and the
>  	     caller for doing this, so we might want to
>  	     reconsider.  */
> -	  return tag_new_usable (newmem);
> +	  newp = tag_new_usable (newmem);
> +	  goto out;
>  	}
>  #endif
>        /* Note the extra SIZE_SZ overhead. */
>        if (oldsize - SIZE_SZ >= nb)
> -        return oldmem;                         /* do nothing */
> +	{
> +	  newp = oldmem;                         /* do nothing */
> +	  goto out;
> +	}
>  
>        /* Must alloc, copy, free. */
>        newmem = __libc_malloc (bytes);
>        if (newmem == 0)
> -        return 0;              /* propagate failure */
> +	{
> +	  newp = NULL;              /* propagate failure */
> +	  goto out;
> +	}
>  
>        memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
>        munmap_chunk (oldp);
> -      return newmem;
> +      newp = newmem;
> +      goto out;
>      }
>  
>    if (SINGLE_THREAD_P)
> @@ -3423,7 +3448,7 @@ __libc_realloc (void *oldmem, size_t bytes)
>        assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
>  	      ar_ptr == arena_for_chunk (mem2chunk (newp)));
>  
> -      return newp;
> +      goto out;
>      }
>  
>    __libc_lock_lock (ar_ptr->mutex);
> @@ -3448,7 +3473,9 @@ __libc_realloc (void *oldmem, size_t bytes)
>          }
>      }
>  
> -  return newp;
> +out:
> +  return _realloc_debug_after (newp, oldmem, orig_bytes, debug_osize,
> +			       RETURN_ADDRESS (0));
>  }
>  libc_hidden_def (__libc_realloc)
>  
> @@ -3467,13 +3494,17 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
>  {
>    mstate ar_ptr;
>    void *p;
> +  size_t orig_bytes = bytes;
>  
> -  if (_memalign_debug_before (alignment, bytes, &p, address))
> -    return p;
> +  if (_memalign_debug_before (alignment, &bytes, &p, address))
> +    goto out;
>  
>    /* If we need less alignment than we give anyway, just relay to malloc.  */
>    if (alignment <= MALLOC_ALIGNMENT)
> -    return __libc_malloc (bytes);
> +    {
> +      p = __libc_malloc (bytes);
> +      goto out;
> +    }
>  
>    /* Otherwise, ensure that it is at least a minimum chunk size */
>    if (alignment < MINSIZE)
> @@ -3484,7 +3515,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
>    if (alignment > SIZE_MAX / 2 + 1)
>      {
>        __set_errno (EINVAL);
> -      return 0;
> +      p = NULL;
> +      goto out;
>      }
>  
>  
> @@ -3502,7 +3534,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
>        p = _int_memalign (&main_arena, alignment, bytes);
>        assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
>  	      &main_arena == arena_for_chunk (mem2chunk (p)));
> -      return tag_new_usable (p);
> +      p = tag_new_usable (p);
> +      goto out;
>      }
>  
>    arena_get (ar_ptr, bytes + alignment + MINSIZE);
> @@ -3520,7 +3553,9 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
>  
>    assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
>            ar_ptr == arena_for_chunk (mem2chunk (p)));
> -  return tag_new_usable (p);
> +  p = tag_new_usable (p);
> +out:
> +  return _memalign_debug_after (p, alignment, orig_bytes, RETURN_ADDRESS (0));
>  }
>  /* For ISO C11.  */
>  weak_alias (__libc_memalign, aligned_alloc)
> @@ -3582,8 +3617,8 @@ __libc_calloc (size_t n, size_t elem_size)
>    if (__malloc_initialized < 0)
>      ptmalloc_init ();
>  
> -  if (_calloc_debug_before (sz, &mem, RETURN_ADDRESS (0)))
> -    return mem;
> +  if (_calloc_debug_before (&sz, &mem, RETURN_ADDRESS (0)))
> +    goto out;
>  
>    MAYBE_INIT_TCACHE ();
>  
> @@ -3639,7 +3674,10 @@ __libc_calloc (size_t n, size_t elem_size)
>  
>    /* Allocation failed even after a retry.  */
>    if (mem == 0)
> -    return 0;
> +    {
> +      mem = NULL;
> +      goto out;
> +    }
>  
>    mchunkptr p = mem2chunk (mem);
>  
> @@ -3647,7 +3685,10 @@ __libc_calloc (size_t n, size_t elem_size)
>       regardless of MORECORE_CLEARS, so we zero the whole block while
>       doing so.  */
>    if (__glibc_unlikely (mtag_enabled))
> -    return tag_new_zero_region (mem, memsize (p));
> +    {
> +      mem = tag_new_zero_region (mem, memsize (p));
> +      goto out;
> +    }
>  
>    INTERNAL_SIZE_T csz = chunksize (p);
>  
> @@ -3655,9 +3696,9 @@ __libc_calloc (size_t n, size_t elem_size)
>    if (chunk_is_mmapped (p))
>      {
>        if (__builtin_expect (perturb_byte, 0))
> -        return memset (mem, 0, sz);
> +        memset (mem, 0, sz);
>  
> -      return mem;
> +      goto out;
>      }
>  
>  #if MORECORE_CLEARS
> @@ -3677,7 +3718,10 @@ __libc_calloc (size_t n, size_t elem_size)
>    assert (nclears >= 3);
>  
>    if (nclears > 9)
> -    return memset (d, 0, clearsize);
> +    {
> +      memset (d, 0, clearsize);
> +      goto out;
> +    }
>  
>    else
>      {
> @@ -3701,7 +3745,8 @@ __libc_calloc (size_t n, size_t elem_size)
>          }
>      }
>  
> -  return mem;
> +out:
> +  return _calloc_debug_after (mem, bytes, RETURN_ADDRESS (0));
>  }
>  
>  /*
> diff --git a/malloc/mcheck-hooks.c b/malloc/mcheck-hooks.c
> new file mode 100644
> index 0000000000..f3520c7659
> --- /dev/null
> +++ b/malloc/mcheck-hooks.c
> @@ -0,0 +1,411 @@
> +/* mcheck debugging hooks for malloc.
> +   Copyright (C) 1990-2021 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +   Written May 1989 by Mike Haertel.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <mcheck.h>
> +#include <libintl.h>
> +
> +/* Arbitrary magical numbers.  */
> +#define MAGICWORD       0xfedabeeb
> +#define MAGICFREE       0xd8675309
> +#define MAGICBYTE       ((char) 0xd7)
> +#define MALLOCFLOOD     ((char) 0x93)
> +#define FREEFLOOD       ((char) 0x95)
> +
> +/* Function to call when something awful happens.  */
> +static void (*abortfunc) (enum mcheck_status);
> +
> +struct hdr
> +{
> +  size_t size;                  /* Exact size requested by user.  */
> +  unsigned long int magic;      /* Magic number to check header integrity.  */
> +  struct hdr *prev;
> +  struct hdr *next;
> +  void *block;                  /* Real block allocated, for memalign.  */
> +  unsigned long int magic2;     /* Extra, keeps us doubleword aligned.  */
> +};
> +
> +/* This is the beginning of the list of all memory blocks allocated.
> +   It is only constructed if the pedantic testing is requested.  */
> +struct hdr *__mcheck_root;
> +
> +/* Nonzero if pedentic checking of all blocks is requested.  */
> +static bool pedantic;
> +
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
> +/* Flag to initialize mcheck on first malloc invocation through -lmcheck.
> +   libmcheck.a overrides this with a strong symbol initialized to 1.  The
> +   symbol cannot be linked against directly during build.  */
> +const int __libc_lmcheck __attribute__ ((weak));
> +compat_symbol (libc, __libc_lmcheck, __libc_lmcheck, GLIBC_2_34);
> +#endif
> +
> +#if defined _LIBC || defined STDC_HEADERS || defined USG
> +# include <string.h>
> +# define flood memset
> +#else
> +static void flood (void *, int, size_t);
> +static void
> +flood (void *ptr, int val, size_t size)
> +{
> +  char *cp = ptr;
> +  while (size--)
> +    *cp++ = val;
> +}
> +#endif
> +
> +static enum mcheck_status
> +checkhdr (const struct hdr *hdr)
> +{
> +  enum mcheck_status status;
> +  bool mcheck_used = __is_malloc_debug_enabled (MALLOC_MCHECK_HOOK);
> +
> +  if (!mcheck_used)
> +    /* Maybe the mcheck used is disabled?  This happens when we find
> +       an error and report it.  */
> +    return MCHECK_OK;
> +
> +  switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
> +    {
> +    default:
> +      status = MCHECK_HEAD;
> +      break;
> +    case MAGICFREE:
> +      status = MCHECK_FREE;
> +      break;
> +    case MAGICWORD:
> +      if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
> +	status = MCHECK_TAIL;
> +      else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
> +	status = MCHECK_HEAD;
> +      else
> +	status = MCHECK_OK;
> +      break;
> +    }
> +  if (status != MCHECK_OK)
> +    {
> +      mcheck_used = 0;
> +      (*abortfunc) (status);
> +      mcheck_used = 1;
> +    }
> +  return status;
> +}
> +
> +enum mcheck_status
> +__mcheck_checkptr (const void *ptr)
> +{
> +  if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
> +      return MCHECK_DISABLED;
> +
> +  if (ptr != NULL)
> +    return checkhdr (((struct hdr *) ptr) - 1);
> +
> +  /* Walk through all the active blocks and test whether they were tampered
> +     with.  */
> +  struct hdr *runp = __mcheck_root;
> +
> +  /* Temporarily turn off the checks.  */
> +  pedantic = false;
> +
> +  while (runp != NULL)
> +    {
> +      (void) checkhdr (runp);
> +
> +      runp = runp->next;
> +    }
> +
> +  /* Turn checks on again.  */
> +  pedantic = true;
> +
> +  return MCHECK_OK;
> +}
> +
> +static void
> +unlink_blk (struct hdr *ptr)
> +{
> +  if (ptr->next != NULL)
> +    {
> +      ptr->next->prev = ptr->prev;
> +      ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
> +                                      + (uintptr_t) ptr->next->next);
> +    }
> +  if (ptr->prev != NULL)
> +    {
> +      ptr->prev->next = ptr->next;
> +      ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
> +                                      + (uintptr_t) ptr->prev->next);
> +    }
> +  else
> +    __mcheck_root = ptr->next;
> +}
> +
> +static void
> +link_blk (struct hdr *hdr)
> +{
> +  hdr->prev = NULL;
> +  hdr->next = __mcheck_root;
> +  __mcheck_root = hdr;
> +  hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
> +
> +  /* And the next block.  */
> +  if (hdr->next != NULL)
> +    {
> +      hdr->next->prev = hdr;
> +      hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
> +                                      + (uintptr_t) hdr->next->next);
> +    }
> +}
> +
> +static void *
> +free_mcheck (void *ptr)
> +{
> +  if (pedantic)
> +    __mcheck_checkptr (NULL);
> +  if (ptr)
> +    {
> +      struct hdr *hdr = ((struct hdr *) ptr) - 1;
> +      checkhdr (hdr);
> +      hdr->magic = MAGICFREE;
> +      hdr->magic2 = MAGICFREE;
> +      unlink_blk (hdr);
> +      hdr->prev = hdr->next = NULL;
> +      flood (ptr, FREEFLOOD, hdr->size);
> +      ptr = hdr->block;
> +    }
> +  return ptr;
> +}
> +
> +static bool
> +malloc_mcheck_before (size_t *sizep, void **victimp)
> +{
> +  size_t size = *sizep;
> +
> +  if (pedantic)
> +    __mcheck_checkptr (NULL);
> +
> +  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
> +    {
> +      __set_errno (ENOMEM);
> +      *victimp = NULL;
> +      return true;
> +    }
> +
> +  *sizep = sizeof (struct hdr) + size + 1;
> +  return false;
> +}
> +
> +static void *
> +malloc_mcheck_after (void *mem, size_t size)
> +{
> +  struct hdr *hdr = mem;
> +
> +  if (hdr == NULL)
> +    return NULL;
> +
> +  hdr->size = size;
> +  link_blk (hdr);
> +  hdr->block = hdr;
> +  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
> +  ((char *) &hdr[1])[size] = MAGICBYTE;
> +  flood ((void *) (hdr + 1), MALLOCFLOOD, size);
> +  return (void *) (hdr + 1);
> +}
> +
> +static bool
> +memalign_mcheck_before (size_t alignment, size_t *sizep, void **victimp)
> +{
> +  struct hdr *hdr;
> +  size_t slop, size = *sizep;
> +
> +  /* Punt to malloc to avoid double headers.  */
> +  if (alignment <= MALLOC_ALIGNMENT)
> +    {
> +      *victimp = __libc_malloc (size);
> +      return true;
> +    }
> +
> +  if (pedantic)
> +    __mcheck_checkptr (NULL);
> +
> +  slop = (sizeof *hdr + alignment - 1) & - alignment;
> +
> +  if (size > ~((size_t) 0) - (slop + 1))
> +    {
> +      __set_errno (ENOMEM);
> +      *victimp = NULL;
> +      return true;
> +    }
> +
> +  *sizep = slop + size + 1;
> +  return false;
> +}
> +
> +static void *
> +memalign_mcheck_after (void *block, size_t alignment, size_t size)
> +{
> +  if (block == NULL)
> +    return NULL;
> +
> +  /* This was served by __libc_malloc, so return as is.  */
> +  if (alignment <= MALLOC_ALIGNMENT)
> +    return block;
> +
> +  size_t slop = (sizeof (struct hdr) + alignment - 1) & - alignment;
> +  struct hdr *hdr = ((struct hdr *) (block + slop)) - 1;
> +
> +  hdr->size = size;
> +  link_blk (hdr);
> +  hdr->block = (void *) block;
> +  hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
> +  ((char *) &hdr[1])[size] = MAGICBYTE;
> +  flood ((void *) (hdr + 1), MALLOCFLOOD, size);
> +  return (void *) (hdr + 1);
> +}
> +
> +static bool
> +realloc_mcheck_before (void **ptrp, size_t *sizep, size_t *oldsize,
> +		       void **victimp)
> +{
> +  size_t size = *sizep;
> +  void *ptr = *ptrp;
> +
> +  /* Handle special cases to avoid adding multiple headers.  */
> +  if (size == 0)
> +    {
> +      __libc_free (ptr);
> +      *victimp = NULL;
> +      return true;
> +    }
> +
> +  if (ptr == NULL)
> +    {
> +      *victimp = __libc_malloc (size);
> +      *oldsize = 0;
> +      return true;
> +    }
> +
> +  if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
> +    {
> +      __set_errno (ENOMEM);
> +      *victimp = NULL;
> +      *oldsize = 0;
> +      return true;
> +    }
> +
> +  if (pedantic)
> +    __mcheck_checkptr (NULL);
> +
> +  struct hdr *hdr;
> +  size_t osize;
> +
> +  /* Update the oldptr for glibc realloc.  */
> +  *ptrp = hdr = ((struct hdr *) ptr) - 1;
> +
> +  osize = hdr->size;
> +
> +  checkhdr (hdr);
> +  unlink_blk (hdr);
> +  if (size < osize)
> +    flood ((char *) ptr + size, FREEFLOOD, osize - size);
> +
> +  *oldsize = osize;
> +  *sizep = sizeof (struct hdr) + size + 1;
> +  return false;
> +}
> +
> +static void *
> +realloc_mcheck_after (void *ptr, void *oldptr, size_t size, size_t osize)
> +{
> +  struct hdr *hdr = ptr;
> +
> +  if (hdr == NULL)
> +    return NULL;
> +
> +  /* Malloc already added the header so don't tamper with it.  */
> +  if (oldptr == NULL)
> +    return ptr;
> +
> +  hdr->size = size;
> +  link_blk (hdr);
> +  hdr->block = hdr;
> +  hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
> +  ((char *) &hdr[1])[size] = MAGICBYTE;
> +  if (size > osize)
> +    flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
> +  return (void *) (hdr + 1);
> +}
> +
> +__attribute__ ((noreturn))
> +static void
> +mabort (enum mcheck_status status)
> +{
> +  const char *msg;
> +  switch (status)
> +    {
> +    case MCHECK_OK:
> +      msg = _ ("memory is consistent, library is buggy\n");
> +      break;
> +    case MCHECK_HEAD:
> +      msg = _ ("memory clobbered before allocated block\n");
> +      break;
> +    case MCHECK_TAIL:
> +      msg = _ ("memory clobbered past end of allocated block\n");
> +      break;
> +    case MCHECK_FREE:
> +      msg = _ ("block freed twice\n");
> +      break;
> +    default:
> +      msg = _ ("bogus mcheck_status, library is buggy\n");
> +      break;
> +    }
> +#ifdef _LIBC
> +  __libc_fatal (msg);
> +#else
> +  fprintf (stderr, "mcheck: %s", msg);
> +  fflush (stderr);
> +  abort ();
> +#endif
> +}
> +
> +int
> +__mcheck_initialize (void (*func) (enum mcheck_status), bool in_pedantic)
> +{
> +  abortfunc = (func != NULL) ? func : &mabort;
> +
> +  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
> +    goto out;
> +
> +  switch (__malloc_initialized)
> +    {
> +    case -1:
> +      ptmalloc_init ();
> +      /* FALLTHROUGH */
> +    case 0:
> +      __malloc_debug_enable (MALLOC_MCHECK_HOOK);
> +      break;
> +    default:
> +      break;
> +    }
> +
> +  if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
> +    return -1;
> +
> +out:
> +  pedantic = in_pedantic;
> +  return 0;
> +}
> diff --git a/malloc/mcheck-init.c b/malloc/mcheck-init.c
> index 9ee69ee5f8..e3d08ae05f 100644
> --- a/malloc/mcheck-init.c
> +++ b/malloc/mcheck-init.c
> @@ -17,17 +17,7 @@
>  
>  /* The object of this file should be installed as libmcheck.a,
>     so one can do -lmcheck to turn on mcheck.  */
> -
> -#include <malloc.h>
> -#include <mcheck.h>
>  #include <shlib-compat.h>
>  
> -static void
> -turn_on_mcheck (void)
> -{
> -  mcheck (NULL);
> -}
> -
> -void (*__malloc_initialize_hook) (void) = turn_on_mcheck;
> -compat_symbol_reference (libc, __malloc_initialize_hook,
> -                         __malloc_initialize_hook, GLIBC_2_0);
> +const int __libc_lmcheck = 1;
> +compat_symbol_reference (libc, __libc_lmcheck, __libc_lmcheck, GLIBC_2_34);
> diff --git a/malloc/mcheck.c b/malloc/mcheck.c
> index 2a1fc645d4..f60766eded 100644
> --- a/malloc/mcheck.c
> +++ b/malloc/mcheck.c
> @@ -1,4 +1,4 @@
> -/* Standard debugging hooks for `malloc'.
> +/* The mcheck() interface.
>     Copyright (C) 1990-2021 Free Software Foundation, Inc.
>     This file is part of the GNU C Library.
>     Written May 1989 by Mike Haertel.
> @@ -23,378 +23,22 @@
>  # include <mcheck.h>
>  # include <stdint.h>
>  # include <stdio.h>
> -# include <libintl.h>
>  # 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;
> +  __mcheck_checkptr (NULL);
>  }
>  #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 __mcheck_initialize (func, false);
>  }
>  #ifdef _LIBC
>  libc_hidden_def (mcheck)
> @@ -403,14 +47,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 __mcheck_initialize (func, true);
>  }
>  
>  enum mcheck_status
>  mprobe (void *ptr)
>  {
> -  return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
> +  return __mcheck_checkptr (ptr);
>  }
> diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
> index fcfe64f26b..27e8f14bb5 100644
> --- a/sysdeps/mach/hurd/i386/libc.abilist
> +++ b/sysdeps/mach/hurd/i386/libc.abilist
> @@ -2223,6 +2223,7 @@ GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
>  GLIBC_2.34 __isnanf128 F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 _hurd_libc_proc_init F
>  GLIBC_2.34 dladdr F
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 6730cbdd6b..5c24c5e77f 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2380,6 +2380,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 63de4fadc3..bf75524649 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -2479,6 +2479,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index 2f13701fd7..3bf0c17629 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2139,6 +2139,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index 9b824f1605..59b64ceebc 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -222,6 +222,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index 443a81b8f7..406108f9ea 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -219,6 +219,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 243de3cf93..af5c560d27 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2354,6 +2354,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 24ae58bb6f..920a9c0bc0 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2307,6 +2307,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 09bebcd5a1..3eea983bd0 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -2491,6 +2491,7 @@ GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
>  GLIBC_2.34 __isnanf128 F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> index 0bafe09253..1a776e945f 100644
> --- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
> @@ -2317,6 +2317,7 @@ GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
>  GLIBC_2.34 __isnanf128 F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index c1fcde4c24..8a7244731d 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -223,6 +223,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 407651cfd7..c4724c9565 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2434,6 +2434,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 7da722a734..ef637690d2 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2405,6 +2405,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index c374607b81..9fde5778c4 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2402,6 +2402,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index b1f426e053..a9ba4ef442 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2399,6 +2399,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 066ceb2258..9c0ea27436 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2397,6 +2397,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 51c563ebbe..46f8d03699 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2405,6 +2405,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 28db715d8a..2ae9770ec6 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2368,6 +2368,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> index ab9f2bd42c..6c4c684a93 100644
> --- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
> @@ -2444,6 +2444,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index 83f8513e17..cbb02febac 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -2461,6 +2461,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index 0fad357bf6..8426990a9b 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -2494,6 +2494,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 424ec8d953..977feb5695 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2281,6 +2281,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 9909fd0e9a..00b74fe710 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2576,6 +2576,7 @@ GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
>  GLIBC_2.34 __isnanf128 F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index 7085989b16..eac837a1ce 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2141,6 +2141,7 @@ GLIBC_2.33 write F
>  GLIBC_2.33 writev F
>  GLIBC_2.33 wscanf F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index a855997957..73bf738b97 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2341,6 +2341,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 12aeb82520..167a715820 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -2459,6 +2459,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index e2d746ad5f..cd22ad1a97 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2318,6 +2318,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index 1ce4b54bf2..b2d5d40e1f 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2314,6 +2314,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index 7d01add713..18f402719b 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2311,6 +2311,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index b5ef3247d7..a71416c70d 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -2454,6 +2454,7 @@ GLIBC_2.34 __glob64_time64 F
>  GLIBC_2.34 __globfree64_time64 F
>  GLIBC_2.34 __gmtime64 F
>  GLIBC_2.34 __gmtime64_r F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __localtime64 F
>  GLIBC_2.34 __localtime64_r F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index 14ae7c8417..254a6746a2 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2340,6 +2340,7 @@ GLIBC_2.33 mknodat F
>  GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 57c4f28d17..c0e6463916 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2296,6 +2296,7 @@ GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
>  GLIBC_2.34 __isnanf128 F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 47211abe4e..b1512a6339 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2395,6 +2395,7 @@ GLIBC_2.33 stat F
>  GLIBC_2.33 stat64 F
>  GLIBC_2.34 _Fork F
>  GLIBC_2.34 __isnanf128 F
> +GLIBC_2.34 __libc_lmcheck D 0x4
>  GLIBC_2.34 __libc_start_main F
>  GLIBC_2.34 __mq_open_2 F
>  GLIBC_2.34 __pthread_cleanup_routine F
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 06/10] mcheck: Wean away from malloc hooks
  2021-07-02 18:34   ` Carlos O'Donell
@ 2021-07-02 18:46     ` Siddhesh Poyarekar
  0 siblings, 0 replies; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 18:46 UTC (permalink / raw)
  To: Carlos O'Donell, libc-alpha; +Cc: dj, fweimer

On 7/3/21 12:04 AM, Carlos O'Donell wrote:
> I do not like the addition of a new ABI for an interface whose functionality
> is worse than valgrind which we have today, and will likely be removed
> in the future.
> 
> We have put __libc_lmcheck into libmcheck.a, which is statically linked
> into the application or a DSO, and so this creates an odd design where
> the application, a DSO, and libc can all have the __libc_lmcheck variable.
> This is not a good way forward for the -lmcheck support since this makes
> the linkage slightly dependent on the executable, the DSOs etc.
> 
> I would rather you deprecate all the APIs and have the implemetnations do
> nothing.
> 
> I don't think any of these functions are actually useful today.

So I realized I'm defending mcheck way too strongly when all the while 
I've been thinking of malloc-check as the tool that has helped me find 
memory issues due to data races in the past.  Valgrind and asan/msan 
have way too much overhead and tend to not reproduce such data races 
that easily.

So I'm fine with diluting mcheck.

> Someone can provide an interposer malloc with all of this functionality,
> and we can to, at some point in the future, and not be bound by compatibility
> requirements (other than the malloc API requirements).

OK, so I can deprecate -lmcheck since that's really the only thing this 
new ABI supports.  However it will eliminate all the mcheck tests I just 
added since they depend on -lmcheck.  Would that be acceptable?

I'll push 1/5 since they can function independently.

Siddhesh

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 08/10] Remove malloc hooks
  2021-07-02 11:38 ` [PATCH v4 08/10] Remove " Siddhesh Poyarekar
@ 2021-07-02 18:48   ` Carlos O'Donell
  2021-07-02 19:06     ` Siddhesh Poyarekar
  0 siblings, 1 reply; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 18:48 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Make malloc hooks symbols compat-only so that new applications cannot
> link against them and remove the declarations from the API.  The
> existing hooks variables are not used in the library anymore.

I *really* like the strategy of your approach calling __libc_malloc
et. al. to avoid the dlopen problem and declare we only support glibc
malloc. I think this patch is a winner, and you could move mtrace
into this DSO, and rename it.
 
> Legacy applications that need hooks functionality need to preload a
> new DSO libmalloc_compathooks.so, which interposes the libc malloc
> functions to execute hooks if they exist.

... and you could implement mtrace this way too without the ABI change.

> Also remove all references to the malloc hooks in the manual.  Mention
> the removal in NEWS and also warn that libmalloc_compathooks.so is a
> temporary measure and may be removed in a future version of glibc.
> 
> memalign makes a comeback as a PLT reference since the initialization
> hooks use them.  tst-mallocstate now needs libmalloc_compathooks.so
> since it uses __malloc_initialize_hook to set up initial heap state to
> emumate emacs.

This patch is broken, there are two tests which it references which
don't exist.
 
> Reviewed-by: DJ Delorie <dj@redhat.com>
> ---
>  Makeconfig                                    |   2 +-
>  NEWS                                          |   9 +
>  malloc/Makefile                               |  15 +-
>  malloc/arena.c                                |   5 -
>  malloc/hooks.c                                | 114 ++++++-----
>  malloc/malloc-compathooks.c                   | 166 +++++++++++++++
>  malloc/malloc.c                               |  10 -
>  malloc/malloc.h                               |  14 --
>  manual/memory.texi                            | 191 +-----------------
>  sysdeps/generic/localplt.data                 |   1 +
>  sysdeps/mach/hurd/i386/localplt.data          |   1 +
>  sysdeps/unix/sysv/linux/aarch64/localplt.data |   1 +
>  sysdeps/unix/sysv/linux/alpha/localplt.data   |   1 +
>  sysdeps/unix/sysv/linux/arc/localplt.data     |   1 +
>  sysdeps/unix/sysv/linux/arm/localplt.data     |   1 +
>  sysdeps/unix/sysv/linux/csky/localplt.data    |   1 +
>  sysdeps/unix/sysv/linux/hppa/localplt.data    |   1 +
>  sysdeps/unix/sysv/linux/i386/localplt.data    |   1 +
>  sysdeps/unix/sysv/linux/ia64/localplt.data    |   1 +
>  .../sysv/linux/m68k/coldfire/localplt.data    |   1 +
>  .../unix/sysv/linux/m68k/m680x0/localplt.data |   1 +
>  .../unix/sysv/linux/microblaze/localplt.data  |   1 +
>  sysdeps/unix/sysv/linux/nios2/localplt.data   |   1 +
>  .../linux/powerpc/powerpc32/fpu/localplt.data |   1 +
>  .../powerpc/powerpc32/nofpu/localplt.data     |   1 +
>  .../linux/powerpc/powerpc64/localplt.data     |   1 +
>  sysdeps/unix/sysv/linux/riscv/localplt.data   |   1 +
>  sysdeps/unix/sysv/linux/s390/localplt.data    |   1 +
>  sysdeps/unix/sysv/linux/sh/localplt.data      |   1 +
>  .../sysv/linux/sparc/sparc32/localplt.data    |   1 +
>  .../sysv/linux/sparc/sparc64/localplt.data    |   1 +
>  sysdeps/x86_64/localplt.data                  |   1 +
>  32 files changed, 284 insertions(+), 265 deletions(-)
>  create mode 100644 malloc/malloc-compathooks.c
> 
> diff --git a/Makeconfig b/Makeconfig
> index efc7351d71..4a88cba647 100644
> --- a/Makeconfig
> +++ b/Makeconfig
> @@ -951,7 +951,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_compathooks

The hooks are a debug feature of this interposable debug malloc.

I think we should identify the library and the purpose e.g.

libc_malloc_debug.so

*cough* libtcmalloc_debug.so.4.5.6 *cough*

>  
>  in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \
>  				    $(libof-$(<F)) \
> diff --git a/NEWS b/NEWS
> index 8e72946c3f..cebe8384bf 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -97,6 +97,15 @@ Deprecated and removed features, and other changes affecting compatibility:
>    mtrace.  Similar functionality can be achieved by using conditional
>    breakpoints within mtrace functions from within gdb.
>  
> +* The deprecated memory allocation hooks __malloc_hook, __realloc_hook,
> +  __memalign_hook and __free_hook are now removed from the API.  Compatibility
> +  symbols are present to support legacy programs but new applications can no
> +  longer link to these symbols.  Further, the hooks no longer have any effect
> +  on glibc functionality.  A compatibility DSO libmalloc_compathooks.so has
> +  been provided as a transitional measure to get hook functionality back for
> +  legacy programs until they are updated to remove references to the memory
> +  allocation hooks.
> +
>  Changes to build and runtime requirements:
>  
>  * On Linux, the shm_open, sem_open, and related functions now expect the
> diff --git a/malloc/Makefile b/malloc/Makefile
> index 328e0be1fd..50d6ad7b77 100644
> --- a/malloc/Makefile
> +++ b/malloc/Makefile
> @@ -42,6 +42,7 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
>  	 tst-malloc-stats-cancellation \
>  	 tst-tcfree1 tst-tcfree2 tst-tcfree3 \
>  	 tst-safe-linking \
> +	 tst-compathooks-off tst-compathooks-on

This is not correct because there is no implementation of these tests?

>  
>  tests-static := \
>  	 tst-interpose-static-nothread \
> @@ -113,8 +114,8 @@ routines = malloc morecore mcheck mtrace obstack reallocarray \
>  install-lib := libmcheck.a
>  non-lib.a := libmcheck.a
>  
> -# Additional library.
> -extra-libs = libmemusage
> +# Additional libraries.
> +extra-libs = libmemusage libmalloc_compathooks
>  extra-libs-others = $(extra-libs)
>  
>  # Helper objects for some tests.
> @@ -129,6 +130,9 @@ test-extras = \
>  libmemusage-routines = memusage
>  libmemusage-inhibit-o = $(filter-out .os,$(object-suffixes))
>  
> +libmalloc_compathooks-routines = malloc-compathooks
> +libmalloc_compathooks-inhibit-o = $(filter-out .os,$(object-suffixes))
> +
>  $(objpfx)tst-malloc-backtrace: $(shared-thread-library)
>  $(objpfx)tst-malloc-thread-exit: $(shared-thread-library)
>  $(objpfx)tst-malloc-thread-fail: $(shared-thread-library)
> @@ -312,3 +316,10 @@ $(objpfx)tst-mallocfork2-mcheck: $(shared-thread-library)
>  $(objpfx)tst-malloc-tcache-leak-malloc-check: $(shared-thread-library)
>  $(objpfx)tst-malloc_info-malloc-check: $(shared-thread-library)
>  $(objpfx)tst-mallocfork2-malloc-check: $(shared-thread-library)
> +
> +tst-compathooks-on-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
> +tst-compathooks-on-mcheck-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
> +tst-compathooks-on-malloc-check-ENV = \
> +	LD_PRELOAD=$(objpfx)libmalloc_compathooks.so> +tst-mallocstate-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
> +tst-mallocstate-malloc-check-ENV = LD_PRELOAD=$(objpfx)libmalloc_compathooks.so
> diff --git a/malloc/arena.c b/malloc/arena.c
> index a8500a25c9..8591c8ea56 100644
> --- a/malloc/arena.c
> +++ b/malloc/arena.c
> @@ -408,11 +408,6 @@ ptmalloc_init (void)
>      __mcheck_initialize (NULL, false);
>  #endif
>  
> -#if HAVE_MALLOC_INIT_HOOK
> -  void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
> -  if (hook != NULL)
> -    (*hook)();
> -#endif
>    __malloc_initialized = 1;
>  }
>  
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 7f3b07ca44..397220aaba 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -42,23 +42,84 @@ enum malloc_debug_hooks
>  static unsigned __malloc_debugging_hooks;
>  
>  /* Forward declarations.  */
> +static void ptmalloc_init (void);
>  
> -#if HAVE_MALLOC_INIT_HOOK
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_24)
>  void (*__malloc_initialize_hook) (void) __attribute__ ((nocommon));
>  compat_symbol (libc, __malloc_initialize_hook,
>  	       __malloc_initialize_hook, GLIBC_2_0);
> +
> +# define MALLOC_INIT_HOOK() ({ \
> +  void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);	      \
> +  if (hook != NULL)							      \
> +    (*hook)();								      \
> +})
> +#else
> +# define MALLOC_INIT_HOOK()
>  #endif
>  
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
> +
> +static void *malloc_hook_ini (size_t, const void *) __THROW;
> +static void *realloc_hook_ini (void *, size_t, const void *) __THROW;
> +static void *memalign_hook_ini (size_t, size_t, const void *) __THROW;
> +
>  void weak_variable (*__free_hook) (void *__ptr,
>                                     const void *) = NULL;
>  void *weak_variable (*__malloc_hook)
> -  (size_t __size, const void *) = NULL;
> +  (size_t __size, const void *) = malloc_hook_ini;
>  void *weak_variable (*__realloc_hook)
> -  (void *__ptr, size_t __size, const void *) = NULL;
> +  (void *__ptr, size_t __size, const void *) = realloc_hook_ini;
>  void *weak_variable (*__memalign_hook)
> -  (size_t __alignment, size_t __size, const void *) = NULL;
> +  (size_t __alignment, size_t __size, const void *) = memalign_hook_ini;
>  
> -static void ptmalloc_init (void);
> +compat_symbol (libc, __free_hook, __free_hook, GLIBC_2_0);
> +compat_symbol (libc, __malloc_hook, __malloc_hook, GLIBC_2_0);
> +compat_symbol (libc, __realloc_hook, __realloc_hook, GLIBC_2_0);
> +compat_symbol (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
> +
> +/* These hooks will get executed only through the interposed allocator
> +   functions in libmalloc_compathooks.  This means that the calls to malloc,
> +   realloc, etc. will lead back into the interposed functions, which is what we
> +   want.
> +
> +   These initial hooks are assumed to be called in a single-threaded context,
> +   so it is safe to reset all hooks at once upon initialization.  */
> +
> +static void
> +generic_hook_ini (void)
> +{
> +  __malloc_hook = NULL;
> +  __realloc_hook = NULL;
> +  __memalign_hook = NULL;
> +  if (__malloc_initialized < 0)
> +    {
> +      ptmalloc_init ();
> +      MALLOC_INIT_HOOK ();
> +    }
> +}
> +
> +static void *
> +malloc_hook_ini (size_t sz, const void *caller)
> +{
> +  generic_hook_ini ();
> +  return malloc (sz);
> +}
> +
> +static void *
> +realloc_hook_ini (void *ptr, size_t sz, const void *caller)
> +{
> +  generic_hook_ini ();
> +  return realloc (ptr, sz);
> +}
> +
> +static void *
> +memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
> +{
> +  generic_hook_ini ();
> +  return memalign (alignment, sz);
> +}
> +#endif
>  
>  static __always_inline bool
>  __is_malloc_debug_enabled (enum malloc_debug_hooks flag)
> @@ -88,14 +149,6 @@ _malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
>    _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
>  		  "PTRDIFF_MAX is not more than half of SIZE_MAX");
>  
> -  void *(*hook) (size_t, const void *)
> -    = atomic_forced_read (__malloc_hook);
> -  if (__builtin_expect (hook != NULL, 0))
> -    {
> -      *victimp = (*hook)(*bytesp, address);
> -      return true;
> -    }
> -
>    if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
>        if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
> @@ -126,14 +179,6 @@ _malloc_debug_after (void *mem, size_t bytes, const void *address)
>  static __always_inline bool
>  _free_debug_before (void **mem, const void *address)
>  {
> -  void (*hook) (void *, const void *)
> -    = atomic_forced_read (__free_hook);
> -  if (__builtin_expect (hook != NULL, 0))
> -    {
> -      (*hook)(*mem, address);
> -      return true;
> -    }
> -
>    if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
>        if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
> @@ -153,14 +198,6 @@ static __always_inline bool
>  _realloc_debug_before (void **oldmem, size_t *bytesp, size_t *oldsize,
>  		       void **victimp, const void *address)
>  {
> -  void *(*hook) (void *, size_t, const void *) =
> -    atomic_forced_read (__realloc_hook);
> -  if (__builtin_expect (hook != NULL, 0))
> -    {
> -      *victimp = (*hook)(*oldmem, *bytesp, address);
> -      return true;
> -    }
> -
>    if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
>        if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
> @@ -194,13 +231,6 @@ static __always_inline bool
>  _memalign_debug_before (size_t alignment, size_t *bytesp, void **victimp,
>  			const void *address)
>  {
> -  void *(*hook) (size_t, size_t, const void *) =
> -    atomic_forced_read (__memalign_hook);
> -  if (__builtin_expect (hook != NULL, 0))
> -    {
> -      *victimp = (*hook)(alignment, *bytesp, address);
> -      return true;
> -    }
>    if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
>        if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
> @@ -233,18 +263,6 @@ _memalign_debug_after (void *mem, size_t alignment, size_t bytes,
>  static __always_inline bool
>  _calloc_debug_before (size_t *bytesp, void **victimp, const void *address)
>  {
> -  void *(*hook) (size_t, const void *) =
> -    atomic_forced_read (__malloc_hook);
> -  if (__builtin_expect (hook != NULL, 0))
> -    {
> -      *victimp = (*hook)(*bytesp, address);
> -
> -      if (*victimp != NULL)
> -	memset (*victimp, 0, *bytesp);
> -
> -      return true;
> -    }
> -
>    /* Memory is zeroed out in the AFTER hook.  */
>    if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
> diff --git a/malloc/malloc-compathooks.c b/malloc/malloc-compathooks.c
> new file mode 100644
> index 0000000000..6d1eaab774
> --- /dev/null
> +++ b/malloc/malloc-compathooks.c
> @@ -0,0 +1,166 @@
> +/* Malloc hooks compatibility DSO.
> +   Copyright (C) 2021 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; see the file COPYING.LIB.  If
> +   not, see <https://www.gnu.org/licenses/>.  */
> +
> +#include <atomic.h>
> +#include <libc-symbols.h>
> +#include <shlib-compat.h>
> +#include <string.h>
> +#include <unistd.h>
> +
> +extern void (*__free_hook) (void *__ptr, const void *);
> +compat_symbol_reference (libc, __free_hook, __free_hook, GLIBC_2_0);
> +extern void * (*__malloc_hook) (size_t __size, const void *);
> +compat_symbol_reference (libc, __malloc_hook, __malloc_hook, GLIBC_2_0);
> +extern void * (*__realloc_hook)
> +     (void *__ptr, size_t __size, const void *);
> +compat_symbol_reference (libc, __realloc_hook, __realloc_hook, GLIBC_2_0);
> +extern void * (*__memalign_hook)
> +  (size_t __alignment, size_t __size, const void *);
> +compat_symbol_reference (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
> +
> +/* Support only the glibc allocators.  */
> +extern void *__libc_malloc (size_t);
> +extern void __libc_free (void *);
> +extern void *__libc_realloc (void *, size_t);
> +extern void *__libc_memalign (size_t, size_t);
> +extern void *__libc_valloc (size_t);
> +extern void *__libc_pvalloc (size_t);
> +extern void *__libc_calloc (size_t, size_t);

Interesting approach, so no dlopen, just a call directly to the library name
function and fail otherwise. I like that!

> +
> +static size_t pagesize;
> +
> +/* The allocator functions.  */
> +
> +static void *
> +__compathook_malloc (size_t bytes)
> +{
> +  void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    return (*hook)(bytes, RETURN_ADDRESS (0));
> +
> +  return __libc_malloc (bytes);
> +}
> +strong_alias (__compathook_malloc, malloc)
> +
> +static void
> +__compathook_free (void *mem)
> +{
> +  void (*hook) (void *, const void *) = atomic_forced_read (__free_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      (*hook)(mem, RETURN_ADDRESS (0));
> +      return;
> +    }
> +  __libc_free (mem);
> +}
> +strong_alias (__compathook_free, free)
> +
> +static void *
> +__compathook_realloc (void *oldmem, size_t bytes)
> +{
> +  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));
> +
> +  return __libc_realloc (oldmem, bytes);
> +}
> +strong_alias (__compathook_realloc, realloc)
> +
> +static void *
> +__compathook_memalign (size_t alignment, size_t bytes)
> +{
> +  void *(*hook) (size_t, size_t, const void *) =
> +    atomic_forced_read (__memalign_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    return (*hook)(alignment, bytes, RETURN_ADDRESS (0));
> +
> +  return __libc_memalign (alignment, bytes);
> +}
> +strong_alias (__compathook_memalign, memalign)
> +
> +static void *
> +__compathook_pvalloc (size_t bytes)
> +{
> +  void *(*hook) (size_t, size_t, const void *) =
> +    atomic_forced_read (__memalign_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      size_t rounded_bytes;
> +
> +      if (!pagesize)
> +	pagesize = sysconf (_SC_PAGESIZE);
> +
> +      /* ALIGN_UP with overflow check.  */
> +      if (__glibc_unlikely (__builtin_add_overflow (bytes,
> +						    pagesize - 1,
> +						    &rounded_bytes)))
> +	{
> +	  errno = ENOMEM;
> +	  return NULL;
> +	}
> +      rounded_bytes = rounded_bytes & -(pagesize - 1);
> +      return (*hook)(pagesize, rounded_bytes, RETURN_ADDRESS (0));
> +    }
> +
> +  return __libc_pvalloc (bytes);
> +}
> +strong_alias (__compathook_pvalloc, pvalloc)
> +
> +static void *
> +__compathook_valloc (size_t bytes)
> +{
> +  void *(*hook) (size_t, size_t, const void *) =
> +    atomic_forced_read (__memalign_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      if (!pagesize)
> +	pagesize = sysconf (_SC_PAGESIZE);
> +
> +      return (*hook)(pagesize, bytes, RETURN_ADDRESS (0));
> +    }
> +
> +  return __libc_valloc (bytes);
> +}
> +strong_alias (__compathook_valloc, valloc)
> +
> +static void *
> +__compathook_calloc (size_t nmemb, size_t size)
> +{
> +  void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      size_t bytes;
> +
> +      if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes)))
> +	{
> +	  errno = ENOMEM;
> +	  return NULL;
> +	}
> +
> +      void *mem = (*hook)(bytes, RETURN_ADDRESS (0));
> +
> +      if (mem != NULL)
> +	memset (mem, 0, bytes);
> +
> +      return mem;
> +    }
> +
> +  return __libc_calloc (nmemb, size);
> +}
> +strong_alias (__compathook_calloc, calloc)
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index c899619e50..f6d7309721 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -570,16 +570,6 @@ tag_at (void *ptr)
>  #define HAVE_MREMAP 0
>  #endif
>  
> -/* We may need to support __malloc_initialize_hook for backwards
> -   compatibility.  */
> -
> -#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_24)
> -# define HAVE_MALLOC_INIT_HOOK 1
> -#else
> -# define HAVE_MALLOC_INIT_HOOK 0
> -#endif
> -
> -
>  /*
>    This version of malloc supports the standard SVID/XPG mallinfo
>    routine that returns a struct containing usage properties and
> diff --git a/malloc/malloc.h b/malloc/malloc.h
> index c1c0896d29..709fa454b5 100644
> --- a/malloc/malloc.h
> +++ b/malloc/malloc.h
> @@ -165,20 +165,6 @@ extern void malloc_stats (void) __THROW;
>  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)
>    __MALLOC_DEPRECATED;
>  
> diff --git a/manual/memory.texi b/manual/memory.texi
> index 28ec2e4e63..e66ecd582d 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.
> @@ -1388,170 +1386,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 hook functions
> -can be safely installed.  If the hook functions call the @code{malloc}-related
> -functions recursively, it is necessary that @code{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 @code{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 @code{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.
>  
> @@ -1686,19 +1520,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 mallinfo2 mallinfo2 (void)
>  Return information about the current dynamic memory usage.
>  @xref{Statistics of Malloc}.
> @@ -1733,7 +1554,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.
> @@ -1758,10 +1579,10 @@ with the SUID or SGID bit set.
>  
>  If the named file is successfully opened, @code{mtrace} installs special
>  handlers for the functions @code{malloc}, @code{realloc}, and
> -@code{free} (@pxref{Hooks for Malloc}).  From then on, all uses of these
> -functions are traced and protocolled into the file.  There is now of
> -course a speed penalty for all calls to the traced functions so tracing
> -should not be enabled during normal use.
> +@code{free}.  From then on, all uses of these functions are traced and
> +protocolled into the file.  There is now of course a speed penalty for all
> +calls to the traced functions so tracing should not be enabled during normal
> +use.
>  
>  This function is a GNU extension and generally not available on other
>  systems.  The prototype can be found in @file{mcheck.h}.
> @@ -1769,7 +1590,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/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data
> index 9b4f35786a..e2083c0ce6 100644
> --- a/sysdeps/generic/localplt.data
> +++ b/sysdeps/generic/localplt.data
> @@ -4,6 +4,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data
> index 47fbe1e2a7..94064ecbc5 100644
> --- a/sysdeps/mach/hurd/i386/localplt.data
> +++ b/sysdeps/mach/hurd/i386/localplt.data
> @@ -6,6 +6,7 @@
>  libc.so: calloc + REL R_386_GLOB_DAT
>  libc.so: free + REL R_386_GLOB_DAT
>  libc.so: malloc + REL R_386_GLOB_DAT
> +libc.so: memalign + REL R_386_GLOB_DAT
>  libc.so: realloc + REL R_386_GLOB_DAT
>  libm.so: matherr + REL R_386_GLOB_DAT
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data
> index 348b3f3793..2c14b652ef 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data
> @@ -4,6 +4,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # If outline atomics are used, libgcc (built outside of glibc) may
> diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
> index 44bf36f4f1..43f6fdaea1 100644
> --- a/sysdeps/unix/sysv/linux/alpha/localplt.data
> +++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
> @@ -18,6 +18,7 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc + RELA R_ALPHA_GLOB_DAT
>  libc.so: free + RELA R_ALPHA_GLOB_DAT
>  libc.so: malloc + RELA R_ALPHA_GLOB_DAT
> +libc.so: memalign + RELA R_ALPHA_GLOB_DAT
>  libc.so: realloc + RELA R_ALPHA_GLOB_DAT
>  libm.so: matherr + RELA R_ALPHA_GLOB_DAT
>  # We used to offer inline functions that used this, so it must be exported.
> diff --git a/sysdeps/unix/sysv/linux/arc/localplt.data b/sysdeps/unix/sysv/linux/arc/localplt.data
> index ac5332caf7..4479e8ee8a 100644
> --- a/sysdeps/unix/sysv/linux/arc/localplt.data
> +++ b/sysdeps/unix/sysv/linux/arc/localplt.data
> @@ -1,5 +1,6 @@
>  libc.so: realloc
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: calloc
>  libc.so: free
>  # At -Os, a struct assignment in libgcc-static pulls this in
> diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data
> index 78896444c6..eb315da2f1 100644
> --- a/sysdeps/unix/sysv/linux/arm/localplt.data
> +++ b/sysdeps/unix/sysv/linux/arm/localplt.data
> @@ -1,6 +1,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: raise
>  libc.so: realloc
>  libm.so: matherr
> diff --git a/sysdeps/unix/sysv/linux/csky/localplt.data b/sysdeps/unix/sysv/linux/csky/localplt.data
> index 817ab2659a..0ed8650b65 100644
> --- a/sysdeps/unix/sysv/linux/csky/localplt.data
> +++ b/sysdeps/unix/sysv/linux/csky/localplt.data
> @@ -4,6 +4,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  # The TLS-enabled version of these functions is interposed from libc.so.
>  ld.so: _dl_signal_error
> diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data
> index baf857a750..09893d4dcf 100644
> --- a/sysdeps/unix/sysv/linux/hppa/localplt.data
> +++ b/sysdeps/unix/sysv/linux/hppa/localplt.data
> @@ -4,6 +4,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libc.so: __sigsetjmp
>  libc.so: _IO_funlockfile
> diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
> index f9bf7fb410..5334875b4b 100644
> --- a/sysdeps/unix/sysv/linux/i386/localplt.data
> +++ b/sysdeps/unix/sysv/linux/i386/localplt.data
> @@ -4,6 +4,7 @@ libc.so: _Unwind_Find_FDE + REL R_386_GLOB_DAT
>  libc.so: calloc + REL R_386_GLOB_DAT
>  libc.so: free + REL R_386_GLOB_DAT
>  libc.so: malloc + REL R_386_GLOB_DAT
> +libc.so: memalign + REL R_386_GLOB_DAT
>  libc.so: realloc + REL R_386_GLOB_DAT
>  libm.so: matherr + REL R_386_GLOB_DAT
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data
> index 174fb88128..1c566a503e 100644
> --- a/sysdeps/unix/sysv/linux/ia64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/ia64/localplt.data
> @@ -1,6 +1,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  libm.so: matherrf
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
> index 42fa90508c..3c5efb7204 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
> @@ -2,6 +2,7 @@ libc.so: __m68k_read_tp
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
> index 34bd4c1aca..843f4e25f2 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
> @@ -3,6 +3,7 @@ libc.so: __m68k_read_tp
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data
> index c3801314c9..0e98d5251e 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/localplt.data
> +++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data
> @@ -2,6 +2,7 @@ libc.so: __errno_location
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The dynamic loader needs __tls_get_addr for TLS.
> diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data
> index 17fcfdd4db..b37987c7c0 100644
> --- a/sysdeps/unix/sysv/linux/nios2/localplt.data
> +++ b/sysdeps/unix/sysv/linux/nios2/localplt.data
> @@ -6,6 +6,7 @@ libc.so: __gedf2
>  libc.so: malloc
>  libc.so: __gtsf2 ?
>  libc.so: __nesf2
> +libc.so: memalign
>  libc.so: __mulsf3
>  libc.so: __floatunsisf
>  libc.so: __addsf3
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
> index c0af84eef7..a02dd5cc24 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
> @@ -2,6 +2,7 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
> index 581e54b95c..d8072597b7 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
> @@ -30,6 +30,7 @@ libc.so: abort ?
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: memset ?
>  libc.so: realloc
>  libm.so: copysignl ?
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
> index d69b7ae646..bb498fbe3a 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
> @@ -1,6 +1,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data
> index e6d5330d5b..0a235592c3 100644
> --- a/sysdeps/unix/sysv/linux/riscv/localplt.data
> +++ b/sysdeps/unix/sysv/linux/riscv/localplt.data
> @@ -4,6 +4,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: memset ?
>  libc.so: realloc
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data
> index c0af84eef7..a02dd5cc24 100644
> --- a/sysdeps/unix/sysv/linux/s390/localplt.data
> +++ b/sysdeps/unix/sysv/linux/s390/localplt.data
> @@ -2,6 +2,7 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data
> index 6491b9e37b..3225177c50 100644
> --- a/sysdeps/unix/sysv/linux/sh/localplt.data
> +++ b/sysdeps/unix/sysv/linux/sh/localplt.data
> @@ -4,6 +4,7 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libc.so: _Unwind_Find_FDE
>  libc.so: _exit
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
> index 38309a1393..be51efd566 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
> @@ -16,6 +16,7 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
> index 6a216f3a5a..809062d46c 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
> @@ -15,6 +15,7 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> +libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
> index d1f2e26612..8f41e92870 100644
> --- a/sysdeps/x86_64/localplt.data
> +++ b/sysdeps/x86_64/localplt.data
> @@ -6,6 +6,7 @@
>  libc.so: calloc + RELA R_X86_64_GLOB_DAT
>  libc.so: free + RELA R_X86_64_GLOB_DAT
>  libc.so: malloc + RELA R_X86_64_GLOB_DAT
> +libc.so: memalign + RELA R_X86_64_GLOB_DAT
>  libc.so: realloc + RELA R_X86_64_GLOB_DAT
>  libm.so: matherr + RELA R_X86_64_GLOB_DAT
>  # The TLS-enabled version of these functions is interposed from libc.so.
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 00/10] Remove malloc hooks
  2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
                   ` (9 preceding siblings ...)
  2021-07-02 11:38 ` [PATCH v4 10/10] Remove __morecore and __default_morecore Siddhesh Poyarekar
@ 2021-07-02 19:05 ` Carlos O'Donell
  2021-07-02 19:15   ` Siddhesh Poyarekar
  10 siblings, 1 reply; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:05 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> This patchset removes the malloc hooks __malloc_hook, __free_hook,
> __realloc_hook and __memalign_hook from the API and leaves compatibility
> symbols so that existing applications can continue to link to them.  The
> reading and execution of the hooks has been moved to a DSO
> libmalloc_compathooks.so, which can be preloaded for applications that
> need it.  By default these hooks no longer have any effect in the
> library.

OK. Good.
 
> Further, the __morecore, __morecore_after_hook and __default_morecore
> hooks have also been moved to compat symbols and removed from the API.
> Existing applications will continue to link to them but they won't have
> any effect on malloc behaviour.

OK. Good.

> To enable this, the MALLOC_CHECK_, mcheck() and mtrace() hooks have been
> weaned away from hooks.  In the process, some mcheck() failures have
> been fixed and the overall behaviour is now simpler to follow.  Finally,
> tr_break and mallwatch symbols have been deprecated and are not used
> anywhere.  Users are advised to use gdb watchpoints and conditional
> breakpoints to debug malloc internals since they ought to provide
> equivalent functionality.

OK.

Thanks for working through this.

This is looking better but we need to discuss the mcheck status and
dropping some of those interfaces, perhaps just deprecating libmcheck.a
and moving the functionality into libc_malloc_debug.so. See further review.

I think we're almost done with a v4 review if we agree on direction.

> Changes from v3:
> - Remove source file dependencies
> - Commit mcheck tests
> 
> Changes from v2:
> - Move hooks dependencies to malloc.o{,sS}
> 
> Changes from v1:
> 
> - Added makefile dependencies for the new hooks files
> - Fixed memset call in calloc debugging hooks
> - Added the tr_break deprecation patch and mcheck test patch to this
>   series
> 
> Siddhesh Poyarekar (10):
>   Drop source dependencies on hooks.c and arena.c
>   mtrace: Deprecate mallwatch and tr_break
>   Move glibc.malloc.check implementation into its own file
>   malloc: Move malloc hook references to hooks.c
>   glibc.malloc.check: Wean away from malloc hooks
>   mcheck: Wean away from malloc hooks
>   mtrace: Wean away from malloc hooks
>   Remove malloc hooks
>   Remove __after_morecore_hook
>   Remove __morecore and __default_morecore
> 
>  Makeconfig                                    |   2 +-
>  NEWS                                          |  18 +
>  include/malloc.h                              |  11 +-
>  include/stdlib.h                              |   3 -
>  malloc/Makefile                               |  23 +-
>  malloc/Versions                               |   3 +
>  malloc/arena.c                                |  26 +-
>  malloc/hooks.c                                | 545 +++++++-----------
>  malloc/malloc-check.c                         | 376 ++++++++++++
>  malloc/malloc-compathooks.c                   | 166 ++++++
>  malloc/malloc-internal.h                      |   6 +
>  malloc/malloc.c                               | 235 ++++----
>  malloc/malloc.h                               |  27 -
>  malloc/mcheck-hooks.c                         | 411 +++++++++++++
>  malloc/mcheck-init.c                          |  14 +-
>  malloc/mcheck.c                               | 369 +-----------
>  malloc/morecore.c                             |  15 +-
>  malloc/mtrace-hooks.c                         | 137 +++++
>  malloc/mtrace.c                               | 276 +--------
>  manual/memory.texi                            | 191 +-----
>  sysdeps/mach/hurd/i386/libc.abilist           |   1 +
>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   1 +
>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   1 +
>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   1 +
>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   1 +
>  sysdeps/unix/sysv/linux/ia64/libc.abilist     |   1 +
>  .../sysv/linux/m68k/coldfire/libc.abilist     |   1 +
>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   1 +
>  .../sysv/linux/microblaze/be/libc.abilist     |   1 +
>  .../sysv/linux/microblaze/le/libc.abilist     |   1 +
>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   1 +
>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   1 +
>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   1 +
>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   1 +
>  sysdeps/unix/sysv/linux/nios2/libc.abilist    |   1 +
>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   1 +
>  .../powerpc/powerpc32/nofpu/libc.abilist      |   1 +
>  .../linux/powerpc/powerpc64/be/libc.abilist   |   1 +
>  .../linux/powerpc/powerpc64/le/libc.abilist   |   1 +
>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   1 +
>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   1 +
>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   1 +
>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   1 +
>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   1 +
>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   1 +
>  .../sysv/linux/sparc/sparc32/libc.abilist     |   1 +
>  .../sysv/linux/sparc/sparc64/libc.abilist     |   1 +
>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   1 +
>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   1 +
>  53 files changed, 1547 insertions(+), 1340 deletions(-)
>  create mode 100644 malloc/malloc-check.c
>  create mode 100644 malloc/malloc-compathooks.c
>  create mode 100644 malloc/mcheck-hooks.c
>  create mode 100644 malloc/mtrace-hooks.c
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c
  2021-07-02 11:38 ` [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c Siddhesh Poyarekar
  2021-07-02 12:12   ` Andreas Schwab
@ 2021-07-02 19:06   ` Carlos O'Donell
  1 sibling, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Dependencies on hooks.c and arena.c get auto-computed when generating
> malloc.o{,s}.d so there is no need to add them manually.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>  malloc/Makefile | 4 ----
>  1 file changed, 4 deletions(-)
> 
> diff --git a/malloc/Makefile b/malloc/Makefile
> index c8256abbbf..2f9b3d596d 100644
> --- a/malloc/Makefile
> +++ b/malloc/Makefile
> @@ -269,10 +269,6 @@ $(objpfx)memusage: memusage.sh
>  	    -e 's|@REPORT_BUGS_TO@|$(REPORT_BUGS_TO)|' $^ > $@.new \
>  	&& rm -f $@ && mv $@.new $@ && chmod +x $@
>  
> -
> -# Extra dependencies
> -$(foreach o,$(all-object-suffixes),$(objpfx)malloc$(o)): arena.c hooks.c
> -
>  # Compile the tests with a flag which suppresses the mallopt call in
>  # the test skeleton.
>  $(tests:%=$(objpfx)%.o): CPPFLAGS += -DTEST_NO_MALLOPT
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 11:38 ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Siddhesh Poyarekar
@ 2021-07-02 19:06   ` Carlos O'Donell
  2021-07-02 20:37   ` Tulio Magno Quites Machado Filho
  1 sibling, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> The variable and function pair appear to provide a way for users to
> set conditional breakpoints in mtrace when a specific address is
> returned by the allocator.  This can be achieved by using conditional
> breakpoints in gdb so it is redundant.  There is no documentation of
> this interface in the manual either, so it appears to have been a hack
> that got added to debug malloc.  Deprecate these symbols and do not
> call tr_break anymore.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
 
> Reviewed-by: DJ Delorie <dj@redhat.com>
> ---
>  NEWS            |  4 ++++
>  malloc/mtrace.c | 57 +++++++++++++++++--------------------------------
>  2 files changed, 24 insertions(+), 37 deletions(-)
> 
> diff --git a/NEWS b/NEWS
> index 60933bd975..8e72946c3f 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -93,6 +93,10 @@ Deprecated and removed features, and other changes affecting compatibility:
>    package managers that delete removed files late during the package
>    upgrade or downgrade process.
>  
> +* The symbols mallwatch and tr_break are now deprecated and no longer used in
> +  mtrace.  Similar functionality can be achieved by using conditional
> +  breakpoints within mtrace functions from within gdb.
> +
>  Changes to build and runtime requirements:
>  
>  * On Linux, the shm_open, sem_open, and related functions now expect the
> diff --git a/malloc/mtrace.c b/malloc/mtrace.c
> index b65b21a933..6c2c58b706 100644
> --- a/malloc/mtrace.c
> +++ b/malloc/mtrace.c
> @@ -50,8 +50,25 @@ static char *malloc_trace_buffer;
>  
>  __libc_lock_define_initialized (static, lock);
>  
> -/* Address to breakpoint on accesses to... */
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
> +/* Compatibility symbols that were introduced to help break at allocation sites
> +   for specific memory allocations.  This is unusable with ASLR, although gdb
> +   may allow predictable allocation addresses.  Even then, gdb has watchpoint
> +   and conditional breakpoint support which should provide the same
> +   functionality without having this kludge.  These symbols are preserved in
> +   case some applications ended up linking against them but they don't actually
> +   do anything anymore; not that they did much before anyway.  */
> +
>  void *mallwatch;
> +compat_symbol (libc, mallwatch, mallwatch, GLIBC_2_0);
> +
> +void
> +tr_break (void)
> +{
> +}
> +compat_symbol (libc, tr_break, tr_break, GLIBC_2_0);
> +#endif
> +
>  
>  /* Old hook values.  */
>  static void (*tr_old_free_hook) (void *ptr, const void *);
> @@ -61,19 +78,6 @@ static void *(*tr_old_realloc_hook) (void *ptr, size_t size,
>  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
> -   tr_break.  */
> -
> -extern void tr_break (void) __THROW;
> -libc_hidden_proto (tr_break)
> -void
> -tr_break (void)
> -{
> -}
> -libc_hidden_def (tr_break)
> -
>  static void
>  tr_where (const void *caller, Dl_info *info)
>  {
> @@ -167,12 +171,6 @@ tr_freehook (void *ptr, const void *caller)
>    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);
> -    }
>    set_default_hooks ();
>    if (tr_old_free_hook != NULL)
>      (*tr_old_free_hook)(ptr, caller);
> @@ -203,9 +201,6 @@ tr_mallochook (size_t size, const void *caller)
>  
>    __libc_lock_unlock (lock);
>  
> -  if (hdr == mallwatch)
> -    tr_break ();
> -
>    return hdr;
>  }
>  
> @@ -214,9 +209,6 @@ 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);
>  
> @@ -247,9 +239,6 @@ tr_reallochook (void *ptr, size_t size, const void *caller)
>  
>    __libc_lock_unlock (lock);
>  
> -  if (hdr == mallwatch)
> -    tr_break ();
> -
>    return hdr;
>  }
>  
> @@ -274,9 +263,6 @@ tr_memalignhook (size_t alignment, size_t size, const void *caller)
>  
>    __libc_lock_unlock (lock);
>  
> -  if (hdr == mallwatch)
> -    tr_break ();
> -
>    return hdr;
>  }
>  
> @@ -296,10 +282,7 @@ release_libc_mem (void)
>  #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!  */
> +/* We enable tracing if the environment variable MALLOC_TRACE is set.  */
>  
>  void
>  mtrace (void)
> @@ -321,7 +304,7 @@ mtrace (void)
>  #else
>    mallfile = getenv (mallenv);
>  #endif
> -  if (mallfile != NULL || mallwatch != NULL)
> +  if (mallfile != NULL)
>      {
>        char *mtb = malloc (TRACE_BUFFER_SIZE);
>        if (mtb == NULL)
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 03/10] Move glibc.malloc.check implementation into its own file
  2021-07-02 11:38 ` [PATCH v4 03/10] Move glibc.malloc.check implementation into its own file Siddhesh Poyarekar
@ 2021-07-02 19:06   ` Carlos O'Donell
  0 siblings, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Separate the malloc check implementation from the malloc hooks.  They
> still use the hooks but are now maintained in a separate file.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>

> ---
>  malloc/hooks.c        | 371 +---------------------------------------
>  malloc/malloc-check.c | 390 ++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 391 insertions(+), 370 deletions(-)
>  create mode 100644 malloc/malloc-check.c
> 
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 8080c3f40e..57a9b55788 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -49,376 +49,7 @@ memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
>    return __libc_memalign (alignment, sz);
>  }
>  
> -/* Whether we are using malloc checking.  */
> -static int using_malloc_checking;
> -
> -/* Activate a standard set of debugging hooks. */
> -void
> -__malloc_check_init (void)
> -{
> -  using_malloc_checking = 1;
> -  __malloc_hook = malloc_check;
> -  __free_hook = free_check;
> -  __realloc_hook = realloc_check;
> -  __memalign_hook = memalign_check;
> -}
> -
> -/* When memory is tagged, the checking data is stored in the user part
> -   of the chunk.  We can't rely on the user not having modified the
> -   tags, so fetch the tag at each location before dereferencing
> -   it.  */
> -#define SAFE_CHAR_OFFSET(p,offset) \
> -  ((unsigned char *) tag_at (((unsigned char *) p) + offset))
> -
> -/* A simple, standard set of debugging hooks.  Overhead is `only' one
> -   byte per chunk; still this will catch most cases of double frees or
> -   overruns.  The goal here is to avoid obscure crashes due to invalid
> -   usage, unlike in the MALLOC_DEBUG code. */
> -
> -static unsigned char
> -magicbyte (const void *p)
> -{
> -  unsigned char magic;
> -
> -  magic = (((uintptr_t) p >> 3) ^ ((uintptr_t) p >> 11)) & 0xFF;
> -  /* Do not return 1.  See the comment in mem2mem_check().  */
> -  if (magic == 1)
> -    ++magic;
> -  return magic;
> -}
> -
> -/* Visualize the chunk as being partitioned into blocks of 255 bytes from the
> -   highest address of the chunk, downwards.  The end of each block tells
> -   us the size of that block, up to the actual size of the requested
> -   memory.  Our magic byte is right at the end of the requested size, so we
> -   must reach it with this iteration, otherwise we have witnessed a memory
> -   corruption.  */
> -static size_t
> -malloc_check_get_size (mchunkptr p)
> -{
> -  size_t size;
> -  unsigned char c;
> -  unsigned char magic = magicbyte (p);
> -
> -  assert (using_malloc_checking == 1);
> -
> -  for (size = CHUNK_HDR_SZ + memsize (p) - 1;
> -       (c = *SAFE_CHAR_OFFSET (p, size)) != magic;
> -       size -= c)
> -    {
> -      if (c <= 0 || size < (c + CHUNK_HDR_SZ))
> -	malloc_printerr ("malloc_check_get_size: memory corruption");
> -    }
> -
> -  /* chunk2mem size.  */
> -  return size - CHUNK_HDR_SZ;
> -}
> -
> -/* Instrument a chunk with overrun detector byte(s) and convert it
> -   into a user pointer with requested size req_sz. */
> -
> -static void *
> -mem2mem_check (void *ptr, size_t req_sz)
> -{
> -  mchunkptr p;
> -  unsigned char *m_ptr = ptr;
> -  size_t max_sz, block_sz, i;
> -  unsigned char magic;
> -
> -  if (!ptr)
> -    return ptr;
> -
> -  p = mem2chunk (ptr);
> -  magic = magicbyte (p);
> -  max_sz = memsize (p);
> -
> -  for (i = max_sz - 1; i > req_sz; i -= block_sz)
> -    {
> -      block_sz = MIN (i - req_sz, 0xff);
> -      /* Don't allow the magic byte to appear in the chain of length bytes.
> -         For the following to work, magicbyte cannot return 0x01.  */
> -      if (block_sz == magic)
> -        --block_sz;
> -
> -      *SAFE_CHAR_OFFSET (m_ptr, i) = block_sz;
> -    }
> -  *SAFE_CHAR_OFFSET (m_ptr, req_sz) = magic;
> -  return (void *) m_ptr;
> -}
> -
> -/* Convert a pointer to be free()d or realloc()ed to a valid chunk
> -   pointer.  If the provided pointer is not valid, return NULL. */
> -
> -static mchunkptr
> -mem2chunk_check (void *mem, unsigned char **magic_p)
> -{
> -  mchunkptr p;
> -  INTERNAL_SIZE_T sz, c;
> -  unsigned char magic;
> -
> -  if (!aligned_OK (mem))
> -    return NULL;
> -
> -  p = mem2chunk (mem);
> -  sz = chunksize (p);
> -  magic = magicbyte (p);
> -  if (!chunk_is_mmapped (p))
> -    {
> -      /* Must be a chunk in conventional heap memory. */
> -      int contig = contiguous (&main_arena);
> -      if ((contig &&
> -           ((char *) p < mp_.sbrk_base ||
> -            ((char *) p + sz) >= (mp_.sbrk_base + main_arena.system_mem))) ||
> -          sz < MINSIZE || sz & MALLOC_ALIGN_MASK || !inuse (p) ||
> -          (!prev_inuse (p) && ((prev_size (p) & MALLOC_ALIGN_MASK) != 0 ||
> -                               (contig && (char *) prev_chunk (p) < mp_.sbrk_base) ||
> -                               next_chunk (prev_chunk (p)) != p)))
> -        return NULL;
> -
> -      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
> -	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
> -	   sz -= c)
> -        {
> -          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
> -            return NULL;
> -        }
> -    }
> -  else
> -    {
> -      unsigned long offset, page_mask = GLRO (dl_pagesize) - 1;
> -
> -      /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
> -         alignment relative to the beginning of a page.  Check this
> -         first. */
> -      offset = (unsigned long) mem & page_mask;
> -      if ((offset != MALLOC_ALIGNMENT && offset != 0 && offset != 0x10 &&
> -           offset != 0x20 && offset != 0x40 && offset != 0x80 && offset != 0x100 &&
> -           offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
> -           offset < 0x2000) ||
> -          !chunk_is_mmapped (p) || prev_inuse (p) ||
> -          ((((unsigned long) p - prev_size (p)) & page_mask) != 0) ||
> -          ((prev_size (p) + sz) & page_mask) != 0)
> -        return NULL;
> -
> -      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
> -	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
> -	   sz -= c)
> -        {
> -          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
> -            return NULL;
> -        }
> -    }
> -
> -  unsigned char* safe_p = SAFE_CHAR_OFFSET (p, sz);
> -  *safe_p ^= 0xFF;
> -  if (magic_p)
> -    *magic_p = safe_p;
> -  return p;
> -}
> -
> -/* Check for corruption of the top chunk.  */
> -static void
> -top_check (void)
> -{
> -  mchunkptr t = top (&main_arena);
> -
> -  if (t == initial_top (&main_arena) ||
> -      (!chunk_is_mmapped (t) &&
> -       chunksize (t) >= MINSIZE &&
> -       prev_inuse (t) &&
> -       (!contiguous (&main_arena) ||
> -        (char *) t + chunksize (t) == mp_.sbrk_base + main_arena.system_mem)))
> -    return;
> -
> -  malloc_printerr ("malloc: top chunk is corrupt");
> -}
> -
> -static void *
> -malloc_check (size_t sz, const void *caller)
> -{
> -  void *victim;
> -  size_t nb;
> -
> -  if (__builtin_add_overflow (sz, 1, &nb))
> -    {
> -      __set_errno (ENOMEM);
> -      return NULL;
> -    }
> -
> -  __libc_lock_lock (main_arena.mutex);
> -  top_check ();
> -  victim = _int_malloc (&main_arena, nb);
> -  __libc_lock_unlock (main_arena.mutex);
> -  return mem2mem_check (tag_new_usable (victim), sz);
> -}
> -
> -static void
> -free_check (void *mem, const void *caller)
> -{
> -  mchunkptr p;
> -
> -  if (!mem)
> -    return;
> -
> -  int err = errno;
> -
> -  /* Quickly check that the freed pointer matches the tag for the memory.
> -     This gives a useful double-free detection.  */
> -  if (__glibc_unlikely (mtag_enabled))
> -    *(volatile char *)mem;
> -
> -  __libc_lock_lock (main_arena.mutex);
> -  p = mem2chunk_check (mem, NULL);
> -  if (!p)
> -    malloc_printerr ("free(): invalid pointer");
> -  if (chunk_is_mmapped (p))
> -    {
> -      __libc_lock_unlock (main_arena.mutex);
> -      munmap_chunk (p);
> -    }
> -  else
> -    {
> -      /* Mark the chunk as belonging to the library again.  */
> -      (void)tag_region (chunk2mem (p), memsize (p));
> -      _int_free (&main_arena, p, 1);
> -      __libc_lock_unlock (main_arena.mutex);
> -    }
> -  __set_errno (err);
> -}
> -
> -static void *
> -realloc_check (void *oldmem, size_t bytes, const void *caller)
> -{
> -  INTERNAL_SIZE_T chnb;
> -  void *newmem = 0;
> -  unsigned char *magic_p;
> -  size_t rb;
> -
> -  if (__builtin_add_overflow (bytes, 1, &rb))
> -    {
> -      __set_errno (ENOMEM);
> -      return NULL;
> -    }
> -  if (oldmem == 0)
> -    return malloc_check (bytes, NULL);
> -
> -  if (bytes == 0)
> -    {
> -      free_check (oldmem, NULL);
> -      return NULL;
> -    }
> -
> -  /* Quickly check that the freed pointer matches the tag for the memory.
> -     This gives a useful double-free detection.  */
> -  if (__glibc_unlikely (mtag_enabled))
> -    *(volatile char *)oldmem;
> -
> -  __libc_lock_lock (main_arena.mutex);
> -  const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p);
> -  __libc_lock_unlock (main_arena.mutex);
> -  if (!oldp)
> -    malloc_printerr ("realloc(): invalid pointer");
> -  const INTERNAL_SIZE_T oldsize = chunksize (oldp);
> -
> -  if (!checked_request2size (rb, &chnb))
> -    {
> -      __set_errno (ENOMEM);
> -      goto invert;
> -    }
> -
> -  __libc_lock_lock (main_arena.mutex);
> -
> -  if (chunk_is_mmapped (oldp))
> -    {
> -#if HAVE_MREMAP
> -      mchunkptr newp = mremap_chunk (oldp, chnb);
> -      if (newp)
> -        newmem = chunk2mem_tag (newp);
> -      else
> -#endif
> -      {
> -	/* Note the extra SIZE_SZ overhead. */
> -        if (oldsize - SIZE_SZ >= chnb)
> -          newmem = oldmem; /* do nothing */
> -        else
> -          {
> -            /* Must alloc, copy, free. */
> -	    top_check ();
> -	    newmem = _int_malloc (&main_arena, rb);
> -            if (newmem)
> -              {
> -                memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
> -                munmap_chunk (oldp);
> -              }
> -          }
> -      }
> -    }
> -  else
> -    {
> -      top_check ();
> -      newmem = _int_realloc (&main_arena, oldp, oldsize, chnb);
> -    }
> -
> -  DIAG_PUSH_NEEDS_COMMENT;
> -#if __GNUC_PREREQ (7, 0)
> -  /* GCC 7 warns about magic_p may be used uninitialized.  But we never
> -     reach here if magic_p is uninitialized.  */
> -  DIAG_IGNORE_NEEDS_COMMENT (7, "-Wmaybe-uninitialized");
> -#endif
> -  /* mem2chunk_check changed the magic byte in the old chunk.
> -     If newmem is NULL, then the old chunk will still be used though,
> -     so we need to invert that change here.  */
> -invert:
> -  if (newmem == NULL)
> -    *magic_p ^= 0xFF;
> -  DIAG_POP_NEEDS_COMMENT;
> -
> -  __libc_lock_unlock (main_arena.mutex);
> -
> -  return mem2mem_check (tag_new_usable (newmem), bytes);
> -}
> -
> -static void *
> -memalign_check (size_t alignment, size_t bytes, const void *caller)
> -{
> -  void *mem;
> -
> -  if (alignment <= MALLOC_ALIGNMENT)
> -    return malloc_check (bytes, NULL);
> -
> -  if (alignment < MINSIZE)
> -    alignment = MINSIZE;
> -
> -  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
> -     power of 2 and will cause overflow in the check below.  */
> -  if (alignment > SIZE_MAX / 2 + 1)
> -    {
> -      __set_errno (EINVAL);
> -      return 0;
> -    }
> -
> -  /* Check for overflow.  */
> -  if (bytes > SIZE_MAX - alignment - MINSIZE)
> -    {
> -      __set_errno (ENOMEM);
> -      return 0;
> -    }
> -
> -  /* Make sure alignment is power of 2.  */
> -  if (!powerof2 (alignment))
> -    {
> -      size_t a = MALLOC_ALIGNMENT * 2;
> -      while (a < alignment)
> -        a <<= 1;
> -      alignment = a;
> -    }
> -
> -  __libc_lock_lock (main_arena.mutex);
> -  top_check ();
> -  mem = _int_memalign (&main_arena, alignment, bytes + 1);
> -  __libc_lock_unlock (main_arena.mutex);
> -  return mem2mem_check (tag_new_usable (mem), bytes);
> -}
> +#include "malloc-check.c"
>  
>  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
>  
> diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
> new file mode 100644
> index 0000000000..dcab880510
> --- /dev/null
> +++ b/malloc/malloc-check.c
> @@ -0,0 +1,390 @@
> +/* glibc.malloc.check implementation.

OK.

> +   Copyright (C) 2001-2021 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +   Contributed by Wolfram Gloger <wg@malloc.de>, 2001.
> +
> +   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; see the file COPYING.LIB.  If
> +   not, see <https://www.gnu.org/licenses/>.  */
> +
> +
> +/* Whether we are using malloc checking.  */
> +static int using_malloc_checking;
> +
> +/* Activate a standard set of debugging hooks. */
> +void
> +__malloc_check_init (void)
> +{
> +  using_malloc_checking = 1;
> +  __malloc_hook = malloc_check;
> +  __free_hook = free_check;
> +  __realloc_hook = realloc_check;
> +  __memalign_hook = memalign_check;
> +}
> +
> +/* When memory is tagged, the checking data is stored in the user part
> +   of the chunk.  We can't rely on the user not having modified the
> +   tags, so fetch the tag at each location before dereferencing
> +   it.  */
> +#define SAFE_CHAR_OFFSET(p,offset) \
> +  ((unsigned char *) tag_at (((unsigned char *) p) + offset))
> +
> +/* A simple, standard set of debugging hooks.  Overhead is `only' one
> +   byte per chunk; still this will catch most cases of double frees or
> +   overruns.  The goal here is to avoid obscure crashes due to invalid
> +   usage, unlike in the MALLOC_DEBUG code. */
> +
> +static unsigned char
> +magicbyte (const void *p)
> +{
> +  unsigned char magic;
> +
> +  magic = (((uintptr_t) p >> 3) ^ ((uintptr_t) p >> 11)) & 0xFF;
> +  /* Do not return 1.  See the comment in mem2mem_check().  */
> +  if (magic == 1)
> +    ++magic;
> +  return magic;
> +}
> +
> +/* Visualize the chunk as being partitioned into blocks of 255 bytes from the
> +   highest address of the chunk, downwards.  The end of each block tells
> +   us the size of that block, up to the actual size of the requested
> +   memory.  Our magic byte is right at the end of the requested size, so we
> +   must reach it with this iteration, otherwise we have witnessed a memory
> +   corruption.  */
> +static size_t
> +malloc_check_get_size (mchunkptr p)
> +{
> +  size_t size;
> +  unsigned char c;
> +  unsigned char magic = magicbyte (p);
> +
> +  assert (using_malloc_checking == 1);
> +
> +  for (size = CHUNK_HDR_SZ + memsize (p) - 1;
> +       (c = *SAFE_CHAR_OFFSET (p, size)) != magic;
> +       size -= c)
> +    {
> +      if (c <= 0 || size < (c + CHUNK_HDR_SZ))
> +	malloc_printerr ("malloc_check_get_size: memory corruption");
> +    }
> +
> +  /* chunk2mem size.  */
> +  return size - CHUNK_HDR_SZ;
> +}
> +
> +/* Instrument a chunk with overrun detector byte(s) and convert it
> +   into a user pointer with requested size req_sz. */
> +
> +static void *
> +mem2mem_check (void *ptr, size_t req_sz)
> +{
> +  mchunkptr p;
> +  unsigned char *m_ptr = ptr;
> +  size_t max_sz, block_sz, i;
> +  unsigned char magic;
> +
> +  if (!ptr)
> +    return ptr;
> +
> +  p = mem2chunk (ptr);
> +  magic = magicbyte (p);
> +  max_sz = memsize (p);
> +
> +  for (i = max_sz - 1; i > req_sz; i -= block_sz)
> +    {
> +      block_sz = MIN (i - req_sz, 0xff);
> +      /* Don't allow the magic byte to appear in the chain of length bytes.
> +         For the following to work, magicbyte cannot return 0x01.  */
> +      if (block_sz == magic)
> +        --block_sz;
> +
> +      *SAFE_CHAR_OFFSET (m_ptr, i) = block_sz;
> +    }
> +  *SAFE_CHAR_OFFSET (m_ptr, req_sz) = magic;
> +  return (void *) m_ptr;
> +}
> +
> +/* Convert a pointer to be free()d or realloc()ed to a valid chunk
> +   pointer.  If the provided pointer is not valid, return NULL. */
> +
> +static mchunkptr
> +mem2chunk_check (void *mem, unsigned char **magic_p)
> +{
> +  mchunkptr p;
> +  INTERNAL_SIZE_T sz, c;
> +  unsigned char magic;
> +
> +  if (!aligned_OK (mem))
> +    return NULL;
> +
> +  p = mem2chunk (mem);
> +  sz = chunksize (p);
> +  magic = magicbyte (p);
> +  if (!chunk_is_mmapped (p))
> +    {
> +      /* Must be a chunk in conventional heap memory. */
> +      int contig = contiguous (&main_arena);
> +      if ((contig &&
> +           ((char *) p < mp_.sbrk_base ||
> +            ((char *) p + sz) >= (mp_.sbrk_base + main_arena.system_mem))) ||
> +          sz < MINSIZE || sz & MALLOC_ALIGN_MASK || !inuse (p) ||
> +          (!prev_inuse (p) && ((prev_size (p) & MALLOC_ALIGN_MASK) != 0 ||
> +                               (contig && (char *) prev_chunk (p) < mp_.sbrk_base) ||
> +                               next_chunk (prev_chunk (p)) != p)))
> +        return NULL;
> +
> +      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
> +	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
> +	   sz -= c)
> +        {
> +          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
> +            return NULL;
> +        }
> +    }
> +  else
> +    {
> +      unsigned long offset, page_mask = GLRO (dl_pagesize) - 1;
> +
> +      /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
> +         alignment relative to the beginning of a page.  Check this
> +         first. */
> +      offset = (unsigned long) mem & page_mask;
> +      if ((offset != MALLOC_ALIGNMENT && offset != 0 && offset != 0x10 &&
> +           offset != 0x20 && offset != 0x40 && offset != 0x80 && offset != 0x100 &&
> +           offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
> +           offset < 0x2000) ||
> +          !chunk_is_mmapped (p) || prev_inuse (p) ||
> +          ((((unsigned long) p - prev_size (p)) & page_mask) != 0) ||
> +          ((prev_size (p) + sz) & page_mask) != 0)
> +        return NULL;
> +
> +      for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
> +	   (c = *SAFE_CHAR_OFFSET (p, sz)) != magic;
> +	   sz -= c)
> +        {
> +          if (c == 0 || sz < (c + CHUNK_HDR_SZ))
> +            return NULL;
> +        }
> +    }
> +
> +  unsigned char* safe_p = SAFE_CHAR_OFFSET (p, sz);
> +  *safe_p ^= 0xFF;
> +  if (magic_p)
> +    *magic_p = safe_p;
> +  return p;
> +}
> +
> +/* Check for corruption of the top chunk.  */
> +static void
> +top_check (void)
> +{
> +  mchunkptr t = top (&main_arena);
> +
> +  if (t == initial_top (&main_arena) ||
> +      (!chunk_is_mmapped (t) &&
> +       chunksize (t) >= MINSIZE &&
> +       prev_inuse (t) &&
> +       (!contiguous (&main_arena) ||
> +        (char *) t + chunksize (t) == mp_.sbrk_base + main_arena.system_mem)))
> +    return;
> +
> +  malloc_printerr ("malloc: top chunk is corrupt");
> +}
> +
> +static void *
> +malloc_check (size_t sz, const void *caller)
> +{
> +  void *victim;
> +  size_t nb;
> +
> +  if (__builtin_add_overflow (sz, 1, &nb))
> +    {
> +      __set_errno (ENOMEM);
> +      return NULL;
> +    }
> +
> +  __libc_lock_lock (main_arena.mutex);
> +  top_check ();
> +  victim = _int_malloc (&main_arena, nb);
> +  __libc_lock_unlock (main_arena.mutex);
> +  return mem2mem_check (tag_new_usable (victim), sz);
> +}
> +
> +static void
> +free_check (void *mem, const void *caller)
> +{
> +  mchunkptr p;
> +
> +  if (!mem)
> +    return;
> +
> +  int err = errno;
> +
> +  /* Quickly check that the freed pointer matches the tag for the memory.
> +     This gives a useful double-free detection.  */
> +  if (__glibc_unlikely (mtag_enabled))
> +    *(volatile char *)mem;
> +
> +  __libc_lock_lock (main_arena.mutex);
> +  p = mem2chunk_check (mem, NULL);
> +  if (!p)
> +    malloc_printerr ("free(): invalid pointer");
> +  if (chunk_is_mmapped (p))
> +    {
> +      __libc_lock_unlock (main_arena.mutex);
> +      munmap_chunk (p);
> +    }
> +  else
> +    {
> +      /* Mark the chunk as belonging to the library again.  */
> +      (void)tag_region (chunk2mem (p), memsize (p));
> +      _int_free (&main_arena, p, 1);
> +      __libc_lock_unlock (main_arena.mutex);
> +    }
> +  __set_errno (err);
> +}
> +
> +static void *
> +realloc_check (void *oldmem, size_t bytes, const void *caller)
> +{
> +  INTERNAL_SIZE_T chnb;
> +  void *newmem = 0;
> +  unsigned char *magic_p;
> +  size_t rb;
> +
> +  if (__builtin_add_overflow (bytes, 1, &rb))
> +    {
> +      __set_errno (ENOMEM);
> +      return NULL;
> +    }
> +  if (oldmem == 0)
> +    return malloc_check (bytes, NULL);
> +
> +  if (bytes == 0)
> +    {
> +      free_check (oldmem, NULL);
> +      return NULL;
> +    }
> +
> +  /* Quickly check that the freed pointer matches the tag for the memory.
> +     This gives a useful double-free detection.  */
> +  if (__glibc_unlikely (mtag_enabled))
> +    *(volatile char *)oldmem;
> +
> +  __libc_lock_lock (main_arena.mutex);
> +  const mchunkptr oldp = mem2chunk_check (oldmem, &magic_p);
> +  __libc_lock_unlock (main_arena.mutex);
> +  if (!oldp)
> +    malloc_printerr ("realloc(): invalid pointer");
> +  const INTERNAL_SIZE_T oldsize = chunksize (oldp);
> +
> +  if (!checked_request2size (rb, &chnb))
> +    {
> +      __set_errno (ENOMEM);
> +      goto invert;
> +    }
> +
> +  __libc_lock_lock (main_arena.mutex);
> +
> +  if (chunk_is_mmapped (oldp))
> +    {
> +#if HAVE_MREMAP
> +      mchunkptr newp = mremap_chunk (oldp, chnb);
> +      if (newp)
> +        newmem = chunk2mem_tag (newp);
> +      else
> +#endif
> +      {
> +	/* Note the extra SIZE_SZ overhead. */
> +        if (oldsize - SIZE_SZ >= chnb)
> +          newmem = oldmem; /* do nothing */
> +        else
> +          {
> +            /* Must alloc, copy, free. */
> +	    top_check ();
> +	    newmem = _int_malloc (&main_arena, rb);
> +            if (newmem)
> +              {
> +                memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
> +                munmap_chunk (oldp);
> +              }
> +          }
> +      }
> +    }
> +  else
> +    {
> +      top_check ();
> +      newmem = _int_realloc (&main_arena, oldp, oldsize, chnb);
> +    }
> +
> +  DIAG_PUSH_NEEDS_COMMENT;
> +#if __GNUC_PREREQ (7, 0)
> +  /* GCC 7 warns about magic_p may be used uninitialized.  But we never
> +     reach here if magic_p is uninitialized.  */
> +  DIAG_IGNORE_NEEDS_COMMENT (7, "-Wmaybe-uninitialized");
> +#endif
> +  /* mem2chunk_check changed the magic byte in the old chunk.
> +     If newmem is NULL, then the old chunk will still be used though,
> +     so we need to invert that change here.  */
> +invert:
> +  if (newmem == NULL)
> +    *magic_p ^= 0xFF;
> +  DIAG_POP_NEEDS_COMMENT;
> +
> +  __libc_lock_unlock (main_arena.mutex);
> +
> +  return mem2mem_check (tag_new_usable (newmem), bytes);
> +}
> +
> +static void *
> +memalign_check (size_t alignment, size_t bytes, const void *caller)
> +{
> +  void *mem;
> +
> +  if (alignment <= MALLOC_ALIGNMENT)
> +    return malloc_check (bytes, NULL);
> +
> +  if (alignment < MINSIZE)
> +    alignment = MINSIZE;
> +
> +  /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
> +     power of 2 and will cause overflow in the check below.  */
> +  if (alignment > SIZE_MAX / 2 + 1)
> +    {
> +      __set_errno (EINVAL);
> +      return 0;
> +    }
> +
> +  /* Check for overflow.  */
> +  if (bytes > SIZE_MAX - alignment - MINSIZE)
> +    {
> +      __set_errno (ENOMEM);
> +      return 0;
> +    }
> +
> +  /* Make sure alignment is power of 2.  */
> +  if (!powerof2 (alignment))
> +    {
> +      size_t a = MALLOC_ALIGNMENT * 2;
> +      while (a < alignment)
> +        a <<= 1;
> +      alignment = a;
> +    }
> +
> +  __libc_lock_lock (main_arena.mutex);
> +  top_check ();
> +  mem = _int_memalign (&main_arena, alignment, bytes + 1);
> +  __libc_lock_unlock (main_arena.mutex);
> +  return mem2mem_check (tag_new_usable (mem), bytes);
> +}
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 10/10] Remove __morecore and __default_morecore
  2021-07-02 11:38 ` [PATCH v4 10/10] Remove __morecore and __default_morecore Siddhesh Poyarekar
@ 2021-07-02 19:06   ` Carlos O'Donell
  0 siblings, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Make the __morecore and __default_morecore symbols compat-only and
> remove their declarations from the API.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
 
> Reviewed-by: DJ Delorie <dj@redhat.com>
> ---
>  NEWS                     |  5 +++++
>  include/stdlib.h         |  3 ---
>  malloc/arena.c           | 12 ++----------
>  malloc/hooks.c           |  3 +++
>  malloc/malloc-internal.h |  5 +++++
>  malloc/malloc.c          |  4 +---
>  malloc/malloc.h          |  8 --------
>  malloc/morecore.c        | 15 +++++++++++++--
>  8 files changed, 29 insertions(+), 26 deletions(-)
> 
> diff --git a/NEWS b/NEWS
> index cebe8384bf..2533919f75 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -106,6 +106,11 @@ Deprecated and removed features, and other changes affecting compatibility:
>    legacy programs until they are updated to remove references to the memory
>    allocation hooks.
>  
> +* The __morecore and __after_morecore_hook malloc hooks and the default
> +  implementation __default_morecore have been removed from the API.  Existing
> +  applications will continue to link against these symbols but the interfaces
> +  no longer have any effect on malloc.
> +
>  Changes to build and runtime requirements:
>  
>  * On Linux, the shm_open, sem_open, and related functions now expect the
> diff --git a/include/stdlib.h b/include/stdlib.h
> index 1f6e1508e4..1c6f70b082 100644
> --- a/include/stdlib.h
> +++ b/include/stdlib.h
> @@ -306,9 +306,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/malloc/arena.c b/malloc/arena.c
> index 8591c8ea56..00e8b5a32f 100644
> --- a/malloc/arena.c
> +++ b/malloc/arena.c
> @@ -272,14 +272,6 @@ next_env_entry (char ***position)
>  #endif
>  
>  
> -#if defined(SHARED) || defined(USE_MTAG)
> -static void *
> -__failing_morecore (ptrdiff_t d)
> -{
> -  return (void *) MORECORE_FAILURE;
> -}
> -#endif
> -
>  #ifdef SHARED
>  extern struct dl_open_hook *_dl_open_hook;
>  libc_hidden_proto (_dl_open_hook);
> @@ -300,7 +292,7 @@ ptmalloc_init (void)
>  	 and that morecore does not support tagged regions, then
>  	 disable it.  */
>        if (__MTAG_SBRK_UNTAGGED)
> -	__morecore = __failing_morecore;
> +	__always_fail_morecore = true;
>  
>        mtag_enabled = true;
>        mtag_mmap_flags = __MTAG_MMAP_FLAGS;
> @@ -313,7 +305,7 @@ ptmalloc_init (void)
>       generic sbrk implementation also enforces this, but it is not
>       used on Hurd.  */
>    if (!__libc_initial)
> -    __morecore = __failing_morecore;
> +    __always_fail_morecore = true;
>  #endif
>  
>    thread_arena = &main_arena;
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 5e9355761a..b40696c8b7 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -81,6 +81,9 @@ compat_symbol (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
>  void weak_variable (*__after_morecore_hook) (void) = NULL;
>  compat_symbol (libc, __after_morecore_hook, __after_morecore_hook, GLIBC_2_0);
>  
> +void *(*__morecore)(ptrdiff_t);
> +compat_symbol (libc, __morecore, __morecore, GLIBC_2_0);
> +
>  /* These hooks will get executed only through the interposed allocator
>     functions in libmalloc_compathooks.  This means that the calls to malloc,
>     realloc, etc. will lead back into the interposed functions, which is what we
> diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h
> index ee0f5697af..b104f7cdbf 100644
> --- a/malloc/malloc-internal.h
> +++ b/malloc/malloc-internal.h
> @@ -21,6 +21,7 @@
>  
>  #include <malloc-machine.h>
>  #include <malloc-sysdep.h>
> +#include <stdbool.h>
>  
>  /* INTERNAL_SIZE_T is the word-size used for internal bookkeeping of
>     chunk sizes.
> @@ -63,6 +64,8 @@
>  
>  #define top(ar_ptr) ((ar_ptr)->top)
>  
> +extern bool __always_fail_morecore attribute_hidden;
> +
>  /* Called in the parent process before a fork.  */
>  void __malloc_fork_lock_parent (void) attribute_hidden;
>  
> @@ -78,4 +81,6 @@ void __malloc_arena_thread_freeres (void) attribute_hidden;
>  /* Activate a standard set of debugging hooks. */
>  void __malloc_check_init (void) attribute_hidden;
>  
> +extern void *__glibc_morecore (ptrdiff_t) attribute_hidden;
> +
>  #endif /* _MALLOC_INTERNAL_H */
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 296e4f9789..79855e93ab 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -382,10 +382,8 @@ __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;
>  
>  /* Memory tagging.  */
>  
> diff --git a/malloc/malloc.h b/malloc/malloc.h
> index d066a05d82..2df0b38050 100644
> --- a/malloc/malloc.h
> +++ b/malloc/malloc.h
> @@ -76,14 +76,6 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__
>  extern void *pvalloc (size_t __size) __THROW __attribute_malloc__
>    __wur __attr_dealloc_free;
>  
> -/* Underlying allocation function; successive calls should return
> -   contiguous pieces of memory.  */
> -extern void *(*__morecore) (ptrdiff_t __size) __MALLOC_DEPRECATED;
> -
> -/* Default value of `__morecore'.  */
> -extern void *__default_morecore (ptrdiff_t __size)
> -__THROW __attribute_malloc__  __MALLOC_DEPRECATED;
> -
>  /* SVID2/XPG mallinfo structure */
>  
>  struct mallinfo
> diff --git a/malloc/morecore.c b/malloc/morecore.c
> index 047228779b..c85a85c0eb 100644
> --- a/malloc/morecore.c
> +++ b/malloc/morecore.c
> @@ -38,16 +38,27 @@ libc_hidden_proto (__sbrk)
>  # define NULL 0
>  #endif
>  
> +#if defined(SHARED) || defined(USE_MTAG)
> +bool __always_fail_morecore = false;
> +#endif
> +
>  /* Allocate INCREMENT more bytes of data space,
>     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)
>  {
> +#if defined(SHARED) || defined(USE_MTAG)
> +  if (__always_fail_morecore)
> +    return NULL;
> +#endif
> +
>    void *result = (void *) __sbrk (increment);
>    if (result == (void *) -1)
>      return NULL;
>  
>    return result;
>  }
> -libc_hidden_def (__default_morecore)
> +#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
> +compat_symbol (libc, __glibc_morecore, __default_morecore, GLIBC_2_0);
> +#endif
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 05/10] glibc.malloc.check: Wean away from malloc hooks
  2021-07-02 11:38 ` [PATCH v4 05/10] glibc.malloc.check: Wean away from malloc hooks Siddhesh Poyarekar
@ 2021-07-02 19:06   ` Carlos O'Donell
  0 siblings, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Set up a new internal debugging hooks flag variable and migrate
> glibc.malloc.check to it so that it no longer uses the malloc hooks.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
 
> Reviewed-by: DJ Delorie <dj@redhat.com>
> ---
>  malloc/arena.c        |  4 +--
>  malloc/hooks.c        | 63 ++++++++++++++++++++++++++++++++++++++++++-
>  malloc/malloc-check.c | 30 ++++++---------------
>  malloc/malloc.c       |  9 +------
>  4 files changed, 73 insertions(+), 33 deletions(-)
> 
> diff --git a/malloc/arena.c b/malloc/arena.c
> index 1861d20006..357a3b0b30 100644
> --- a/malloc/arena.c
> +++ b/malloc/arena.c
> @@ -210,7 +210,7 @@ TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp)
>  {
>    int32_t value = (int32_t) valp->numval;
>    if (value != 0)
> -    __malloc_check_init ();
> +    __malloc_debug_enable (MALLOC_CHECK_HOOK);
>  }
>  
>  # define TUNABLE_CALLBACK_FNDECL(__name, __type) \
> @@ -400,7 +400,7 @@ ptmalloc_init (void)
>          }
>      }
>    if (s && s[0] != '\0' && s[0] != '0')
> -    __malloc_check_init ();
> +    __malloc_debug_enable (MALLOC_CHECK_HOOK);
>  #endif
>  
>  #if HAVE_MALLOC_INIT_HOOK
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 4960aafd08..77855801c8 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -21,6 +21,8 @@
>     corrupt pointer is detected: do nothing (0), print an error message
>     (1), or call abort() (2). */
>  
> +#  include <stdbool.h>
> +
>  /* Define and initialize the hook variables.  These weak definitions must
>     appear before any use of the variables in a function (arena.c uses one).  */
>  #ifndef weak_variable
> @@ -29,6 +31,14 @@
>  # define weak_variable weak_function
>  #endif
>  
> +/* The internal malloc debugging hooks.  */
> +enum malloc_debug_hooks
> +{
> +  MALLOC_NONE_HOOK = 0,
> +  MALLOC_CHECK_HOOK = 1 << 0,	/* MALLOC_CHECK_ or glibc.malloc.check.  */
> +};
> +static unsigned __malloc_debugging_hooks;
> +
>  /* Forward declarations.  */
>  
>  #if HAVE_MALLOC_INIT_HOOK
> @@ -48,6 +58,24 @@ void *weak_variable (*__memalign_hook)
>  
>  static void ptmalloc_init (void);
>  
> +static __always_inline bool
> +__is_malloc_debug_enabled (enum malloc_debug_hooks flag)
> +{
> +  return __malloc_debugging_hooks & flag;
> +}
> +
> +static __always_inline void
> +__malloc_debug_enable (enum malloc_debug_hooks flag)
> +{
> +  __malloc_debugging_hooks |= flag;
> +}
> +
> +static __always_inline void
> +__malloc_debug_disable (enum malloc_debug_hooks flag)
> +{
> +  __malloc_debugging_hooks &= ~flag;
> +}
> +
>  #include "malloc-check.c"
>  
>  static __always_inline bool
> @@ -63,6 +91,12 @@ _malloc_debug_before (size_t bytes, void **victimp, const void *address)
>        *victimp = (*hook)(bytes, address);
>        return true;
>      }
> +
> +  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +    {
> +      *victimp = malloc_check (bytes);
> +      return true;
> +    }
>    return false;
>  }
>  
> @@ -76,6 +110,12 @@ _free_debug_before (void *mem, const void *address)
>        (*hook)(mem, address);
>        return true;
>      }
> +
> +  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +    {
> +      free_check (mem);
> +      return true;
> +    }
>    return false;
>  }
>  
> @@ -91,6 +131,12 @@ _realloc_debug_before (void *oldmem, size_t bytes, void **victimp,
>        return true;
>      }
>  
> +  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +    {
> +      *victimp = realloc_check (oldmem, bytes);
> +      return true;
> +    }
> +
>    return false;
>  }
>  
> @@ -105,6 +151,13 @@ _memalign_debug_before (size_t alignment, size_t bytes, void **victimp,
>        *victimp = (*hook)(alignment, bytes, address);
>        return true;
>      }
> +
> +  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +    {
> +      *victimp = memalign_check (alignment, bytes);
> +      return true;
> +    }
> +
>    return false;
>  }
>  
> @@ -120,6 +173,14 @@ _calloc_debug_before (size_t bytes, void **victimp, const void *address)
>  	memset (*victimp, 0, bytes);
>        return true;
>      }
> +
> +  if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
> +    {
> +      *victimp = malloc_check (bytes);
> +      if (*victimp != NULL)
> +	memset (*victimp, 0, bytes);
> +      return true;
> +    }
>    return false;
>  }
>  
> @@ -195,7 +256,7 @@ malloc_set_state (void *msptr)
>    __realloc_hook = NULL;
>    __free_hook = NULL;
>    __memalign_hook = NULL;
> -  using_malloc_checking = 0;
> +  __malloc_debug_disable (MALLOC_CHECK_HOOK);
>  
>    /* Patch the dumped heap.  We no longer try to integrate into the
>       existing heap.  Instead, we mark the existing chunks as mmapped.
> diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
> index dcab880510..a85e519498 100644
> --- a/malloc/malloc-check.c
> +++ b/malloc/malloc-check.c
> @@ -18,20 +18,6 @@
>     not, see <https://www.gnu.org/licenses/>.  */
>  
>  
> -/* Whether we are using malloc checking.  */
> -static int using_malloc_checking;
> -
> -/* Activate a standard set of debugging hooks. */
> -void
> -__malloc_check_init (void)
> -{
> -  using_malloc_checking = 1;
> -  __malloc_hook = malloc_check;
> -  __free_hook = free_check;
> -  __realloc_hook = realloc_check;
> -  __memalign_hook = memalign_check;
> -}
> -
>  /* When memory is tagged, the checking data is stored in the user part
>     of the chunk.  We can't rely on the user not having modified the
>     tags, so fetch the tag at each location before dereferencing
> @@ -69,7 +55,7 @@ malloc_check_get_size (mchunkptr p)
>    unsigned char c;
>    unsigned char magic = magicbyte (p);
>  
> -  assert (using_malloc_checking == 1);
> +  assert (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK));
>  
>    for (size = CHUNK_HDR_SZ + memsize (p) - 1;
>         (c = *SAFE_CHAR_OFFSET (p, size)) != magic;
> @@ -203,7 +189,7 @@ top_check (void)
>  }
>  
>  static void *
> -malloc_check (size_t sz, const void *caller)
> +malloc_check (size_t sz)
>  {
>    void *victim;
>    size_t nb;
> @@ -222,7 +208,7 @@ malloc_check (size_t sz, const void *caller)
>  }
>  
>  static void
> -free_check (void *mem, const void *caller)
> +free_check (void *mem)
>  {
>    mchunkptr p;
>  
> @@ -256,7 +242,7 @@ free_check (void *mem, const void *caller)
>  }
>  
>  static void *
> -realloc_check (void *oldmem, size_t bytes, const void *caller)
> +realloc_check (void *oldmem, size_t bytes)
>  {
>    INTERNAL_SIZE_T chnb;
>    void *newmem = 0;
> @@ -269,11 +255,11 @@ realloc_check (void *oldmem, size_t bytes, const void *caller)
>        return NULL;
>      }
>    if (oldmem == 0)
> -    return malloc_check (bytes, NULL);
> +    return malloc_check (bytes);
>  
>    if (bytes == 0)
>      {
> -      free_check (oldmem, NULL);
> +      free_check (oldmem);
>        return NULL;
>      }
>  
> @@ -348,12 +334,12 @@ invert:
>  }
>  
>  static void *
> -memalign_check (size_t alignment, size_t bytes, const void *caller)
> +memalign_check (size_t alignment, size_t bytes)
>  {
>    void *mem;
>  
>    if (alignment <= MALLOC_ALIGNMENT)
> -    return malloc_check (bytes, NULL);
> +    return malloc_check (bytes);
>  
>    if (alignment < MINSIZE)
>      alignment = MINSIZE;
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 75ca6ec3f0..60753446a1 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -1124,13 +1124,6 @@ static void munmap_chunk(mchunkptr p);
>  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 ------------------  */
>  
>  
> @@ -5078,7 +5071,7 @@ musable (void *mem)
>  
>        p = mem2chunk (mem);
>  
> -      if (__builtin_expect (using_malloc_checking == 1, 0))
> +      if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
>  	return malloc_check_get_size (p);
>  
>        if (chunk_is_mmapped (p))
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 09/10] Remove __after_morecore_hook
  2021-07-02 11:38 ` [PATCH v4 09/10] Remove __after_morecore_hook Siddhesh Poyarekar
@ 2021-07-02 19:06   ` Carlos O'Donell
  0 siblings, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Remove __after_morecore_hook from the API and finalize the symbol so
> that it can no longer be used in new applications.  Old applications
> using __after_morecore_hook will find that their hook is no longer
> called.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
 
> Reviewed-by: DJ Delorie <dj@redhat.com>
> ---
>  malloc/hooks.c  |  3 +++
>  malloc/malloc.c | 30 +-----------------------------
>  malloc/malloc.h |  5 -----
>  3 files changed, 4 insertions(+), 34 deletions(-)
> 
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 397220aaba..5e9355761a 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -78,6 +78,9 @@ compat_symbol (libc, __malloc_hook, __malloc_hook, GLIBC_2_0);
>  compat_symbol (libc, __realloc_hook, __realloc_hook, GLIBC_2_0);
>  compat_symbol (libc, __memalign_hook, __memalign_hook, GLIBC_2_0);
>  
> +void weak_variable (*__after_morecore_hook) (void) = NULL;
> +compat_symbol (libc, __after_morecore_hook, __after_morecore_hook, GLIBC_2_0);
> +
>  /* These hooks will get executed only through the interposed allocator
>     functions in libmalloc_compathooks.  This means that the calls to malloc,
>     realloc, etc. will lead back into the interposed functions, which is what we
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index f6d7309721..296e4f9789 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -1988,16 +1988,6 @@ static void     malloc_consolidate (mstate);
>  
>  /* -------------- Early definitions for debugging hooks ---------------- */
>  
> -/* Define and initialize the hook variables.  These weak definitions must
> -   appear before any use of the variables in a function (arena.c uses one).  */
> -#ifndef weak_variable
> -/* In GNU libc we want the hook variables to be weak definitions to
> -   avoid a problem with Emacs.  */
> -# define weak_variable weak_function
> -#endif
> -
> -void weak_variable (*__after_morecore_hook) (void) = NULL;
> -
>  /* This function is called from the arena shutdown hook, to free the
>     thread cache (if it exists).  */
>  static void tcache_thread_shutdown (void);
> @@ -2622,14 +2612,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
> @@ -2768,13 +2751,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 */
> @@ -2933,10 +2909,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);
> diff --git a/malloc/malloc.h b/malloc/malloc.h
> index 709fa454b5..d066a05d82 100644
> --- a/malloc/malloc.h
> +++ b/malloc/malloc.h
> @@ -164,10 +164,5 @@ 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 __after_morecore_hook) (void)
> -  __MALLOC_DEPRECATED;
> -
> -
>  __END_DECLS
>  #endif /* malloc.h */
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 07/10] mtrace: Wean away from malloc hooks
  2021-07-02 11:38 ` [PATCH v4 07/10] mtrace: " Siddhesh Poyarekar
@ 2021-07-02 19:06   ` Carlos O'Donell
  0 siblings, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Split mtrace hooks into before and after and adapt to the new internal
> debugging hooks infrastructure.  With this, the malloc hooks are
> unused internally and can be removed from the main library.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
 
> This also eliminates the only use of memalign through a PLT in the
> library, so checklocalplt data needs to be updated to reflect that.
> ---
>  include/malloc.h                              |   1 +
>  malloc/hooks.c                                |  40 ++-
>  malloc/mtrace-hooks.c                         | 137 ++++++++++
>  malloc/mtrace.c                               | 233 +-----------------
>  sysdeps/generic/localplt.data                 |   1 -
>  sysdeps/mach/hurd/i386/localplt.data          |   1 -
>  sysdeps/unix/sysv/linux/aarch64/localplt.data |   1 -
>  sysdeps/unix/sysv/linux/alpha/localplt.data   |   1 -
>  sysdeps/unix/sysv/linux/arc/localplt.data     |   1 -
>  sysdeps/unix/sysv/linux/arm/localplt.data     |   1 -
>  sysdeps/unix/sysv/linux/csky/localplt.data    |   1 -
>  sysdeps/unix/sysv/linux/hppa/localplt.data    |   1 -
>  sysdeps/unix/sysv/linux/i386/localplt.data    |   1 -
>  sysdeps/unix/sysv/linux/ia64/localplt.data    |   1 -
>  .../sysv/linux/m68k/coldfire/localplt.data    |   1 -
>  .../unix/sysv/linux/m68k/m680x0/localplt.data |   1 -
>  .../unix/sysv/linux/microblaze/localplt.data  |   1 -
>  sysdeps/unix/sysv/linux/nios2/localplt.data   |   1 -
>  .../linux/powerpc/powerpc32/fpu/localplt.data |   1 -
>  .../powerpc/powerpc32/nofpu/localplt.data     |   1 -
>  .../linux/powerpc/powerpc64/localplt.data     |   1 -
>  sysdeps/unix/sysv/linux/riscv/localplt.data   |   1 -
>  sysdeps/unix/sysv/linux/s390/localplt.data    |   1 -
>  sysdeps/unix/sysv/linux/sh/localplt.data      |   1 -
>  .../sysv/linux/sparc/sparc32/localplt.data    |   1 -
>  .../sysv/linux/sparc/sparc64/localplt.data    |   1 -
>  sysdeps/x86_64/localplt.data                  |   1 -
>  27 files changed, 182 insertions(+), 252 deletions(-)
>  create mode 100644 malloc/mtrace-hooks.c
> 
> diff --git a/include/malloc.h b/include/malloc.h
> index bb1123d9d3..6169d486f5 100644
> --- a/include/malloc.h
> +++ b/include/malloc.h
> @@ -15,6 +15,7 @@ typedef struct malloc_state *mstate;
>  #define __malloc_initialized __libc_malloc_initialized
>  /* Nonzero if the malloc is already initialized.  */
>  extern int __malloc_initialized attribute_hidden;
> +extern FILE *__mtrace_mallstream attribute_hidden;
>  
>  enum mcheck_status __mcheck_checkptr (const void *) attribute_hidden;
>  extern int __mcheck_initialize (void (*) (enum mcheck_status), bool)
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 7b500e5671..7f3b07ca44 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -37,6 +37,7 @@ enum malloc_debug_hooks
>    MALLOC_NONE_HOOK = 0,
>    MALLOC_CHECK_HOOK = 1 << 0,	/* MALLOC_CHECK_ or glibc.malloc.check.  */
>    MALLOC_MCHECK_HOOK = 1 << 1,	/* mcheck()  */
> +  MALLOC_MTRACE_HOOK = 1 << 2,	/* mtrace()  */
>  };
>  static unsigned __malloc_debugging_hooks;
>  
> @@ -79,6 +80,7 @@ __malloc_debug_disable (enum malloc_debug_hooks flag)
>  
>  #include "malloc-check.c"
>  #include "mcheck-hooks.c"
> +#include "mtrace-hooks.c"
>  
>  static __always_inline bool
>  _malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
> @@ -111,8 +113,13 @@ _malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
>  static __always_inline void *
>  _malloc_debug_after (void *mem, size_t bytes, const void *address)
>  {
> -  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> -    mem = malloc_mcheck_after (mem, bytes);
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
> +    {
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> +	mem = malloc_mcheck_after (mem, bytes);
> +      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
> +	mem = malloc_mtrace_after (mem, bytes, address);
> +    }
>    return mem;
>  }
>  
> @@ -129,6 +136,8 @@ _free_debug_before (void **mem, const void *address)
>  
>    if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
> +      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
> +	free_mtrace (mem, address);
>        if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
>  	*mem = free_mcheck (*mem);
>        if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
> @@ -171,8 +180,13 @@ static __always_inline void *
>  _realloc_debug_after (void *mem, void *oldmem, size_t bytes, size_t oldsize,
>  		      const void *address)
>  {
> -  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> -    mem = realloc_mcheck_after (mem, oldmem, bytes, oldsize);
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
> +    {
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> +	mem = realloc_mcheck_after (mem, oldmem, bytes, oldsize);
> +      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
> +	mem = realloc_mtrace_after (mem, oldmem, bytes, address);
> +    }
>    return mem;
>  }
>  
> @@ -206,8 +220,13 @@ static __always_inline void *
>  _memalign_debug_after (void *mem, size_t alignment, size_t bytes,
>  		       const void *address)
>  {
> -  if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> -    mem = memalign_mcheck_after (mem, alignment, bytes);
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
> +    {
> +      if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
> +	mem = memalign_mcheck_after (mem, alignment, bytes);
> +      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
> +	mem = memalign_mtrace_after (mem, bytes, address);
> +    }
>    return mem;
>  }
>  
> @@ -244,11 +263,16 @@ _calloc_debug_before (size_t *bytesp, void **victimp, const void *address)
>  static __always_inline void *
>  _calloc_debug_after (void *mem, size_t bytes, const void *address)
>  {
> -  if (__glibc_unlikely (__malloc_debugging_hooks) && mem != NULL)
> +  if (__glibc_unlikely (__malloc_debugging_hooks))
>      {
>        if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
>  	mem = malloc_mcheck_after (mem, bytes);
> -      memset (mem, 0, bytes);
> +      if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK))
> +	mem = malloc_mtrace_after (mem, bytes, address);
> +      /* mtrace uses __libc_calloc to do the zeroing.  */
> +      if (mem != NULL && __is_malloc_debug_enabled (MALLOC_CHECK_HOOK
> +						    | MALLOC_MCHECK_HOOK))
> +	memset (mem, 0, bytes);
>      }
>    return mem;
>  }
> diff --git a/malloc/mtrace-hooks.c b/malloc/mtrace-hooks.c
> new file mode 100644
> index 0000000000..c1c6d6a6e9
> --- /dev/null
> +++ b/malloc/mtrace-hooks.c
> @@ -0,0 +1,137 @@
> +
> +# include <libc-lock.h>
> +
> +#include <kernel-features.h>
> +
> +FILE *__mtrace_mallstream;
> +
> +__libc_lock_define_initialized (static, lock);
> +
> +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 (__mtrace_mallstream, "@ %s%s%s[%p] ",
> +                   info->dli_fname ? : "", info->dli_fname ? ":" : "",
> +                   buf, caller);
> +        }
> +      else
> +        fprintf (__mtrace_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 bool
> +free_mtrace (void *ptr, const void *caller)
> +{
> +  if (ptr == NULL)
> +    return true;
> +
> +  Dl_info mem;
> +  Dl_info *info = lock_and_info (caller, &mem);
> +  tr_where (caller, info);
> +  /* Be sure to print it first.  */
> +  fprintf (__mtrace_mallstream, "- %p\n", ptr);
> +  __libc_lock_unlock (lock);
> +
> +  /* Continue on to free.  */
> +  return false;
> +}
> +
> +static void *
> +malloc_mtrace_after (void *block, size_t size, const void *caller)
> +{
> +  Dl_info mem;
> +  Dl_info *info = lock_and_info (caller, &mem);
> +
> +  tr_where (caller, info);
> +  /* We could be printing a NULL here; that's OK.  */
> +  fprintf (__mtrace_mallstream, "+ %p %#lx\n", block,
> +	   (unsigned long int) size);
> +
> +  __libc_lock_unlock (lock);
> +
> +  return block;
> +}
> +
> +static void *
> +realloc_mtrace_after (void *block, const void *oldptr, size_t size,
> +		      const void *caller)
> +{
> +  Dl_info mem;
> +  Dl_info *info = lock_and_info (caller, &mem);
> +
> +  tr_where (caller, info);
> +  if (block == NULL)
> +    {
> +      if (size != 0)
> +        /* Failed realloc.  */
> +        fprintf (__mtrace_mallstream, "! %p %#lx\n", oldptr,
> +		 (unsigned long int) size);
> +      else
> +        fprintf (__mtrace_mallstream, "- %p\n", oldptr);
> +    }
> +  else if (oldptr == NULL)
> +    fprintf (__mtrace_mallstream, "+ %p %#lx\n", block,
> +	     (unsigned long int) size);
> +  else
> +    {
> +      fprintf (__mtrace_mallstream, "< %p\n", oldptr);
> +      tr_where (caller, info);
> +      fprintf (__mtrace_mallstream, "> %p %#lx\n", block,
> +	       (unsigned long int) size);
> +    }
> +
> +  __libc_lock_unlock (lock);
> +
> +  return block;
> +}
> +
> +static void *
> +memalign_mtrace_after (void *block, size_t size, const void *caller)
> +{
> +  Dl_info mem;
> +  Dl_info *info = lock_and_info (caller, &mem);
> +
> +  tr_where (caller, info);
> +  /* We could be printing a NULL here; that's OK.  */
> +  fprintf (__mtrace_mallstream, "+ %p %#lx\n", block,
> +	   (unsigned long int) size);
> +
> +  __libc_lock_unlock (lock);
> +
> +  return block;
> +}
> diff --git a/malloc/mtrace.c b/malloc/mtrace.c
> index 6c2c58b706..2cc4507e25 100644
> --- a/malloc/mtrace.c
> +++ b/malloc/mtrace.c
> @@ -22,7 +22,6 @@
>  # define _MALLOC_INTERNAL
>  # include <malloc.h>
>  # include <mcheck.h>
> -# include <libc-lock.h>
>  #endif
>  
>  #include <dlfcn.h>
> @@ -35,20 +34,14 @@
>  
>  #include <libc-internal.h>
>  #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);
> +static const char mallenv[] = "MALLOC_TRACE";
>  
>  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
>  /* Compatibility symbols that were introduced to help break at allocation sites
> @@ -69,204 +62,6 @@ tr_break (void)
>  compat_symbol (libc, tr_break, tr_break, GLIBC_2_0);
>  #endif
>  
> -
> -/* 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 *);
> -
> -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 *, const void *);
> -static void * tr_mallochook (size_t, const void *);
> -static void * tr_reallochook (void *, size_t, const void *);
> -static void * tr_memalignhook (size_t, size_t, const void *);
> -
> -/* Set all the default non-trace hooks.  */
> -static __always_inline void
> -set_default_hooks (void)
> -{
> -  __free_hook = tr_old_free_hook;
> -  __malloc_hook = tr_old_malloc_hook;
> -  __realloc_hook = tr_old_realloc_hook;
> -  __memalign_hook = tr_old_memalign_hook;
> -}
> -
> -/* Set all of the tracing hooks used for mtrace.  */
> -static __always_inline void
> -set_trace_hooks (void)
> -{
> -  __free_hook = tr_freehook;
> -  __malloc_hook = tr_mallochook;
> -  __realloc_hook = tr_reallochook;
> -  __memalign_hook = tr_memalignhook;
> -}
> -
> -/* Save the current set of hooks as the default hooks.  */
> -static __always_inline void
> -save_default_hooks (void)
> -{
> -  tr_old_free_hook = __free_hook;
> -  tr_old_malloc_hook = __malloc_hook;
> -  tr_old_realloc_hook = __realloc_hook;
> -  tr_old_memalign_hook = __memalign_hook;
> -}
> -
> -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);
> -  set_default_hooks ();
> -  if (tr_old_free_hook != NULL)
> -    (*tr_old_free_hook)(ptr, caller);
> -  else
> -    free (ptr);
> -  set_trace_hooks ();
> -  __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);
> -
> -  set_default_hooks ();
> -  if (tr_old_malloc_hook != NULL)
> -    hdr = (void *) (*tr_old_malloc_hook)(size, caller);
> -  else
> -    hdr = (void *) malloc (size);
> -  set_trace_hooks ();
> -
> -  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);
> -
> -  return hdr;
> -}
> -
> -static void *
> -tr_reallochook (void *ptr, size_t size, const void *caller)
> -{
> -  void *hdr;
> -
> -  Dl_info mem;
> -  Dl_info *info = lock_and_info (caller, &mem);
> -
> -  set_default_hooks ();
> -  if (tr_old_realloc_hook != NULL)
> -    hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
> -  else
> -    hdr = (void *) realloc (ptr, size);
> -  set_trace_hooks ();
> -
> -  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);
> -
> -  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);
> -
> -  set_default_hooks ();
> -  if (tr_old_memalign_hook != NULL)
> -    hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
> -  else
> -    hdr = (void *) memalign (alignment, size);
> -  set_trace_hooks ();
> -
> -  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);
> -
> -  return hdr;
> -}
> -
> -
>  #ifdef _LIBC
>  
>  /* This function gets called to make sure all memory the library
> @@ -276,7 +71,7 @@ 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)
> +  if (__mtrace_mallstream != NULL)
>      __libc_freeres ();
>  }
>  #endif
> @@ -293,7 +88,7 @@ mtrace (void)
>    char *mallfile;
>  
>    /* Don't panic if we're called more than once.  */
> -  if (mallstream != NULL)
> +  if (__mtrace_mallstream != NULL)
>      return;
>  
>  #ifdef _LIBC
> @@ -310,15 +105,15 @@ mtrace (void)
>        if (mtb == NULL)
>          return;
>  
> -      mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
> -      if (mallstream != NULL)
> +      __mtrace_mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null",
> +				   "wce");
> +      if (__mtrace_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");
> -	  save_default_hooks ();
> -	  set_trace_hooks ();
> +          setvbuf (__mtrace_mallstream, malloc_trace_buffer, _IOFBF,
> +		   TRACE_BUFFER_SIZE);
> +          fprintf (__mtrace_mallstream, "= Start\n");
>  #ifdef _LIBC
>            if (!added_atexit_handler)
>              {
> @@ -336,15 +131,11 @@ mtrace (void)
>  void
>  muntrace (void)
>  {
> -  if (mallstream == NULL)
> +  if (__mtrace_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;
> -  set_default_hooks ();
> +  FILE *f = __mtrace_mallstream;
> +  __mtrace_mallstream = NULL;
>  
>    fprintf (f, "= End\n");
>    fclose (f);
> diff --git a/sysdeps/generic/localplt.data b/sysdeps/generic/localplt.data
> index e2083c0ce6..9b4f35786a 100644
> --- a/sysdeps/generic/localplt.data
> +++ b/sysdeps/generic/localplt.data
> @@ -4,7 +4,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/mach/hurd/i386/localplt.data b/sysdeps/mach/hurd/i386/localplt.data
> index 94064ecbc5..47fbe1e2a7 100644
> --- a/sysdeps/mach/hurd/i386/localplt.data
> +++ b/sysdeps/mach/hurd/i386/localplt.data
> @@ -6,7 +6,6 @@
>  libc.so: calloc + REL R_386_GLOB_DAT
>  libc.so: free + REL R_386_GLOB_DAT
>  libc.so: malloc + REL R_386_GLOB_DAT
> -libc.so: memalign + REL R_386_GLOB_DAT
>  libc.so: realloc + REL R_386_GLOB_DAT
>  libm.so: matherr + REL R_386_GLOB_DAT
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/aarch64/localplt.data b/sysdeps/unix/sysv/linux/aarch64/localplt.data
> index 2c14b652ef..348b3f3793 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/aarch64/localplt.data
> @@ -4,7 +4,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # If outline atomics are used, libgcc (built outside of glibc) may
> diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
> index 43f6fdaea1..44bf36f4f1 100644
> --- a/sysdeps/unix/sysv/linux/alpha/localplt.data
> +++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
> @@ -18,7 +18,6 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc + RELA R_ALPHA_GLOB_DAT
>  libc.so: free + RELA R_ALPHA_GLOB_DAT
>  libc.so: malloc + RELA R_ALPHA_GLOB_DAT
> -libc.so: memalign + RELA R_ALPHA_GLOB_DAT
>  libc.so: realloc + RELA R_ALPHA_GLOB_DAT
>  libm.so: matherr + RELA R_ALPHA_GLOB_DAT
>  # We used to offer inline functions that used this, so it must be exported.
> diff --git a/sysdeps/unix/sysv/linux/arc/localplt.data b/sysdeps/unix/sysv/linux/arc/localplt.data
> index 4479e8ee8a..ac5332caf7 100644
> --- a/sysdeps/unix/sysv/linux/arc/localplt.data
> +++ b/sysdeps/unix/sysv/linux/arc/localplt.data
> @@ -1,6 +1,5 @@
>  libc.so: realloc
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: calloc
>  libc.so: free
>  # At -Os, a struct assignment in libgcc-static pulls this in
> diff --git a/sysdeps/unix/sysv/linux/arm/localplt.data b/sysdeps/unix/sysv/linux/arm/localplt.data
> index eb315da2f1..78896444c6 100644
> --- a/sysdeps/unix/sysv/linux/arm/localplt.data
> +++ b/sysdeps/unix/sysv/linux/arm/localplt.data
> @@ -1,7 +1,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: raise
>  libc.so: realloc
>  libm.so: matherr
> diff --git a/sysdeps/unix/sysv/linux/csky/localplt.data b/sysdeps/unix/sysv/linux/csky/localplt.data
> index 0ed8650b65..817ab2659a 100644
> --- a/sysdeps/unix/sysv/linux/csky/localplt.data
> +++ b/sysdeps/unix/sysv/linux/csky/localplt.data
> @@ -4,7 +4,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  # The TLS-enabled version of these functions is interposed from libc.so.
>  ld.so: _dl_signal_error
> diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data
> index 09893d4dcf..baf857a750 100644
> --- a/sysdeps/unix/sysv/linux/hppa/localplt.data
> +++ b/sysdeps/unix/sysv/linux/hppa/localplt.data
> @@ -4,7 +4,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libc.so: __sigsetjmp
>  libc.so: _IO_funlockfile
> diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
> index 5334875b4b..f9bf7fb410 100644
> --- a/sysdeps/unix/sysv/linux/i386/localplt.data
> +++ b/sysdeps/unix/sysv/linux/i386/localplt.data
> @@ -4,7 +4,6 @@ libc.so: _Unwind_Find_FDE + REL R_386_GLOB_DAT
>  libc.so: calloc + REL R_386_GLOB_DAT
>  libc.so: free + REL R_386_GLOB_DAT
>  libc.so: malloc + REL R_386_GLOB_DAT
> -libc.so: memalign + REL R_386_GLOB_DAT
>  libc.so: realloc + REL R_386_GLOB_DAT
>  libm.so: matherr + REL R_386_GLOB_DAT
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/ia64/localplt.data b/sysdeps/unix/sysv/linux/ia64/localplt.data
> index 1c566a503e..174fb88128 100644
> --- a/sysdeps/unix/sysv/linux/ia64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/ia64/localplt.data
> @@ -1,7 +1,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  libm.so: matherrf
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
> index 3c5efb7204..42fa90508c 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/localplt.data
> @@ -2,7 +2,6 @@ libc.so: __m68k_read_tp
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
> index 843f4e25f2..34bd4c1aca 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/localplt.data
> @@ -3,7 +3,6 @@ libc.so: __m68k_read_tp
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/microblaze/localplt.data b/sysdeps/unix/sysv/linux/microblaze/localplt.data
> index 0e98d5251e..c3801314c9 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/localplt.data
> +++ b/sysdeps/unix/sysv/linux/microblaze/localplt.data
> @@ -2,7 +2,6 @@ libc.so: __errno_location
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The dynamic loader needs __tls_get_addr for TLS.
> diff --git a/sysdeps/unix/sysv/linux/nios2/localplt.data b/sysdeps/unix/sysv/linux/nios2/localplt.data
> index b37987c7c0..17fcfdd4db 100644
> --- a/sysdeps/unix/sysv/linux/nios2/localplt.data
> +++ b/sysdeps/unix/sysv/linux/nios2/localplt.data
> @@ -6,7 +6,6 @@ libc.so: __gedf2
>  libc.so: malloc
>  libc.so: __gtsf2 ?
>  libc.so: __nesf2
> -libc.so: memalign
>  libc.so: __mulsf3
>  libc.so: __floatunsisf
>  libc.so: __addsf3
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
> index a02dd5cc24..c0af84eef7 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/localplt.data
> @@ -2,7 +2,6 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
> index d8072597b7..581e54b95c 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/localplt.data
> @@ -30,7 +30,6 @@ libc.so: abort ?
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: memset ?
>  libc.so: realloc
>  libm.so: copysignl ?
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
> index bb498fbe3a..d69b7ae646 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/localplt.data
> @@ -1,7 +1,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/riscv/localplt.data b/sysdeps/unix/sysv/linux/riscv/localplt.data
> index 0a235592c3..e6d5330d5b 100644
> --- a/sysdeps/unix/sysv/linux/riscv/localplt.data
> +++ b/sysdeps/unix/sysv/linux/riscv/localplt.data
> @@ -4,7 +4,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: memset ?
>  libc.so: realloc
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/s390/localplt.data b/sysdeps/unix/sysv/linux/s390/localplt.data
> index a02dd5cc24..c0af84eef7 100644
> --- a/sysdeps/unix/sysv/linux/s390/localplt.data
> +++ b/sysdeps/unix/sysv/linux/s390/localplt.data
> @@ -2,7 +2,6 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/sh/localplt.data b/sysdeps/unix/sysv/linux/sh/localplt.data
> index 3225177c50..6491b9e37b 100644
> --- a/sysdeps/unix/sysv/linux/sh/localplt.data
> +++ b/sysdeps/unix/sysv/linux/sh/localplt.data
> @@ -4,7 +4,6 @@
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libc.so: _Unwind_Find_FDE
>  libc.so: _exit
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
> index be51efd566..38309a1393 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/localplt.data
> @@ -16,7 +16,6 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
> index 809062d46c..6a216f3a5a 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/localplt.data
> @@ -15,7 +15,6 @@ libc.so: _Unwind_Find_FDE
>  libc.so: calloc
>  libc.so: free
>  libc.so: malloc
> -libc.so: memalign
>  libc.so: realloc
>  libm.so: matherr
>  # The TLS-enabled version of these functions is interposed from libc.so.
> diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
> index 8f41e92870..d1f2e26612 100644
> --- a/sysdeps/x86_64/localplt.data
> +++ b/sysdeps/x86_64/localplt.data
> @@ -6,7 +6,6 @@
>  libc.so: calloc + RELA R_X86_64_GLOB_DAT
>  libc.so: free + RELA R_X86_64_GLOB_DAT
>  libc.so: malloc + RELA R_X86_64_GLOB_DAT
> -libc.so: memalign + RELA R_X86_64_GLOB_DAT
>  libc.so: realloc + RELA R_X86_64_GLOB_DAT
>  libm.so: matherr + RELA R_X86_64_GLOB_DAT
>  # The TLS-enabled version of these functions is interposed from libc.so.
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 08/10] Remove malloc hooks
  2021-07-02 18:48   ` Carlos O'Donell
@ 2021-07-02 19:06     ` Siddhesh Poyarekar
  0 siblings, 0 replies; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 19:06 UTC (permalink / raw)
  To: Carlos O'Donell, libc-alpha; +Cc: dj, fweimer

On 7/3/21 12:18 AM, Carlos O'Donell wrote:
> On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
>> Make malloc hooks symbols compat-only so that new applications cannot
>> link against them and remove the declarations from the API.  The
>> existing hooks variables are not used in the library anymore.
> 
> I *really* like the strategy of your approach calling __libc_malloc
> et. al. to avoid the dlopen problem and declare we only support glibc
> malloc. I think this patch is a winner, and you could move mtrace
> into this DSO, and rename it.
>   
>> Legacy applications that need hooks functionality need to preload a
>> new DSO libmalloc_compathooks.so, which interposes the libc malloc
>> functions to execute hooks if they exist.
> 
> ... and you could implement mtrace this way too without the ABI change.

Hmm, ok.

>> Also remove all references to the malloc hooks in the manual.  Mention
>> the removal in NEWS and also warn that libmalloc_compathooks.so is a
>> temporary measure and may be removed in a future version of glibc.
>>
>> memalign makes a comeback as a PLT reference since the initialization
>> hooks use them.  tst-mallocstate now needs libmalloc_compathooks.so
>> since it uses __malloc_initialize_hook to set up initial heap state to
>> emumate emacs.
> 
> This patch is broken, there are two tests which it references which
> don't exist.

Indeed, sorry, I forgot to git-add the tests :/  I'll fix that up.

> The hooks are a debug feature of this interposable debug malloc.
> 
> I think we should identify the library and the purpose e.g.
> 
> libc_malloc_debug.so
> 
> *cough* libtcmalloc_debug.so.4.5.6 *cough*

OK, I'll move all the debug hooks into the DSO.

/me wipes a tear as he says goodbye to malloc-check.

Siddhesh

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 04/10] malloc: Move malloc hook references to hooks.c
  2021-07-02 11:38 ` [PATCH v4 04/10] malloc: Move malloc hook references to hooks.c Siddhesh Poyarekar
@ 2021-07-02 19:07   ` Carlos O'Donell
  0 siblings, 0 replies; 35+ messages in thread
From: Carlos O'Donell @ 2021-07-02 19:07 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: dj, fweimer

On 7/2/21 7:38 AM, Siddhesh Poyarekar wrote:
> Make the core malloc code hooks free and instead only have entry
> points for _*_debug_before inline functions.
> 
> This also introduces the first (albeit very constrained) breakage for
> malloc hooks behaviour.  The hook variables no longer call
> ptmalloc_init, it is called directly on first invocation of an
> allocator function.  This breaks debugging hooks that may depend on
> overriding the hook symbols with their own implementations due to
> which ptmalloc_init is never called.  In other words, it breaks hooks
> users that use the malloc hooks to have their own implementation of
> malloc that is conflicting with glibc malloc, which is not the
> intended use of the hooks as documented.
> 
> None of the three debugging hooks in glibc depend on this behaviour
> and hence continue to work as before.  In any case, future patches
> that move the hooks out into their own layer ought to bring back this
> functionality.  As a result, the breakage will not be visible to the
> user in the end.

LGTM.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
 
> Reviewed-by: DJ Delorie <dj@redhat.com>
> ---
>  malloc/arena.c           |   2 -
>  malloc/hooks.c           | 110 ++++++++++++++++++++++++++++++++-------
>  malloc/malloc-internal.h |   1 +
>  malloc/malloc.c          |  85 ++++++++++--------------------
>  4 files changed, 119 insertions(+), 79 deletions(-)
> 
> diff --git a/malloc/arena.c b/malloc/arena.c
> index 7eb110445e..1861d20006 100644
> --- a/malloc/arena.c
> +++ b/malloc/arena.c
> @@ -44,8 +44,6 @@
>  
>  /***************************************************************************/
>  
> -#define top(ar_ptr) ((ar_ptr)->top)
> -
>  /* A heap is a single contiguous memory region holding (coalesceable)
>     malloc_chunks.  It is allocated with mmap() and always starts at an
>     address aligned to HEAP_MAX_SIZE.  */
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 57a9b55788..4960aafd08 100644
> --- a/malloc/hooks.c
> +++ b/malloc/hooks.c
> @@ -21,35 +21,107 @@
>     corrupt pointer is detected: do nothing (0), print an error message
>     (1), or call abort() (2). */
>  
> -/* Hooks for debugging versions.  The initial hooks just call the
> -   initialization routine, then do the normal work. */
> +/* Define and initialize the hook variables.  These weak definitions must
> +   appear before any use of the variables in a function (arena.c uses one).  */
> +#ifndef weak_variable
> +/* In GNU libc we want the hook variables to be weak definitions to
> +   avoid a problem with Emacs.  */
> +# define weak_variable weak_function
> +#endif
> +
> +/* Forward declarations.  */
> +
> +#if HAVE_MALLOC_INIT_HOOK
> +void (*__malloc_initialize_hook) (void) __attribute__ ((nocommon));
> +compat_symbol (libc, __malloc_initialize_hook,
> +	       __malloc_initialize_hook, GLIBC_2_0);
> +#endif
> +
> +void weak_variable (*__free_hook) (void *__ptr,
> +                                   const void *) = NULL;
> +void *weak_variable (*__malloc_hook)
> +  (size_t __size, const void *) = NULL;
> +void *weak_variable (*__realloc_hook)
> +  (void *__ptr, size_t __size, const void *) = NULL;
> +void *weak_variable (*__memalign_hook)
> +  (size_t __alignment, size_t __size, const void *) = NULL;
> +
> +static void ptmalloc_init (void);
>  
> -static void *
> -malloc_hook_ini (size_t sz, const void *caller)
> +#include "malloc-check.c"
> +
> +static __always_inline bool
> +_malloc_debug_before (size_t bytes, void **victimp, const void *address)
>  {
> -  __malloc_hook = NULL;
> -  ptmalloc_init ();
> -  return __libc_malloc (sz);
> +  _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
> +                  "PTRDIFF_MAX is not more than half of SIZE_MAX");
> +
> +  void *(*hook) (size_t, const void *)
> +    = atomic_forced_read (__malloc_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      *victimp = (*hook)(bytes, address);
> +      return true;
> +    }
> +  return false;
>  }
>  
> -static void *
> -realloc_hook_ini (void *ptr, size_t sz, const void *caller)
> +static __always_inline bool
> +_free_debug_before (void *mem, const void *address)
>  {
> -  __malloc_hook = NULL;
> -  __realloc_hook = NULL;
> -  ptmalloc_init ();
> -  return __libc_realloc (ptr, sz);
> +  void (*hook) (void *, const void *)
> +    = atomic_forced_read (__free_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      (*hook)(mem, address);
> +      return true;
> +    }
> +  return false;
>  }
>  
> -static void *
> -memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
> +static __always_inline bool
> +_realloc_debug_before (void *oldmem, size_t bytes, void **victimp,
> +			const void *address)
>  {
> -  __memalign_hook = NULL;
> -  ptmalloc_init ();
> -  return __libc_memalign (alignment, sz);
> +  void *(*hook) (void *, size_t, const void *) =
> +    atomic_forced_read (__realloc_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      *victimp = (*hook)(oldmem, bytes, address);
> +      return true;
> +    }
> +
> +  return false;
>  }
>  
> -#include "malloc-check.c"
> +static __always_inline bool
> +_memalign_debug_before (size_t alignment, size_t bytes, void **victimp,
> +			 const void *address)
> +{
> +  void *(*hook) (size_t, size_t, const void *) =
> +    atomic_forced_read (__memalign_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      *victimp = (*hook)(alignment, bytes, address);
> +      return true;
> +    }
> +  return false;
> +}
> +
> +static __always_inline bool
> +_calloc_debug_before (size_t bytes, void **victimp, const void *address)
> +{
> +  void *(*hook) (size_t, const void *) =
> +    atomic_forced_read (__malloc_hook);
> +  if (__builtin_expect (hook != NULL, 0))
> +    {
> +      *victimp = (*hook)(bytes, address);
> +      if (*victimp != NULL)
> +	memset (*victimp, 0, bytes);
> +      return true;
> +    }
> +  return false;
> +}
>  
>  #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
>  
> diff --git a/malloc/malloc-internal.h b/malloc/malloc-internal.h
> index 258f29584e..ee0f5697af 100644
> --- a/malloc/malloc-internal.h
> +++ b/malloc/malloc-internal.h
> @@ -61,6 +61,7 @@
>  /* The corresponding bit mask value.  */
>  #define MALLOC_ALIGN_MASK (MALLOC_ALIGNMENT - 1)
>  
> +#define top(ar_ptr) ((ar_ptr)->top)
>  
>  /* Called in the parent process before a fork.  */
>  void __malloc_fork_lock_parent (void) attribute_hidden;
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 0e2e1747e0..75ca6ec3f0 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -2013,30 +2013,6 @@ static void     malloc_consolidate (mstate);
>  # define weak_variable weak_function
>  #endif
>  
> -/* Forward declarations.  */
> -static void *malloc_hook_ini (size_t sz,
> -                              const void *caller) __THROW;
> -static void *realloc_hook_ini (void *ptr, size_t sz,
> -                               const void *caller) __THROW;
> -static void *memalign_hook_ini (size_t alignment, size_t sz,
> -                                const void *caller) __THROW;
> -
> -#if HAVE_MALLOC_INIT_HOOK
> -void (*__malloc_initialize_hook) (void) __attribute__ ((nocommon));
> -compat_symbol (libc, __malloc_initialize_hook,
> -	       __malloc_initialize_hook, GLIBC_2_0);
> -#endif
> -
> -void weak_variable (*__free_hook) (void *__ptr,
> -                                   const void *) = NULL;
> -void *weak_variable (*__malloc_hook)
> -  (size_t __size, const void *) = malloc_hook_ini;
> -void *weak_variable (*__realloc_hook)
> -  (void *__ptr, size_t __size, const void *)
> -  = realloc_hook_ini;
> -void *weak_variable (*__memalign_hook)
> -  (size_t __alignment, size_t __size, const void *)
> -  = memalign_hook_ini;
>  void weak_variable (*__after_morecore_hook) (void) = NULL;
>  
>  /* This function is called from the arena shutdown hook, to free the
> @@ -2065,6 +2041,9 @@ free_perturb (char *p, size_t n)
>  
>  #include <stap-probe.h>
>  
> +/* ----------------- Support for debugging hooks -------------------- */
> +#include "hooks.c"
> +
>  /* ------------------- Support for multiple arenas -------------------- */
>  #include "arena.c"
>  
> @@ -2425,10 +2404,6 @@ do_check_malloc_state (mstate av)
>  #endif
>  
>  
> -/* ----------------- Support for debugging hooks -------------------- */
> -#include "hooks.c"
> -
> -
>  /* ----------- Routines dealing with system allocation -------------- */
>  
>  /*
> @@ -3225,13 +3200,12 @@ __libc_malloc (size_t bytes)
>    mstate ar_ptr;
>    void *victim;
>  
> -  _Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
> -                  "PTRDIFF_MAX is not more than half of SIZE_MAX");
> +  if (__malloc_initialized < 0)
> +    ptmalloc_init ();
> +
> +  if (_malloc_debug_before (bytes, &victim, RETURN_ADDRESS (0)))
> +    return 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 USE_TCACHE
>    /* int_free also calls request2size, be careful to not pad twice.  */
>    size_t tbytes;
> @@ -3292,13 +3266,11 @@ __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 (_free_debug_before (mem, RETURN_ADDRESS (0)))
> +    return;
>  
>    if (mem == 0)                              /* free(0) has no effect */
>      return;
> @@ -3351,10 +3323,11 @@ __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_debug_before (oldmem, bytes, &newp, RETURN_ADDRESS (0)))
> +    return newp;
>  
>  #if REALLOC_ZERO_BYTES_FREES
>    if (bytes == 0 && oldmem != NULL)
> @@ -3490,6 +3463,9 @@ void *
>  __libc_memalign (size_t alignment, size_t bytes)
>  {
>    void *address = RETURN_ADDRESS (0);
> +  if (__malloc_initialized < 0)
> +    ptmalloc_init ();
> +
>    return _mid_memalign (alignment, bytes, address);
>  }
>  
> @@ -3499,10 +3475,8 @@ _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 (_memalign_debug_before (alignment, bytes, &p, address))
> +    return p;
>  
>    /* If we need less alignment than we give anyway, just relay to malloc.  */
>    if (alignment <= MALLOC_ALIGNMENT)
> @@ -3612,16 +3586,11 @@ __libc_calloc (size_t n, size_t elem_size)
>  
>    sz = bytes;
>  
> -  void *(*hook) (size_t, const void *) =
> -    atomic_forced_read (__malloc_hook);
> -  if (__builtin_expect (hook != NULL, 0))
> -    {
> -      mem = (*hook)(sz, RETURN_ADDRESS (0));
> -      if (mem == 0)
> -        return 0;
> +  if (__malloc_initialized < 0)
> +    ptmalloc_init ();
>  
> -      return memset (mem, 0, sz);
> -    }
> +  if (_calloc_debug_before (sz, &mem, RETURN_ADDRESS (0)))
> +    return mem;
>  
>    MAYBE_INIT_TCACHE ();
>  
> 


-- 
Cheers,
Carlos.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 00/10] Remove malloc hooks
  2021-07-02 19:05 ` [PATCH v4 00/10] Remove malloc hooks Carlos O'Donell
@ 2021-07-02 19:15   ` Siddhesh Poyarekar
  2021-07-02 19:33     ` Siddhesh Poyarekar
  0 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 19:15 UTC (permalink / raw)
  To: Carlos O'Donell, libc-alpha; +Cc: dj, fweimer

On 7/3/21 12:35 AM, Carlos O'Donell wrote:
> Thanks for working through this.
> 
> This is looking better but we need to discuss the mcheck status and
> dropping some of those interfaces, perhaps just deprecating libmcheck.a
> and moving the functionality into libc_malloc_debug.so. See further review.
> 
> I think we're almost done with a v4 review if we agree on direction.

Thanks, I'm kinda emotional about malloc-check since it's bailed me out 
a number of times when valgrind/asan couldn't, but I suppose moving it 
along with the other debugging features to a different DSO isn't that 
bad.  I'll keep them mostly weaned off the hooks but also move them to 
the DSO.  Since it's in the DSO, mcheck can continue using the 
__malloc_initialize_hook to run the first mcheck() and we don't need a 
new ABI.

I'll commit the first 4 patches (since they're source shuffling anyway) 
and make a v5 from the rest.  Can I take till about Monday night to post 
the next set?  I think it would be a pretty big security gain for us to 
finally move the debugging hooks out of the main library for 2.34.

Thanks,
Siddhesh

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 00/10] Remove malloc hooks
  2021-07-02 19:15   ` Siddhesh Poyarekar
@ 2021-07-02 19:33     ` Siddhesh Poyarekar
  0 siblings, 0 replies; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 19:33 UTC (permalink / raw)
  To: Siddhesh Poyarekar, Carlos O'Donell, libc-alpha; +Cc: fweimer

On 7/3/21 12:45 AM, Siddhesh Poyarekar via Libc-alpha wrote:
> I'll commit the first 4 patches (since they're source shuffling anyway) 

I only pushed the first 3.  I'll need the 4th one to make the next 
patchset cleaner now that we don't want any trace of debugging in the 
main malloc.

Siddhesh

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 11:38 ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Siddhesh Poyarekar
  2021-07-02 19:06   ` Carlos O'Donell
@ 2021-07-02 20:37   ` Tulio Magno Quites Machado Filho
  2021-07-02 20:42     ` Adhemerval Zanella
  2021-07-02 20:43     ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Florian Weimer
  1 sibling, 2 replies; 35+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2021-07-02 20:37 UTC (permalink / raw)
  To: Siddhesh Poyarekar, libc-alpha; +Cc: fweimer

Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:

> The variable and function pair appear to provide a way for users to
> set conditional breakpoints in mtrace when a specific address is
> returned by the allocator.  This can be achieved by using conditional
> breakpoints in gdb so it is redundant.  There is no documentation of
> this interface in the manual either, so it appears to have been a hack
> that got added to debug malloc.  Deprecate these symbols and do not
> call tr_break anymore.

I noticed new build failures on ppc64le after this patch when using GCC 8 and 9.

/tmp/ccg1QEe7.s: Assembler messages:
/tmp/ccg1QEe7.s: Error: `__SImallwatch_0' can't be equated to common symbol `mallwatch'

I can't reproduce the issue when using GCC 10 or newer.

-- 
Tulio Magno

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 20:37   ` Tulio Magno Quites Machado Filho
@ 2021-07-02 20:42     ` Adhemerval Zanella
  2021-07-02 20:46       ` Siddhesh Poyarekar
  2021-07-02 20:43     ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Florian Weimer
  1 sibling, 1 reply; 35+ messages in thread
From: Adhemerval Zanella @ 2021-07-02 20:42 UTC (permalink / raw)
  To: Tulio Magno Quites Machado Filho, Siddhesh Poyarekar, libc-alpha; +Cc: fweimer



On 02/07/2021 17:37, Tulio Magno Quites Machado Filho via Libc-alpha wrote:
> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
> 
>> The variable and function pair appear to provide a way for users to
>> set conditional breakpoints in mtrace when a specific address is
>> returned by the allocator.  This can be achieved by using conditional
>> breakpoints in gdb so it is redundant.  There is no documentation of
>> this interface in the manual either, so it appears to have been a hack
>> that got added to debug malloc.  Deprecate these symbols and do not
>> call tr_break anymore.
> 
> I noticed new build failures on ppc64le after this patch when using GCC 8 and 9.
> 
> /tmp/ccg1QEe7.s: Assembler messages:
> /tmp/ccg1QEe7.s: Error: `__SImallwatch_0' can't be equated to common symbol `mallwatch'
> 
> I can't reproduce the issue when using GCC 10 or newer.
> 

I think we will need to use __attribute__ ((nocommon)) on mallwatch.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 20:37   ` Tulio Magno Quites Machado Filho
  2021-07-02 20:42     ` Adhemerval Zanella
@ 2021-07-02 20:43     ` Florian Weimer
  2021-07-02 20:47       ` Siddhesh Poyarekar
  1 sibling, 1 reply; 35+ messages in thread
From: Florian Weimer @ 2021-07-02 20:43 UTC (permalink / raw)
  To: Tulio Magno Quites Machado Filho; +Cc: Siddhesh Poyarekar, libc-alpha

* Tulio Magno Quites Machado Filho:

> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
>
>> The variable and function pair appear to provide a way for users to
>> set conditional breakpoints in mtrace when a specific address is
>> returned by the allocator.  This can be achieved by using conditional
>> breakpoints in gdb so it is redundant.  There is no documentation of
>> this interface in the manual either, so it appears to have been a hack
>> that got added to debug malloc.  Deprecate these symbols and do not
>> call tr_break anymore.
>
> I noticed new build failures on ppc64le after this patch when using GCC 8 and 9.
>
> /tmp/ccg1QEe7.s: Assembler messages:
> /tmp/ccg1QEe7.s: Error: `__SImallwatch_0' can't be equated to common symbol `mallwatch'
>
> I can't reproduce the issue when using GCC 10 or newer.

Missing __attribute__ ((nocommon)).  GCC 10 defaults to -fno-common.

I plan to write a patch that builds glibc unconditionally with
-fno-common, then the attribute won't be needed even with older GCC.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 20:42     ` Adhemerval Zanella
@ 2021-07-02 20:46       ` Siddhesh Poyarekar
  2021-07-02 20:56         ` Tulio Magno Quites Machado Filho
  0 siblings, 1 reply; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 20:46 UTC (permalink / raw)
  To: Adhemerval Zanella, Tulio Magno Quites Machado Filho, libc-alpha; +Cc: fweimer

On 7/3/21 2:12 AM, Adhemerval Zanella wrote:
> 
> 
> On 02/07/2021 17:37, Tulio Magno Quites Machado Filho via Libc-alpha wrote:
>> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
>>
>>> The variable and function pair appear to provide a way for users to
>>> set conditional breakpoints in mtrace when a specific address is
>>> returned by the allocator.  This can be achieved by using conditional
>>> breakpoints in gdb so it is redundant.  There is no documentation of
>>> this interface in the manual either, so it appears to have been a hack
>>> that got added to debug malloc.  Deprecate these symbols and do not
>>> call tr_break anymore.
>>
>> I noticed new build failures on ppc64le after this patch when using GCC 8 and 9.
>>
>> /tmp/ccg1QEe7.s: Assembler messages:
>> /tmp/ccg1QEe7.s: Error: `__SImallwatch_0' can't be equated to common symbol `mallwatch'
>>
>> I can't reproduce the issue when using GCC 10 or newer.
>>
> 
> I think we will need to use __attribute__ ((nocommon)) on mallwatch.
> 

Thanks for looking into it Adhemerval.  Tulio, can you please check if 
that fixes the build and if it does, push a patch with that?  x86_64 
continues to build fine with the attribute.

Thanks,
Siddhesh

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 20:43     ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Florian Weimer
@ 2021-07-02 20:47       ` Siddhesh Poyarekar
  0 siblings, 0 replies; 35+ messages in thread
From: Siddhesh Poyarekar @ 2021-07-02 20:47 UTC (permalink / raw)
  To: Florian Weimer, Tulio Magno Quites Machado Filho; +Cc: libc-alpha

On 7/3/21 2:13 AM, Florian Weimer via Libc-alpha wrote:
> * Tulio Magno Quites Machado Filho:
> 
>> Siddhesh Poyarekar via Libc-alpha <libc-alpha@sourceware.org> writes:
>>
>>> The variable and function pair appear to provide a way for users to
>>> set conditional breakpoints in mtrace when a specific address is
>>> returned by the allocator.  This can be achieved by using conditional
>>> breakpoints in gdb so it is redundant.  There is no documentation of
>>> this interface in the manual either, so it appears to have been a hack
>>> that got added to debug malloc.  Deprecate these symbols and do not
>>> call tr_break anymore.
>>
>> I noticed new build failures on ppc64le after this patch when using GCC 8 and 9.
>>
>> /tmp/ccg1QEe7.s: Assembler messages:
>> /tmp/ccg1QEe7.s: Error: `__SImallwatch_0' can't be equated to common symbol `mallwatch'
>>
>> I can't reproduce the issue when using GCC 10 or newer.
> 
> Missing __attribute__ ((nocommon)).  GCC 10 defaults to -fno-common.
> 
> I plan to write a patch that builds glibc unconditionally with
> -fno-common, then the attribute won't be needed even with older GCC.

Ahh OK, that would do too.

Thanks,
Siddhesh

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 20:46       ` Siddhesh Poyarekar
@ 2021-07-02 20:56         ` Tulio Magno Quites Machado Filho
  2021-07-02 21:03           ` Florian Weimer
  0 siblings, 1 reply; 35+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2021-07-02 20:56 UTC (permalink / raw)
  To: Siddhesh Poyarekar, Adhemerval Zanella, libc-alpha; +Cc: fweimer

Siddhesh Poyarekar <siddhesh@sourceware.org> writes:

> Thanks for looking into it Adhemerval.  Tulio, can you please check if 
> that fixes the build and if it does, push a patch with that?  x86_64 
> continues to build fine with the attribute.

It does work!  I can push it indeed, but first...

> I plan to write a patch that builds glibc unconditionally with
> -fno-common, then the attribute won't be needed even with older GCC.

Florian, how is your plan on this?  Would you like me to push this patch first?

-- 
Tulio Magno

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break
  2021-07-02 20:56         ` Tulio Magno Quites Machado Filho
@ 2021-07-02 21:03           ` Florian Weimer
  2021-07-02 21:46             ` [COMMITTED] mtrace: Add attribute nocommon to mallwatch Tulio Magno Quites Machado Filho
  0 siblings, 1 reply; 35+ messages in thread
From: Florian Weimer @ 2021-07-02 21:03 UTC (permalink / raw)
  To: Tulio Magno Quites Machado Filho
  Cc: Siddhesh Poyarekar, Adhemerval Zanella, libc-alpha

* Tulio Magno Quites Machado Filho:

> Siddhesh Poyarekar <siddhesh@sourceware.org> writes:
>
>> Thanks for looking into it Adhemerval.  Tulio, can you please check if 
>> that fixes the build and if it does, push a patch with that?  x86_64 
>> continues to build fine with the attribute.
>
> It does work!  I can push it indeed, but first...
>
>> I plan to write a patch that builds glibc unconditionally with
>> -fno-common, then the attribute won't be needed even with older GCC.
>
> Florian, how is your plan on this?  Would you like me to push this
> patch first?

That patch is still weeks away and is probably 2.35 anyway.  Please go
ahead with the localized fix.

Thanks,
Florian


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [COMMITTED] mtrace: Add attribute nocommon to mallwatch
  2021-07-02 21:03           ` Florian Weimer
@ 2021-07-02 21:46             ` Tulio Magno Quites Machado Filho
  0 siblings, 0 replies; 35+ messages in thread
From: Tulio Magno Quites Machado Filho @ 2021-07-02 21:46 UTC (permalink / raw)
  To: libc-alpha; +Cc: Florian Weimer, Siddhesh Poyarekar, Adhemerval Zanella

Avoid compilation errors GCC versions that do not default to
-fno-common, e.g. GCC <= 9.

Fixes commit 00d28960c5388a582a0485e07629b553c32dde49 ("mtrace:
Deprecate mallwatch and tr_break").

Suggested-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Suggested-by: Florian Weimer <fweimer@redhat.com>
---
 malloc/mtrace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/malloc/mtrace.c b/malloc/mtrace.c
index 6c2c58b706..f5b8321c6b 100644
--- a/malloc/mtrace.c
+++ b/malloc/mtrace.c
@@ -59,7 +59,7 @@ __libc_lock_define_initialized (static, lock);
    case some applications ended up linking against them but they don't actually
    do anything anymore; not that they did much before anyway.  */
 
-void *mallwatch;
+void *mallwatch __attribute__ ((nocommon));
 compat_symbol (libc, mallwatch, mallwatch, GLIBC_2_0);
 
 void
-- 
2.31.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2021-07-02 21:47 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-02 11:38 [PATCH v4 00/10] Remove malloc hooks Siddhesh Poyarekar
2021-07-02 11:38 ` [PATCH v4 01/10] Drop source dependencies on hooks.c and arena.c Siddhesh Poyarekar
2021-07-02 12:12   ` Andreas Schwab
2021-07-02 19:06   ` Carlos O'Donell
2021-07-02 11:38 ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Siddhesh Poyarekar
2021-07-02 19:06   ` Carlos O'Donell
2021-07-02 20:37   ` Tulio Magno Quites Machado Filho
2021-07-02 20:42     ` Adhemerval Zanella
2021-07-02 20:46       ` Siddhesh Poyarekar
2021-07-02 20:56         ` Tulio Magno Quites Machado Filho
2021-07-02 21:03           ` Florian Weimer
2021-07-02 21:46             ` [COMMITTED] mtrace: Add attribute nocommon to mallwatch Tulio Magno Quites Machado Filho
2021-07-02 20:43     ` [PATCH v4 02/10] mtrace: Deprecate mallwatch and tr_break Florian Weimer
2021-07-02 20:47       ` Siddhesh Poyarekar
2021-07-02 11:38 ` [PATCH v4 03/10] Move glibc.malloc.check implementation into its own file Siddhesh Poyarekar
2021-07-02 19:06   ` Carlos O'Donell
2021-07-02 11:38 ` [PATCH v4 04/10] malloc: Move malloc hook references to hooks.c Siddhesh Poyarekar
2021-07-02 19:07   ` Carlos O'Donell
2021-07-02 11:38 ` [PATCH v4 05/10] glibc.malloc.check: Wean away from malloc hooks Siddhesh Poyarekar
2021-07-02 19:06   ` Carlos O'Donell
2021-07-02 11:38 ` [PATCH v4 06/10] mcheck: " Siddhesh Poyarekar
2021-07-02 18:34   ` Carlos O'Donell
2021-07-02 18:46     ` Siddhesh Poyarekar
2021-07-02 11:38 ` [PATCH v4 07/10] mtrace: " Siddhesh Poyarekar
2021-07-02 19:06   ` Carlos O'Donell
2021-07-02 11:38 ` [PATCH v4 08/10] Remove " Siddhesh Poyarekar
2021-07-02 18:48   ` Carlos O'Donell
2021-07-02 19:06     ` Siddhesh Poyarekar
2021-07-02 11:38 ` [PATCH v4 09/10] Remove __after_morecore_hook Siddhesh Poyarekar
2021-07-02 19:06   ` Carlos O'Donell
2021-07-02 11:38 ` [PATCH v4 10/10] Remove __morecore and __default_morecore Siddhesh Poyarekar
2021-07-02 19:06   ` Carlos O'Donell
2021-07-02 19:05 ` [PATCH v4 00/10] Remove malloc hooks Carlos O'Donell
2021-07-02 19:15   ` Siddhesh Poyarekar
2021-07-02 19:33     ` Siddhesh Poyarekar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).