1 /* glibc.malloc.check implementation.
2 Copyright (C) 2001-2023 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, see <https://www.gnu.org/licenses/>. */
19 #define __mremap mremap
22 /* When memory is tagged, the checking data is stored in the user part
23 of the chunk. We can't rely on the user not having modified the
24 tags, so fetch the tag at each location before dereferencing
26 #define SAFE_CHAR_OFFSET(p,offset) \
27 ((unsigned char *) tag_at (((unsigned char *) p) + offset))
29 /* A simple, standard set of debugging hooks. Overhead is `only' one
30 byte per chunk; still this will catch most cases of double frees or
31 overruns. The goal here is to avoid obscure crashes due to invalid
32 usage, unlike in the MALLOC_DEBUG code. */
35 magicbyte (const void *p
)
39 magic
= (((uintptr_t) p
>> 3) ^ ((uintptr_t) p
>> 11)) & 0xFF;
40 /* Do not return 1. See the comment in mem2mem_check(). */
46 /* Visualize the chunk as being partitioned into blocks of 255 bytes from the
47 highest address of the chunk, downwards. The end of each block tells
48 us the size of that block, up to the actual size of the requested
49 memory. Our magic byte is right at the end of the requested size, so we
50 must reach it with this iteration, otherwise we have witnessed a memory
53 malloc_check_get_size (void *mem
)
57 mchunkptr p
= mem2chunk (mem
);
58 unsigned char magic
= magicbyte (p
);
60 for (size
= CHUNK_HDR_SZ
+ memsize (p
) - 1;
61 (c
= *SAFE_CHAR_OFFSET (p
, size
)) != magic
;
64 if (c
<= 0 || size
< (c
+ CHUNK_HDR_SZ
))
65 malloc_printerr ("malloc_check_get_size: memory corruption");
69 return size
- CHUNK_HDR_SZ
;
72 /* Instrument a chunk with overrun detector byte(s) and convert it
73 into a user pointer with requested size req_sz. */
76 mem2mem_check (void *ptr
, size_t req_sz
)
79 unsigned char *m_ptr
= ptr
;
80 size_t max_sz
, block_sz
, i
;
87 magic
= magicbyte (p
);
90 for (i
= max_sz
- 1; i
> req_sz
; i
-= block_sz
)
92 block_sz
= MIN (i
- req_sz
, 0xff);
93 /* Don't allow the magic byte to appear in the chain of length bytes.
94 For the following to work, magicbyte cannot return 0x01. */
95 if (block_sz
== magic
)
98 *SAFE_CHAR_OFFSET (m_ptr
, i
) = block_sz
;
100 *SAFE_CHAR_OFFSET (m_ptr
, req_sz
) = magic
;
101 return (void *) m_ptr
;
104 /* Convert a pointer to be free()d or realloc()ed to a valid chunk
105 pointer. If the provided pointer is not valid, return NULL. */
108 mem2chunk_check (void *mem
, unsigned char **magic_p
)
111 INTERNAL_SIZE_T sz
, c
;
114 if (!aligned_OK (mem
))
119 magic
= magicbyte (p
);
120 if (!chunk_is_mmapped (p
))
122 /* Must be a chunk in conventional heap memory. */
123 int contig
= contiguous (&main_arena
);
125 ((char *) p
< mp_
.sbrk_base
||
126 ((char *) p
+ sz
) >= (mp_
.sbrk_base
+ main_arena
.system_mem
))) ||
127 sz
< MINSIZE
|| sz
& MALLOC_ALIGN_MASK
|| !inuse (p
) ||
128 (!prev_inuse (p
) && ((prev_size (p
) & MALLOC_ALIGN_MASK
) != 0 ||
129 (contig
&& (char *) prev_chunk (p
) < mp_
.sbrk_base
) ||
130 next_chunk (prev_chunk (p
)) != p
)))
133 for (sz
= CHUNK_HDR_SZ
+ memsize (p
) - 1;
134 (c
= *SAFE_CHAR_OFFSET (p
, sz
)) != magic
;
137 if (c
== 0 || sz
< (c
+ CHUNK_HDR_SZ
))
143 unsigned long offset
, page_mask
= GLRO (dl_pagesize
) - 1;
145 /* mmap()ed chunks have MALLOC_ALIGNMENT or higher power-of-two
146 alignment relative to the beginning of a page. Check this
148 offset
= (unsigned long) mem
& page_mask
;
149 if ((offset
!= MALLOC_ALIGNMENT
&& offset
!= 0 && offset
!= 0x10 &&
150 offset
!= 0x20 && offset
!= 0x40 && offset
!= 0x80 && offset
!= 0x100 &&
151 offset
!= 0x200 && offset
!= 0x400 && offset
!= 0x800 && offset
!= 0x1000 &&
153 !chunk_is_mmapped (p
) || prev_inuse (p
) ||
154 ((((unsigned long) p
- prev_size (p
)) & page_mask
) != 0) ||
155 ((prev_size (p
) + sz
) & page_mask
) != 0)
158 for (sz
= CHUNK_HDR_SZ
+ memsize (p
) - 1;
159 (c
= *SAFE_CHAR_OFFSET (p
, sz
)) != magic
;
162 if (c
== 0 || sz
< (c
+ CHUNK_HDR_SZ
))
167 unsigned char* safe_p
= SAFE_CHAR_OFFSET (p
, sz
);
174 /* Check for corruption of the top chunk. */
178 mchunkptr t
= top (&main_arena
);
180 if (t
== initial_top (&main_arena
) ||
181 (!chunk_is_mmapped (t
) &&
182 chunksize (t
) >= MINSIZE
&&
184 (!contiguous (&main_arena
) ||
185 (char *) t
+ chunksize (t
) == mp_
.sbrk_base
+ main_arena
.system_mem
)))
188 malloc_printerr ("malloc: top chunk is corrupt");
192 malloc_check (size_t sz
)
197 if (__builtin_add_overflow (sz
, 1, &nb
))
199 __set_errno (ENOMEM
);
203 __libc_lock_lock (main_arena
.mutex
);
205 victim
= _int_malloc (&main_arena
, nb
);
206 __libc_lock_unlock (main_arena
.mutex
);
207 return mem2mem_check (tag_new_usable (victim
), sz
);
211 free_check (void *mem
)
220 /* Quickly check that the freed pointer matches the tag for the memory.
221 This gives a useful double-free detection. */
222 if (__glibc_unlikely (mtag_enabled
))
223 *(volatile char *)mem
;
225 __libc_lock_lock (main_arena
.mutex
);
226 p
= mem2chunk_check (mem
, NULL
);
228 malloc_printerr ("free(): invalid pointer");
229 if (chunk_is_mmapped (p
))
231 __libc_lock_unlock (main_arena
.mutex
);
236 /* Mark the chunk as belonging to the library again. */
237 (void)tag_region (chunk2mem (p
), memsize (p
));
238 _int_free (&main_arena
, p
, 1);
239 __libc_lock_unlock (main_arena
.mutex
);
245 realloc_check (void *oldmem
, size_t bytes
)
247 INTERNAL_SIZE_T chnb
;
249 unsigned char *magic_p
;
252 if (__builtin_add_overflow (bytes
, 1, &rb
))
254 __set_errno (ENOMEM
);
258 return malloc_check (bytes
);
266 /* Quickly check that the freed pointer matches the tag for the memory.
267 This gives a useful double-free detection. */
268 if (__glibc_unlikely (mtag_enabled
))
269 *(volatile char *)oldmem
;
271 __libc_lock_lock (main_arena
.mutex
);
272 const mchunkptr oldp
= mem2chunk_check (oldmem
, &magic_p
);
273 __libc_lock_unlock (main_arena
.mutex
);
275 malloc_printerr ("realloc(): invalid pointer");
276 const INTERNAL_SIZE_T oldsize
= chunksize (oldp
);
278 chnb
= checked_request2size (rb
);
281 __set_errno (ENOMEM
);
285 __libc_lock_lock (main_arena
.mutex
);
287 if (chunk_is_mmapped (oldp
))
290 mchunkptr newp
= mremap_chunk (oldp
, chnb
);
292 newmem
= chunk2mem_tag (newp
);
296 /* Note the extra SIZE_SZ overhead. */
297 if (oldsize
- SIZE_SZ
>= chnb
)
298 newmem
= oldmem
; /* do nothing */
301 /* Must alloc, copy, free. */
303 newmem
= _int_malloc (&main_arena
, rb
);
306 memcpy (newmem
, oldmem
, oldsize
- CHUNK_HDR_SZ
);
315 newmem
= _int_realloc (&main_arena
, oldp
, oldsize
, chnb
);
318 DIAG_PUSH_NEEDS_COMMENT
;
319 #if __GNUC_PREREQ (7, 0)
320 /* GCC 7 warns about magic_p may be used uninitialized. But we never
321 reach here if magic_p is uninitialized. */
322 DIAG_IGNORE_NEEDS_COMMENT (7, "-Wmaybe-uninitialized");
324 /* mem2chunk_check changed the magic byte in the old chunk.
325 If newmem is NULL, then the old chunk will still be used though,
326 so we need to invert that change here. */
330 DIAG_POP_NEEDS_COMMENT
;
332 __libc_lock_unlock (main_arena
.mutex
);
334 return mem2mem_check (tag_new_usable (newmem
), bytes
);
338 memalign_check (size_t alignment
, size_t bytes
)
342 if (alignment
<= MALLOC_ALIGNMENT
)
343 return malloc_check (bytes
);
345 if (alignment
< MINSIZE
)
348 /* If the alignment is greater than SIZE_MAX / 2 + 1 it cannot be a
349 power of 2 and will cause overflow in the check below. */
350 if (alignment
> SIZE_MAX
/ 2 + 1)
352 __set_errno (EINVAL
);
356 /* Check for overflow. */
357 if (bytes
> SIZE_MAX
- alignment
- MINSIZE
)
359 __set_errno (ENOMEM
);
363 /* Make sure alignment is power of 2. */
364 if (!powerof2 (alignment
))
366 size_t a
= MALLOC_ALIGNMENT
* 2;
367 while (a
< alignment
)
372 __libc_lock_lock (main_arena
.mutex
);
374 mem
= _int_memalign (&main_arena
, alignment
, bytes
+ 1);
375 __libc_lock_unlock (main_arena
.mutex
);
376 return mem2mem_check (tag_new_usable (mem
), bytes
);
380 TUNABLE_CALLBACK (set_mallopt_check
) (tunable_val_t
*valp
)
382 int32_t value
= (int32_t) valp
->numval
;
384 __malloc_debug_enable (MALLOC_CHECK_HOOK
);
388 initialize_malloc_check (void)
390 /* This is the copy of the malloc initializer that we pulled in along with
391 malloc-check. This does not affect any of the libc malloc structures. */
393 TUNABLE_GET (check
, int32_t, TUNABLE_CALLBACK (set_mallopt_check
));
394 return __is_malloc_debug_enabled (MALLOC_CHECK_HOOK
);