2.9
[glibc/nacl-glibc.git] / malloc / mcheck.c
blob524acc755c5dd49c2fdde75e7ace40e987c46ef9
1 /* Standard debugging hooks for `malloc'.
2 Copyright (C) 1990-1997,1999,2000-2002,2007 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 if (size == 0)
269 freehook (ptr, caller);
270 return NULL;
273 struct hdr *hdr;
274 __malloc_size_t osize;
276 if (pedantic)
277 mcheck_check_all ();
279 if (ptr)
281 hdr = ((struct hdr *) ptr) - 1;
282 osize = hdr->size;
284 checkhdr (hdr);
285 unlink_blk (hdr);
286 if (size < osize)
287 flood ((char *) ptr + size, FREEFLOOD, osize - size);
289 else
291 osize = 0;
292 hdr = NULL;
294 __free_hook = old_free_hook;
295 __malloc_hook = old_malloc_hook;
296 __memalign_hook = old_memalign_hook;
297 __realloc_hook = old_realloc_hook;
298 if (old_realloc_hook != NULL)
299 hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
300 sizeof (struct hdr) + size + 1,
301 caller);
302 else
303 hdr = (struct hdr *) realloc ((__ptr_t) hdr,
304 sizeof (struct hdr) + size + 1);
305 __free_hook = freehook;
306 __malloc_hook = mallochook;
307 __memalign_hook = memalignhook;
308 __realloc_hook = reallochook;
309 if (hdr == NULL)
310 return NULL;
312 hdr->size = size;
313 link_blk (hdr);
314 hdr->block = hdr;
315 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
316 ((char *) &hdr[1])[size] = MAGICBYTE;
317 if (size > osize)
318 flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
319 return (__ptr_t) (hdr + 1);
322 __attribute__ ((noreturn))
323 static void
324 mabort (enum mcheck_status status)
326 const char *msg;
327 switch (status)
329 case MCHECK_OK:
330 msg = _("memory is consistent, library is buggy\n");
331 break;
332 case MCHECK_HEAD:
333 msg = _("memory clobbered before allocated block\n");
334 break;
335 case MCHECK_TAIL:
336 msg = _("memory clobbered past end of allocated block\n");
337 break;
338 case MCHECK_FREE:
339 msg = _("block freed twice\n");
340 break;
341 default:
342 msg = _("bogus mcheck_status, library is buggy\n");
343 break;
345 #ifdef _LIBC
346 __libc_fatal (msg);
347 #else
348 fprintf (stderr, "mcheck: %s", msg);
349 fflush (stderr);
350 abort ();
351 #endif
355 mcheck (func)
356 void (*func) (enum mcheck_status);
358 abortfunc = (func != NULL) ? func : &mabort;
360 /* These hooks may not be safely inserted if malloc is already in use. */
361 if (__malloc_initialized <= 0 && !mcheck_used)
363 /* We call malloc() once here to ensure it is initialized. */
364 void *p = malloc (0);
365 free (p);
367 old_free_hook = __free_hook;
368 __free_hook = freehook;
369 old_malloc_hook = __malloc_hook;
370 __malloc_hook = mallochook;
371 old_memalign_hook = __memalign_hook;
372 __memalign_hook = memalignhook;
373 old_realloc_hook = __realloc_hook;
374 __realloc_hook = reallochook;
375 mcheck_used = 1;
378 return mcheck_used ? 0 : -1;
380 #ifdef _LIBC
381 libc_hidden_def (mcheck)
382 #endif
385 mcheck_pedantic (func)
386 void (*func) (enum mcheck_status);
388 int res = mcheck (func);
389 if (res == 0)
390 pedantic = 1;
391 return res;
394 enum mcheck_status
395 mprobe (__ptr_t ptr)
397 return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;