[6/8] Remove malloc hooks
Checks
Commit Message
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.
---
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
Comments
Siddhesh Poyarekar <siddhesh@sourceware.org> writes:
> 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.
> diff --git a/Makeconfig b/Makeconfig
> index 407df9e6a1..991d6d3e99 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
New library, ok.
> diff --git a/NEWS b/NEWS
> index 536e80721a..8a7226aef2 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -68,6 +68,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.
> +
Ok.
> diff --git a/malloc/Makefile b/malloc/Makefile
> index f9433af880..7d07b94a03 100644
> --- a/malloc/Makefile
> +++ b/malloc/Makefile
> @@ -41,6 +41,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
Ok.
> -# Additional library.
> -extra-libs = libmemusage
> +# Additional libraries.
> +extra-libs = libmemusage libmalloc_compathooks
> extra-libs-others = $(extra-libs)
Ok.
> @@ -128,6 +129,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))
Ok.
> @@ -313,3 +317,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
Ok.
> 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;
> }
Ok.
> diff --git a/malloc/hooks.c b/malloc/hooks.c
> index 492e9aac63..cc9ffc8b63 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)
2_24? Not 2_34?
> 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
Ok.
> +#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
Ok. Why not free_hook?
> __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;
> - }
> -
Yay! Ok.
> @@ -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;
> - }
> -
Ok.
> @@ -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;
> - }
> -
Ok.
> @@ -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;
> - }
Ok.
> 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;
> - }
> -
Ok.
> 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);
Ok.
> +static size_t pagesize;
Ok.
> +/* 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)
Ok.
> +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)
Ok.
> +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)
Ok.
> +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)
Ok.
> +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)
Ok.
> +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)
Ok.
> +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)
Ok.
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index 5ea12d1d3b..16ad933c66 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
> -
> -
Ok.
> 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;
Ok.
> 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}
> -
> . . .
> -The @code{mcheck} function (@pxref{Heap Consistency Checking}) works by
> -installing such hooks.
> -
Ok.
> @@ -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.
> -
Ok.
> @@ -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{}}}
Ok.
> @@ -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.
Ok.
> @@ -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{}}}
Ok.
On 6/25/21 5:01 AM, DJ Delorie via Libc-alpha wrote:
>> diff --git a/malloc/hooks.c b/malloc/hooks.c
>> index 492e9aac63..cc9ffc8b63 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)
>
> 2_24? Not 2_34?
__malloc_initialize_hook was made compat in 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
>
> Ok.
>
>> +#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
>
> Ok. Why not free_hook?
free_hook started out as NULL, so there's no need to reset it. It also
cannot legitimately be the first malloc function to be called (except
with NULL, which is a nop anyway)
Siddhesh
@@ -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)) \
@@ -68,6 +68,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
@@ -41,6 +41,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 \
@@ -112,8 +113,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.
@@ -128,6 +129,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)
@@ -313,3 +317,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
@@ -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;
}
@@ -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;
- }
-
if (__glibc_unlikely (__malloc_debugging_hooks))
{
if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
new file mode 100644
@@ -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)
@@ -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
@@ -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;
@@ -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
@@ -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.
@@ -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.
@@ -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
@@ -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.
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
@@ -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
@@ -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.
@@ -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.
@@ -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.
@@ -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
@@ -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.
@@ -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 ?
@@ -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.
@@ -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.
@@ -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.
@@ -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
@@ -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.
@@ -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.
@@ -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.