@@ -1,3 +1,138 @@
+2018-06-29 DJ Delorie <dj@redhat.com>
+ Carlos O'Donell <carlos@redhat.com>
+
+ [BZ #23328]
+ * Makeconfig (built-modules): Add libmalloc-extras.
+ * NEWS: Describe deprecation of hooks.
+ * catgets/Makefile (tst-catgets-ENV): Preload libmalloc-extras.so.
+ * elf/Makefile (tests-special): Remove tst-leaks1-static-mem.out.
+ (noload-ENV): Preload libmalloc-extras.so.
+ ($(objpfx)tst-leaks1-static-mem.out): Remove.
+ (tst-leaks1-ENV): Likewise.
+ * iconvdata/Makefile (tst-loading-ENV): Likewise.
+ * include/stdlib.h: Remove __default_morecore prototype.
+ * intl/tst-gettext.sh: Preload libmalloc-extras.so.
+ * libio/Makefile (test-fmemopen-ENV): Likewise.
+ (tst-fopenloc-ENV): Likewise.
+ (tst-bz22415-ENV): Likewise.
+ * localedata/Makefile (tst-leaks-ENV): Likewise.
+ * malloc/Makefile (tests): Add tst-malloc-weak-usable.
+ (tests-static): Add tst-malloc-weak-usable-static.
+ Remove tst-malloc-usable-static.
+ [ifneq (no,$(have-tunables))] (tests-static): Remove
+ tst-malloc-usable-tunables-static.
+ (extra-libs): Add libmalloc-extras.
+ (libmalloc-extras-routines): Define.
+ (LDLIBS-libmalloc-extras.so): Define.
+ (LDFLAGS-malloc-extras.so): Define.
+ ($(objpfx)libmalloc-extras.so): Define.
+ (tst-mtrace-ENV): Preload libmalloc-extras.so.
+ (tst-malloc-usable-ENV): Likewise.
+ (tst-malloc-usable-tunables-ENV): Likewise.
+ (tst-malloc-weak-usable-ENV): Define.
+ (tst-malloc-weak-usable-static-ENV): Define.
+ (tst-dynarray-ENV): Likewise.
+ (tst-dynarray-fail-ENV): Likewise.
+ * malloc/Versions (libc.GLIBC_PRIVATE): Add __glibc_free_hook,
+ __glibc_malloc_hook, __glibc_realloc_hook, __glibc_memalign_hook,
+ __glibc_malloc_check_request, __glibC_malloc_check_enable.
+ * malloc/hooks.c: Define declrations for malloc_check,
+ free_check, realloc_check, and memalign_check.
+ (malloc_hook_ini): Call interposable API and use local hooks.
+ (realloc_hook_ini): Likewise.
+ (memalign_hook_ini): Likewise.
+ (__glibc_malloc_check_request): New global data.
+ (__malloc_check_init): Install but don't enable hooks.
+ (__glibc_malloc_check_enable): New function.
+ (mem2mem_check): Adjust comment.
+ (mem2chunk_check): Adjust comment.
+ (malloc_set_state): Use local hooks.
+ * malloc/malloc-extras.c: New file.
+ * malloc/malloc-hooks.h: Add prototypes for __glibc_free_hook,
+ __glibc_malloc_hook, __glibc_realloc_hook, __glibc_memalign_hook,
+ __glibc_malloc_check_request, __glibc_malloc_check_enable.
+ * malloc/malloc-internal.h: Add prototypes for __malloc_check_init,
+ __glibc_morecore.
+ * malloc/malloc.c: Remove prototypes for __default_morecore,
+ mem2mem_check, top_check, malloc_check, free_check, realloc_check, and
+ memalign_check.
+ (MORECORE): Call __glibc_morecore directly.
+ (__morecore): Declare as compat symbol conditional on
+ SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+ (__free_hook): Rename to...
+ (__glibc_free_hook): ...this. And declare as compat symbol
+ __free_hook conditional on
+ SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+ (__malloc_hook): Rename to...
+ (__glibc_malloc_hook): ...this. And declare as compat symbol
+ __malloc_hook conditional on
+ SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+ (__realloc_hook): Rename to...
+ (__glibc_realloc_hook): ...this. And declare as compat symbol
+ __glibc_realloc_hook conditional on
+ SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+ (__memalign_hook): Rename to...
+ (__glibc_memalign_hook): ...this. And declare as compat symbol
+ __glibc_memalign_hook conditional on
+ SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+ (__after_morecore_hook): Declare as compat symbol conditional on
+ SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+ (sysmalloc): Do not call __after_morecore_hook.
+ (systrim): Likewise.
+ (__libc_malloc): Call ptmalloc_init() and remove hook calls.
+ (__libc_free): Likewise.
+ (__libc_realloc): Likewise.
+ (__libc_calloc): Likewise.
+ (_mid_memaligin): Don't call __memalign_hook.
+ * malloc/malloc.h: Remove public hook declarations for __free_hook,
+ __malloc_hook, __realloc_hook, __memalign_hook, and
+ __after_morecore_hook. Remove delcaration of __default_morecore,
+ and __morecore.
+ * malloc/mcheck.c: Remove most code, leaving an empty implementation
+ of the APIs for mcheck_check_all, mcheck, mcheck_pedantic, and mprobe.
+ * malloc/morecore.c (__default_morecore): Rename to...
+ (__glibc_morecore): ...this. Define as compat symbol
+ __default_morecore conditional on
+ SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28).
+ * malloc/mtrace.c: Remove most code, leaving an empty implementation
+ of the APIs for mallwatch, tr_break, mtrace, and muntrace.
+ * malloc/tst-malloc-usable-static-tunables.c: Remove file.
+ * malloc/tst-malloc-usable-static.c: Remove file.
+ * malloc/tst-malloc-weak-usable-static.c: New file.
+ * malloc/tst-malloc-weak-usable.c: New file.
+ * malloc/tst-mtrace.sh: Preload libmalloc-extras.so.
+ * manual/memory.texi (Summary of Malloc): Remove "Hooks for Malloc".
+ (Hooks for Malloc): Remove.
+ (mcheck): Remove @mtasuconst{:malloc_hooks} safety not.
+ (mprobe): Likewise.
+ (mtrace): Likewise.
+ (muntrace): Likewise.
+ (Heap Consistency Checking): Document need for libmalloc-extra.so.
+ (Allocation Debugging): Likewise.
+ * misc/Makefile (tst-error1-ENV): Likewise.
+ (tst-allocate_once-ENV): Likewise.
+ * nptl/Makefile (tst-atfork2-ENV): Likewise.
+ (tst-stack3-ENV): Likewise.
+ * posix/Makefile (tst-fnmatch-ENV): Likewise.
+ (bug-regex2-ENV): Likewise.
+ (bug-regex14-ENV): Likewise.
+ (bug-regex21-ENV): Likewise.
+ (bug-regex31-ENV): Likewise.
+ (bug-regex36-ENV): Likewise.
+ (tst-vfork3-ENV): Likewise.
+ (tst-rxspencer-no-utf8-ENV): Likewise.
+ (tst-pcre-ENV): Likewise.
+ (tst-boost-ENV): Likewise.
+ (bug-ga2-ENV): Likewise.
+ (bug-glob2-ENV): Likewise.
+ (tst-glob-tilde-ENV): Likewise.
+ * posix/tst-vfork3.c (do_prepare): Unset LD_PRELOAD.
+ * resolv/Makefile (tst-leaks-ENV): Preload libmalloc-extras.so.
+ (tst-leaks2-ENV): Likewise.
+ (tst-resolv-res_ninit-ENV): Likewise.
+ * stdio-common/Makefile (tst-printf-bz18872-ENV): Likewise.
+ (tst-vfprintf-width-prec-ENV): Likewise.
+
2018-06-29 DJ Delorie <dj@redhat.com>
Carlos O'Donell <carlos@redhat.com>
@@ -929,7 +929,7 @@ libio-include = -I$(..)libio
built-modules = iconvprogs iconvdata ldconfig lddlibc4 libmemusage \
libSegFault libpcprofile librpcsvc locale-programs \
memusagestat nonlib nscd extramodules libnldbl libsupport \
- testsuite
+ testsuite libmalloc-extras
in-module = $(subst -,_,$(firstword $(libof-$(basename $(@F))) \
$(libof-$(<F)) \
@@ -58,6 +58,32 @@ Major new features:
Deprecated and removed features, and other changes affecting compatibility:
+* The malloc function redirection hooks for __free_hook, __malloc_hook,
+ __realloc_hook and __memalign_hook and their functionality has been
+ deprecated and is no longer available to newly compiled applications.
+ In addition the __morecore, __default_morecore, and
+ __after_morecore_hook which allow overriding some of the basic
+ allocation mechanisms in malloc have also been deprected and are no
+ longer available to newly compiled applications. Applications already
+ using these malloc hooks can continue to operate by prelodaing, via
+ LD_PRELOAD, the provided libmalloc-extras.so shared object. This
+ shared object implements a malloc interposer that provides all the
+ features previously provided by the hooks (with the exception of
+ __morcore and __after_morecore_hook which are unused). This includes
+ all of the functionality provided by mcheck, mcheck_check_pedantic,
+ mcheck_check_all, mprobe, MALLOC_CHECK_, mallopt's M_CHECK_ACTION set
+ to non-zero, mtrace and muntrace. The malloc hooks are deprecated
+ because they are not thread safe, pose a security risk, and impose
+ restrictions on the malloc internals which impact maintenance and
+ future performance enhancements. The entire malloc family of APIs
+ must be implemented by an interposing library, and partial
+ implementation using the hooks are no longer supported in libc.so.
+ Lastly, all of the functionality described here is no longer supported
+ for statically linked applications. In statically linked
+ applications, just like in legacy applications that don't preload
+ libmalloc-extras.so, the impacted APIs will do nothing, or return
+ appropriate error codes depending on their semantics.
+
* The nonstandard header files <libio.h> and <_G_config.h> are no longer
installed. Software that was using either header should be updated to
use standard <stdio.h> interfaces instead.
@@ -56,7 +56,8 @@ generated += tst-catgets.mtrace tst-catgets-mem.out
generated-dirs += de
-tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de MALLOC_TRACE=$(objpfx)tst-catgets.mtrace
+tst-catgets-ENV = NLSPATH="$(objpfx)%l/%N.cat" LANG=de MALLOC_TRACE=$(objpfx)tst-catgets.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
ifeq ($(run-built-tests),yes)
# This test just checks whether the program produces any error or not.
@@ -205,7 +205,7 @@ endif
tests += $(tests-execstack-$(have-z-execstack))
ifeq ($(run-built-tests),yes)
tests-special += $(objpfx)tst-leaks1-mem.out \
- $(objpfx)tst-leaks1-static-mem.out $(objpfx)noload-mem.out \
+ $(objpfx)noload-mem.out \
$(objpfx)tst-ldconfig-X.out
endif
tlsmod17a-suffixes = 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
@@ -812,7 +812,8 @@ $(objpfx)noload.out: $(objpfx)testobj5.so
$(objpfx)noload-mem.out: $(objpfx)noload.out
$(common-objpfx)malloc/mtrace $(objpfx)noload.mtrace > $@; \
$(evaluate-test)
-noload-ENV = MALLOC_TRACE=$(objpfx)noload.mtrace
+noload-ENV = MALLOC_TRACE=$(objpfx)noload.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
LDFLAGS-nodelete = -rdynamic
LDFLAGS-nodelmod1.so = -Wl,--enable-new-dtags,-z,nodelete
@@ -1227,11 +1228,15 @@ $(objpfx)tst-leaks1-mem.out: $(objpfx)tst-leaks1.out
$(evaluate-test)
$(objpfx)tst-leaks1-static: $(common-objpfx)dlfcn/libdl.a
-$(objpfx)tst-leaks1-static-mem.out: $(objpfx)tst-leaks1-static.out
- $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks1-static.mtrace > $@; \
- $(evaluate-test)
-tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace
+tst-leaks1-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
+# Static applications no longer support tracing. All of the hooks used
+# for tracing have been removed. However, we can still test that the
+# application runs using the existing API calls without crashing.
+# Note that there is no tst-leaks1-static-mem.out target which runs
+# mtrace in this case because no *.mtrace file would be generated, again
+# we are just testing that the application itself doesn't crash.
tst-leaks1-static-ENV = MALLOC_TRACE=$(objpfx)tst-leaks1-static.mtrace
$(objpfx)tst-addr1: $(libdl)
@@ -292,7 +292,8 @@ cpp-srcs-left := $(modules) $(generated-modules) $(libJIS-routines) \
lib := iconvdata
include $(patsubst %,$(..)libof-iterator.mk,$(cpp-srcs-left))
-tst-loading-ENV = MALLOC_TRACE=$(objpfx)tst-loading.mtrace
+tst-loading-ENV = MALLOC_TRACE=$(objpfx)tst-loading.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)mtrace-tst-loading.out: $(objpfx)tst-loading.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-loading.mtrace > $@; \
$(evaluate-test)
@@ -285,9 +285,6 @@ libc_hidden_proto (__qfcvt_r)
# define MB_CUR_MAX (_NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_MB_CUR_MAX))
# endif
-extern void *__default_morecore (ptrdiff_t) __THROW;
-libc_hidden_proto (__default_morecore)
-
struct abort_msg_s
{
unsigned int size;
@@ -50,6 +50,7 @@ msgfmt -o ${objpfx}domaindir/existing-locale/LC_TIME/existing-time-domain.mo \
${test_program_prefix_before_env} \
${run_program_env} \
MALLOC_TRACE=$malloc_trace \
+LD_PRELOAD=${common_objpfx}/malloc/libmalloc-extras.so \
LOCPATH=${objpfx}localedir:${common_objpfx}localedata \
${test_program_prefix_after_env} \
${objpfx}tst-gettext > ${objpfx}tst-gettext.out ${objpfx}domaindir
@@ -154,9 +154,12 @@ CFLAGS-tst_putwc.c += -DOBJPFX=\"$(objpfx)\"
tst_wprintf2-ARGS = "Some Text"
-test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace
-tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace
-tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace
+test-fmemopen-ENV = MALLOC_TRACE=$(objpfx)test-fmemopen.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
+tst-fopenloc-ENV = MALLOC_TRACE=$(objpfx)tst-fopenloc.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
+tst-bz22415-ENV = MALLOC_TRACE=$(objpfx)tst-bz22415.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
generated += test-fmemopen.mtrace test-fmemopen.check
generated += tst-fopenloc.mtrace tst-fopenloc.check
@@ -385,7 +385,8 @@ $(INSTALL-SUPPORTED-LOCALES): install-locales-dir
tst-setlocale-ENV = LC_ALL=ja_JP.EUC-JP
tst-wctype-ENV = LC_ALL=ja_JP.EUC-JP
-tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace
+tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace \
+ LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
$(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks.mtrace > $@; \
$(evaluate-test)
@@ -38,11 +38,12 @@ tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \
tst-malloc_info \
tst-malloc-too-large \
tst-malloc-stats-cancellation \
+ tst-malloc-weak-usable
tests-static := \
tst-interpose-static-nothread \
tst-interpose-static-thread \
- tst-malloc-usable-static \
+ tst-malloc-weak-usable-static
tests-internal := tst-mallocstate tst-scratch_buffer
@@ -54,7 +55,6 @@ tests-internal += \
ifneq (no,$(have-tunables))
tests += tst-malloc-usable-tunables
-tests-static += tst-malloc-usable-static-tunables
endif
tests += $(tests-static)
@@ -78,7 +78,7 @@ install-lib := libmcheck.a
non-lib.a := libmcheck.a
# Additional library.
-extra-libs = libmemusage
+extra-libs = libmemusage libmalloc-extras
extra-libs-others = $(extra-libs)
# Helper objects for some tests.
@@ -143,6 +143,11 @@ $(objpfx)memusagestat.o: sysincludes = # nothing
endif
endif
+libmalloc-extras-routines = malloc-extras
+LDLIBS-libmalloc-extras.so = $(shared-thread-library)
+LDFLAGS-malloc-extras.so = -Wl,-z,nodelete
+$(objpfx)libmalloc-extras.so: $(libdl)
+
# Another goal which can be used to override the configure decision.
.PHONY: do-memusagestat
do-memusagestat: $(objpfx)memusagestat
@@ -189,11 +194,14 @@ endif
endif
endif
+tst-mtrace-ENV = LD_PRELOAD=$(objpfx)libmalloc-extras.so
tst-mcheck-ENV = MALLOC_CHECK_=3
-tst-malloc-usable-ENV = MALLOC_CHECK_=3
-tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV)
-tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
-tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
+tst-malloc-usable-ENV = MALLOC_CHECK_=3 LD_PRELOAD=$(objpfx)libmalloc-extras.so
+tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \
+ LD_PRELOAD=$(objpfx)libmalloc-extras.so
+# Do not preload libmalloc-extras.so for tst-malloc-weak-usable* tests.
+tst-malloc-weak-usable-ENV = MALLOC_CHECK_=3
+tst-malloc-weak-usable-static-ENV = MALLOC_CHECK_=3
ifeq ($(experimental-malloc),yes)
CPPFLAGS-malloc.c += -DUSE_TCACHE=1
@@ -239,12 +247,14 @@ $(objpfx)tst-interpose-static-nothread: $(objpfx)tst-interpose-aux-nothread.o
$(objpfx)tst-interpose-static-thread: \
$(objpfx)tst-interpose-aux-thread.o $(static-thread-library)
-tst-dynarray-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray.mtrace
+tst-dynarray-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-dynarray-mem.out: $(objpfx)tst-dynarray.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray.mtrace > $@; \
$(evaluate-test)
-tst-dynarray-fail-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray-fail.mtrace
+tst-dynarray-fail-ENV = MALLOC_TRACE=$(objpfx)tst-dynarray-fail.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-dynarray-fail-mem.out: $(objpfx)tst-dynarray-fail.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-dynarray-fail.mtrace > $@; \
$(evaluate-test)
@@ -92,5 +92,13 @@ libc {
__libc_alloc_buffer_copy_bytes;
__libc_alloc_buffer_copy_string;
__libc_alloc_buffer_create_failure;
+
+ # Implementation of libmalloc-extras.so.
+ __glibc_free_hook;
+ __glibc_malloc_hook;
+ __glibc_realloc_hook;
+ __glibc_memalign_hook;
+ __glibc_malloc_check_request;
+ __glibc_malloc_check_enable;
}
}
@@ -21,46 +21,82 @@
corrupt pointer is detected: do nothing (0), print an error message
(1), or call abort() (2). */
+/* Forward declarations of the check functions for use by the hooks. */
+static void *malloc_check(size_t sz, const void *caller);
+static void free_check(void *mem, const void *caller);
+static void *realloc_check(void *oldmem, size_t bytes,
+ const void *caller);
+static void *memalign_check(size_t alignment, size_t bytes,
+ const void *caller);
+
/* Hooks for debugging versions. The initial hooks just call the
initialization routine, then do the normal work. */
static void *
malloc_hook_ini (size_t sz, const void *caller)
{
- __malloc_hook = NULL;
+ __glibc_malloc_hook = NULL;
ptmalloc_init ();
- return __libc_malloc (sz);
+ /* We can't call __libc_malloc because it doesn't support hooks; we
+ have to re-call the interposed malloc which does, if it's present
+ (which it should be, else we wouldn't get here in the first
+ place. */
+ return malloc (sz);
}
static void *
realloc_hook_ini (void *ptr, size_t sz, const void *caller)
{
- __malloc_hook = NULL;
- __realloc_hook = NULL;
+ __glibc_malloc_hook = NULL;
+ __glibc_realloc_hook = NULL;
ptmalloc_init ();
- return __libc_realloc (ptr, sz);
+ return realloc (ptr, sz);
}
static void *
memalign_hook_ini (size_t alignment, size_t sz, const void *caller)
{
- __memalign_hook = NULL;
+ __glibc_memalign_hook = NULL;
ptmalloc_init ();
- return __libc_memalign (alignment, sz);
+ return memalign (alignment, sz);
}
/* Whether we are using malloc checking. */
static int using_malloc_checking;
-/* Activate a standard set of debugging hooks. */
+/* In __malloc_check_init we do not enable checking, but we install
+ the hooks. The hooks are no longer used unless libmalloc-extras.so
+ is preloaded. Therefore we leave the hooks disabled until
+ the library tells us it has enabled them. The value is a simple
+ protocol, it starts 0, we install the check hooks and set it to 1,
+ the interposing implementation calls __glibc_malloc_check_enable
+ when ready, and we set using_malloc_checking to 1 and
+ __glibc_malloc_check_request to zero. That completes the transition
+ between libc.so and libmalloc-extras.so. */
+int __glibc_malloc_check_request;
+
+/* Install a standard set of debugging hooks. */
void
__malloc_check_init (void)
+{
+ /* Don't enable checking yet... */
+ using_malloc_checking = 0;
+ /* Request that libmalloc-extras.so enable checking once it has
+ been loaded. */
+ __glibc_malloc_check_request = 1;
+ __glibc_malloc_hook = malloc_check;
+ __glibc_free_hook = free_check;
+ __glibc_realloc_hook = realloc_check;
+ __glibc_memalign_hook = memalign_check;
+}
+
+/* Enable the installed debugging hooks.
+ Called from libmalloc-extras.so. */
+void
+__glibc_malloc_check_enable (void)
{
using_malloc_checking = 1;
- __malloc_hook = malloc_check;
- __free_hook = free_check;
- __realloc_hook = realloc_check;
- __memalign_hook = memalign_check;
+ __glibc_malloc_check_request = 0;
}
/* A simple, standard set of debugging hooks. Overhead is `only' one
@@ -109,8 +145,7 @@ malloc_check_get_size (mchunkptr p)
}
/* Instrument a chunk with overrun detector byte(s) and convert it
- into a user pointer with requested size req_sz. */
-
+ into a user pointer with requested size req_sz. */
static void *
mem2mem_check (void *ptr, size_t req_sz)
{
@@ -142,8 +177,7 @@ mem2mem_check (void *ptr, size_t req_sz)
}
/* Convert a pointer to be free()d or realloc()ed to a valid chunk
- pointer. If the provided pointer is not valid, return NULL. */
-
+ pointer. If the provided pointer is not valid, return NULL. */
static mchunkptr
mem2chunk_check (void *mem, unsigned char **magic_p)
{
@@ -453,10 +487,10 @@ malloc_set_state (void *msptr)
cannot be more than one thread when we reach this point. */
/* Disable the malloc hooks (and malloc checking). */
- __malloc_hook = NULL;
- __realloc_hook = NULL;
- __free_hook = NULL;
- __memalign_hook = NULL;
+ __glibc_malloc_hook = NULL;
+ __glibc_realloc_hook = NULL;
+ __glibc_free_hook = NULL;
+ __glibc_memalign_hook = NULL;
using_malloc_checking = 0;
/* Patch the dumped heap. We no longer try to integrate into the
new file mode 100644
@@ -0,0 +1,792 @@
+/* Provide malloc hook functionality outside of libc.
+ Copyright (C) 2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <atomic.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <malloc.h>
+#include <errno.h>
+#include <libintl.h>
+#include <stdarg.h>
+
+#include <libc-internal.h>
+
+#include "malloc-internal.h"
+#include "malloc-hooks.h"
+#include "mcheck.h"
+
+static void *(*next_malloc) (size_t) = NULL;
+static void (*next_free) (void *) = NULL;
+static void *(*next_realloc) (void *, size_t) = NULL;
+static void *(*next_calloc) (size_t, size_t) = NULL;
+static void *(*next_memalign) (size_t, size_t) = NULL;
+static size_t (*next_malloc_usable_size) (void *) = NULL;
+
+#define TRACE_BUFFER_SIZE 512
+
+static FILE *mallstream;
+static const char mallenv[] = "MALLOC_TRACE";
+static char *malloc_trace_buffer;
+
+__libc_lock_define_initialized (static, lock);
+
+#define TRACE_LOCK(caller, info) \
+ caller = RETURN_ADDRESS (0); \
+ dladdr (caller, &info); \
+ __libc_lock_lock (lock);
+
+#define TRACE_LOCK_N(caller, info) \
+ dladdr (caller, &info); \
+ __libc_lock_lock (lock);
+
+#define TRACE_UNLOCK() \
+ __libc_lock_unlock (lock);
+
+
+/*======================================================================*/
+/* mtrace support. */
+
+static void
+tr_where (const void *caller, Dl_info *info)
+{
+ if (caller != NULL)
+ {
+ if (info != NULL)
+ {
+ fprintf (mallstream, "@ %s%s",
+ info->dli_fname ? : "", info->dli_fname ? ":" : "");
+
+ if (info->dli_sname != NULL)
+ {
+ if (caller > (const void *) info->dli_saddr)
+ fprintf (mallstream, "(%s+0x%lx)", info->dli_sname,
+ (long unsigned)(caller - (const void *) info->dli_saddr));
+ else
+ fprintf (mallstream, "(%s-0x%lx)", info->dli_sname,
+ (long unsigned)((const void *) info->dli_saddr - caller));
+ }
+
+ fprintf (mallstream, "[%p] ", caller);
+ }
+ else
+ fprintf (mallstream, "@ [%p] ", caller);
+ }
+}
+
+
+/*======================================================================*/
+/* mcheck support. */
+
+/* Function to call when something awful happens. */
+static void (*abortfunc) (enum mcheck_status);
+
+static int __malloc_extras_initialized = 0;
+
+/* Arbitrary magical numbers. */
+#define MAGICWORD 0xfedabeeb
+#define MAGICFREE 0xd8675309
+#define MAGICBYTE ((char) 0xd7)
+#define MALLOCFLOOD ((char) 0x93)
+#define FREEFLOOD ((char) 0x95)
+
+struct hdr
+{
+ size_t size; /* Exact size requested by user. */
+ unsigned long int magic; /* Magic number to check header integrity. */
+ struct hdr *prev;
+ struct hdr *next;
+ void *block; /* Real block allocated, for memalign. */
+ unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
+};
+
+/* This is the beginning of the list of all memory blocks allocated.
+ It is only constructed if the pedantic testing is requested. */
+static struct hdr *root;
+
+static int mcheck_used;
+
+/* Nonzero if pedentic checking of all blocks is requested. */
+static int pedantic;
+
+static void
+flood (void *ptr, int val, size_t size)
+{
+ char *cp = ptr;
+ while (size--)
+ *cp++ = val;
+}
+
+static enum mcheck_status
+checkhdr (const struct hdr *hdr)
+{
+ enum mcheck_status status;
+
+ if (!mcheck_used)
+ /* Maybe the mcheck used is disabled? This happens when we find
+ an error and report it. */
+ return MCHECK_OK;
+
+ switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
+ {
+ default:
+ status = MCHECK_HEAD;
+ break;
+ case MAGICFREE:
+ status = MCHECK_FREE;
+ break;
+ case MAGICWORD:
+ if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
+ status = MCHECK_TAIL;
+ else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
+ status = MCHECK_HEAD;
+ else
+ status = MCHECK_OK;
+ break;
+ }
+ if (status != MCHECK_OK)
+ {
+ mcheck_used = 0;
+ (*abortfunc) (status);
+ mcheck_used = 1;
+ }
+ return status;
+}
+
+void
+mcheck_check_all (void)
+{
+ /* Walk through all the active blocks and test whether they were tampered
+ with. */
+ struct hdr *runp = root;
+
+ /* Temporarily turn off the checks. */
+ pedantic = 0;
+
+ while (runp != NULL)
+ {
+ (void) checkhdr (runp);
+
+ runp = runp->next;
+ }
+
+ /* Turn checks on again. */
+ pedantic = 1;
+}
+
+static void
+unlink_blk (struct hdr *ptr)
+{
+ if (ptr->next != NULL)
+ {
+ ptr->next->prev = ptr->prev;
+ ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
+ + (uintptr_t) ptr->next->next);
+ }
+ if (ptr->prev != NULL)
+ {
+ ptr->prev->next = ptr->next;
+ ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
+ + (uintptr_t) ptr->prev->next);
+ }
+ else
+ root = ptr->next;
+}
+
+static void
+link_blk (struct hdr *hdr)
+{
+ hdr->prev = NULL;
+ hdr->next = root;
+ root = hdr;
+ hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
+
+ /* And the next block. */
+ if (hdr->next != NULL)
+ {
+ hdr->next->prev = hdr;
+ hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
+ + (uintptr_t) hdr->next->next);
+ }
+}
+
+__attribute__ ((noreturn))
+static void
+mabort (enum mcheck_status status)
+{
+ const char *msg;
+ switch (status)
+ {
+ case MCHECK_OK:
+ msg = _ ("memory is consistent, library is buggy\n");
+ break;
+ case MCHECK_HEAD:
+ msg = _ ("memory clobbered before allocated block\n");
+ break;
+ case MCHECK_TAIL:
+ msg = _ ("memory clobbered past end of allocated block\n");
+ break;
+ case MCHECK_FREE:
+ msg = _ ("block freed twice\n");
+ break;
+ default:
+ msg = _ ("bogus mcheck_status, library is buggy\n");
+ break;
+ }
+ fprintf (stderr, "mcheck: %s", msg);
+ fflush (stderr);
+ abort ();
+}
+
+/* Memory barrier so that GCC does not optimize out the argument. */
+#define malloc_opt_barrier(x) \
+ ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
+
+int
+mcheck (void (*func) (enum mcheck_status))
+{
+ abortfunc = (func != NULL) ? func : &mabort;
+ setbuf (stdout, NULL);
+
+ /* These hooks may not be safely inserted if malloc is already in use. */
+ if (__malloc_extras_initialized <= 0 && !mcheck_used)
+ {
+ /* We call malloc () once here to ensure it is initialized. */
+ void *p = malloc (0);
+ p = realloc (p, 16);
+ void *p2 = memalign (4, 0);
+ /* GCC might optimize out the malloc/free pair without a barrier. */
+ p = malloc_opt_barrier (p);
+ p2 = malloc_opt_barrier (p2);
+ free (p);
+ free (p2);
+
+ mcheck_used = 1;
+ }
+
+ return mcheck_used ? 0 : -1;
+}
+
+int
+mcheck_pedantic (void (*func) (enum mcheck_status))
+{
+ int res = mcheck (func);
+ if (res == 0)
+ pedantic = 1;
+ return res;
+}
+
+enum mcheck_status
+mprobe (void *ptr)
+{
+ return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+}
+
+/* For these, a round/align of zero means "don't". */
+
+#define cfa() __builtin_return_address (0)
+
+#define MCHECK_PRE(size, align_ptr_to) \
+ if (mcheck_used) \
+ { \
+ if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1) - align_ptr_to) \
+ { \
+ __set_errno (ENOMEM); \
+ return NULL; \
+ } \
+ size += align_ptr_to; \
+ size += sizeof (struct hdr) + 1; \
+ }
+
+
+#define MCHECK_POST_NOFLOOD(ptr, original_size, align_to) \
+ if (mcheck_used) \
+ { \
+ void *block = (void *) ptr; \
+ struct hdr *hdr = (struct hdr *) block; \
+ ptr = (void *) (hdr + 1); \
+ if (align_to) \
+ { \
+ ptr = PTR_ALIGN_UP (ptr, align_to); \
+ hdr = (struct hdr *)ptr - 1; \
+ } \
+ hdr->size = original_size; \
+ link_blk (hdr); \
+ hdr->block = (void *) block; \
+ hdr->magic2 = (uintptr_t) block ^ MAGICWORD; \
+ ((char *) &hdr[1])[original_size] = MAGICBYTE; \
+ }
+
+
+#define MCHECK_POST(ptr, original_size, align_to) \
+ if (mcheck_used) \
+ { \
+ MCHECK_POST_NOFLOOD (ptr, original_size, align_to); \
+ flood (ptr, MALLOCFLOOD, original_size); \
+ }
+
+#define MCHECK_PREFREE(ptr) \
+ if (mcheck_used && ptr != NULL) \
+ { \
+ struct hdr *hdr = ((struct hdr *) ptr) - 1; \
+ checkhdr (hdr); \
+ hdr->magic = MAGICFREE; \
+ hdr->magic2 = MAGICFREE; \
+ unlink_blk (hdr); \
+ hdr->prev = hdr->next = NULL; \
+ flood (ptr, FREEFLOOD, hdr->size); \
+ ptr = hdr->block; \
+ }
+
+/*======================================================================*/
+/* mallwatch, hooks */
+
+/* Address to breakpoint on accesses to... */
+void *mallwatch = (void *) (-1);
+
+/* This function is called when the block being alloc'd, realloc'd, or
+ freed has an address matching the variable "mallwatch". In a debugger,
+ set "mallwatch" to the address of interest, then put a breakpoint on
+ tr_break. */
+
+extern void tr_break (void) __THROW;
+libc_hidden_proto (tr_break)
+void __attribute__ ((noinline))
+tr_break (void)
+{
+ /* Never optimize it away either. */
+ asm ("");
+}
+
+static int recursing = 0;
+
+/* Call a hook function FUNC, and if recusion is detected return
+ with value ERV. In addition we check for
+ __glibc_malloc_check_requested to see if the runtime is waiting
+ to know if the hooks are active and if malloc_usable_size can
+ use the more accurate checking sizes for chunks. */
+#define HOOK(func, erv) \
+ if (next_##func == NULL) \
+ { \
+ int r; \
+ r = atomic_load_acquire (&recursing); \
+ if (r) \
+ return erv; \
+ __typeof__ (next_##func) tmp; \
+ atomic_add (&recursing, 1); \
+ tmp = dlsym (RTLD_NEXT, #func); \
+ atomic_store_relaxed (&next_##func, tmp); \
+ if (tmp == NULL) \
+ abort (); \
+ atomic_add (&recursing, -1); \
+ atomic_store_relaxed (&__malloc_extras_initialized, 1); \
+ if (__glibc_malloc_check_request) \
+ __glibc_malloc_check_enable (); \
+ }
+
+void *
+malloc (size_t sz)
+{
+ void *rv;
+ size_t original_size = sz;
+ void *caller;
+ Dl_info info;
+
+ void *(*hook) (size_t, const void *)
+ = atomic_forced_read (__glibc_malloc_hook);
+ if (__builtin_expect (hook != NULL, 0))
+ return (*hook) (sz, RETURN_ADDRESS (0));
+
+ HOOK (malloc, NULL);
+
+ MCHECK_PRE (sz, 0);
+
+ rv = next_malloc (sz);
+
+ MCHECK_POST (rv, original_size, 0);
+
+ if (mallstream)
+ {
+ TRACE_LOCK (caller, info);
+ tr_where (caller, &info);
+ /* We could be printing a NULL here; that's OK. */
+ fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+ TRACE_UNLOCK ();
+ }
+
+ if (rv == mallwatch)
+ tr_break ();
+
+ return rv;
+}
+
+void
+free (void *ptr)
+{
+ void *caller;
+ Dl_info info;
+
+ if (ptr == NULL)
+ return;
+
+ void (*hook) (void *, const void *)
+ = atomic_forced_read (__glibc_free_hook);
+ if (__builtin_expect (hook != NULL, 0))
+ {
+ (*hook)(ptr, RETURN_ADDRESS (0));
+ return;
+ }
+
+ HOOK (free, );
+
+ if (mallstream && ptr)
+ {
+ TRACE_LOCK (caller, info);
+ tr_where (caller, &info);
+ /* We could be printing a NULL here; that's OK. */
+ fprintf (mallstream, "- %p\n", ptr);
+ TRACE_UNLOCK ();
+ }
+
+ if (ptr == mallwatch)
+ tr_break ();
+
+ MCHECK_PREFREE (ptr);
+
+ next_free (ptr);
+
+ return;
+}
+
+void *
+realloc (void *ptr, size_t sz)
+{
+ void *rv;
+ size_t original_size = sz;
+ void *caller;
+ Dl_info info;
+
+ void *(*hook) (void *, size_t, const void *) =
+ atomic_forced_read (__glibc_realloc_hook);
+ if (__builtin_expect (hook != NULL, 0))
+ return (*hook)(ptr, sz, RETURN_ADDRESS (0));
+
+ HOOK (realloc, NULL);
+
+ if (ptr == mallwatch)
+ tr_break ();
+
+ MCHECK_PREFREE (ptr);
+ MCHECK_PRE (sz, 0);
+
+ rv = next_realloc (ptr, sz);
+
+ MCHECK_POST (ptr, original_size, 0);
+
+ if (mallstream)
+ {
+ TRACE_LOCK (caller, info);
+ tr_where (caller, &info);
+
+ if (rv == NULL)
+ {
+ if (original_size != 0)
+ /* Failed realloc. */
+ fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) original_size);
+ else
+ fprintf (mallstream, "- %p\n", ptr);
+ }
+ else if (ptr == NULL)
+ fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+ else
+ {
+ fprintf (mallstream, "< %p\n", ptr);
+ tr_where (caller, &info);
+ fprintf (mallstream, "> %p %#lx\n", rv, (unsigned long int) original_size);
+ }
+
+ TRACE_UNLOCK ();
+ }
+
+ if (rv == mallwatch)
+ tr_break ();
+
+ return rv;
+}
+
+void *
+calloc (size_t sz1, size_t sz2)
+{
+ void *rv;
+ size_t original_size;
+ size_t sz = sz1 * sz2;
+ void *caller;
+ Dl_info info;
+
+#define HALF_INTERNAL_SIZE_T \
+ (((size_t) 1) << (8 * sizeof (size_t) / 2))
+ if (__builtin_expect ((sz1 | sz2) >= HALF_INTERNAL_SIZE_T, 0))
+ {
+ if (sz1 != 0 && sz / sz1 != sz2)
+ {
+ __set_errno (ENOMEM);
+ return 0;
+ }
+ }
+
+ original_size = sz;
+
+ void *(*hook) (size_t, const void *) =
+ atomic_forced_read (__glibc_malloc_hook);
+ if (__builtin_expect (hook != NULL, 0))
+ {
+ rv = (*hook)(sz, RETURN_ADDRESS (0));
+ if (rv == 0)
+ return 0;
+
+ memset (rv, 0, sz);
+
+ if (rv == mallwatch)
+ tr_break ();
+
+ return rv;
+ }
+
+ HOOK (calloc, NULL);
+
+ MCHECK_PRE (sz, 0);
+
+ rv = next_calloc (sz, 1);
+
+ MCHECK_POST_NOFLOOD (rv, sz, 0);
+
+ if (mallstream)
+ {
+ TRACE_LOCK (caller, info);
+ tr_where (caller, &info);
+ /* We could be printing a NULL here; that's OK. */
+ fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+ TRACE_UNLOCK ();
+ }
+
+ if (rv == mallwatch)
+ tr_break ();
+
+ return rv;
+}
+
+static void *
+memalign_common (size_t sz1, size_t sz2, void *caller)
+{
+ void *rv;
+ size_t original_size = sz2;
+ Dl_info info;
+
+ void *(*hook) (size_t, size_t, const void *) =
+ atomic_forced_read (__glibc_memalign_hook);
+ if (__builtin_expect (hook != NULL, 0))
+ return (*hook)(sz1, sz2, RETURN_ADDRESS (0));
+
+ HOOK (memalign, NULL);
+
+ MCHECK_PRE (sz2, sz1);
+
+ rv = next_memalign (sz1, sz2);
+
+ MCHECK_POST (rv, original_size, sz1);
+
+ if (mallstream)
+ {
+ TRACE_LOCK_N (caller, info);
+ tr_where (caller, &info);
+ /* We could be printing a NULL here; that's OK. */
+ fprintf (mallstream, "+ %p %#lx\n", rv, (unsigned long int) original_size);
+ TRACE_UNLOCK ();
+ }
+
+ if (rv == mallwatch)
+ tr_break ();
+
+ return rv;
+}
+
+void *
+memalign (size_t sz1, size_t sz2)
+{
+ return memalign_common (sz1, sz2, RETURN_ADDRESS (0));
+}
+
+int
+posix_memalign (void **memptr, size_t alignment, size_t size)
+{
+ void *rvptr;
+
+ /* Test whether the SIZE argument is valid. It must be a power of
+ two multiple of sizeof (void *). */
+ if (alignment % sizeof (void *) != 0
+ || !powerof2 (alignment / sizeof (void *))
+ || alignment == 0)
+ return EINVAL;
+
+ rvptr = memalign_common (alignment, size, RETURN_ADDRESS (0));
+
+ if (rvptr)
+ {
+ *memptr = rvptr;
+ return 0;
+ }
+
+ return ENOMEM;
+}
+
+static size_t remembered_pagesize = 0;
+
+static inline size_t
+pagesize (void)
+{
+ size_t rv = atomic_load_relaxed (&remembered_pagesize);
+ if (remembered_pagesize == 0)
+ {
+ rv = sysconf (_SC_PAGESIZE);
+ atomic_store_relaxed (&remembered_pagesize, rv);
+ }
+ return rv;
+}
+
+void *
+valloc (size_t sz)
+{
+ return memalign_common (sysconf (_SC_PAGESIZE), sz, RETURN_ADDRESS (0));
+}
+
+void *
+pvalloc (size_t sz)
+{
+ size_t rounded_bytes = ALIGN_UP (sz, pagesize ());
+ return memalign_common (pagesize (), rounded_bytes, RETURN_ADDRESS (0));
+}
+
+size_t
+malloc_usable_size (void *ptr)
+{
+ size_t rv;
+
+ HOOK (malloc_usable_size, 0);
+
+ if (!mcheck_used)
+ rv = next_malloc_usable_size (ptr);
+ else
+ {
+ struct hdr *hdr = (struct hdr *) ptr;
+ -- hdr;
+ rv = hdr->size;
+ }
+
+ return rv;
+}
+
+/*======================================================================*/
+
+/* This function gets called to make sure all memory the library
+ allocates get freed and so does not irritate the user when studying
+ the mtrace output. */
+static void
+release_libc_mem (void)
+{
+ /* Only call the free function if we still are running in mtrace mode. */
+ if (mallstream != NULL)
+ __libc_freeres ();
+}
+
+void
+mtrace (void)
+{
+ char *mallfile;
+ static int added_atexit_handler = 0;
+
+ /* Don't panic if we're called more than once. */
+ if (mallstream != NULL)
+ {
+ fprintf (mallstream, "= Restart?\n");
+ return;
+ }
+
+ mallfile = getenv (mallenv);
+ if (mallfile != NULL || mallwatch != NULL)
+ {
+ char *mtb = malloc (TRACE_BUFFER_SIZE);
+ if (mtb == NULL)
+ return;
+
+ mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
+ if (mallstream != NULL)
+ {
+ /* Be sure it doesn't malloc its buffer! */
+ malloc_trace_buffer = mtb;
+ setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
+ fprintf (mallstream, "= Start\n");
+
+ if (!added_atexit_handler)
+ {
+ added_atexit_handler = 1;
+ atexit ((void (*)(void))release_libc_mem);
+ }
+
+ }
+ else
+ free (mtb);
+ }
+}
+
+void
+muntrace (void)
+{
+ if (mallstream == NULL)
+ return;
+
+ /* Do the reverse of what done in mtrace: first reset the hooks and
+ MALLSTREAM, and only after that write the trailer and close the
+ file. */
+ FILE *f = mallstream;
+ mallstream = NULL;
+
+ fprintf (f, "= End\n");
+ fclose (f);
+}
+
+/*======================================================================*/
+/* user interface */
+
+void __attribute__ ((constructor))
+mtrace_extras_ctor (void)
+{
+ /* Enable checking if it was requested early. */
+ if (__glibc_malloc_check_request)
+ __glibc_malloc_check_enable ();
+}
+
+void __attribute__ ((destructor))
+mtrace_extras_dtor (void)
+{
+ if (mallstream)
+ {
+ __libc_freeres ();
+ fprintf (mallstream, "= Unload?\n");
+ }
+}
@@ -20,5 +20,13 @@
#define _MALLOC_HOOKS_H
void (*__malloc_initialize_hook) (void);
+extern void (* __glibc_free_hook) (void *__ptr, const void *);
+extern void *(* __glibc_malloc_hook)(size_t __size, const void *);
+extern void *(* __glibc_realloc_hook)(void *__ptr, size_t __size, const void *);
+extern void *(* __glibc_memalign_hook)(size_t __alignment, size_t __size, const void *);
+
+/* Private APIs for libmalloc-extras.so interaction with hooks. */
+extern int __glibc_malloc_check_request;
+void __glibc_malloc_check_enable (void);
#endif /* _MALLOC_HOOKS_H */
@@ -94,4 +94,8 @@ check_mul_overflow_size_t (size_t left, size_t right, size_t *result)
#endif
}
+void __malloc_check_init (void) __THROW attribute_hidden;
+
+void *__glibc_morecore (ptrdiff_t increment) attribute_hidden;
+
#endif /* _MALLOC_INTERNAL_H */
@@ -357,11 +357,12 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
/* Definition for getting more memory from the OS. */
-#define MORECORE (*__morecore)
+#define MORECORE (__glibc_morecore)
#define MORECORE_FAILURE 0
-void * __default_morecore (ptrdiff_t);
-void *(*__morecore)(ptrdiff_t) = __default_morecore;
-
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+void *(*__morecore)(ptrdiff_t) = __glibc_morecore;
+compat_symbol (libc, __morecore, __morecore, GLIBC_2_0);
+#endif
#include <string.h>
@@ -998,20 +999,11 @@ static void* _mid_memalign(size_t, size_t, void *);
static void malloc_printerr(const char *str) __attribute__ ((noreturn));
-static void* mem2mem_check(void *p, size_t sz);
-static void top_check(void);
static void munmap_chunk(mchunkptr p);
#if HAVE_MREMAP
static mchunkptr mremap_chunk(mchunkptr p, size_t new_size);
#endif
-static void* malloc_check(size_t sz, const void *caller);
-static void free_check(void* mem, const void *caller);
-static void* realloc_check(void* oldmem, size_t bytes,
- const void *caller);
-static void* memalign_check(size_t alignment, size_t bytes,
- const void *caller);
-
/* ------------------ MMAP support ------------------ */
@@ -1831,6 +1823,13 @@ static void malloc_consolidate (mstate);
# define weak_variable weak_function
#endif
+#if HAVE_MALLOC_INIT_HOOK
+void weak_variable (*__malloc_initialize_hook) (void) = NULL;
+compat_symbol (libc, __malloc_initialize_hook,
+ __malloc_initialize_hook, GLIBC_2_0);
+#endif
+
+
/* Forward declarations. */
static void *malloc_hook_ini (size_t sz,
const void *caller) __THROW;
@@ -1839,24 +1838,33 @@ static void *realloc_hook_ini (void *ptr, size_t sz,
static void *memalign_hook_ini (size_t alignment, size_t sz,
const void *caller) __THROW;
-#if HAVE_MALLOC_INIT_HOOK
-void weak_variable (*__malloc_initialize_hook) (void) = NULL;
-compat_symbol (libc, __malloc_initialize_hook,
- __malloc_initialize_hook, GLIBC_2_0);
-#endif
-void weak_variable (*__free_hook) (void *__ptr,
+void weak_variable (*__glibc_free_hook) (void *__ptr,
const void *) = NULL;
-void *weak_variable (*__malloc_hook)
+void *weak_variable (*__glibc_malloc_hook)
(size_t __size, const void *) = malloc_hook_ini;
-void *weak_variable (*__realloc_hook)
+void *weak_variable (*__glibc_realloc_hook)
(void *__ptr, size_t __size, const void *)
= realloc_hook_ini;
-void *weak_variable (*__memalign_hook)
+void *weak_variable (*__glibc_memalign_hook)
(size_t __alignment, size_t __size, const void *)
= memalign_hook_ini;
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
void weak_variable (*__after_morecore_hook) (void) = NULL;
+/* When building the shared library we include compat symbols for the
+ hooks. When building a static application we don't, but we also
+ don't define the hooks in any public header, so static applications
+ should not compile. */
+compat_symbol (libc, __glibc_free_hook, __free_hook, GLIBC_2_0);
+compat_symbol (libc, __glibc_malloc_hook, __malloc_hook, GLIBC_2_0);
+compat_symbol (libc, __glibc_realloc_hook, __realloc_hook, GLIBC_2_0);
+compat_symbol (libc, __glibc_memalign_hook, __memalign_hook, GLIBC_2_0);
+compat_symbol (libc, __after_morecore_hook, __after_morecore_hook, GLIBC_2_0);
+#endif
+
+
/* This function is called from the arena shutdown hook, to free the
thread cache (if it exists). */
static void tcache_thread_shutdown (void);
@@ -2474,14 +2482,7 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av)
LIBC_PROBE (memory_sbrk_more, 2, brk, size);
}
- if (brk != (char *) (MORECORE_FAILURE))
- {
- /* Call the `morecore' hook if necessary. */
- void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
- if (__builtin_expect (hook != NULL, 0))
- (*hook)();
- }
- else
+ if (brk == (char *) (MORECORE_FAILURE))
{
/*
If have mmap, try using it as a backup when MORECORE fails or
@@ -2618,13 +2619,6 @@ sysmalloc (INTERNAL_SIZE_T nb, mstate av)
correction = 0;
snd_brk = (char *) (MORECORE (0));
}
- else
- {
- /* Call the `morecore' hook if necessary. */
- void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
- if (__builtin_expect (hook != NULL, 0))
- (*hook)();
- }
}
/* handle non-contiguous cases */
@@ -2782,10 +2776,6 @@ systrim (size_t pad, mstate av)
*/
MORECORE (-extra);
- /* Call the `morecore' hook if necessary. */
- void (*hook) (void) = atomic_forced_read (__after_morecore_hook);
- if (__builtin_expect (hook != NULL, 0))
- (*hook)();
new_brk = (char *) (MORECORE (0));
LIBC_PROBE (memory_sbrk_less, 2, new_brk, extra);
@@ -3013,10 +3003,8 @@ __libc_malloc (size_t bytes)
mstate ar_ptr;
void *victim;
- void *(*hook) (size_t, const void *)
- = atomic_forced_read (__malloc_hook);
- if (__builtin_expect (hook != NULL, 0))
- return (*hook)(bytes, RETURN_ADDRESS (0));
+ if (__malloc_initialized < 0)
+ ptmalloc_init ();
#if USE_TCACHE
/* int_free also calls request2size, be careful to not pad twice. */
size_t tbytes;
@@ -3071,13 +3059,8 @@ __libc_free (void *mem)
mstate ar_ptr;
mchunkptr p; /* chunk corresponding to mem */
- void (*hook) (void *, const void *)
- = atomic_forced_read (__free_hook);
- if (__builtin_expect (hook != NULL, 0))
- {
- (*hook)(mem, RETURN_ADDRESS (0));
- return;
- }
+ if (__malloc_initialized < 0)
+ ptmalloc_init ();
if (mem == 0) /* free(0) has no effect */
return;
@@ -3117,10 +3100,8 @@ __libc_realloc (void *oldmem, size_t bytes)
void *newp; /* chunk to return */
- void *(*hook) (void *, size_t, const void *) =
- atomic_forced_read (__realloc_hook);
- if (__builtin_expect (hook != NULL, 0))
- return (*hook)(oldmem, bytes, RETURN_ADDRESS (0));
+ if (__malloc_initialized < 0)
+ ptmalloc_init ();
#if REALLOC_ZERO_BYTES_FREES
if (bytes == 0 && oldmem != NULL)
@@ -3246,11 +3227,6 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
mstate ar_ptr;
void *p;
- void *(*hook) (size_t, size_t, const void *) =
- atomic_forced_read (__memalign_hook);
- if (__builtin_expect (hook != NULL, 0))
- return (*hook)(alignment, bytes, address);
-
/* If we need less alignment than we give anyway, just relay to malloc. */
if (alignment <= MALLOC_ALIGNMENT)
return __libc_malloc (bytes);
@@ -3369,17 +3345,8 @@ __libc_calloc (size_t n, size_t elem_size)
}
}
- void *(*hook) (size_t, const void *) =
- atomic_forced_read (__malloc_hook);
- if (__builtin_expect (hook != NULL, 0))
- {
- sz = bytes;
- mem = (*hook)(sz, RETURN_ADDRESS (0));
- if (mem == 0)
- return 0;
-
- return memset (mem, 0, sz);
- }
+ if (__malloc_initialized < 0)
+ ptmalloc_init ();
sz = bytes;
@@ -71,14 +71,6 @@ extern void *valloc (size_t __size) __THROW __attribute_malloc__ __wur;
__size to nearest pagesize. */
extern void *pvalloc (size_t __size) __THROW __attribute_malloc__ __wur;
-/* Underlying allocation function; successive calls should return
- contiguous pieces of memory. */
-extern void *(*__morecore) (ptrdiff_t __size);
-
-/* Default value of `__morecore'. */
-extern void *__default_morecore (ptrdiff_t __size)
-__THROW __attribute_malloc__;
-
/* SVID2/XPG mallinfo structure */
struct mallinfo
@@ -139,23 +131,6 @@ extern void malloc_stats (void) __THROW;
/* Output information about state of allocator to stream FP. */
extern int malloc_info (int __options, FILE *__fp) __THROW;
-/* Hooks for debugging and user-defined versions. */
-extern void (*__MALLOC_HOOK_VOLATILE __free_hook) (void *__ptr,
- const void *)
-__MALLOC_DEPRECATED;
-extern void *(*__MALLOC_HOOK_VOLATILE __malloc_hook)(size_t __size,
- const void *)
-__MALLOC_DEPRECATED;
-extern void *(*__MALLOC_HOOK_VOLATILE __realloc_hook)(void *__ptr,
- size_t __size,
- const void *)
-__MALLOC_DEPRECATED;
-extern void *(*__MALLOC_HOOK_VOLATILE __memalign_hook)(size_t __alignment,
- size_t __size,
- const void *)
-__MALLOC_DEPRECATED;
-extern void (*__MALLOC_HOOK_VOLATILE __after_morecore_hook) (void);
-
/* Activate a standard set of debugging hooks. */
extern void __malloc_check_init (void) __THROW __MALLOC_DEPRECATED;
@@ -27,374 +27,19 @@
# include <errno.h>
#endif
-/* Old hook values. */
-static void (*old_free_hook)(void *ptr, const void *);
-static void *(*old_malloc_hook) (size_t size, const void *);
-static void *(*old_memalign_hook) (size_t alignment, size_t size,
- const void *);
-static void *(*old_realloc_hook) (void *ptr, size_t size,
- const void *);
-
-/* Function to call when something awful happens. */
-static void (*abortfunc) (enum mcheck_status);
-
-/* Arbitrary magical numbers. */
-#define MAGICWORD 0xfedabeeb
-#define MAGICFREE 0xd8675309
-#define MAGICBYTE ((char) 0xd7)
-#define MALLOCFLOOD ((char) 0x93)
-#define FREEFLOOD ((char) 0x95)
-
-struct hdr
-{
- size_t size; /* Exact size requested by user. */
- unsigned long int magic; /* Magic number to check header integrity. */
- struct hdr *prev;
- struct hdr *next;
- void *block; /* Real block allocated, for memalign. */
- unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
-};
-
-/* This is the beginning of the list of all memory blocks allocated.
- It is only constructed if the pedantic testing is requested. */
-static struct hdr *root;
-
-static int mcheck_used;
-
-/* Nonzero if pedentic checking of all blocks is requested. */
-static int pedantic;
-
-#if defined _LIBC || defined STDC_HEADERS || defined USG
-# include <string.h>
-# define flood memset
-#else
-static void flood (void *, int, size_t);
-static void
-flood (void *ptr, int val, size_t size)
-{
- char *cp = ptr;
- while (size--)
- *cp++ = val;
-}
-#endif
-
-static enum mcheck_status
-checkhdr (const struct hdr *hdr)
-{
- enum mcheck_status status;
-
- if (!mcheck_used)
- /* Maybe the mcheck used is disabled? This happens when we find
- an error and report it. */
- return MCHECK_OK;
-
- switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
- {
- default:
- status = MCHECK_HEAD;
- break;
- case MAGICFREE:
- status = MCHECK_FREE;
- break;
- case MAGICWORD:
- if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
- status = MCHECK_TAIL;
- else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
- status = MCHECK_HEAD;
- else
- status = MCHECK_OK;
- break;
- }
- if (status != MCHECK_OK)
- {
- mcheck_used = 0;
- (*abortfunc) (status);
- mcheck_used = 1;
- }
- return status;
-}
-
void
mcheck_check_all (void)
{
- /* Walk through all the active blocks and test whether they were tampered
- with. */
- struct hdr *runp = root;
-
- /* Temporarily turn off the checks. */
- pedantic = 0;
-
- while (runp != NULL)
- {
- (void) checkhdr (runp);
-
- runp = runp->next;
- }
-
- /* Turn checks on again. */
- pedantic = 1;
}
#ifdef _LIBC
libc_hidden_def (mcheck_check_all)
#endif
-static void
-unlink_blk (struct hdr *ptr)
-{
- if (ptr->next != NULL)
- {
- ptr->next->prev = ptr->prev;
- ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
- + (uintptr_t) ptr->next->next);
- }
- if (ptr->prev != NULL)
- {
- ptr->prev->next = ptr->next;
- ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
- + (uintptr_t) ptr->prev->next);
- }
- else
- root = ptr->next;
-}
-
-static void
-link_blk (struct hdr *hdr)
-{
- hdr->prev = NULL;
- hdr->next = root;
- root = hdr;
- hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
-
- /* And the next block. */
- if (hdr->next != NULL)
- {
- hdr->next->prev = hdr;
- hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
- + (uintptr_t) hdr->next->next);
- }
-}
-static void
-freehook (void *ptr, const void *caller)
-{
- if (pedantic)
- mcheck_check_all ();
- if (ptr)
- {
- struct hdr *hdr = ((struct hdr *) ptr) - 1;
- checkhdr (hdr);
- hdr->magic = MAGICFREE;
- hdr->magic2 = MAGICFREE;
- unlink_blk (hdr);
- hdr->prev = hdr->next = NULL;
- flood (ptr, FREEFLOOD, hdr->size);
- ptr = hdr->block;
- }
- __free_hook = old_free_hook;
- if (old_free_hook != NULL)
- (*old_free_hook)(ptr, caller);
- else
- free (ptr);
- __free_hook = freehook;
-}
-
-static void *
-mallochook (size_t size, const void *caller)
-{
- struct hdr *hdr;
-
- if (pedantic)
- mcheck_check_all ();
-
- if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
- {
- __set_errno (ENOMEM);
- return NULL;
- }
-
- __malloc_hook = old_malloc_hook;
- if (old_malloc_hook != NULL)
- hdr = (struct hdr *) (*old_malloc_hook)(sizeof (struct hdr) + size + 1,
- caller);
- else
- hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
- __malloc_hook = mallochook;
- if (hdr == NULL)
- return NULL;
-
- hdr->size = size;
- link_blk (hdr);
- hdr->block = hdr;
- hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
- ((char *) &hdr[1])[size] = MAGICBYTE;
- flood ((void *) (hdr + 1), MALLOCFLOOD, size);
- return (void *) (hdr + 1);
-}
-
-static void *
-memalignhook (size_t alignment, size_t size,
- const void *caller)
-{
- struct hdr *hdr;
- size_t slop;
- char *block;
-
- if (pedantic)
- mcheck_check_all ();
-
- slop = (sizeof *hdr + alignment - 1) & - alignment;
-
- if (size > ~((size_t) 0) - (slop + 1))
- {
- __set_errno (ENOMEM);
- return NULL;
- }
-
- __memalign_hook = old_memalign_hook;
- if (old_memalign_hook != NULL)
- block = (*old_memalign_hook)(alignment, slop + size + 1, caller);
- else
- block = memalign (alignment, slop + size + 1);
- __memalign_hook = memalignhook;
- if (block == NULL)
- return NULL;
-
- hdr = ((struct hdr *) (block + slop)) - 1;
-
- hdr->size = size;
- link_blk (hdr);
- hdr->block = (void *) block;
- hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
- ((char *) &hdr[1])[size] = MAGICBYTE;
- flood ((void *) (hdr + 1), MALLOCFLOOD, size);
- return (void *) (hdr + 1);
-}
-
-static void *
-reallochook (void *ptr, size_t size, const void *caller)
-{
- if (size == 0)
- {
- freehook (ptr, caller);
- return NULL;
- }
-
- struct hdr *hdr;
- size_t osize;
-
- if (pedantic)
- mcheck_check_all ();
-
- if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
- {
- __set_errno (ENOMEM);
- return NULL;
- }
-
- if (ptr)
- {
- hdr = ((struct hdr *) ptr) - 1;
- osize = hdr->size;
-
- checkhdr (hdr);
- unlink_blk (hdr);
- if (size < osize)
- flood ((char *) ptr + size, FREEFLOOD, osize - size);
- }
- else
- {
- osize = 0;
- hdr = NULL;
- }
- __free_hook = old_free_hook;
- __malloc_hook = old_malloc_hook;
- __memalign_hook = old_memalign_hook;
- __realloc_hook = old_realloc_hook;
- if (old_realloc_hook != NULL)
- hdr = (struct hdr *) (*old_realloc_hook)((void *) hdr,
- sizeof (struct hdr) + size + 1,
- caller);
- else
- hdr = (struct hdr *) realloc ((void *) hdr,
- sizeof (struct hdr) + size + 1);
- __free_hook = freehook;
- __malloc_hook = mallochook;
- __memalign_hook = memalignhook;
- __realloc_hook = reallochook;
- if (hdr == NULL)
- return NULL;
-
- hdr->size = size;
- link_blk (hdr);
- hdr->block = hdr;
- hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
- ((char *) &hdr[1])[size] = MAGICBYTE;
- if (size > osize)
- flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
- return (void *) (hdr + 1);
-}
-
-__attribute__ ((noreturn))
-static void
-mabort (enum mcheck_status status)
-{
- const char *msg;
- switch (status)
- {
- case MCHECK_OK:
- msg = _ ("memory is consistent, library is buggy\n");
- break;
- case MCHECK_HEAD:
- msg = _ ("memory clobbered before allocated block\n");
- break;
- case MCHECK_TAIL:
- msg = _ ("memory clobbered past end of allocated block\n");
- break;
- case MCHECK_FREE:
- msg = _ ("block freed twice\n");
- break;
- default:
- msg = _ ("bogus mcheck_status, library is buggy\n");
- break;
- }
-#ifdef _LIBC
- __libc_fatal (msg);
-#else
- fprintf (stderr, "mcheck: %s", msg);
- fflush (stderr);
- abort ();
-#endif
-}
-
-/* Memory barrier so that GCC does not optimize out the argument. */
-#define malloc_opt_barrier(x) \
- ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
int
mcheck (void (*func) (enum mcheck_status))
{
- abortfunc = (func != NULL) ? func : &mabort;
-
- /* These hooks may not be safely inserted if malloc is already in use. */
- if (__malloc_initialized <= 0 && !mcheck_used)
- {
- /* We call malloc() once here to ensure it is initialized. */
- void *p = malloc (0);
- /* GCC might optimize out the malloc/free pair without a barrier. */
- p = malloc_opt_barrier (p);
- free (p);
-
- old_free_hook = __free_hook;
- __free_hook = freehook;
- old_malloc_hook = __malloc_hook;
- __malloc_hook = mallochook;
- old_memalign_hook = __memalign_hook;
- __memalign_hook = memalignhook;
- old_realloc_hook = __realloc_hook;
- __realloc_hook = reallochook;
- mcheck_used = 1;
- }
-
- return mcheck_used ? 0 : -1;
+ return 0;
}
#ifdef _LIBC
libc_hidden_def (mcheck)
@@ -403,14 +48,11 @@ libc_hidden_def (mcheck)
int
mcheck_pedantic (void (*func) (enum mcheck_status))
{
- int res = mcheck (func);
- if (res == 0)
- pedantic = 1;
- return res;
+ return 0;
}
enum mcheck_status
mprobe (void *ptr)
{
- return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+ return MCHECK_DISABLED;
}
@@ -42,7 +42,7 @@ libc_hidden_proto (__sbrk)
and return the start of data space, or NULL on errors.
If INCREMENT is negative, shrink data space. */
void *
-__default_morecore (ptrdiff_t increment)
+__glibc_morecore (ptrdiff_t increment)
{
void *result = (void *) __sbrk (increment);
if (result == (void *) -1)
@@ -50,4 +50,6 @@ __default_morecore (ptrdiff_t increment)
return result;
}
-libc_hidden_def (__default_morecore)
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+compat_symbol (libc, __glibc_morecore, __default_morecore, GLIBC_2_0);
+#endif
@@ -37,30 +37,12 @@
#include <dso_handle.h>
#include <libio/iolibio.h>
-#define setvbuf(s, b, f, l) _IO_setvbuf (s, b, f, l)
-#define fwrite(buf, size, count, fp) _IO_fwrite (buf, size, count, fp)
#include <kernel-features.h>
-#define TRACE_BUFFER_SIZE 512
-
-static FILE *mallstream;
-static const char mallenv[] = "MALLOC_TRACE";
-static char *malloc_trace_buffer;
-
-__libc_lock_define_initialized (static, lock);
-
/* Address to breakpoint on accesses to... */
void *mallwatch;
-/* Old hook values. */
-static void (*tr_old_free_hook) (void *ptr, const void *);
-static void *(*tr_old_malloc_hook) (size_t size, const void *);
-static void *(*tr_old_realloc_hook) (void *ptr, size_t size,
- const void *);
-static void *(*tr_old_memalign_hook) (size_t __alignment, size_t __size,
- const void *);
-
/* This function is called when the block being alloc'd, realloc'd, or
freed has an address matching the variable "mallwatch". In a debugger,
set "mallwatch" to the address of interest, then put a breakpoint on
@@ -74,275 +56,20 @@ tr_break (void)
}
libc_hidden_def (tr_break)
-static void
-tr_where (const void *caller, Dl_info *info)
-{
- if (caller != NULL)
- {
- if (info != NULL)
- {
- char *buf = (char *) "";
- if (info->dli_sname != NULL)
- {
- size_t len = strlen (info->dli_sname);
- buf = alloca (len + 6 + 2 * sizeof (void *));
-
- buf[0] = '(';
- __stpcpy (_fitoa (caller >= (const void *) info->dli_saddr
- ? caller - (const void *) info->dli_saddr
- : (const void *) info->dli_saddr - caller,
- __stpcpy (__mempcpy (buf + 1, info->dli_sname,
- len),
- caller >= (void *) info->dli_saddr
- ? "+0x" : "-0x"),
- 16, 0),
- ")");
- }
-
- fprintf (mallstream, "@ %s%s%s[%p] ",
- info->dli_fname ? : "", info->dli_fname ? ":" : "",
- buf, caller);
- }
- else
- fprintf (mallstream, "@ [%p] ", caller);
- }
-}
-
-static Dl_info *
-lock_and_info (const void *caller, Dl_info *mem)
-{
- if (caller == NULL)
- return NULL;
-
- Dl_info *res = _dl_addr (caller, mem, NULL, NULL) ? mem : NULL;
-
- __libc_lock_lock (lock);
-
- return res;
-}
-
-static void
-tr_freehook (void *ptr, const void *caller)
-{
- if (ptr == NULL)
- return;
-
- Dl_info mem;
- Dl_info *info = lock_and_info (caller, &mem);
- tr_where (caller, info);
- /* Be sure to print it first. */
- fprintf (mallstream, "- %p\n", ptr);
- if (ptr == mallwatch)
- {
- __libc_lock_unlock (lock);
- tr_break ();
- __libc_lock_lock (lock);
- }
- __free_hook = tr_old_free_hook;
- if (tr_old_free_hook != NULL)
- (*tr_old_free_hook)(ptr, caller);
- else
- free (ptr);
- __free_hook = tr_freehook;
- __libc_lock_unlock (lock);
-}
-
-static void *
-tr_mallochook (size_t size, const void *caller)
-{
- void *hdr;
-
- Dl_info mem;
- Dl_info *info = lock_and_info (caller, &mem);
-
- __malloc_hook = tr_old_malloc_hook;
- if (tr_old_malloc_hook != NULL)
- hdr = (void *) (*tr_old_malloc_hook)(size, caller);
- else
- hdr = (void *) malloc (size);
- __malloc_hook = tr_mallochook;
-
- tr_where (caller, info);
- /* We could be printing a NULL here; that's OK. */
- fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
-
- __libc_lock_unlock (lock);
-
- if (hdr == mallwatch)
- tr_break ();
-
- return hdr;
-}
-
-static void *
-tr_reallochook (void *ptr, size_t size, const void *caller)
-{
- void *hdr;
-
- if (ptr == mallwatch)
- tr_break ();
-
- Dl_info mem;
- Dl_info *info = lock_and_info (caller, &mem);
-
- __free_hook = tr_old_free_hook;
- __malloc_hook = tr_old_malloc_hook;
- __realloc_hook = tr_old_realloc_hook;
- if (tr_old_realloc_hook != NULL)
- hdr = (void *) (*tr_old_realloc_hook)(ptr, size, caller);
- else
- hdr = (void *) realloc (ptr, size);
- __free_hook = tr_freehook;
- __malloc_hook = tr_mallochook;
- __realloc_hook = tr_reallochook;
-
- tr_where (caller, info);
- if (hdr == NULL)
- {
- if (size != 0)
- /* Failed realloc. */
- fprintf (mallstream, "! %p %#lx\n", ptr, (unsigned long int) size);
- else
- fprintf (mallstream, "- %p\n", ptr);
- }
- else if (ptr == NULL)
- fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
- else
- {
- fprintf (mallstream, "< %p\n", ptr);
- tr_where (caller, info);
- fprintf (mallstream, "> %p %#lx\n", hdr, (unsigned long int) size);
- }
-
- __libc_lock_unlock (lock);
-
- if (hdr == mallwatch)
- tr_break ();
-
- return hdr;
-}
-
-static void *
-tr_memalignhook (size_t alignment, size_t size, const void *caller)
-{
- void *hdr;
-
- Dl_info mem;
- Dl_info *info = lock_and_info (caller, &mem);
-
- __memalign_hook = tr_old_memalign_hook;
- __malloc_hook = tr_old_malloc_hook;
- if (tr_old_memalign_hook != NULL)
- hdr = (void *) (*tr_old_memalign_hook)(alignment, size, caller);
- else
- hdr = (void *) memalign (alignment, size);
- __memalign_hook = tr_memalignhook;
- __malloc_hook = tr_mallochook;
-
- tr_where (caller, info);
- /* We could be printing a NULL here; that's OK. */
- fprintf (mallstream, "+ %p %#lx\n", hdr, (unsigned long int) size);
-
- __libc_lock_unlock (lock);
-
- if (hdr == mallwatch)
- tr_break ();
-
- return hdr;
-}
-
-
-#ifdef _LIBC
-
-/* This function gets called to make sure all memory the library
- allocates get freed and so does not irritate the user when studying
- the mtrace output. */
-static void __libc_freeres_fn_section
-release_libc_mem (void)
-{
- /* Only call the free function if we still are running in mtrace mode. */
- if (mallstream != NULL)
- __libc_freeres ();
-}
-#endif
-
-
/* We enable tracing if either the environment variable MALLOC_TRACE
is set, or if the variable mallwatch has been patched to an address
that the debugging user wants us to stop on. When patching mallwatch,
- don't forget to set a breakpoint on tr_break! */
+ don't forget to set a breakpoint on tr_break! In all of these cases
+ we call mtrace() and that is interposed by libmalloc-extras.so. */
void
mtrace (void)
{
-#ifdef _LIBC
- static int added_atexit_handler;
-#endif
- char *mallfile;
-
- /* Don't panic if we're called more than once. */
- if (mallstream != NULL)
- return;
-
-#ifdef _LIBC
- /* When compiling the GNU libc we use the secure getenv function
- which prevents the misuse in case of SUID or SGID enabled
- programs. */
- mallfile = __libc_secure_getenv (mallenv);
-#else
- mallfile = getenv (mallenv);
-#endif
- if (mallfile != NULL || mallwatch != NULL)
- {
- char *mtb = malloc (TRACE_BUFFER_SIZE);
- if (mtb == NULL)
- return;
-
- mallstream = fopen (mallfile != NULL ? mallfile : "/dev/null", "wce");
- if (mallstream != NULL)
- {
- /* Be sure it doesn't malloc its buffer! */
- malloc_trace_buffer = mtb;
- setvbuf (mallstream, malloc_trace_buffer, _IOFBF, TRACE_BUFFER_SIZE);
- fprintf (mallstream, "= Start\n");
- tr_old_free_hook = __free_hook;
- __free_hook = tr_freehook;
- tr_old_malloc_hook = __malloc_hook;
- __malloc_hook = tr_mallochook;
- tr_old_realloc_hook = __realloc_hook;
- __realloc_hook = tr_reallochook;
- tr_old_memalign_hook = __memalign_hook;
- __memalign_hook = tr_memalignhook;
-#ifdef _LIBC
- if (!added_atexit_handler)
- {
- added_atexit_handler = 1;
- __cxa_atexit ((void (*)(void *))release_libc_mem, NULL,
- __dso_handle);
- }
-#endif
- }
- else
- free (mtb);
- }
+ return;
}
void
muntrace (void)
{
- if (mallstream == NULL)
- return;
-
- /* Do the reverse of what done in mtrace: first reset the hooks and
- MALLSTREAM, and only after that write the trailer and close the
- file. */
- FILE *f = mallstream;
- mallstream = NULL;
- __free_hook = tr_old_free_hook;
- __malloc_hook = tr_old_malloc_hook;
- __realloc_hook = tr_old_realloc_hook;
- __memalign_hook = tr_old_memalign_hook;
-
- fprintf (f, "= End\n");
- fclose (f);
+ return;
}
deleted file mode 100644
@@ -1 +0,0 @@
-#include <malloc/tst-malloc-usable.c>
deleted file mode 100644
@@ -1 +0,0 @@
-#include <malloc/tst-malloc-usable.c>
new file mode 100644
@@ -0,0 +1 @@
+#include <malloc/tst-malloc-weak-usable.c>
new file mode 100644
@@ -0,0 +1,60 @@
+/* Ensure that malloc_usable_size returns the request size with
+ MALLOC_CHECK_ exported to a positive value and no preloaded
+ libmalloc-extras.so.
+
+ Copyright (C) 2012-2018 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+/* In this test we are purposely not loading libmalloc-extras.so
+ to test that the malloc_usable_size() correctly falls back to
+ the chunk size, and does not try to parse the check data which
+ is not present. */
+
+static int
+do_test (void)
+{
+ size_t usable_size;
+ void *p = malloc (5);
+ if (!p)
+ {
+ printf ("memory allocation failed\n");
+ return 1;
+ }
+
+ usable_size = malloc_usable_size (p);
+
+ /* Set a reasonably wide test check here. The point is that
+ without the checking code we are going to get the chunk
+ size back, and that might vary by architecture in theory.
+ On a 64-bit arch it should be no larger than 32-bytes given
+ the present struct layout, and likely 24 bytes. */
+ if (usable_size < 5 || usable_size > 32)
+ {
+ printf ("malloc_usable_size: expected > 5 || < 32 but got %zu\n", usable_size);
+ return 1;
+ }
+
+ memset (p, 0, usable_size);
+ free (p);
+ return 0;
+}
+
+#include <support/test-driver.c>
@@ -30,6 +30,7 @@ trap "rm -f ${common_objpfx}malloc/tst-mtrace.leak; exit 1" 1 2 15
${test_program_prefix_before_env} \
${run_program_env} \
MALLOC_TRACE=${common_objpfx}malloc/tst-mtrace.leak \
+LD_PRELOAD=${common_objpfx}/malloc/libmalloc-extras.so \
${test_program_prefix_after_env} \
${common_objpfx}malloc/tst-mtrace || status=1
@@ -328,8 +328,6 @@ any time (or never).
* Malloc Tunable Parameters:: Use @code{mallopt} to adjust allocation
parameters.
* Heap Consistency Checking:: Automatic checking for errors.
-* Hooks for Malloc:: You can use these hooks for debugging
- programs that use @code{malloc}.
* Statistics of Malloc:: Getting information about how much
memory your program is using.
* Summary of Malloc:: Summary of @code{malloc} and related functions.
@@ -347,21 +345,21 @@ this function is in @file{stdlib.h}.
@standards{ISO, malloc.h}
@standards{ISO, stdlib.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asulock{}}@acunsafe{@aculock{} @acsfd{} @acsmem{}}}
-@c Malloc hooks and __morecore pointers, as well as such parameters as
-@c max_n_mmaps and max_mmapped_mem, are accessed without guards, so they
-@c could pose a thread safety issue; in order to not declare malloc
-@c MT-unsafe, it's modifying the hooks and parameters while multiple
-@c threads are active that is regarded as unsafe. An arena's next field
-@c is initialized and never changed again, except for main_arena's,
-@c that's protected by list_lock; next_free is only modified while
-@c list_lock is held too. All other data members of an arena, as well
-@c as the metadata of the memory areas assigned to it, are only modified
-@c while holding the arena's mutex (fastbin pointers use catomic ops
-@c because they may be modified by free without taking the arena's
-@c lock). Some reassurance was needed for fastbins, for it wasn't clear
-@c how they were initialized. It turns out they are always
-@c zero-initialized: main_arena's, for being static data, and other
-@c arena's, for being just-mmapped memory.
+
+@c Malloc parameters such as max_n_mmaps and max_mmapped_mem, are
+@c accessed without guards, so they could pose a thread safety issue; in
+@c order to not declare malloc MT-unsafe, it's modifying the hooks and
+@c parameters while multiple threads are active that is regarded as
+@c unsafe. An arena's next field is initialized and never changed
+@c again, except for main_arena's, that's protected by list_lock;
+@c next_free is only modified while list_lock is held too. All other
+@c data members of an arena, as well as the metadata of the memory areas
+@c assigned to it, are only modified while holding the arena's mutex
+@c (fastbin pointers use catomic ops because they may be modified by
+@c free without taking the arena's lock). Some reassurance was needed
+@c for fastbins, for it wasn't clear how they were initialized. It
+@c turns out they are always zero-initialized: main_arena's, for being
+@c static data, and other arena's, for being just-mmapped memory.
@c Leaking file descriptors and memory in case of cancellation is
@c unavoidable without disabling cancellation, but the lock situation is
@@ -375,7 +373,6 @@ this function is in @file{stdlib.h}.
@c __libc_malloc @asulock @aculock @acsfd @acsmem
@c force_reg ok
-@c *malloc_hook unguarded
@c arena_lock @asulock @aculock @acsfd @acsmem
@c mutex_lock @asulock @aculock
@c arena_get2 @asulock @aculock @acsfd @acsmem
@@ -506,11 +503,8 @@ this function is in @file{stdlib.h}.
@c set_foot dup ok
@c contiguous ok
@c MORECORE ok
-@c *__morecore ok unguarded
-@c __default_morecore
@c sbrk ok
@c force_reg dup ok
-@c *__after_morecore_hook unguarded
@c set_noncontiguous ok
@c malloc_printerr dup ok
@c _int_free (have_lock) @acsfd @acsmem [@asulock @aculock]
@@ -543,7 +537,6 @@ this function is in @file{stdlib.h}.
@c malloc_consolidate dup ok
@c systrim ok
@c MORECORE dup ok
-@c *__after_morecore_hook dup unguarded
@c set_head dup ok
@c check_malloc_state ok/disabled
@c top dup ok
@@ -695,7 +688,6 @@ The prototype for this function is in @file{stdlib.h}.
@c each gets a signal whose handler free()s large (non-fastbin-able)
@c blocks from each other's arena, we deadlock; this is a more general
@c case of @asulock.
-@c *__free_hook unguarded
@c mem2chunk ok
@c chunk_is_mmapped ok, chunk bits not modified after allocation
@c chunksize ok
@@ -764,7 +756,6 @@ You can make the block longer by calling @code{realloc} or
@c issues arise, plus the realloc hook, also accessed without guards.
@c __libc_realloc @asulock @aculock @acsfd @acsmem
-@c *__realloc_hook unguarded
@c __libc_free dup @asulock @aculock @acsfd @acsmem
@c __libc_malloc dup @asulock @aculock @acsfd @acsmem
@c mem2chunk dup ok
@@ -885,7 +876,6 @@ is declared in @file{stdlib.h}.
@c Same caveats as malloc.
@c __libc_calloc @asulock @aculock @acsfd @acsmem
-@c *__malloc_hook dup unguarded
@c memset dup ok
@c arena_get @asulock @aculock @acsfd @acsmem
@c arena_lock dup @asulock @aculock @acsfd @acsmem
@@ -967,7 +957,6 @@ portability to modern non-POSIX systems than @code{posix_memalign}.
@c _int_memalign, with the arena still locked.
@c __libc_memalign @asulock @aculock @acsfd @acsmem
-@c *__memalign_hook dup unguarded
@c __libc_malloc dup @asulock @aculock @acsfd @acsmem
@c arena_get dup @asulock @aculock @acsfd @acsmem
@c _int_memalign @acsfd @acsmem
@@ -1056,9 +1045,7 @@ systems that do not support @w{ISO C11}.
@c next_env_entry ok
@c strcspn dup ok
@c __libc_mallopt dup @mtasuconst:mallopt [setting mp_]
-@c __malloc_check_init @mtasuconst:malloc_hooks [setting hooks]
@c *__malloc_initialize_hook unguarded, ok
-@c *__memalign_hook dup ok, unguarded
@c arena_get dup @asulock @aculock @acsfd @acsmem
@c _int_valloc @acsfd @acsmem
@c malloc_consolidate dup ok
@@ -1206,9 +1193,13 @@ using the @code{mcheck} function. This function is a GNU extension,
declared in @file{mcheck.h}.
@pindex mcheck.h
+The functionality associated with @code{MALLOC_CHECK_} or @code{mcheck}
+is disabled by default. To enable the functionality you must preload
+the @code{libmalloc-extras.so} library.
+
@deftypefun int mcheck (void (*@var{abortfn}) (enum mcheck_status @var{status}))
@standards{GNU, mcheck.h}
-@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck} @mtasuconst{:malloc_hooks}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
+@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
@c The hooks must be set up before malloc is first used, which sort of
@c implies @mtuinit/@asuinit but since the function is a no-op if malloc
@c was already used, that doesn't pose any safety issues. The actual
@@ -1261,7 +1252,7 @@ must be called before the first such function.
@end deftypefun
@deftypefun {enum mcheck_status} mprobe (void *@var{pointer})
-@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck} @mtasuconst{:malloc_hooks}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
+@safety{@prelim{}@mtunsafe{@mtasurace{:mcheck}}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{}}}
@c The linked list of headers may be modified concurrently by other
@c threads, and it may find a partial update if called from a signal
@c handler. It's mostly read only, so cancelling it might be safe, but
@@ -1334,173 +1325,6 @@ compatibility. Both @code{MALLOC_CHECK_} and @samp{-lmcheck} should
uncover the same bugs - but using @code{MALLOC_CHECK_} you don't need to
recompile your application.
-@node Hooks for Malloc
-@subsubsection Memory Allocation Hooks
-@cindex allocation hooks, for @code{malloc}
-
-@Theglibc{} lets you modify the behavior of @code{malloc},
-@code{realloc}, and @code{free} by specifying appropriate hook
-functions. You can use these hooks to help you debug programs that use
-dynamic memory allocation, for example.
-
-The hook variables are declared in @file{malloc.h}.
-@pindex malloc.h
-
-@defvar __malloc_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to the function that
-@code{malloc} uses whenever it is called. You should define this
-function to look like @code{malloc}; that is, like:
-
-@smallexample
-void *@var{function} (size_t @var{size}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{malloc} function was called. This value allows you to trace
-the memory consumption of the program.
-@end defvar
-
-@defvar __realloc_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to function that @code{realloc}
-uses whenever it is called. You should define this function to look
-like @code{realloc}; that is, like:
-
-@smallexample
-void *@var{function} (void *@var{ptr}, size_t @var{size}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{realloc} function was called. This value allows you to trace the
-memory consumption of the program.
-@end defvar
-
-@defvar __free_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to function that @code{free}
-uses whenever it is called. You should define this function to look
-like @code{free}; that is, like:
-
-@smallexample
-void @var{function} (void *@var{ptr}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{free} function was called. This value allows you to trace the
-memory consumption of the program.
-@end defvar
-
-@defvar __memalign_hook
-@standards{GNU, malloc.h}
-The value of this variable is a pointer to function that @code{aligned_alloc},
-@code{memalign}, @code{posix_memalign} and @code{valloc} use whenever they
-are called. You should define this function to look like @code{aligned_alloc};
-that is, like:
-
-@smallexample
-void *@var{function} (size_t @var{alignment}, size_t @var{size}, const void *@var{caller})
-@end smallexample
-
-The value of @var{caller} is the return address found on the stack when
-the @code{aligned_alloc}, @code{memalign}, @code{posix_memalign} or
-@code{valloc} functions are called. This value allows you to trace the
-memory consumption of the program.
-@end defvar
-
-You must make sure that the function you install as a hook for one of
-these functions does not call that function recursively without restoring
-the old value of the hook first! Otherwise, your program will get stuck
-in an infinite recursion. Before calling the function recursively, one
-should make sure to restore all the hooks to their previous value. When
-coming back from the recursive call, all the hooks should be resaved
-since a hook might modify itself.
-
-An issue to look out for is the time at which the malloc hook functions
-can be safely installed. If the hook functions call the malloc-related
-functions recursively, it is necessary that malloc has already properly
-initialized itself at the time when @code{__malloc_hook} etc. is
-assigned to. On the other hand, if the hook functions provide a
-complete malloc implementation of their own, it is vital that the hooks
-are assigned to @emph{before} the very first @code{malloc} call has
-completed, because otherwise a chunk obtained from the ordinary,
-un-hooked malloc may later be handed to @code{__free_hook}, for example.
-
-Here is an example showing how to use @code{__malloc_hook} and
-@code{__free_hook} properly. It installs a function that prints out
-information every time @code{malloc} or @code{free} is called. We just
-assume here that @code{realloc} and @code{memalign} are not used in our
-program.
-
-@smallexample
-/* Prototypes for __malloc_hook, __free_hook */
-#include <malloc.h>
-
-/* Prototypes for our hooks. */
-static void my_init_hook (void);
-static void *my_malloc_hook (size_t, const void *);
-static void my_free_hook (void*, const void *);
-
-static void
-my_init (void)
-@{
- old_malloc_hook = __malloc_hook;
- old_free_hook = __free_hook;
- __malloc_hook = my_malloc_hook;
- __free_hook = my_free_hook;
-@}
-
-static void *
-my_malloc_hook (size_t size, const void *caller)
-@{
- void *result;
- /* Restore all old hooks */
- __malloc_hook = old_malloc_hook;
- __free_hook = old_free_hook;
- /* Call recursively */
- result = malloc (size);
- /* Save underlying hooks */
- old_malloc_hook = __malloc_hook;
- old_free_hook = __free_hook;
- /* @r{@code{printf} might call @code{malloc}, so protect it too.} */
- printf ("malloc (%u) returns %p\n", (unsigned int) size, result);
- /* Restore our own hooks */
- __malloc_hook = my_malloc_hook;
- __free_hook = my_free_hook;
- return result;
-@}
-
-static void
-my_free_hook (void *ptr, const void *caller)
-@{
- /* Restore all old hooks */
- __malloc_hook = old_malloc_hook;
- __free_hook = old_free_hook;
- /* Call recursively */
- free (ptr);
- /* Save underlying hooks */
- old_malloc_hook = __malloc_hook;
- old_free_hook = __free_hook;
- /* @r{@code{printf} might call @code{free}, so protect it too.} */
- printf ("freed pointer %p\n", ptr);
- /* Restore our own hooks */
- __malloc_hook = my_malloc_hook;
- __free_hook = my_free_hook;
-@}
-
-main ()
-@{
- my_init ();
- @dots{}
-@}
-@end smallexample
-
-The @code{mcheck} function (@pxref{Heap Consistency Checking}) works by
-installing such hooks.
-
-@c __morecore, __after_morecore_hook are undocumented
-@c It's not clear whether to document them.
-
@node Statistics of Malloc
@subsubsection Statistics for Memory Allocation with @code{malloc}
@@ -1632,19 +1456,6 @@ Tell @code{malloc} to perform occasional consistency checks on
dynamically allocated memory, and to call @var{abortfn} when an
inconsistency is found. @xref{Heap Consistency Checking}.
-@item void *(*__malloc_hook) (size_t @var{size}, const void *@var{caller})
-A pointer to a function that @code{malloc} uses whenever it is called.
-
-@item void *(*__realloc_hook) (void *@var{ptr}, size_t @var{size}, const void *@var{caller})
-A pointer to a function that @code{realloc} uses whenever it is called.
-
-@item void (*__free_hook) (void *@var{ptr}, const void *@var{caller})
-A pointer to a function that @code{free} uses whenever it is called.
-
-@item void (*__memalign_hook) (size_t @var{size}, size_t @var{alignment}, const void *@var{caller})
-A pointer to a function that @code{aligned_alloc}, @code{memalign},
-@code{posix_memalign} and @code{valloc} use whenever they are called.
-
@item struct mallinfo mallinfo (void)
Return information about the current dynamic memory usage.
@xref{Statistics of Malloc}.
@@ -1667,6 +1478,10 @@ the location. To do this the application must be started in a special
mode which is enabled by an environment variable. There are no speed
penalties for the program if the debugging mode is not enabled.
+The allocation debugging functionality is only safe for use in
+single-threaded programs and requires preloading
+@code{libmalloc-extras.so}.
+
@menu
* Tracing malloc:: How to install the tracing functionality.
* Using the Memory Debugger:: Example programs excerpts.
@@ -1679,7 +1494,7 @@ penalties for the program if the debugging mode is not enabled.
@deftypefun void mtrace (void)
@standards{GNU, mcheck.h}
-@safety{@prelim{}@mtunsafe{@mtsenv{} @mtasurace{:mtrace} @mtasuconst{:malloc_hooks} @mtuinit{}}@asunsafe{@asuinit{} @ascuheap{} @asucorrupt{} @asulock{}}@acunsafe{@acuinit{} @acucorrupt{} @aculock{} @acsfd{} @acsmem{}}}
+@safety{@prelim{}@mtunsafe{@mtsenv{} @mtasurace{:mtrace} @mtuinit{}}@asunsafe{@asuinit{} @ascuheap{} @asucorrupt{} @asulock{}}@acunsafe{@acuinit{} @acucorrupt{} @aculock{} @acsfd{} @acsmem{}}}
@c Like the mcheck hooks, these are not designed with thread safety in
@c mind, because the hook pointers are temporarily modified without
@c regard to other threads, signals or cancellation.
@@ -1715,7 +1530,7 @@ systems. The prototype can be found in @file{mcheck.h}.
@deftypefun void muntrace (void)
@standards{GNU, mcheck.h}
-@safety{@prelim{}@mtunsafe{@mtasurace{:mtrace} @mtasuconst{:malloc_hooks} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{}}@acunsafe{@acucorrupt{} @acsmem{} @aculock{} @acsfd{}}}
+@safety{@prelim{}@mtunsafe{@mtasurace{:mtrace} @mtslocale{}}@asunsafe{@asucorrupt{} @ascuheap{}}@acunsafe{@acucorrupt{} @acsmem{} @aculock{} @acsfd{}}}
@c muntrace @mtasurace:mtrace @mtslocale @asucorrupt @ascuheap @acucorrupt @acsmem @aculock @acsfd
@c fprintf (fputs) dup @mtslocale @asucorrupt @ascuheap @acsmem @aculock @acucorrupt
@@ -135,13 +135,15 @@ $(objpfx)libg.a: $(dep-dummy-lib); $(make-dummy-lib)
$(objpfx)tst-tsearch: $(libm)
-tst-error1-ENV = MALLOC_TRACE=$(objpfx)tst-error1.mtrace
+tst-error1-ENV = MALLOC_TRACE=$(objpfx)tst-error1.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
tst-error1-ARGS = $(objpfx)tst-error1.out
$(objpfx)tst-error1-mem.out: $(objpfx)tst-error1.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-error1.mtrace > $@; \
$(evaluate-test)
-tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace
+tst-allocate_once-ENV = MALLOC_TRACE=$(objpfx)tst-allocate_once.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
$(evaluate-test)
@@ -529,10 +529,12 @@ tst-umask1-ARGS = $(objpfx)tst-umask1.temp
$(objpfx)tst-atfork2: $(libdl) $(shared-thread-library)
LDFLAGS-tst-atfork2 = -rdynamic
-tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace
+tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-atfork2mod.so: $(shared-thread-library)
-tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace
+tst-stack3-ENV = MALLOC_TRACE=$(objpfx)tst-stack3.mtrace \
+ LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
$(objpfx)tst-stack3-mem.out: $(objpfx)tst-stack3.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-stack3.mtrace > $@; \
$(evaluate-test)
@@ -278,43 +278,50 @@ annexc-CFLAGS = -O
$(objpfx)annexc: annexc.c
$(native-compile)
-tst-fnmatch-ENV += MALLOC_TRACE=$(objpfx)tst-fnmatch.mtrace
+tst-fnmatch-ENV += MALLOC_TRACE=$(objpfx)tst-fnmatch.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-fnmatch-mem.out: $(objpfx)tst-fnmatch.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-fnmatch.mtrace > $@; \
$(evaluate-test)
-bug-regex2-ENV = MALLOC_TRACE=$(objpfx)bug-regex2.mtrace
+bug-regex2-ENV = MALLOC_TRACE=$(objpfx)bug-regex2.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)bug-regex2-mem.out: $(objpfx)bug-regex2.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-regex2.mtrace > $@; \
$(evaluate-test)
-bug-regex14-ENV = MALLOC_TRACE=$(objpfx)bug-regex14.mtrace
+bug-regex14-ENV = MALLOC_TRACE=$(objpfx)bug-regex14.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)bug-regex14-mem.out: $(objpfx)bug-regex14.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-regex14.mtrace > $@; \
$(evaluate-test)
-bug-regex21-ENV = MALLOC_TRACE=$(objpfx)bug-regex21.mtrace
+bug-regex21-ENV = MALLOC_TRACE=$(objpfx)bug-regex21.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)bug-regex21-mem.out: $(objpfx)bug-regex21.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-regex21.mtrace > $@; \
$(evaluate-test)
-bug-regex31-ENV = MALLOC_TRACE=$(objpfx)bug-regex31.mtrace
+bug-regex31-ENV = MALLOC_TRACE=$(objpfx)bug-regex31.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)bug-regex31-mem.out: $(objpfx)bug-regex31.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-regex31.mtrace > $@; \
$(evaluate-test)
-bug-regex36-ENV = MALLOC_TRACE=$(objpfx)bug-regex36.mtrace
+bug-regex36-ENV = MALLOC_TRACE=$(objpfx)bug-regex36.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)bug-regex36-mem.out: $(objpfx)bug-regex36.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-regex36.mtrace > $@; \
$(evaluate-test)
-tst-vfork3-ENV = MALLOC_TRACE=$(objpfx)tst-vfork3.mtrace
+tst-vfork3-ENV = MALLOC_TRACE=$(objpfx)tst-vfork3.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-vfork3-mem.out: $(objpfx)tst-vfork3.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-vfork3.mtrace > $@; \
@@ -323,18 +330,21 @@ $(objpfx)tst-vfork3-mem.out: $(objpfx)tst-vfork3.out
# tst-rxspencer.mtrace is not generated, only
# tst-rxspencer-no-utf8.mtrace, since otherwise the file has almost
# 100M and takes very long time to process.
-tst-rxspencer-no-utf8-ENV += MALLOC_TRACE=$(objpfx)tst-rxspencer-no-utf8.mtrace
+tst-rxspencer-no-utf8-ENV += MALLOC_TRACE=$(objpfx)tst-rxspencer-no-utf8.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-rxspencer-no-utf8-mem.out: $(objpfx)tst-rxspencer-no-utf8.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-rxspencer-no-utf8.mtrace \
> $@; \
$(evaluate-test)
-tst-pcre-ENV = MALLOC_TRACE=$(objpfx)tst-pcre.mtrace
+tst-pcre-ENV = MALLOC_TRACE=$(objpfx)tst-pcre.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-pcre-mem.out: $(objpfx)tst-pcre.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-pcre.mtrace > $@; \
$(evaluate-test)
-tst-boost-ENV = MALLOC_TRACE=$(objpfx)tst-boost.mtrace
+tst-boost-ENV = MALLOC_TRACE=$(objpfx)tst-boost.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-boost-mem.out: $(objpfx)tst-boost.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-boost.mtrace > $@; \
$(evaluate-test)
@@ -347,15 +357,18 @@ $(objpfx)bug-ga2-mem.out: $(objpfx)bug-ga2.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-ga2.mtrace > $@; \
$(evaluate-test)
-bug-ga2-ENV = MALLOC_TRACE=$(objpfx)bug-ga2.mtrace
+bug-ga2-ENV = MALLOC_TRACE=$(objpfx)bug-ga2.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
-bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bug-glob2.mtrace
+bug-glob2-ENV = MALLOC_TRACE=$(objpfx)bug-glob2.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out
$(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \
$(evaluate-test)
-tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace
+tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \
@@ -147,6 +147,12 @@ do_prepare (void)
FAIL_EXIT1 ("out of memory");
strcpy (stpcpy (tmpdirname, test_dir), "/tst-vfork3.XXXXXX");
+ /* We have preloaded libmalloc-extras.so to implement mtrace().
+ We unset LD_PRELOAD since the children run via /bin/sh which
+ uses the system libc which may lack the integration required
+ by libmalloc-extras.so. */
+ unsetenv("LD_PRELOAD");
+
tmpdirname = mkdtemp (tmpdirname);
if (tmpdirname == NULL)
FAIL_EXIT1 ("could not create temporary directory");
@@ -152,17 +152,20 @@ $(objpfx)tst-res_hconf_reorder: $(libdl) $(shared-thread-library)
tst-res_hconf_reorder-ENV = RESOLV_REORDER=on
$(objpfx)tst-leaks: $(objpfx)libresolv.so
-tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace
+tst-leaks-ENV = MALLOC_TRACE=$(objpfx)tst-leaks.mtrace \
+ LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
$(objpfx)mtrace-tst-leaks.out: $(objpfx)tst-leaks.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks.mtrace > $@; \
$(evaluate-test)
-tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace
+tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace \
+ LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
$(objpfx)mtrace-tst-leaks2.out: $(objpfx)tst-leaks2.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-leaks2.mtrace > $@; \
$(evaluate-test)
-tst-resolv-res_ninit-ENV = MALLOC_TRACE=$(objpfx)tst-resolv-res_ninit.mtrace
+tst-resolv-res_ninit-ENV = MALLOC_TRACE=$(objpfx)tst-resolv-res_ninit.mtrace \
+ LD_PRELOAD=$(objpfx)/../malloc/libmalloc-extras.so
$(objpfx)mtrace-tst-resolv-res_ninit.out: $(objpfx)tst-resolv-res_ninit.out
$(common-objpfx)malloc/mtrace \
$(objpfx)tst-resolv-res_ninit.mtrace > $@; \
@@ -91,9 +91,11 @@ $(objpfx)tst-swprintf.out: $(gen-locales)
$(objpfx)tst-vfprintf-mbs-prec.out: $(gen-locales)
endif
-tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace
+tst-printf-bz18872-ENV = MALLOC_TRACE=$(objpfx)tst-printf-bz18872.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
tst-vfprintf-width-prec-ENV = \
- MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace
+ MALLOC_TRACE=$(objpfx)tst-vfprintf-width-prec.mtrace \
+ LD_PRELOAD=$(objpfx)../malloc/libmalloc-extras.so
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)' > $@; \