@@ -4,6 +4,11 @@
# ifndef _ISOMAC
# include <rtld-malloc.h>
+# include <stdbool.h>
+# include <mcheck.h>
+
+struct malloc_state;
+typedef struct malloc_state *mstate;
/* In the GNU libc we rename the global variable
`__malloc_initialized' to `__libc_malloc_initialized'. */
@@ -11,8 +16,9 @@
/* Nonzero if the malloc is already initialized. */
extern int __malloc_initialized attribute_hidden;
-struct malloc_state;
-typedef struct malloc_state *mstate;
+enum mcheck_status __mcheck_checkptr (const void *) attribute_hidden;
+extern int __mcheck_initialize (void (*) (enum mcheck_status), bool)
+ attribute_hidden;
# endif /* !_ISOMAC */
@@ -91,9 +91,7 @@ tests-exclude-mcheck = tst-mallocstate \
tst-malloc-usable-static \
tst-malloc-usable-static-tunables \
tst-malloc-usable-tunables \
- tst-malloc_info \
- tst-memalign \
- tst-posix_memalign
+ tst-malloc_info
tests-mcheck = $(filter-out $(tests-exclude-mcheck), $(tests))
@@ -272,7 +270,7 @@ $(objpfx)memusage: memusage.sh
# Extra dependencies
$(foreach o,$(all-object-suffixes),$(objpfx)malloc$(o)): arena.c hooks.c
-hooks.c: malloc-check.c
+hooks.c: malloc-check.c mcheck-hooks.c
# Compile the tests with a flag which suppresses the mallopt call in
# the test skeleton.
@@ -67,6 +67,9 @@ libc {
GLIBC_2.33 {
mallinfo2;
}
+ GLIBC_2.34 {
+ __libc_lmcheck;
+ }
GLIBC_PRIVATE {
# Internal startup hook for libpthread.
__libc_malloc_pthread_startup;
@@ -403,6 +403,11 @@ ptmalloc_init (void)
__malloc_debug_enable (MALLOC_CHECK_HOOK);
#endif
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+ if (__libc_lmcheck)
+ __mcheck_initialize (NULL, false);
+#endif
+
#if HAVE_MALLOC_INIT_HOOK
void (*hook) (void) = atomic_forced_read (__malloc_initialize_hook);
if (hook != NULL)
@@ -36,6 +36,7 @@ enum malloc_debug_hooks
{
MALLOC_NONE_HOOK = 0,
MALLOC_CHECK_HOOK = 1 << 0, /* MALLOC_CHECK_ or glibc.malloc.check. */
+ MALLOC_MCHECK_HOOK = 1 << 1, /* mcheck() */
};
static unsigned __malloc_debugging_hooks;
@@ -77,113 +78,181 @@ __malloc_debug_disable (enum malloc_debug_hooks flag)
}
#include "malloc-check.c"
+#include "mcheck-hooks.c"
static __always_inline bool
-_malloc_debug_before (size_t bytes, void **victimp, const void *address)
+_malloc_debug_before (size_t *bytesp, void **victimp, const void *address)
{
_Static_assert (PTRDIFF_MAX <= SIZE_MAX / 2,
- "PTRDIFF_MAX is not more than half of SIZE_MAX");
+ "PTRDIFF_MAX is not more than half of SIZE_MAX");
void *(*hook) (size_t, const void *)
= atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
{
- *victimp = (*hook)(bytes, address);
+ *victimp = (*hook)(*bytesp, address);
return true;
}
- if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+ if (__glibc_unlikely (__malloc_debugging_hooks))
{
- *victimp = malloc_check (bytes);
- return true;
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ && malloc_mcheck_before (bytesp, victimp))
+ return true;
+ if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+ {
+ *victimp = malloc_check (*bytesp);
+ return true;
+ }
}
return false;
}
+static __always_inline void *
+_malloc_debug_after (void *mem, size_t bytes, const void *address)
+{
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+ mem = malloc_mcheck_after (mem, bytes);
+ return mem;
+}
+
static __always_inline bool
-_free_debug_before (void *mem, const void *address)
+_free_debug_before (void **mem, const void *address)
{
void (*hook) (void *, const void *)
= atomic_forced_read (__free_hook);
if (__builtin_expect (hook != NULL, 0))
{
- (*hook)(mem, address);
+ (*hook)(*mem, address);
return true;
}
- if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+ if (__glibc_unlikely (__malloc_debugging_hooks))
{
- free_check (mem);
- return true;
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ *mem = free_mcheck (*mem);
+ if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+ {
+ free_check (*mem);
+ return true;
+ }
}
return false;
}
static __always_inline bool
-_realloc_debug_before (void *oldmem, size_t bytes, void **victimp,
- const void *address)
+_realloc_debug_before (void **oldmem, size_t *bytesp, size_t *oldsize,
+ void **victimp, const void *address)
{
void *(*hook) (void *, size_t, const void *) =
atomic_forced_read (__realloc_hook);
if (__builtin_expect (hook != NULL, 0))
{
- *victimp = (*hook)(oldmem, bytes, address);
+ *victimp = (*hook)(*oldmem, *bytesp, address);
return true;
}
- if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+ if (__glibc_unlikely (__malloc_debugging_hooks))
{
- *victimp = realloc_check (oldmem, bytes);
- return true;
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ && realloc_mcheck_before (oldmem, bytesp, oldsize, victimp))
+ return true;
+ if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+ {
+ *victimp = realloc_check (*oldmem, *bytesp);
+ return true;
+ }
}
return false;
}
+static __always_inline void *
+_realloc_debug_after (void *mem, void *oldmem, size_t bytes, size_t oldsize,
+ const void *address)
+{
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+ mem = realloc_mcheck_after (mem, oldmem, bytes, oldsize);
+ return mem;
+}
+
static __always_inline bool
-_memalign_debug_before (size_t alignment, size_t bytes, void **victimp,
- const void *address)
+_memalign_debug_before (size_t alignment, size_t *bytesp, void **victimp,
+ const void *address)
{
void *(*hook) (size_t, size_t, const void *) =
atomic_forced_read (__memalign_hook);
if (__builtin_expect (hook != NULL, 0))
{
- *victimp = (*hook)(alignment, bytes, address);
+ *victimp = (*hook)(alignment, *bytesp, address);
return true;
}
-
- if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+ if (__glibc_unlikely (__malloc_debugging_hooks))
{
- *victimp = memalign_check (alignment, bytes);
- return true;
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ && memalign_mcheck_before (alignment, bytesp, victimp))
+ return true;
+ if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+ {
+ *victimp = memalign_check (alignment, *bytesp);
+ return true;
+ }
}
return false;
}
+static __always_inline void *
+_memalign_debug_after (void *mem, size_t alignment, size_t bytes,
+ const void *address)
+{
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK) && mem != NULL)
+ mem = memalign_mcheck_after (mem, alignment, bytes);
+ return mem;
+}
+
static __always_inline bool
-_calloc_debug_before (size_t bytes, void **victimp, const void *address)
+_calloc_debug_before (size_t *bytesp, void **victimp, const void *address)
{
void *(*hook) (size_t, const void *) =
atomic_forced_read (__malloc_hook);
if (__builtin_expect (hook != NULL, 0))
{
- *victimp = (*hook)(bytes, address);
+ *victimp = (*hook)(*bytesp, address);
+
if (*victimp != NULL)
- memset (*victimp, 0, bytes);
+ memset (*victimp, 0, *bytesp);
+
return true;
}
- if (__glibc_unlikely (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK)))
+ /* Memory is zeroed out in the AFTER hook. */
+ if (__glibc_unlikely (__malloc_debugging_hooks))
{
- *victimp = malloc_check (bytes);
- if (*victimp != NULL)
- memset (*victimp, 0, bytes);
- return true;
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK)
+ && malloc_mcheck_before (bytesp, victimp))
+ return true;
+ if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+ {
+ *victimp = malloc_check (*bytesp);
+ return true;
+ }
}
return false;
}
+static __always_inline void *
+_calloc_debug_after (void *mem, size_t bytes, const void *address)
+{
+ if (__glibc_unlikely (__malloc_debugging_hooks) && mem != NULL)
+ {
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ mem = malloc_mcheck_after (mem, bytes);
+ memset (mem, 0, bytes);
+ }
+ return mem;
+}
+
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_25)
/* Support for restoring dumped heaps contained in historic Emacs
@@ -3191,13 +3191,14 @@ void *
__libc_malloc (size_t bytes)
{
mstate ar_ptr;
- void *victim;
+ void *victim = NULL;
+ size_t orig_bytes = bytes;
if (__malloc_initialized < 0)
ptmalloc_init ();
- if (_malloc_debug_before (bytes, &victim, RETURN_ADDRESS (0)))
- return victim;
+ if (_malloc_debug_before (&bytes, &victim, RETURN_ADDRESS (0)))
+ goto out;
#if USE_TCACHE
/* int_free also calls request2size, be careful to not pad twice. */
@@ -3205,7 +3206,8 @@ __libc_malloc (size_t bytes)
if (!checked_request2size (bytes, &tbytes))
{
__set_errno (ENOMEM);
- return NULL;
+ victim = NULL;
+ goto out;
}
size_t tc_idx = csize2tidx (tbytes);
@@ -3217,7 +3219,8 @@ __libc_malloc (size_t bytes)
&& tcache->counts[tc_idx] > 0)
{
victim = tcache_get (tc_idx);
- return tag_new_usable (victim);
+ victim = tag_new_usable (victim);
+ goto out;
}
DIAG_POP_NEEDS_COMMENT;
#endif
@@ -3227,7 +3230,7 @@ __libc_malloc (size_t bytes)
victim = tag_new_usable (_int_malloc (&main_arena, bytes));
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
&main_arena == arena_for_chunk (mem2chunk (victim)));
- return victim;
+ goto out;
}
arena_get (ar_ptr, bytes);
@@ -3249,7 +3252,9 @@ __libc_malloc (size_t bytes)
assert (!victim || chunk_is_mmapped (mem2chunk (victim)) ||
ar_ptr == arena_for_chunk (mem2chunk (victim)));
- return victim;
+
+out:
+ return _malloc_debug_after (victim, orig_bytes, RETURN_ADDRESS (0));
}
libc_hidden_def (__libc_malloc)
@@ -3262,7 +3267,7 @@ __libc_free (void *mem)
if (__malloc_initialized < 0)
ptmalloc_init ();
- if (_free_debug_before (mem, RETURN_ADDRESS (0)))
+ if (_free_debug_before (&mem, RETURN_ADDRESS (0)))
return;
if (mem == 0) /* free(0) has no effect */
@@ -3315,23 +3320,30 @@ __libc_realloc (void *oldmem, size_t bytes)
INTERNAL_SIZE_T nb; /* padded request size */
void *newp; /* chunk to return */
+ size_t orig_bytes = bytes, debug_osize = 0;
if (__malloc_initialized < 0)
ptmalloc_init ();
- if (_realloc_debug_before (oldmem, bytes, &newp, RETURN_ADDRESS (0)))
- return newp;
+ if (_realloc_debug_before (&oldmem, &bytes, &debug_osize, &newp,
+ RETURN_ADDRESS (0)))
+ goto out;
#if REALLOC_ZERO_BYTES_FREES
if (bytes == 0 && oldmem != NULL)
{
- __libc_free (oldmem); return 0;
+ __libc_free (oldmem);
+ newp = NULL;
+ goto out;
}
#endif
/* realloc of null is supposed to be same as malloc */
if (oldmem == 0)
- return __libc_malloc (bytes);
+ {
+ newp = __libc_malloc (bytes);
+ goto out;
+ }
/* Perform a quick check to ensure that the pointer's tag matches the
memory's tag. */
@@ -3365,7 +3377,8 @@ __libc_realloc (void *oldmem, size_t bytes)
if (!checked_request2size (bytes, &nb))
{
__set_errno (ENOMEM);
- return NULL;
+ newp = NULL;
+ goto out;
}
if (chunk_is_mmapped (oldp))
@@ -3377,7 +3390,10 @@ __libc_realloc (void *oldmem, size_t bytes)
/* Must alloc, copy, free. */
void *newmem = __libc_malloc (bytes);
if (newmem == 0)
- return NULL;
+ {
+ newp = NULL;
+ goto out;
+ }
/* Copy as many bytes as are available from the old chunk
and fit into the new size. NB: The overhead for faked
mmapped chunks is only SIZE_SZ, not CHUNK_HDR_SZ as for
@@ -3385,7 +3401,8 @@ __libc_realloc (void *oldmem, size_t bytes)
if (bytes > oldsize - SIZE_SZ)
bytes = oldsize - SIZE_SZ;
memcpy (newmem, oldmem, bytes);
- return newmem;
+ newp = newmem;
+ goto out;
}
void *newmem;
@@ -3400,21 +3417,29 @@ __libc_realloc (void *oldmem, size_t bytes)
reused. There's a performance hit for both us and the
caller for doing this, so we might want to
reconsider. */
- return tag_new_usable (newmem);
+ newp = tag_new_usable (newmem);
+ goto out;
}
#endif
/* Note the extra SIZE_SZ overhead. */
if (oldsize - SIZE_SZ >= nb)
- return oldmem; /* do nothing */
+ {
+ newp = oldmem; /* do nothing */
+ goto out;
+ }
/* Must alloc, copy, free. */
newmem = __libc_malloc (bytes);
if (newmem == 0)
- return 0; /* propagate failure */
+ {
+ newp = NULL; /* propagate failure */
+ goto out;
+ }
memcpy (newmem, oldmem, oldsize - CHUNK_HDR_SZ);
munmap_chunk (oldp);
- return newmem;
+ newp = newmem;
+ goto out;
}
if (SINGLE_THREAD_P)
@@ -3423,7 +3448,7 @@ __libc_realloc (void *oldmem, size_t bytes)
assert (!newp || chunk_is_mmapped (mem2chunk (newp)) ||
ar_ptr == arena_for_chunk (mem2chunk (newp)));
- return newp;
+ goto out;
}
__libc_lock_lock (ar_ptr->mutex);
@@ -3448,7 +3473,9 @@ __libc_realloc (void *oldmem, size_t bytes)
}
}
- return newp;
+out:
+ return _realloc_debug_after (newp, oldmem, orig_bytes, debug_osize,
+ RETURN_ADDRESS (0));
}
libc_hidden_def (__libc_realloc)
@@ -3467,13 +3494,17 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
{
mstate ar_ptr;
void *p;
+ size_t orig_bytes = bytes;
- if (_memalign_debug_before (alignment, bytes, &p, address))
- return p;
+ if (_memalign_debug_before (alignment, &bytes, &p, address))
+ goto out;
/* If we need less alignment than we give anyway, just relay to malloc. */
if (alignment <= MALLOC_ALIGNMENT)
- return __libc_malloc (bytes);
+ {
+ p = __libc_malloc (bytes);
+ goto out;
+ }
/* Otherwise, ensure that it is at least a minimum chunk size */
if (alignment < MINSIZE)
@@ -3484,7 +3515,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
if (alignment > SIZE_MAX / 2 + 1)
{
__set_errno (EINVAL);
- return 0;
+ p = NULL;
+ goto out;
}
@@ -3502,7 +3534,8 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
p = _int_memalign (&main_arena, alignment, bytes);
assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
&main_arena == arena_for_chunk (mem2chunk (p)));
- return tag_new_usable (p);
+ p = tag_new_usable (p);
+ goto out;
}
arena_get (ar_ptr, bytes + alignment + MINSIZE);
@@ -3520,7 +3553,9 @@ _mid_memalign (size_t alignment, size_t bytes, void *address)
assert (!p || chunk_is_mmapped (mem2chunk (p)) ||
ar_ptr == arena_for_chunk (mem2chunk (p)));
- return tag_new_usable (p);
+ p = tag_new_usable (p);
+out:
+ return _memalign_debug_after (p, alignment, orig_bytes, RETURN_ADDRESS (0));
}
/* For ISO C11. */
weak_alias (__libc_memalign, aligned_alloc)
@@ -3582,8 +3617,8 @@ __libc_calloc (size_t n, size_t elem_size)
if (__malloc_initialized < 0)
ptmalloc_init ();
- if (_calloc_debug_before (sz, &mem, RETURN_ADDRESS (0)))
- return mem;
+ if (_calloc_debug_before (&sz, &mem, RETURN_ADDRESS (0)))
+ goto out;
MAYBE_INIT_TCACHE ();
@@ -3639,7 +3674,10 @@ __libc_calloc (size_t n, size_t elem_size)
/* Allocation failed even after a retry. */
if (mem == 0)
- return 0;
+ {
+ mem = NULL;
+ goto out;
+ }
mchunkptr p = mem2chunk (mem);
@@ -3647,7 +3685,10 @@ __libc_calloc (size_t n, size_t elem_size)
regardless of MORECORE_CLEARS, so we zero the whole block while
doing so. */
if (__glibc_unlikely (mtag_enabled))
- return tag_new_zero_region (mem, memsize (p));
+ {
+ mem = tag_new_zero_region (mem, memsize (p));
+ goto out;
+ }
INTERNAL_SIZE_T csz = chunksize (p);
@@ -3655,9 +3696,9 @@ __libc_calloc (size_t n, size_t elem_size)
if (chunk_is_mmapped (p))
{
if (__builtin_expect (perturb_byte, 0))
- return memset (mem, 0, sz);
+ memset (mem, 0, sz);
- return mem;
+ goto out;
}
#if MORECORE_CLEARS
@@ -3677,7 +3718,10 @@ __libc_calloc (size_t n, size_t elem_size)
assert (nclears >= 3);
if (nclears > 9)
- return memset (d, 0, clearsize);
+ {
+ memset (d, 0, clearsize);
+ goto out;
+ }
else
{
@@ -3701,7 +3745,8 @@ __libc_calloc (size_t n, size_t elem_size)
}
}
- return mem;
+out:
+ return _calloc_debug_after (mem, bytes, RETURN_ADDRESS (0));
}
/*
new file mode 100644
@@ -0,0 +1,411 @@
+/* mcheck debugging hooks for malloc.
+ Copyright (C) 1990-2021 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written May 1989 by Mike Haertel.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
+#include <mcheck.h>
+#include <libintl.h>
+
+/* Arbitrary magical numbers. */
+#define MAGICWORD 0xfedabeeb
+#define MAGICFREE 0xd8675309
+#define MAGICBYTE ((char) 0xd7)
+#define MALLOCFLOOD ((char) 0x93)
+#define FREEFLOOD ((char) 0x95)
+
+/* Function to call when something awful happens. */
+static void (*abortfunc) (enum mcheck_status);
+
+struct hdr
+{
+ size_t size; /* Exact size requested by user. */
+ unsigned long int magic; /* Magic number to check header integrity. */
+ struct hdr *prev;
+ struct hdr *next;
+ void *block; /* Real block allocated, for memalign. */
+ unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
+};
+
+/* This is the beginning of the list of all memory blocks allocated.
+ It is only constructed if the pedantic testing is requested. */
+struct hdr *__mcheck_root;
+
+/* Nonzero if pedentic checking of all blocks is requested. */
+static bool pedantic;
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_34)
+/* Flag to initialize mcheck on first malloc invocation through -lmcheck.
+ libmcheck.a overrides this with a strong symbol initialized to 1. The
+ symbol cannot be linked against directly during build. */
+const int __libc_lmcheck __attribute__ ((weak));
+compat_symbol (libc, __libc_lmcheck, __libc_lmcheck, GLIBC_2_34);
+#endif
+
+#if defined _LIBC || defined STDC_HEADERS || defined USG
+# include <string.h>
+# define flood memset
+#else
+static void flood (void *, int, size_t);
+static void
+flood (void *ptr, int val, size_t size)
+{
+ char *cp = ptr;
+ while (size--)
+ *cp++ = val;
+}
+#endif
+
+static enum mcheck_status
+checkhdr (const struct hdr *hdr)
+{
+ enum mcheck_status status;
+ bool mcheck_used = __is_malloc_debug_enabled (MALLOC_MCHECK_HOOK);
+
+ if (!mcheck_used)
+ /* Maybe the mcheck used is disabled? This happens when we find
+ an error and report it. */
+ return MCHECK_OK;
+
+ switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
+ {
+ default:
+ status = MCHECK_HEAD;
+ break;
+ case MAGICFREE:
+ status = MCHECK_FREE;
+ break;
+ case MAGICWORD:
+ if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
+ status = MCHECK_TAIL;
+ else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
+ status = MCHECK_HEAD;
+ else
+ status = MCHECK_OK;
+ break;
+ }
+ if (status != MCHECK_OK)
+ {
+ mcheck_used = 0;
+ (*abortfunc) (status);
+ mcheck_used = 1;
+ }
+ return status;
+}
+
+enum mcheck_status
+__mcheck_checkptr (const void *ptr)
+{
+ if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ return MCHECK_DISABLED;
+
+ if (ptr != NULL)
+ return checkhdr (((struct hdr *) ptr) - 1);
+
+ /* Walk through all the active blocks and test whether they were tampered
+ with. */
+ struct hdr *runp = __mcheck_root;
+
+ /* Temporarily turn off the checks. */
+ pedantic = false;
+
+ while (runp != NULL)
+ {
+ (void) checkhdr (runp);
+
+ runp = runp->next;
+ }
+
+ /* Turn checks on again. */
+ pedantic = true;
+
+ return MCHECK_OK;
+}
+
+static void
+unlink_blk (struct hdr *ptr)
+{
+ if (ptr->next != NULL)
+ {
+ ptr->next->prev = ptr->prev;
+ ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
+ + (uintptr_t) ptr->next->next);
+ }
+ if (ptr->prev != NULL)
+ {
+ ptr->prev->next = ptr->next;
+ ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
+ + (uintptr_t) ptr->prev->next);
+ }
+ else
+ __mcheck_root = ptr->next;
+}
+
+static void
+link_blk (struct hdr *hdr)
+{
+ hdr->prev = NULL;
+ hdr->next = __mcheck_root;
+ __mcheck_root = hdr;
+ hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
+
+ /* And the next block. */
+ if (hdr->next != NULL)
+ {
+ hdr->next->prev = hdr;
+ hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
+ + (uintptr_t) hdr->next->next);
+ }
+}
+
+static void *
+free_mcheck (void *ptr)
+{
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+ if (ptr)
+ {
+ struct hdr *hdr = ((struct hdr *) ptr) - 1;
+ checkhdr (hdr);
+ hdr->magic = MAGICFREE;
+ hdr->magic2 = MAGICFREE;
+ unlink_blk (hdr);
+ hdr->prev = hdr->next = NULL;
+ flood (ptr, FREEFLOOD, hdr->size);
+ ptr = hdr->block;
+ }
+ return ptr;
+}
+
+static bool
+malloc_mcheck_before (size_t *sizep, void **victimp)
+{
+ size_t size = *sizep;
+
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+
+ if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+ {
+ __set_errno (ENOMEM);
+ *victimp = NULL;
+ return true;
+ }
+
+ *sizep = sizeof (struct hdr) + size + 1;
+ return false;
+}
+
+static void *
+malloc_mcheck_after (void *mem, size_t size)
+{
+ struct hdr *hdr = mem;
+
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->size = size;
+ link_blk (hdr);
+ hdr->block = hdr;
+ hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
+ ((char *) &hdr[1])[size] = MAGICBYTE;
+ flood ((void *) (hdr + 1), MALLOCFLOOD, size);
+ return (void *) (hdr + 1);
+}
+
+static bool
+memalign_mcheck_before (size_t alignment, size_t *sizep, void **victimp)
+{
+ struct hdr *hdr;
+ size_t slop, size = *sizep;
+
+ /* Punt to malloc to avoid double headers. */
+ if (alignment <= MALLOC_ALIGNMENT)
+ {
+ *victimp = __libc_malloc (size);
+ return true;
+ }
+
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+
+ slop = (sizeof *hdr + alignment - 1) & - alignment;
+
+ if (size > ~((size_t) 0) - (slop + 1))
+ {
+ __set_errno (ENOMEM);
+ *victimp = NULL;
+ return true;
+ }
+
+ *sizep = slop + size + 1;
+ return false;
+}
+
+static void *
+memalign_mcheck_after (void *block, size_t alignment, size_t size)
+{
+ if (block == NULL)
+ return NULL;
+
+ /* This was served by __libc_malloc, so return as is. */
+ if (alignment <= MALLOC_ALIGNMENT)
+ return block;
+
+ size_t slop = (sizeof (struct hdr) + alignment - 1) & - alignment;
+ struct hdr *hdr = ((struct hdr *) (block + slop)) - 1;
+
+ hdr->size = size;
+ link_blk (hdr);
+ hdr->block = (void *) block;
+ hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
+ ((char *) &hdr[1])[size] = MAGICBYTE;
+ flood ((void *) (hdr + 1), MALLOCFLOOD, size);
+ return (void *) (hdr + 1);
+}
+
+static bool
+realloc_mcheck_before (void **ptrp, size_t *sizep, size_t *oldsize,
+ void **victimp)
+{
+ size_t size = *sizep;
+ void *ptr = *ptrp;
+
+ /* Handle special cases to avoid adding multiple headers. */
+ if (size == 0)
+ {
+ __libc_free (ptr);
+ *victimp = NULL;
+ return true;
+ }
+
+ if (ptr == NULL)
+ {
+ *victimp = __libc_malloc (size);
+ *oldsize = 0;
+ return true;
+ }
+
+ if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
+ {
+ __set_errno (ENOMEM);
+ *victimp = NULL;
+ *oldsize = 0;
+ return true;
+ }
+
+ if (pedantic)
+ __mcheck_checkptr (NULL);
+
+ struct hdr *hdr;
+ size_t osize;
+
+ /* Update the oldptr for glibc realloc. */
+ *ptrp = hdr = ((struct hdr *) ptr) - 1;
+
+ osize = hdr->size;
+
+ checkhdr (hdr);
+ unlink_blk (hdr);
+ if (size < osize)
+ flood ((char *) ptr + size, FREEFLOOD, osize - size);
+
+ *oldsize = osize;
+ *sizep = sizeof (struct hdr) + size + 1;
+ return false;
+}
+
+static void *
+realloc_mcheck_after (void *ptr, void *oldptr, size_t size, size_t osize)
+{
+ struct hdr *hdr = ptr;
+
+ if (hdr == NULL)
+ return NULL;
+
+ /* Malloc already added the header so don't tamper with it. */
+ if (oldptr == NULL)
+ return ptr;
+
+ hdr->size = size;
+ link_blk (hdr);
+ hdr->block = hdr;
+ hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
+ ((char *) &hdr[1])[size] = MAGICBYTE;
+ if (size > osize)
+ flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
+ return (void *) (hdr + 1);
+}
+
+__attribute__ ((noreturn))
+static void
+mabort (enum mcheck_status status)
+{
+ const char *msg;
+ switch (status)
+ {
+ case MCHECK_OK:
+ msg = _ ("memory is consistent, library is buggy\n");
+ break;
+ case MCHECK_HEAD:
+ msg = _ ("memory clobbered before allocated block\n");
+ break;
+ case MCHECK_TAIL:
+ msg = _ ("memory clobbered past end of allocated block\n");
+ break;
+ case MCHECK_FREE:
+ msg = _ ("block freed twice\n");
+ break;
+ default:
+ msg = _ ("bogus mcheck_status, library is buggy\n");
+ break;
+ }
+#ifdef _LIBC
+ __libc_fatal (msg);
+#else
+ fprintf (stderr, "mcheck: %s", msg);
+ fflush (stderr);
+ abort ();
+#endif
+}
+
+int
+__mcheck_initialize (void (*func) (enum mcheck_status), bool in_pedantic)
+{
+ abortfunc = (func != NULL) ? func : &mabort;
+
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ goto out;
+
+ switch (__malloc_initialized)
+ {
+ case -1:
+ ptmalloc_init ();
+ /* FALLTHROUGH */
+ case 0:
+ __malloc_debug_enable (MALLOC_MCHECK_HOOK);
+ break;
+ default:
+ break;
+ }
+
+ if (!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ return -1;
+
+out:
+ pedantic = in_pedantic;
+ return 0;
+}
@@ -17,17 +17,7 @@
/* The object of this file should be installed as libmcheck.a,
so one can do -lmcheck to turn on mcheck. */
-
-#include <malloc.h>
-#include <mcheck.h>
#include <shlib-compat.h>
-static void
-turn_on_mcheck (void)
-{
- mcheck (NULL);
-}
-
-void (*__malloc_initialize_hook) (void) = turn_on_mcheck;
-compat_symbol_reference (libc, __malloc_initialize_hook,
- __malloc_initialize_hook, GLIBC_2_0);
+const int __libc_lmcheck = 1;
+compat_symbol_reference (libc, __libc_lmcheck, __libc_lmcheck, GLIBC_2_34);
@@ -1,4 +1,4 @@
-/* Standard debugging hooks for `malloc'.
+/* The mcheck() interface.
Copyright (C) 1990-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Written May 1989 by Mike Haertel.
@@ -23,378 +23,22 @@
# include <mcheck.h>
# include <stdint.h>
# include <stdio.h>
-# include <libintl.h>
# include <errno.h>
#endif
-/* Old hook values. */
-static void (*old_free_hook)(void *ptr, const void *);
-static void *(*old_malloc_hook) (size_t size, const void *);
-static void *(*old_memalign_hook) (size_t alignment, size_t size,
- const void *);
-static void *(*old_realloc_hook) (void *ptr, size_t size,
- const void *);
-
-/* Function to call when something awful happens. */
-static void (*abortfunc) (enum mcheck_status);
-
-/* Arbitrary magical numbers. */
-#define MAGICWORD 0xfedabeeb
-#define MAGICFREE 0xd8675309
-#define MAGICBYTE ((char) 0xd7)
-#define MALLOCFLOOD ((char) 0x93)
-#define FREEFLOOD ((char) 0x95)
-
-struct hdr
-{
- size_t size; /* Exact size requested by user. */
- unsigned long int magic; /* Magic number to check header integrity. */
- struct hdr *prev;
- struct hdr *next;
- void *block; /* Real block allocated, for memalign. */
- unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
-};
-
-/* This is the beginning of the list of all memory blocks allocated.
- It is only constructed if the pedantic testing is requested. */
-static struct hdr *root;
-
-static int mcheck_used;
-
-/* Nonzero if pedentic checking of all blocks is requested. */
-static int pedantic;
-
-#if defined _LIBC || defined STDC_HEADERS || defined USG
-# include <string.h>
-# define flood memset
-#else
-static void flood (void *, int, size_t);
-static void
-flood (void *ptr, int val, size_t size)
-{
- char *cp = ptr;
- while (size--)
- *cp++ = val;
-}
-#endif
-
-static enum mcheck_status
-checkhdr (const struct hdr *hdr)
-{
- enum mcheck_status status;
-
- if (!mcheck_used)
- /* Maybe the mcheck used is disabled? This happens when we find
- an error and report it. */
- return MCHECK_OK;
-
- switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
- {
- default:
- status = MCHECK_HEAD;
- break;
- case MAGICFREE:
- status = MCHECK_FREE;
- break;
- case MAGICWORD:
- if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
- status = MCHECK_TAIL;
- else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
- status = MCHECK_HEAD;
- else
- status = MCHECK_OK;
- break;
- }
- if (status != MCHECK_OK)
- {
- mcheck_used = 0;
- (*abortfunc) (status);
- mcheck_used = 1;
- }
- return status;
-}
-
void
mcheck_check_all (void)
{
- /* Walk through all the active blocks and test whether they were tampered
- with. */
- struct hdr *runp = root;
-
- /* Temporarily turn off the checks. */
- pedantic = 0;
-
- while (runp != NULL)
- {
- (void) checkhdr (runp);
-
- runp = runp->next;
- }
-
- /* Turn checks on again. */
- pedantic = 1;
+ __mcheck_checkptr (NULL);
}
#ifdef _LIBC
libc_hidden_def (mcheck_check_all)
#endif
-static void
-unlink_blk (struct hdr *ptr)
-{
- if (ptr->next != NULL)
- {
- ptr->next->prev = ptr->prev;
- ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
- + (uintptr_t) ptr->next->next);
- }
- if (ptr->prev != NULL)
- {
- ptr->prev->next = ptr->next;
- ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
- + (uintptr_t) ptr->prev->next);
- }
- else
- root = ptr->next;
-}
-
-static void
-link_blk (struct hdr *hdr)
-{
- hdr->prev = NULL;
- hdr->next = root;
- root = hdr;
- hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
-
- /* And the next block. */
- if (hdr->next != NULL)
- {
- hdr->next->prev = hdr;
- hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
- + (uintptr_t) hdr->next->next);
- }
-}
-static void
-freehook (void *ptr, const void *caller)
-{
- if (pedantic)
- mcheck_check_all ();
- if (ptr)
- {
- struct hdr *hdr = ((struct hdr *) ptr) - 1;
- checkhdr (hdr);
- hdr->magic = MAGICFREE;
- hdr->magic2 = MAGICFREE;
- unlink_blk (hdr);
- hdr->prev = hdr->next = NULL;
- flood (ptr, FREEFLOOD, hdr->size);
- ptr = hdr->block;
- }
- __free_hook = old_free_hook;
- if (old_free_hook != NULL)
- (*old_free_hook)(ptr, caller);
- else
- free (ptr);
- __free_hook = freehook;
-}
-
-static void *
-mallochook (size_t size, const void *caller)
-{
- struct hdr *hdr;
-
- if (pedantic)
- mcheck_check_all ();
-
- if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
- {
- __set_errno (ENOMEM);
- return NULL;
- }
-
- __malloc_hook = old_malloc_hook;
- if (old_malloc_hook != NULL)
- hdr = (struct hdr *) (*old_malloc_hook)(sizeof (struct hdr) + size + 1,
- caller);
- else
- hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
- __malloc_hook = mallochook;
- if (hdr == NULL)
- return NULL;
-
- hdr->size = size;
- link_blk (hdr);
- hdr->block = hdr;
- hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
- ((char *) &hdr[1])[size] = MAGICBYTE;
- flood ((void *) (hdr + 1), MALLOCFLOOD, size);
- return (void *) (hdr + 1);
-}
-
-static void *
-memalignhook (size_t alignment, size_t size,
- const void *caller)
-{
- struct hdr *hdr;
- size_t slop;
- char *block;
-
- if (pedantic)
- mcheck_check_all ();
-
- slop = (sizeof *hdr + alignment - 1) & - alignment;
-
- if (size > ~((size_t) 0) - (slop + 1))
- {
- __set_errno (ENOMEM);
- return NULL;
- }
-
- __memalign_hook = old_memalign_hook;
- if (old_memalign_hook != NULL)
- block = (*old_memalign_hook)(alignment, slop + size + 1, caller);
- else
- block = memalign (alignment, slop + size + 1);
- __memalign_hook = memalignhook;
- if (block == NULL)
- return NULL;
-
- hdr = ((struct hdr *) (block + slop)) - 1;
-
- hdr->size = size;
- link_blk (hdr);
- hdr->block = (void *) block;
- hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
- ((char *) &hdr[1])[size] = MAGICBYTE;
- flood ((void *) (hdr + 1), MALLOCFLOOD, size);
- return (void *) (hdr + 1);
-}
-
-static void *
-reallochook (void *ptr, size_t size, const void *caller)
-{
- if (size == 0)
- {
- freehook (ptr, caller);
- return NULL;
- }
-
- struct hdr *hdr;
- size_t osize;
-
- if (pedantic)
- mcheck_check_all ();
-
- if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
- {
- __set_errno (ENOMEM);
- return NULL;
- }
-
- if (ptr)
- {
- hdr = ((struct hdr *) ptr) - 1;
- osize = hdr->size;
-
- checkhdr (hdr);
- unlink_blk (hdr);
- if (size < osize)
- flood ((char *) ptr + size, FREEFLOOD, osize - size);
- }
- else
- {
- osize = 0;
- hdr = NULL;
- }
- __free_hook = old_free_hook;
- __malloc_hook = old_malloc_hook;
- __memalign_hook = old_memalign_hook;
- __realloc_hook = old_realloc_hook;
- if (old_realloc_hook != NULL)
- hdr = (struct hdr *) (*old_realloc_hook)((void *) hdr,
- sizeof (struct hdr) + size + 1,
- caller);
- else
- hdr = (struct hdr *) realloc ((void *) hdr,
- sizeof (struct hdr) + size + 1);
- __free_hook = freehook;
- __malloc_hook = mallochook;
- __memalign_hook = memalignhook;
- __realloc_hook = reallochook;
- if (hdr == NULL)
- return NULL;
-
- hdr->size = size;
- link_blk (hdr);
- hdr->block = hdr;
- hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
- ((char *) &hdr[1])[size] = MAGICBYTE;
- if (size > osize)
- flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
- return (void *) (hdr + 1);
-}
-
-__attribute__ ((noreturn))
-static void
-mabort (enum mcheck_status status)
-{
- const char *msg;
- switch (status)
- {
- case MCHECK_OK:
- msg = _ ("memory is consistent, library is buggy\n");
- break;
- case MCHECK_HEAD:
- msg = _ ("memory clobbered before allocated block\n");
- break;
- case MCHECK_TAIL:
- msg = _ ("memory clobbered past end of allocated block\n");
- break;
- case MCHECK_FREE:
- msg = _ ("block freed twice\n");
- break;
- default:
- msg = _ ("bogus mcheck_status, library is buggy\n");
- break;
- }
-#ifdef _LIBC
- __libc_fatal (msg);
-#else
- fprintf (stderr, "mcheck: %s", msg);
- fflush (stderr);
- abort ();
-#endif
-}
-
-/* Memory barrier so that GCC does not optimize out the argument. */
-#define malloc_opt_barrier(x) \
- ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
-
int
mcheck (void (*func) (enum mcheck_status))
{
- abortfunc = (func != NULL) ? func : &mabort;
-
- /* These hooks may not be safely inserted if malloc is already in use. */
- if (__malloc_initialized <= 0 && !mcheck_used)
- {
- /* We call malloc() once here to ensure it is initialized. */
- void *p = malloc (0);
- /* GCC might optimize out the malloc/free pair without a barrier. */
- p = malloc_opt_barrier (p);
- free (p);
-
- old_free_hook = __free_hook;
- __free_hook = freehook;
- old_malloc_hook = __malloc_hook;
- __malloc_hook = mallochook;
- old_memalign_hook = __memalign_hook;
- __memalign_hook = memalignhook;
- old_realloc_hook = __realloc_hook;
- __realloc_hook = reallochook;
- mcheck_used = 1;
- }
-
- return mcheck_used ? 0 : -1;
+ return __mcheck_initialize (func, false);
}
#ifdef _LIBC
libc_hidden_def (mcheck)
@@ -403,14 +47,11 @@ libc_hidden_def (mcheck)
int
mcheck_pedantic (void (*func) (enum mcheck_status))
{
- int res = mcheck (func);
- if (res == 0)
- pedantic = 1;
- return res;
+ return __mcheck_initialize (func, true);
}
enum mcheck_status
mprobe (void *ptr)
{
- return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
+ return __mcheck_checkptr (ptr);
}
@@ -2223,6 +2223,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 _hurd_libc_proc_init F
GLIBC_2.34 dladdr F
@@ -2376,6 +2376,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2475,6 +2475,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2135,6 +2135,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -221,6 +221,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -218,6 +218,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2349,6 +2349,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2302,6 +2302,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2486,6 +2486,7 @@ GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2313,6 +2313,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -222,6 +222,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2429,6 +2429,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2400,6 +2400,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2397,6 +2397,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2394,6 +2394,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2392,6 +2392,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2400,6 +2400,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2364,6 +2364,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2439,6 +2439,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2456,6 +2456,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2489,6 +2489,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2277,6 +2277,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2572,6 +2572,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2137,6 +2137,7 @@ GLIBC_2.33 write F
GLIBC_2.33 writev F
GLIBC_2.33 wscanf F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2337,6 +2337,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2454,6 +2454,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2314,6 +2314,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2309,6 +2309,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2306,6 +2306,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2449,6 +2449,7 @@ GLIBC_2.34 __glob64_time64 F
GLIBC_2.34 __globfree64_time64 F
GLIBC_2.34 __gmtime64 F
GLIBC_2.34 __gmtime64_r F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __localtime64 F
GLIBC_2.34 __localtime64_r F
@@ -2336,6 +2336,7 @@ GLIBC_2.33 mknodat F
GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2292,6 +2292,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F
@@ -2391,6 +2391,7 @@ GLIBC_2.33 stat F
GLIBC_2.33 stat64 F
GLIBC_2.34 _Fork F
GLIBC_2.34 __isnanf128 F
+GLIBC_2.34 __libc_lmcheck D 0x4
GLIBC_2.34 __libc_start_main F
GLIBC_2.34 __mq_open_2 F
GLIBC_2.34 __pthread_cleanup_routine F