1 /* Standard debugging hooks for `malloc'.
2 Copyright (C) 1990-2020 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Written May 1989 by Mike Haertel.
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
8 License as published by the Free Software Foundation; either
9 version 2.1 of the 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; if not, see
18 <https://www.gnu.org/licenses/>. */
20 #ifndef _MALLOC_INTERNAL
21 # define _MALLOC_INTERNAL
30 /* Old hook values. */
31 static void (*old_free_hook
)(void *ptr
, const void *);
32 static void *(*old_malloc_hook
) (size_t size
, const void *);
33 static void *(*old_memalign_hook
) (size_t alignment
, size_t size
,
35 static void *(*old_realloc_hook
) (void *ptr
, size_t size
,
38 /* Function to call when something awful happens. */
39 static void (*abortfunc
) (enum mcheck_status
);
41 /* Arbitrary magical numbers. */
42 #define MAGICWORD 0xfedabeeb
43 #define MAGICFREE 0xd8675309
44 #define MAGICBYTE ((char) 0xd7)
45 #define MALLOCFLOOD ((char) 0x93)
46 #define FREEFLOOD ((char) 0x95)
50 size_t size
; /* Exact size requested by user. */
51 unsigned long int magic
; /* Magic number to check header integrity. */
54 void *block
; /* Real block allocated, for memalign. */
55 unsigned long int magic2
; /* Extra, keeps us doubleword aligned. */
58 /* This is the beginning of the list of all memory blocks allocated.
59 It is only constructed if the pedantic testing is requested. */
60 static struct hdr
*root
;
62 static int mcheck_used
;
64 /* Nonzero if pedentic checking of all blocks is requested. */
67 #if defined _LIBC || defined STDC_HEADERS || defined USG
71 static void flood (void *, int, size_t);
73 flood (void *ptr
, int val
, size_t size
)
81 static enum mcheck_status
82 checkhdr (const struct hdr
*hdr
)
84 enum mcheck_status status
;
87 /* Maybe the mcheck used is disabled? This happens when we find
88 an error and report it. */
91 switch (hdr
->magic
^ ((uintptr_t) hdr
->prev
+ (uintptr_t) hdr
->next
))
100 if (((char *) &hdr
[1])[hdr
->size
] != MAGICBYTE
)
101 status
= MCHECK_TAIL
;
102 else if ((hdr
->magic2
^ (uintptr_t) hdr
->block
) != MAGICWORD
)
103 status
= MCHECK_HEAD
;
108 if (status
!= MCHECK_OK
)
111 (*abortfunc
) (status
);
118 mcheck_check_all (void)
120 /* Walk through all the active blocks and test whether they were tampered
122 struct hdr
*runp
= root
;
124 /* Temporarily turn off the checks. */
129 (void) checkhdr (runp
);
134 /* Turn checks on again. */
138 libc_hidden_def (mcheck_check_all
)
142 unlink_blk (struct hdr
*ptr
)
144 if (ptr
->next
!= NULL
)
146 ptr
->next
->prev
= ptr
->prev
;
147 ptr
->next
->magic
= MAGICWORD
^ ((uintptr_t) ptr
->next
->prev
148 + (uintptr_t) ptr
->next
->next
);
150 if (ptr
->prev
!= NULL
)
152 ptr
->prev
->next
= ptr
->next
;
153 ptr
->prev
->magic
= MAGICWORD
^ ((uintptr_t) ptr
->prev
->prev
154 + (uintptr_t) ptr
->prev
->next
);
161 link_blk (struct hdr
*hdr
)
166 hdr
->magic
= MAGICWORD
^ (uintptr_t) hdr
->next
;
168 /* And the next block. */
169 if (hdr
->next
!= NULL
)
171 hdr
->next
->prev
= hdr
;
172 hdr
->next
->magic
= MAGICWORD
^ ((uintptr_t) hdr
173 + (uintptr_t) hdr
->next
->next
);
177 freehook (void *ptr
, const void *caller
)
183 struct hdr
*hdr
= ((struct hdr
*) ptr
) - 1;
185 hdr
->magic
= MAGICFREE
;
186 hdr
->magic2
= MAGICFREE
;
188 hdr
->prev
= hdr
->next
= NULL
;
189 flood (ptr
, FREEFLOOD
, hdr
->size
);
192 __free_hook
= old_free_hook
;
193 if (old_free_hook
!= NULL
)
194 (*old_free_hook
)(ptr
, caller
);
197 __free_hook
= freehook
;
201 mallochook (size_t size
, const void *caller
)
208 if (size
> ~((size_t) 0) - (sizeof (struct hdr
) + 1))
210 __set_errno (ENOMEM
);
214 __malloc_hook
= old_malloc_hook
;
215 if (old_malloc_hook
!= NULL
)
216 hdr
= (struct hdr
*) (*old_malloc_hook
)(sizeof (struct hdr
) + size
+ 1,
219 hdr
= (struct hdr
*) malloc (sizeof (struct hdr
) + size
+ 1);
220 __malloc_hook
= mallochook
;
227 hdr
->magic2
= (uintptr_t) hdr
^ MAGICWORD
;
228 ((char *) &hdr
[1])[size
] = MAGICBYTE
;
229 flood ((void *) (hdr
+ 1), MALLOCFLOOD
, size
);
230 return (void *) (hdr
+ 1);
234 memalignhook (size_t alignment
, size_t size
,
244 slop
= (sizeof *hdr
+ alignment
- 1) & - alignment
;
246 if (size
> ~((size_t) 0) - (slop
+ 1))
248 __set_errno (ENOMEM
);
252 __memalign_hook
= old_memalign_hook
;
253 if (old_memalign_hook
!= NULL
)
254 block
= (*old_memalign_hook
)(alignment
, slop
+ size
+ 1, caller
);
256 block
= memalign (alignment
, slop
+ size
+ 1);
257 __memalign_hook
= memalignhook
;
261 hdr
= ((struct hdr
*) (block
+ slop
)) - 1;
265 hdr
->block
= (void *) block
;
266 hdr
->magic2
= (uintptr_t) block
^ MAGICWORD
;
267 ((char *) &hdr
[1])[size
] = MAGICBYTE
;
268 flood ((void *) (hdr
+ 1), MALLOCFLOOD
, size
);
269 return (void *) (hdr
+ 1);
273 reallochook (void *ptr
, size_t size
, const void *caller
)
277 freehook (ptr
, caller
);
287 if (size
> ~((size_t) 0) - (sizeof (struct hdr
) + 1))
289 __set_errno (ENOMEM
);
295 hdr
= ((struct hdr
*) ptr
) - 1;
301 flood ((char *) ptr
+ size
, FREEFLOOD
, osize
- size
);
308 __free_hook
= old_free_hook
;
309 __malloc_hook
= old_malloc_hook
;
310 __memalign_hook
= old_memalign_hook
;
311 __realloc_hook
= old_realloc_hook
;
312 if (old_realloc_hook
!= NULL
)
313 hdr
= (struct hdr
*) (*old_realloc_hook
)((void *) hdr
,
314 sizeof (struct hdr
) + size
+ 1,
317 hdr
= (struct hdr
*) realloc ((void *) hdr
,
318 sizeof (struct hdr
) + size
+ 1);
319 __free_hook
= freehook
;
320 __malloc_hook
= mallochook
;
321 __memalign_hook
= memalignhook
;
322 __realloc_hook
= reallochook
;
329 hdr
->magic2
= (uintptr_t) hdr
^ MAGICWORD
;
330 ((char *) &hdr
[1])[size
] = MAGICBYTE
;
332 flood ((char *) (hdr
+ 1) + osize
, MALLOCFLOOD
, size
- osize
);
333 return (void *) (hdr
+ 1);
336 __attribute__ ((noreturn
))
338 mabort (enum mcheck_status status
)
344 msg
= _ ("memory is consistent, library is buggy\n");
347 msg
= _ ("memory clobbered before allocated block\n");
350 msg
= _ ("memory clobbered past end of allocated block\n");
353 msg
= _ ("block freed twice\n");
356 msg
= _ ("bogus mcheck_status, library is buggy\n");
362 fprintf (stderr
, "mcheck: %s", msg
);
368 /* Memory barrier so that GCC does not optimize out the argument. */
369 #define malloc_opt_barrier(x) \
370 ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
373 mcheck (void (*func
) (enum mcheck_status
))
375 abortfunc
= (func
!= NULL
) ? func
: &mabort
;
377 /* These hooks may not be safely inserted if malloc is already in use. */
378 if (__malloc_initialized
<= 0 && !mcheck_used
)
380 /* We call malloc() once here to ensure it is initialized. */
381 void *p
= malloc (0);
382 /* GCC might optimize out the malloc/free pair without a barrier. */
383 p
= malloc_opt_barrier (p
);
386 old_free_hook
= __free_hook
;
387 __free_hook
= freehook
;
388 old_malloc_hook
= __malloc_hook
;
389 __malloc_hook
= mallochook
;
390 old_memalign_hook
= __memalign_hook
;
391 __memalign_hook
= memalignhook
;
392 old_realloc_hook
= __realloc_hook
;
393 __realloc_hook
= reallochook
;
397 return mcheck_used
? 0 : -1;
400 libc_hidden_def (mcheck
)
404 mcheck_pedantic (void (*func
) (enum mcheck_status
))
406 int res
= mcheck (func
);
415 return mcheck_used
? checkhdr (((struct hdr
*) ptr
) - 1) : MCHECK_DISABLED
;