2 Copyright (C) 2021 Free Software Foundation, Inc.
3 Copyright The GNU Toolchain Authors.
4 This file is part of the GNU C Library.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If
18 not, see <https://www.gnu.org/licenses/>. */
21 #include <libc-symbols.h>
22 #include <shlib-compat.h>
25 #include <sys/param.h>
27 #if SHLIB_COMPAT (libc_malloc_debug, GLIBC_2_0, GLIBC_2_34)
28 /* Support only the glibc allocators. */
29 extern void *__libc_malloc (size_t);
30 extern void __libc_free (void *);
31 extern void *__libc_realloc (void *, size_t);
32 extern void *__libc_memalign (size_t, size_t);
33 extern void *__libc_valloc (size_t);
34 extern void *__libc_pvalloc (size_t);
35 extern void *__libc_calloc (size_t, size_t);
37 #define DEBUG_FN(fn) \
38 static __typeof (__libc_ ## fn) __debug_ ## fn
48 static int debug_initialized
= -1;
50 enum malloc_debug_hooks
53 MALLOC_MCHECK_HOOK
= 1 << 0, /* mcheck() */
54 MALLOC_MTRACE_HOOK
= 1 << 1, /* mtrace() */
55 MALLOC_CHECK_HOOK
= 1 << 2, /* MALLOC_CHECK_ or glibc.malloc.check. */
57 static unsigned __malloc_debugging_hooks
;
59 static __always_inline
bool
60 __is_malloc_debug_enabled (enum malloc_debug_hooks flag
)
62 return __malloc_debugging_hooks
& flag
;
65 static __always_inline
void
66 __malloc_debug_enable (enum malloc_debug_hooks flag
)
68 __malloc_debugging_hooks
|= flag
;
71 static __always_inline
void
72 __malloc_debug_disable (enum malloc_debug_hooks flag
)
74 __malloc_debugging_hooks
&= ~flag
;
79 #include "malloc-check.c"
81 #if SHLIB_COMPAT (libc_malloc_debug, GLIBC_2_0, GLIBC_2_24)
82 extern void (*__malloc_initialize_hook
) (void);
83 compat_symbol_reference (libc
, __malloc_initialize_hook
,
84 __malloc_initialize_hook
, GLIBC_2_0
);
87 static void *malloc_hook_ini (size_t, const void *) __THROW
;
88 static void *realloc_hook_ini (void *, size_t, const void *) __THROW
;
89 static void *memalign_hook_ini (size_t, size_t, const void *) __THROW
;
91 void (*__free_hook
) (void *, const void *) = NULL
;
92 void *(*__malloc_hook
) (size_t, const void *) = malloc_hook_ini
;
93 void *(*__realloc_hook
) (void *, size_t, const void *) = realloc_hook_ini
;
94 void *(*__memalign_hook
) (size_t, size_t, const void *) = memalign_hook_ini
;
96 /* Hooks for debugging versions. The initial hooks just call the
97 initialization routine, then do the normal work. */
99 /* These hooks will get executed only through the interposed allocator
100 functions in libc_malloc_debug.so. This means that the calls to malloc,
101 realloc, etc. will lead back into the interposed functions, which is what we
104 These initial hooks are assumed to be called in a single-threaded context,
105 so it is safe to reset all hooks at once upon initialization. */
108 generic_hook_ini (void)
110 debug_initialized
= 0;
111 __malloc_hook
= NULL
;
112 __realloc_hook
= NULL
;
113 __memalign_hook
= NULL
;
115 /* malloc check does not quite co-exist with libc malloc, so initialize
116 either on or the other. */
117 if (!initialize_malloc_check ())
118 /* The compiler does not know that these functions are allocators, so it
119 will not try to optimize it away. */
120 __libc_free (__libc_malloc (0));
122 #if SHLIB_COMPAT (libc_malloc_debug, GLIBC_2_0, GLIBC_2_24)
123 void (*hook
) (void) = __malloc_initialize_hook
;
128 debug_initialized
= 1;
132 malloc_hook_ini (size_t sz
, const void *caller
)
135 return __debug_malloc (sz
);
139 realloc_hook_ini (void *ptr
, size_t sz
, const void *caller
)
142 return __debug_realloc (ptr
, sz
);
146 memalign_hook_ini (size_t alignment
, size_t sz
, const void *caller
)
149 return __debug_memalign (alignment
, sz
);
152 static size_t pagesize
;
154 /* These variables are used for undumping support. Chunked are marked
155 as using mmap, but we leave them alone if they fall into this
156 range. NB: The chunk size for these chunks only includes the
157 initial size field (of SIZE_SZ bytes), there is no trailing size
158 field (unlike with regular mmapped chunks). */
159 static mchunkptr dumped_main_arena_start
; /* Inclusive. */
160 static mchunkptr dumped_main_arena_end
; /* Exclusive. */
162 /* True if the pointer falls into the dumped arena. Use this after
163 chunk_is_mmapped indicates a chunk is mmapped. */
164 #define DUMPED_MAIN_ARENA_CHUNK(p) \
165 ((p) >= dumped_main_arena_start && (p) < dumped_main_arena_end)
167 /* The allocator functions. */
170 __debug_malloc (size_t bytes
)
172 void *(*hook
) (size_t, const void *) = atomic_forced_read (__malloc_hook
);
173 if (__builtin_expect (hook
!= NULL
, 0))
174 return (*hook
)(bytes
, RETURN_ADDRESS (0));
177 size_t orig_bytes
= bytes
;
178 if ((!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
)
179 || !malloc_mcheck_before (&bytes
, &victim
)))
181 victim
= (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
)
182 ? malloc_check (bytes
) : __libc_malloc (bytes
));
184 if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
) && victim
!= NULL
)
185 victim
= malloc_mcheck_after (victim
, orig_bytes
);
186 if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK
))
187 malloc_mtrace_after (victim
, orig_bytes
, RETURN_ADDRESS (0));
191 strong_alias (__debug_malloc
, malloc
)
194 __debug_free (void *mem
)
196 void (*hook
) (void *, const void *) = atomic_forced_read (__free_hook
);
197 if (__builtin_expect (hook
!= NULL
, 0))
199 (*hook
)(mem
, RETURN_ADDRESS (0));
203 if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
))
204 mem
= free_mcheck (mem
);
206 if (DUMPED_MAIN_ARENA_CHUNK (mem2chunk (mem
)))
208 else if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
212 if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK
))
213 free_mtrace (mem
, RETURN_ADDRESS (0));
215 strong_alias (__debug_free
, free
)
218 __debug_realloc (void *oldmem
, size_t bytes
)
220 void *(*hook
) (void *, size_t, const void *) =
221 atomic_forced_read (__realloc_hook
);
222 if (__builtin_expect (hook
!= NULL
, 0))
223 return (*hook
)(oldmem
, bytes
, RETURN_ADDRESS (0));
225 size_t orig_bytes
= bytes
, oldsize
= 0;
228 if ((!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
)
229 || !realloc_mcheck_before (&oldmem
, &bytes
, &oldsize
, &victim
)))
231 mchunkptr oldp
= mem2chunk (oldmem
);
233 /* If this is a faked mmapped chunk from the dumped main arena,
234 always make a copy (and do not free the old chunk). */
235 if (DUMPED_MAIN_ARENA_CHUNK (oldp
))
237 if (bytes
== 0 && oldmem
!= NULL
)
241 const INTERNAL_SIZE_T osize
= chunksize (oldp
);
242 /* Must alloc, copy, free. */
243 victim
= __debug_malloc (bytes
);
244 /* Copy as many bytes as are available from the old chunk
245 and fit into the new size. NB: The overhead for faked
246 mmapped chunks is only SIZE_SZ, not CHUNK_HDR_SZ as for
247 regular mmapped chunks. */
250 if (bytes
> osize
- SIZE_SZ
)
251 bytes
= osize
- SIZE_SZ
;
252 memcpy (victim
, oldmem
, bytes
);
256 else if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
257 victim
= realloc_check (oldmem
, bytes
);
259 victim
= __libc_realloc (oldmem
, bytes
);
261 if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
) && victim
!= NULL
)
262 victim
= realloc_mcheck_after (victim
, oldmem
, orig_bytes
,
264 if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK
))
265 realloc_mtrace_after (victim
, oldmem
, orig_bytes
, RETURN_ADDRESS (0));
269 strong_alias (__debug_realloc
, realloc
)
272 _debug_mid_memalign (size_t alignment
, size_t bytes
, const void *address
)
274 void *(*hook
) (size_t, size_t, const void *) =
275 atomic_forced_read (__memalign_hook
);
276 if (__builtin_expect (hook
!= NULL
, 0))
277 return (*hook
)(alignment
, bytes
, address
);
280 size_t orig_bytes
= bytes
;
282 if ((!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
)
283 || !memalign_mcheck_before (alignment
, &bytes
, &victim
)))
285 victim
= (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
)
286 ? memalign_check (alignment
, bytes
)
287 : __libc_memalign (alignment
, bytes
));
289 if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
) && victim
!= NULL
)
290 victim
= memalign_mcheck_after (victim
, alignment
, orig_bytes
);
291 if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK
))
292 memalign_mtrace_after (victim
, orig_bytes
, address
);
298 __debug_memalign (size_t alignment
, size_t bytes
)
300 return _debug_mid_memalign (alignment
, bytes
, RETURN_ADDRESS (0));
302 strong_alias (__debug_memalign
, memalign
)
303 strong_alias (__debug_memalign
, aligned_alloc
)
306 __debug_pvalloc (size_t bytes
)
308 size_t rounded_bytes
;
311 pagesize
= sysconf (_SC_PAGESIZE
);
313 /* ALIGN_UP with overflow check. */
314 if (__glibc_unlikely (__builtin_add_overflow (bytes
,
321 rounded_bytes
= rounded_bytes
& -(pagesize
- 1);
323 return _debug_mid_memalign (pagesize
, rounded_bytes
, RETURN_ADDRESS (0));
325 strong_alias (__debug_pvalloc
, pvalloc
)
328 __debug_valloc (size_t bytes
)
331 pagesize
= sysconf (_SC_PAGESIZE
);
333 return _debug_mid_memalign (pagesize
, bytes
, RETURN_ADDRESS (0));
335 strong_alias (__debug_valloc
, valloc
)
338 __debug_posix_memalign (void **memptr
, size_t alignment
, size_t bytes
)
340 /* Test whether the SIZE argument is valid. It must be a power of
341 two multiple of sizeof (void *). */
342 if (alignment
% sizeof (void *) != 0
343 || !powerof2 (alignment
/ sizeof (void *))
347 *memptr
= _debug_mid_memalign (alignment
, bytes
, RETURN_ADDRESS (0));
354 strong_alias (__debug_posix_memalign
, posix_memalign
)
357 __debug_calloc (size_t nmemb
, size_t size
)
361 if (__glibc_unlikely (__builtin_mul_overflow (nmemb
, size
, &bytes
)))
367 void *(*hook
) (size_t, const void *) = atomic_forced_read (__malloc_hook
);
368 if (__builtin_expect (hook
!= NULL
, 0))
370 void *mem
= (*hook
)(bytes
, RETURN_ADDRESS (0));
373 memset (mem
, 0, bytes
);
378 size_t orig_bytes
= bytes
;
381 if ((!__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
)
382 || !malloc_mcheck_before (&bytes
, &victim
)))
384 victim
= (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
)
385 ? malloc_check (bytes
) : __libc_malloc (bytes
));
389 if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
))
390 victim
= malloc_mcheck_after (victim
, orig_bytes
);
391 memset (victim
, 0, orig_bytes
);
393 if (__is_malloc_debug_enabled (MALLOC_MTRACE_HOOK
))
394 malloc_mtrace_after (victim
, orig_bytes
, RETURN_ADDRESS (0));
398 strong_alias (__debug_calloc
, calloc
)
401 malloc_usable_size (void *mem
)
406 if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK
))
407 return mcheck_usable_size (mem
);
408 if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
409 return malloc_check_get_size (mem
);
411 mchunkptr p
= mem2chunk (mem
);
412 if (DUMPED_MAIN_ARENA_CHUNK (p
))
413 return chunksize (p
) - SIZE_SZ
;
415 return musable (mem
);
418 #define LIBC_SYMBOL(sym) libc_ ## sym
419 #define SYMHANDLE(sym) sym ## _handle
421 #define LOAD_SYM(sym) ({ \
422 static void *SYMHANDLE (sym); \
423 if (SYMHANDLE (sym) == NULL) \
424 SYMHANDLE (sym) = dlsym (RTLD_NEXT, #sym); \
429 malloc_info (int options
, FILE *fp
)
431 if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
432 return __malloc_info (options
, fp
);
434 int (*LIBC_SYMBOL (malloc_info
)) (int, FILE *) = LOAD_SYM (malloc_info
);
435 if (LIBC_SYMBOL (malloc_info
) == NULL
)
438 return LIBC_SYMBOL (malloc_info
) (options
, fp
);
442 mallopt (int param_number
, int value
)
444 if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
445 return __libc_mallopt (param_number
, value
);
447 int (*LIBC_SYMBOL (mallopt
)) (int, int) = LOAD_SYM (mallopt
);
448 if (LIBC_SYMBOL (mallopt
) == NULL
)
451 return LIBC_SYMBOL (mallopt
) (param_number
, value
);
457 if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
458 return __malloc_stats ();
460 void (*LIBC_SYMBOL (malloc_stats
)) (void) = LOAD_SYM (malloc_stats
);
461 if (LIBC_SYMBOL (malloc_stats
) == NULL
)
464 LIBC_SYMBOL (malloc_stats
) ();
470 if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
471 return __libc_mallinfo2 ();
473 struct mallinfo2 (*LIBC_SYMBOL (mallinfo2
)) (void) = LOAD_SYM (mallinfo2
);
474 if (LIBC_SYMBOL (mallinfo2
) == NULL
)
476 struct mallinfo2 ret
= {0};
480 return LIBC_SYMBOL (mallinfo2
) ();
486 if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
487 return __libc_mallinfo ();
489 struct mallinfo (*LIBC_SYMBOL (mallinfo
)) (void) = LOAD_SYM (mallinfo
);
490 if (LIBC_SYMBOL (mallinfo
) == NULL
)
492 struct mallinfo ret
= {0};
496 return LIBC_SYMBOL (mallinfo
) ();
500 malloc_trim (size_t s
)
502 if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK
))
503 return __malloc_trim (s
);
505 int (*LIBC_SYMBOL (malloc_trim
)) (size_t) = LOAD_SYM (malloc_trim
);
506 if (LIBC_SYMBOL (malloc_trim
) == NULL
)
509 return LIBC_SYMBOL (malloc_trim
) (s
);
512 #if SHLIB_COMPAT (libc_malloc_debug, GLIBC_2_0, GLIBC_2_25)
514 /* Support for restoring dumped heaps contained in historic Emacs
515 executables. The heap saving feature (malloc_get_state) is no
516 longer implemented in this version of glibc, but we have a heap
517 rewriter in malloc_set_state which transforms the heap into a
518 version compatible with current malloc. */
520 #define MALLOC_STATE_MAGIC 0x444c4541l
521 #define MALLOC_STATE_VERSION (0 * 0x100l + 5l) /* major*0x100 + minor */
523 struct malloc_save_state
527 mbinptr av
[NBINS
* 2 + 2];
529 int sbrked_mem_bytes
;
530 unsigned long trim_threshold
;
531 unsigned long top_pad
;
532 unsigned int n_mmaps_max
;
533 unsigned long mmap_threshold
;
535 unsigned long max_sbrked_mem
;
536 unsigned long max_total_mem
; /* Always 0, for backwards compatibility. */
537 unsigned int n_mmaps
;
538 unsigned int max_n_mmaps
;
539 unsigned long mmapped_mem
;
540 unsigned long max_mmapped_mem
;
541 int using_malloc_checking
;
542 unsigned long max_fast
;
543 unsigned long arena_test
;
544 unsigned long arena_max
;
545 unsigned long narenas
;
548 /* Dummy implementation which always fails. We need to provide this
549 symbol so that existing Emacs binaries continue to work with
552 malloc_get_state (void)
554 __set_errno (ENOSYS
);
557 compat_symbol (libc_malloc_debug
, malloc_get_state
, malloc_get_state
,
561 malloc_set_state (void *msptr
)
563 struct malloc_save_state
*ms
= (struct malloc_save_state
*) msptr
;
565 if (ms
->magic
!= MALLOC_STATE_MAGIC
)
568 /* Must fail if the major version is too high. */
569 if ((ms
->version
& ~0xffl
) > (MALLOC_STATE_VERSION
& ~0xffl
))
572 if (debug_initialized
== 1)
575 bool check_was_enabled
= __is_malloc_debug_enabled (MALLOC_CHECK_HOOK
);
577 /* It's not too late, so disable MALLOC_CHECK_ and all of the hooks. */
578 __malloc_hook
= NULL
;
579 __realloc_hook
= NULL
;
581 __memalign_hook
= NULL
;
582 __malloc_debug_disable (MALLOC_CHECK_HOOK
);
584 /* We do not need to perform locking here because malloc_set_state
585 must be called before the first call into the malloc subsytem (usually via
586 __malloc_initialize_hook). pthread_create always calls calloc and thus
587 must be called only afterwards, so there cannot be more than one thread
588 when we reach this point. Also handle initialization if either we ended
589 up being called before the first malloc or through the hook when
590 malloc-check was enabled. */
591 if (debug_initialized
< 0)
593 else if (check_was_enabled
)
594 __libc_free (__libc_malloc (0));
596 /* Patch the dumped heap. We no longer try to integrate into the
597 existing heap. Instead, we mark the existing chunks as mmapped.
598 Together with the update to dumped_main_arena_start and
599 dumped_main_arena_end, realloc and free will recognize these
600 chunks as dumped fake mmapped chunks and never free them. */
602 /* Find the chunk with the lowest address with the heap. */
603 mchunkptr chunk
= NULL
;
605 size_t *candidate
= (size_t *) ms
->sbrk_base
;
606 size_t *end
= (size_t *) (ms
->sbrk_base
+ ms
->sbrked_mem_bytes
);
607 while (candidate
< end
)
610 chunk
= mem2chunk ((void *) (candidate
+ 1));
619 /* Iterate over the dumped heap and patch the chunks so that they
620 are treated as fake mmapped chunks. */
621 mchunkptr top
= ms
->av
[2];
626 /* Mark chunk as mmapped, to trigger the fallback path. */
627 size_t size
= chunksize (chunk
);
628 set_head (chunk
, size
| IS_MMAPPED
);
630 chunk
= next_chunk (chunk
);
633 /* The dumped fake mmapped chunks all lie in this address range. */
634 dumped_main_arena_start
= (mchunkptr
) ms
->sbrk_base
;
635 dumped_main_arena_end
= top
;
639 compat_symbol (libc_malloc_debug
, malloc_set_state
, malloc_set_state
,
643 /* Do not allow linking against the library. */
644 compat_symbol (libc_malloc_debug
, aligned_alloc
, aligned_alloc
, GLIBC_2_16
);
645 compat_symbol (libc_malloc_debug
, calloc
, calloc
, GLIBC_2_0
);
646 compat_symbol (libc_malloc_debug
, free
, free
, GLIBC_2_0
);
647 compat_symbol (libc_malloc_debug
, mallinfo2
, mallinfo2
, GLIBC_2_33
);
648 compat_symbol (libc_malloc_debug
, mallinfo
, mallinfo
, GLIBC_2_0
);
649 compat_symbol (libc_malloc_debug
, malloc_info
, malloc_info
, GLIBC_2_10
);
650 compat_symbol (libc_malloc_debug
, malloc
, malloc
, GLIBC_2_0
);
651 compat_symbol (libc_malloc_debug
, malloc_stats
, malloc_stats
, GLIBC_2_0
);
652 compat_symbol (libc_malloc_debug
, malloc_trim
, malloc_trim
, GLIBC_2_0
);
653 compat_symbol (libc_malloc_debug
, malloc_usable_size
, malloc_usable_size
,
655 compat_symbol (libc_malloc_debug
, mallopt
, mallopt
, GLIBC_2_0
);
656 compat_symbol (libc_malloc_debug
, mcheck_check_all
, mcheck_check_all
,
658 compat_symbol (libc_malloc_debug
, mcheck
, mcheck
, GLIBC_2_0
);
659 compat_symbol (libc_malloc_debug
, mcheck_pedantic
, mcheck_pedantic
, GLIBC_2_2
);
660 compat_symbol (libc_malloc_debug
, memalign
, memalign
, GLIBC_2_0
);
661 compat_symbol (libc_malloc_debug
, mprobe
, mprobe
, GLIBC_2_0
);
662 compat_symbol (libc_malloc_debug
, mtrace
, mtrace
, GLIBC_2_0
);
663 compat_symbol (libc_malloc_debug
, muntrace
, muntrace
, GLIBC_2_0
);
664 compat_symbol (libc_malloc_debug
, posix_memalign
, posix_memalign
, GLIBC_2_2
);
665 compat_symbol (libc_malloc_debug
, pvalloc
, pvalloc
, GLIBC_2_0
);
666 compat_symbol (libc_malloc_debug
, realloc
, realloc
, GLIBC_2_0
);
667 compat_symbol (libc_malloc_debug
, valloc
, valloc
, GLIBC_2_0
);
668 compat_symbol (libc_malloc_debug
, __free_hook
, __free_hook
, GLIBC_2_0
);
669 compat_symbol (libc_malloc_debug
, __malloc_hook
, __malloc_hook
, GLIBC_2_0
);
670 compat_symbol (libc_malloc_debug
, __realloc_hook
, __realloc_hook
, GLIBC_2_0
);
671 compat_symbol (libc_malloc_debug
, __memalign_hook
, __memalign_hook
, GLIBC_2_0
);