/* Malloc debug DSO. Copyright (C) 2021 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; see the file COPYING.LIB. If not, see . */ #include #include #include #include #include #include /* Support only the glibc allocators. */ extern void *__libc_malloc (size_t); extern void __libc_free (void *); extern void *__libc_realloc (void *, size_t); extern void *__libc_memalign (size_t, size_t); extern void *__libc_valloc (size_t); extern void *__libc_pvalloc (size_t); extern void *__libc_calloc (size_t, size_t); #define DEBUG_FN(fn) \ static __typeof (__libc_ ## fn) __debug_ ## fn DEBUG_FN(malloc); DEBUG_FN(free); DEBUG_FN(realloc); DEBUG_FN(memalign); DEBUG_FN(valloc); DEBUG_FN(pvalloc); DEBUG_FN(calloc); extern void (*__free_hook) (void *, const void *); compat_symbol_reference (libc, __free_hook, __free_hook, GLIBC_2_0); extern void * (*__malloc_hook) (size_t, const void *); compat_symbol_reference (libc, __malloc_hook, __malloc_hook, GLIBC_2_0); extern void * (*__realloc_hook) (void *, size_t, const void *); compat_symbol_reference (libc, __realloc_hook, __realloc_hook, GLIBC_2_0); extern void * (*__memalign_hook) (size_t, size_t, const void *); compat_symbol_reference (libc, __memalign_hook, __memalign_hook, GLIBC_2_0); static size_t pagesize; /* The allocator functions. */ static void * __debug_malloc (size_t bytes) { void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) return (*hook)(bytes, RETURN_ADDRESS (0)); return __libc_malloc (bytes); } strong_alias (__debug_malloc, malloc) static void __debug_free (void *mem) { void (*hook) (void *, const void *) = atomic_forced_read (__free_hook); if (__builtin_expect (hook != NULL, 0)) { (*hook)(mem, RETURN_ADDRESS (0)); return; } __libc_free (mem); } strong_alias (__debug_free, free) static void * __debug_realloc (void *oldmem, size_t bytes) { void *(*hook) (void *, size_t, const void *) = atomic_forced_read (__realloc_hook); if (__builtin_expect (hook != NULL, 0)) return (*hook)(oldmem, bytes, RETURN_ADDRESS (0)); return __libc_realloc (oldmem, bytes); } strong_alias (__debug_realloc, realloc) static void * _debug_mid_memalign (size_t alignment, size_t bytes, const void *address) { void *(*hook) (size_t, size_t, const void *) = atomic_forced_read (__memalign_hook); if (__builtin_expect (hook != NULL, 0)) return (*hook)(alignment, bytes, address); return __libc_memalign (alignment, bytes); } static void * __debug_memalign (size_t alignment, size_t bytes) { return _debug_mid_memalign (alignment, bytes, RETURN_ADDRESS (0)); } strong_alias (__debug_memalign, memalign) strong_alias (__debug_memalign, aligned_alloc) static void * __debug_pvalloc (size_t bytes) { size_t rounded_bytes; if (!pagesize) pagesize = sysconf (_SC_PAGESIZE); /* ALIGN_UP with overflow check. */ if (__glibc_unlikely (__builtin_add_overflow (bytes, pagesize - 1, &rounded_bytes))) { errno = ENOMEM; return NULL; } rounded_bytes = rounded_bytes & -(pagesize - 1); return _debug_mid_memalign (pagesize, rounded_bytes, RETURN_ADDRESS (0)); } strong_alias (__debug_pvalloc, pvalloc) static void * __debug_valloc (size_t bytes) { if (!pagesize) pagesize = sysconf (_SC_PAGESIZE); return _debug_mid_memalign (pagesize, bytes, RETURN_ADDRESS (0)); } strong_alias (__debug_valloc, valloc) static int __debug_posix_memalign (void **memptr, size_t alignment, size_t bytes) { /* 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; *memptr = _debug_mid_memalign (alignment, bytes, RETURN_ADDRESS (0)); if (*memptr == NULL) return ENOMEM; return 0; } strong_alias (__debug_posix_memalign, posix_memalign) static void * __debug_calloc (size_t nmemb, size_t size) { void *(*hook) (size_t, const void *) = atomic_forced_read (__malloc_hook); if (__builtin_expect (hook != NULL, 0)) { size_t bytes; if (__glibc_unlikely (__builtin_mul_overflow (nmemb, size, &bytes))) { errno = ENOMEM; return NULL; } void *mem = (*hook)(bytes, RETURN_ADDRESS (0)); if (mem != NULL) memset (mem, 0, bytes); return mem; } return __libc_calloc (nmemb, size); } strong_alias (__debug_calloc, calloc)