mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-08 14:20:07 +00:00
190 lines
5.2 KiB
C
190 lines
5.2 KiB
C
|
/* 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 <https://www.gnu.org/licenses/>. */
|
||
|
|
||
|
#include <atomic.h>
|
||
|
#include <libc-symbols.h>
|
||
|
#include <shlib-compat.h>
|
||
|
#include <string.h>
|
||
|
#include <unistd.h>
|
||
|
#include <sys/param.h>
|
||
|
|
||
|
/* 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)
|