Update ChangeLog
[glibc.git] / malloc / mcheck.c
blobc5addc55afebd5026dc7706f7aa6f83c982984d6
1 /* Standard debugging hooks for `malloc'.
2 Copyright (C) 1990-2012 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 <http://www.gnu.org/licenses/>. */
20 #ifndef _MALLOC_INTERNAL
21 # define _MALLOC_INTERNAL
22 # include <malloc.h>
23 # include <mcheck.h>
24 # include <stdint.h>
25 # include <stdio.h>
26 # include <libintl.h>
27 # include <errno.h>
28 #endif
30 /* Old hook values. */
31 static void (*old_free_hook) (__ptr_t ptr, const __ptr_t);
32 static __ptr_t (*old_malloc_hook) (__malloc_size_t size, const __ptr_t);
33 static __ptr_t (*old_memalign_hook) (__malloc_size_t alignment,
34 __malloc_size_t size,
35 const __ptr_t);
36 static __ptr_t (*old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
37 const __ptr_t);
39 /* Function to call when something awful happens. */
40 static void (*abortfunc) (enum mcheck_status);
42 /* Arbitrary magical numbers. */
43 #define MAGICWORD 0xfedabeeb
44 #define MAGICFREE 0xd8675309
45 #define MAGICBYTE ((char) 0xd7)
46 #define MALLOCFLOOD ((char) 0x93)
47 #define FREEFLOOD ((char) 0x95)
49 struct hdr
51 __malloc_size_t size; /* Exact size requested by user. */
52 unsigned long int magic; /* Magic number to check header integrity. */
53 struct hdr *prev;
54 struct hdr *next;
55 __ptr_t block; /* Real block allocated, for memalign. */
56 unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
59 /* This is the beginning of the list of all memory blocks allocated.
60 It is only constructed if the pedantic testing is requested. */
61 static struct hdr *root;
63 static int mcheck_used;
65 /* Nonzero if pedentic checking of all blocks is requested. */
66 static int pedantic;
68 #if defined _LIBC || defined STDC_HEADERS || defined USG
69 # include <string.h>
70 # define flood memset
71 #else
72 static void flood (__ptr_t, int, __malloc_size_t);
73 static void
74 flood (ptr, val, size)
75 __ptr_t ptr;
76 int val;
77 __malloc_size_t size;
79 char *cp = ptr;
80 while (size--)
81 *cp++ = val;
83 #endif
85 static enum mcheck_status
86 checkhdr (const struct hdr *hdr)
88 enum mcheck_status status;
90 if (!mcheck_used)
91 /* Maybe the mcheck used is disabled? This happens when we find
92 an error and report it. */
93 return MCHECK_OK;
95 switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
97 default:
98 status = MCHECK_HEAD;
99 break;
100 case MAGICFREE:
101 status = MCHECK_FREE;
102 break;
103 case MAGICWORD:
104 if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
105 status = MCHECK_TAIL;
106 else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
107 status = MCHECK_HEAD;
108 else
109 status = MCHECK_OK;
110 break;
112 if (status != MCHECK_OK)
114 mcheck_used = 0;
115 (*abortfunc) (status);
116 mcheck_used = 1;
118 return status;
121 void
122 mcheck_check_all (void)
124 /* Walk through all the active blocks and test whether they were tampered
125 with. */
126 struct hdr *runp = root;
128 /* Temporarily turn off the checks. */
129 pedantic = 0;
131 while (runp != NULL)
133 (void) checkhdr (runp);
135 runp = runp->next;
138 /* Turn checks on again. */
139 pedantic = 1;
141 #ifdef _LIBC
142 libc_hidden_def (mcheck_check_all)
143 #endif
145 static void
146 unlink_blk (struct hdr *ptr)
148 if (ptr->next != NULL)
150 ptr->next->prev = ptr->prev;
151 ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
152 + (uintptr_t) ptr->next->next);
154 if (ptr->prev != NULL)
156 ptr->prev->next = ptr->next;
157 ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
158 + (uintptr_t) ptr->prev->next);
160 else
161 root = ptr->next;
164 static void
165 link_blk (struct hdr *hdr)
167 hdr->prev = NULL;
168 hdr->next = root;
169 root = hdr;
170 hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
172 /* And the next block. */
173 if (hdr->next != NULL)
175 hdr->next->prev = hdr;
176 hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
177 + (uintptr_t) hdr->next->next);
180 static void
181 freehook (__ptr_t ptr, const __ptr_t caller)
183 if (pedantic)
184 mcheck_check_all ();
185 if (ptr)
187 struct hdr *hdr = ((struct hdr *) ptr) - 1;
188 checkhdr (hdr);
189 hdr->magic = MAGICFREE;
190 hdr->magic2 = MAGICFREE;
191 unlink_blk (hdr);
192 hdr->prev = hdr->next = NULL;
193 flood (ptr, FREEFLOOD, hdr->size);
194 ptr = hdr->block;
196 __free_hook = old_free_hook;
197 if (old_free_hook != NULL)
198 (*old_free_hook) (ptr, caller);
199 else
200 free (ptr);
201 __free_hook = freehook;
204 static __ptr_t
205 mallochook (__malloc_size_t size, const __ptr_t caller)
207 struct hdr *hdr;
209 if (pedantic)
210 mcheck_check_all ();
212 if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
214 __set_errno (ENOMEM);
215 return NULL;
218 __malloc_hook = old_malloc_hook;
219 if (old_malloc_hook != NULL)
220 hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
221 caller);
222 else
223 hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
224 __malloc_hook = mallochook;
225 if (hdr == NULL)
226 return NULL;
228 hdr->size = size;
229 link_blk (hdr);
230 hdr->block = hdr;
231 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
232 ((char *) &hdr[1])[size] = MAGICBYTE;
233 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
234 return (__ptr_t) (hdr + 1);
237 static __ptr_t
238 memalignhook (__malloc_size_t alignment, __malloc_size_t size,
239 const __ptr_t caller)
241 struct hdr *hdr;
242 __malloc_size_t slop;
243 char *block;
245 if (pedantic)
246 mcheck_check_all ();
248 slop = (sizeof *hdr + alignment - 1) & -alignment;
250 if (size > ~((size_t) 0) - (slop + 1))
252 __set_errno (ENOMEM);
253 return NULL;
256 __memalign_hook = old_memalign_hook;
257 if (old_memalign_hook != NULL)
258 block = (*old_memalign_hook) (alignment, slop + size + 1, caller);
259 else
260 block = memalign (alignment, slop + size + 1);
261 __memalign_hook = memalignhook;
262 if (block == NULL)
263 return NULL;
265 hdr = ((struct hdr *) (block + slop)) - 1;
267 hdr->size = size;
268 link_blk (hdr);
269 hdr->block = (__ptr_t) block;
270 hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
271 ((char *) &hdr[1])[size] = MAGICBYTE;
272 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
273 return (__ptr_t) (hdr + 1);
276 static __ptr_t
277 reallochook (__ptr_t ptr, __malloc_size_t size, const __ptr_t caller)
279 if (size == 0)
281 freehook (ptr, caller);
282 return NULL;
285 struct hdr *hdr;
286 __malloc_size_t osize;
288 if (pedantic)
289 mcheck_check_all ();
291 if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
293 __set_errno (ENOMEM);
294 return NULL;
297 if (ptr)
299 hdr = ((struct hdr *) ptr) - 1;
300 osize = hdr->size;
302 checkhdr (hdr);
303 unlink_blk (hdr);
304 if (size < osize)
305 flood ((char *) ptr + size, FREEFLOOD, osize - size);
307 else
309 osize = 0;
310 hdr = NULL;
312 __free_hook = old_free_hook;
313 __malloc_hook = old_malloc_hook;
314 __memalign_hook = old_memalign_hook;
315 __realloc_hook = old_realloc_hook;
316 if (old_realloc_hook != NULL)
317 hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
318 sizeof (struct hdr) + size + 1,
319 caller);
320 else
321 hdr = (struct hdr *) realloc ((__ptr_t) hdr,
322 sizeof (struct hdr) + size + 1);
323 __free_hook = freehook;
324 __malloc_hook = mallochook;
325 __memalign_hook = memalignhook;
326 __realloc_hook = reallochook;
327 if (hdr == NULL)
328 return NULL;
330 hdr->size = size;
331 link_blk (hdr);
332 hdr->block = hdr;
333 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
334 ((char *) &hdr[1])[size] = MAGICBYTE;
335 if (size > osize)
336 flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
337 return (__ptr_t) (hdr + 1);
340 __attribute__ ((noreturn))
341 static void
342 mabort (enum mcheck_status status)
344 const char *msg;
345 switch (status)
347 case MCHECK_OK:
348 msg = _("memory is consistent, library is buggy\n");
349 break;
350 case MCHECK_HEAD:
351 msg = _("memory clobbered before allocated block\n");
352 break;
353 case MCHECK_TAIL:
354 msg = _("memory clobbered past end of allocated block\n");
355 break;
356 case MCHECK_FREE:
357 msg = _("block freed twice\n");
358 break;
359 default:
360 msg = _("bogus mcheck_status, library is buggy\n");
361 break;
363 #ifdef _LIBC
364 __libc_fatal (msg);
365 #else
366 fprintf (stderr, "mcheck: %s", msg);
367 fflush (stderr);
368 abort ();
369 #endif
372 /* Memory barrier so that GCC does not optimize out the argument. */
373 #define malloc_opt_barrier(x) \
374 ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
377 mcheck (func)
378 void (*func) (enum mcheck_status);
380 abortfunc = (func != NULL) ? func : &mabort;
382 /* These hooks may not be safely inserted if malloc is already in use. */
383 if (__malloc_initialized <= 0 && !mcheck_used)
385 /* We call malloc() once here to ensure it is initialized. */
386 void *p = malloc (0);
387 /* GCC might optimize out the malloc/free pair without a barrier. */
388 p = malloc_opt_barrier (p);
389 free (p);
391 old_free_hook = __free_hook;
392 __free_hook = freehook;
393 old_malloc_hook = __malloc_hook;
394 __malloc_hook = mallochook;
395 old_memalign_hook = __memalign_hook;
396 __memalign_hook = memalignhook;
397 old_realloc_hook = __realloc_hook;
398 __realloc_hook = reallochook;
399 mcheck_used = 1;
402 return mcheck_used ? 0 : -1;
404 #ifdef _LIBC
405 libc_hidden_def (mcheck)
406 #endif
409 mcheck_pedantic (func)
410 void (*func) (enum mcheck_status);
412 int res = mcheck (func);
413 if (res == 0)
414 pedantic = 1;
415 return res;
418 enum mcheck_status
419 mprobe (__ptr_t ptr)
421 return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;