Fix entries.
[glibc.git] / malloc / mcheck.c
blob8cae506e4d8cf2c936a6353e452b23645fdc75c2
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) __P ((__ptr_t ptr, __const __ptr_t));
32 static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size, const __ptr_t));
33 static __ptr_t (*old_memalign_hook) __P ((__malloc_size_t alignment,
34 __malloc_size_t size,
35 const __ptr_t));
36 static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size,
37 __const __ptr_t));
39 /* Function to call when something awful happens. */
40 static void (*abortfunc) __P ((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 __P ((__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 checkhdr __P ((const struct hdr *));
86 static enum mcheck_status
87 checkhdr (hdr)
88 const struct hdr *hdr;
90 enum mcheck_status status;
92 if (!mcheck_used)
93 /* Maybe the mcheck used is disabled? This happens when we find
94 an error and report it. */
95 return MCHECK_OK;
97 switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
99 default:
100 status = MCHECK_HEAD;
101 break;
102 case MAGICFREE:
103 status = MCHECK_FREE;
104 break;
105 case MAGICWORD:
106 if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
107 status = MCHECK_TAIL;
108 else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
109 status = MCHECK_HEAD;
110 else
111 status = MCHECK_OK;
112 break;
114 if (status != MCHECK_OK)
116 mcheck_used = 0;
117 (*abortfunc) (status);
118 mcheck_used = 1;
120 return status;
123 void
124 mcheck_check_all ()
126 /* Walk through all the active blocks and test whether they were tempered
127 with. */
128 struct hdr *runp = root;
130 /* Temporarily turn off the checks. */
131 pedantic = 0;
133 while (runp != NULL)
135 (void) checkhdr (runp);
137 runp = runp->next;
140 /* Turn checks on again. */
141 pedantic = 1;
143 #ifdef _LIBC
144 libc_hidden_def (mcheck_check_all)
145 #endif
147 static void unlink_blk __P ((struct hdr *ptr));
148 static void
149 unlink_blk (ptr)
150 struct hdr *ptr;
152 if (ptr->next != NULL)
154 ptr->next->prev = ptr->prev;
155 ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
156 + (uintptr_t) ptr->next->next);
158 if (ptr->prev != NULL)
160 ptr->prev->next = ptr->next;
161 ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
162 + (uintptr_t) ptr->prev->next);
164 else
165 root = ptr->next;
168 static void link_blk __P ((struct hdr *ptr));
169 static void
170 link_blk (hdr)
171 struct hdr *hdr;
173 hdr->prev = NULL;
174 hdr->next = root;
175 root = hdr;
176 hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
178 /* And the next block. */
179 if (hdr->next != NULL)
181 hdr->next->prev = hdr;
182 hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
183 + (uintptr_t) hdr->next->next);
187 static void freehook __P ((__ptr_t, const __ptr_t));
188 static void
189 freehook (ptr, caller)
190 __ptr_t ptr;
191 const __ptr_t caller;
193 if (pedantic)
194 mcheck_check_all ();
195 if (ptr)
197 struct hdr *hdr = ((struct hdr *) ptr) - 1;
198 checkhdr (hdr);
199 hdr->magic = MAGICFREE;
200 hdr->magic2 = MAGICFREE;
201 unlink_blk (hdr);
202 hdr->prev = hdr->next = NULL;
203 flood (ptr, FREEFLOOD, hdr->size);
204 ptr = hdr->block;
206 __free_hook = old_free_hook;
207 if (old_free_hook != NULL)
208 (*old_free_hook) (ptr, caller);
209 else
210 free (ptr);
211 __free_hook = freehook;
214 static __ptr_t mallochook __P ((__malloc_size_t, const __ptr_t));
215 static __ptr_t
216 mallochook (size, caller)
217 __malloc_size_t size;
218 const __ptr_t caller;
220 struct hdr *hdr;
222 if (pedantic)
223 mcheck_check_all ();
225 __malloc_hook = old_malloc_hook;
226 if (old_malloc_hook != NULL)
227 hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
228 caller);
229 else
230 hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
231 __malloc_hook = mallochook;
232 if (hdr == NULL)
233 return NULL;
235 hdr->size = size;
236 link_blk (hdr);
237 hdr->block = hdr;
238 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
239 ((char *) &hdr[1])[size] = MAGICBYTE;
240 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
241 return (__ptr_t) (hdr + 1);
244 static __ptr_t memalignhook __P ((__malloc_size_t, __malloc_size_t,
245 const __ptr_t));
246 static __ptr_t
247 memalignhook (alignment, size, caller)
248 __malloc_size_t alignment, size;
249 const __ptr_t caller;
251 struct hdr *hdr;
252 __malloc_size_t slop;
253 char *block;
255 if (pedantic)
256 mcheck_check_all ();
258 slop = (sizeof *hdr + alignment - 1) & -alignment;
260 __memalign_hook = old_memalign_hook;
261 if (old_memalign_hook != NULL)
262 block = (*old_memalign_hook) (alignment, slop + size + 1, caller);
263 else
264 block = memalign (alignment, slop + size + 1);
265 __memalign_hook = memalignhook;
266 if (block == NULL)
267 return NULL;
269 hdr = ((struct hdr *) (block + slop)) - 1;
271 hdr->size = size;
272 link_blk (hdr);
273 hdr->block = (__ptr_t) block;
274 hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
275 ((char *) &hdr[1])[size] = MAGICBYTE;
276 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
277 return (__ptr_t) (hdr + 1);
280 static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
281 static __ptr_t
282 reallochook (ptr, size, caller)
283 __ptr_t ptr;
284 __malloc_size_t size;
285 const __ptr_t caller;
287 struct hdr *hdr;
288 __malloc_size_t osize;
290 if (pedantic)
291 mcheck_check_all ();
293 if (ptr)
295 hdr = ((struct hdr *) ptr) - 1;
296 osize = hdr->size;
298 checkhdr (hdr);
299 unlink_blk (hdr);
300 if (size < osize)
301 flood ((char *) ptr + size, FREEFLOOD, osize - size);
303 else
305 osize = 0;
306 hdr = NULL;
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) ((__ptr_t) hdr,
314 sizeof (struct hdr) + size + 1,
315 caller);
316 else
317 hdr = (struct hdr *) realloc ((__ptr_t) hdr,
318 sizeof (struct hdr) + size + 1);
319 __free_hook = freehook;
320 __malloc_hook = mallochook;
321 __memalign_hook = memalignhook;
322 __realloc_hook = reallochook;
323 if (hdr == NULL)
324 return NULL;
326 hdr->size = size;
327 link_blk (hdr);
328 hdr->block = hdr;
329 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
330 ((char *) &hdr[1])[size] = MAGICBYTE;
331 if (size > osize)
332 flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
333 return (__ptr_t) (hdr + 1);
336 static void mabort __P ((enum mcheck_status status))
337 __attribute__ ((noreturn));
338 static void
339 mabort (status)
340 enum mcheck_status status;
342 const char *msg;
343 switch (status)
345 case MCHECK_OK:
346 msg = _("memory is consistent, library is buggy\n");
347 break;
348 case MCHECK_HEAD:
349 msg = _("memory clobbered before allocated block\n");
350 break;
351 case MCHECK_TAIL:
352 msg = _("memory clobbered past end of allocated block\n");
353 break;
354 case MCHECK_FREE:
355 msg = _("block freed twice\n");
356 break;
357 default:
358 msg = _("bogus mcheck_status, library is buggy\n");
359 break;
361 #ifdef _LIBC
362 __libc_fatal (msg);
363 #else
364 fprintf (stderr, "mcheck: %s", msg);
365 fflush (stderr);
366 abort ();
367 #endif
371 mcheck (func)
372 void (*func) __P ((enum mcheck_status));
374 abortfunc = (func != NULL) ? func : &mabort;
376 /* These hooks may not be safely inserted if malloc is already in use. */
377 if (__malloc_initialized <= 0 && !mcheck_used)
379 /* We call malloc() once here to ensure it is initialized. */
380 void *p = malloc (0);
381 free (p);
383 old_free_hook = __free_hook;
384 __free_hook = freehook;
385 old_malloc_hook = __malloc_hook;
386 __malloc_hook = mallochook;
387 old_memalign_hook = __memalign_hook;
388 __memalign_hook = memalignhook;
389 old_realloc_hook = __realloc_hook;
390 __realloc_hook = reallochook;
391 mcheck_used = 1;
394 return mcheck_used ? 0 : -1;
396 #ifdef _LIBC
397 libc_hidden_def (mcheck)
398 #endif
401 mcheck_pedantic (func)
402 void (*func) __P ((enum mcheck_status));
404 int res = mcheck (func);
405 if (res == 0)
406 pedantic = 1;
407 return res;
410 enum mcheck_status
411 mprobe (__ptr_t ptr)
413 return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;