[BZ #4455]
[glibc.git] / malloc / mcheck.c
blob02379d219dd0738b64985917232b0e33dbb1ff5b
1 /* Standard debugging hooks for `malloc'.
2 Copyright (C) 1990-1997,99,2000,01,02 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, write to the Free
18 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA. */
21 #ifndef _MALLOC_INTERNAL
22 # define _MALLOC_INTERNAL
23 # include <malloc.h>
24 # include <mcheck.h>
25 # include <stdint.h>
26 # include <stdio.h>
27 # include <libintl.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 tempered
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 __malloc_hook = old_malloc_hook;
213 if (old_malloc_hook != NULL)
214 hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
215 caller);
216 else
217 hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
218 __malloc_hook = mallochook;
219 if (hdr == NULL)
220 return NULL;
222 hdr->size = size;
223 link_blk (hdr);
224 hdr->block = hdr;
225 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
226 ((char *) &hdr[1])[size] = MAGICBYTE;
227 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
228 return (__ptr_t) (hdr + 1);
231 static __ptr_t
232 memalignhook (__malloc_size_t alignment, __malloc_size_t size,
233 const __ptr_t caller)
235 struct hdr *hdr;
236 __malloc_size_t slop;
237 char *block;
239 if (pedantic)
240 mcheck_check_all ();
242 slop = (sizeof *hdr + alignment - 1) & -alignment;
244 __memalign_hook = old_memalign_hook;
245 if (old_memalign_hook != NULL)
246 block = (*old_memalign_hook) (alignment, slop + size + 1, caller);
247 else
248 block = memalign (alignment, slop + size + 1);
249 __memalign_hook = memalignhook;
250 if (block == NULL)
251 return NULL;
253 hdr = ((struct hdr *) (block + slop)) - 1;
255 hdr->size = size;
256 link_blk (hdr);
257 hdr->block = (__ptr_t) block;
258 hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
259 ((char *) &hdr[1])[size] = MAGICBYTE;
260 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
261 return (__ptr_t) (hdr + 1);
264 static __ptr_t
265 reallochook (__ptr_t ptr, __malloc_size_t size, const __ptr_t caller)
267 struct hdr *hdr;
268 __malloc_size_t osize;
270 if (pedantic)
271 mcheck_check_all ();
273 if (ptr)
275 hdr = ((struct hdr *) ptr) - 1;
276 osize = hdr->size;
278 checkhdr (hdr);
279 unlink_blk (hdr);
280 if (size < osize)
281 flood ((char *) ptr + size, FREEFLOOD, osize - size);
283 else
285 osize = 0;
286 hdr = NULL;
288 __free_hook = old_free_hook;
289 __malloc_hook = old_malloc_hook;
290 __memalign_hook = old_memalign_hook;
291 __realloc_hook = old_realloc_hook;
292 if (old_realloc_hook != NULL)
293 hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
294 sizeof (struct hdr) + size + 1,
295 caller);
296 else
297 hdr = (struct hdr *) realloc ((__ptr_t) hdr,
298 sizeof (struct hdr) + size + 1);
299 __free_hook = freehook;
300 __malloc_hook = mallochook;
301 __memalign_hook = memalignhook;
302 __realloc_hook = reallochook;
303 if (hdr == NULL)
304 return NULL;
306 hdr->size = size;
307 link_blk (hdr);
308 hdr->block = hdr;
309 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
310 ((char *) &hdr[1])[size] = MAGICBYTE;
311 if (size > osize)
312 flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
313 return (__ptr_t) (hdr + 1);
316 __attribute__ ((noreturn))
317 static void
318 mabort (enum mcheck_status status)
320 const char *msg;
321 switch (status)
323 case MCHECK_OK:
324 msg = _("memory is consistent, library is buggy\n");
325 break;
326 case MCHECK_HEAD:
327 msg = _("memory clobbered before allocated block\n");
328 break;
329 case MCHECK_TAIL:
330 msg = _("memory clobbered past end of allocated block\n");
331 break;
332 case MCHECK_FREE:
333 msg = _("block freed twice\n");
334 break;
335 default:
336 msg = _("bogus mcheck_status, library is buggy\n");
337 break;
339 #ifdef _LIBC
340 __libc_fatal (msg);
341 #else
342 fprintf (stderr, "mcheck: %s", msg);
343 fflush (stderr);
344 abort ();
345 #endif
349 mcheck (func)
350 void (*func) (enum mcheck_status);
352 abortfunc = (func != NULL) ? func : &mabort;
354 /* These hooks may not be safely inserted if malloc is already in use. */
355 if (__malloc_initialized <= 0 && !mcheck_used)
357 /* We call malloc() once here to ensure it is initialized. */
358 void *p = malloc (0);
359 free (p);
361 old_free_hook = __free_hook;
362 __free_hook = freehook;
363 old_malloc_hook = __malloc_hook;
364 __malloc_hook = mallochook;
365 old_memalign_hook = __memalign_hook;
366 __memalign_hook = memalignhook;
367 old_realloc_hook = __realloc_hook;
368 __realloc_hook = reallochook;
369 mcheck_used = 1;
372 return mcheck_used ? 0 : -1;
374 #ifdef _LIBC
375 libc_hidden_def (mcheck)
376 #endif
379 mcheck_pedantic (func)
380 void (*func) (enum mcheck_status);
382 int res = mcheck (func);
383 if (res == 0)
384 pedantic = 1;
385 return res;
388 enum mcheck_status
389 mprobe (__ptr_t ptr)
391 return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;