]> git.ipfire.org Git - thirdparty/glibc.git/blame - malloc/mcheck.c
Update.
[thirdparty/glibc.git] / malloc / mcheck.c
CommitLineData
6d52618b 1/* Standard debugging hooks for `malloc'.
159a2e1a 2 Copyright (C) 1990-1997, 1999, 2000, 2001 Free Software Foundation, Inc.
6d52618b
UD
3 Written May 1989 by Mike Haertel.
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with this library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19
20 The author may be reached (Email) at the address mike@ai.mit.edu,
21 or (US mail) as Mike Haertel c/o Free Software Foundation. */
22
23#ifndef _MALLOC_INTERNAL
9756dfe1
UD
24# define _MALLOC_INTERNAL
25# include <malloc.h>
26# include <mcheck.h>
8e605e78 27# include <stdint.h>
9756dfe1 28# include <stdio.h>
4360eafd 29# include <libintl.h>
6d52618b
UD
30#endif
31
32/* Old hook values. */
a2b08ee5
UD
33static void (*old_free_hook) __P ((__ptr_t ptr, __const __ptr_t));
34static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size, const __ptr_t));
35static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size,
36 __const __ptr_t));
6d52618b
UD
37
38/* Function to call when something awful happens. */
39static void (*abortfunc) __P ((enum mcheck_status));
40
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)
47
48struct hdr
49 {
8e605e78 50 __malloc_size_t size; /* Exact size requested by user. */
6d52618b 51 unsigned long int magic; /* Magic number to check header integrity. */
8e605e78
UD
52 struct hdr *prev;
53 struct hdr *next;
6d52618b
UD
54 };
55
8e605e78
UD
56/* This is the beginning of the list of all memory blocks allocated.
57 It is only constructed if the pedantic testing is requested. */
58static struct hdr *root;
59
60/* Nonzero if pedentic checking of all blocks is requested. */
61static int pedantic;
62
9756dfe1
UD
63#if defined _LIBC || defined STDC_HEADERS || defined USG
64# include <string.h>
65# define flood memset
6d52618b
UD
66#else
67static void flood __P ((__ptr_t, int, __malloc_size_t));
68static void
69flood (ptr, val, size)
70 __ptr_t ptr;
71 int val;
72 __malloc_size_t size;
73{
74 char *cp = ptr;
75 while (size--)
76 *cp++ = val;
77}
78#endif
79
80static enum mcheck_status checkhdr __P ((const struct hdr *));
81static enum mcheck_status
82checkhdr (hdr)
83 const struct hdr *hdr;
84{
85 enum mcheck_status status;
8e605e78 86 switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
6d52618b
UD
87 {
88 default:
89 status = MCHECK_HEAD;
90 break;
91 case MAGICFREE:
92 status = MCHECK_FREE;
93 break;
94 case MAGICWORD:
95 if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
96 status = MCHECK_TAIL;
97 else
98 status = MCHECK_OK;
99 break;
100 }
101 if (status != MCHECK_OK)
102 (*abortfunc) (status);
103 return status;
104}
105
77e1d15a
UD
106void
107mcheck_check_all ()
8e605e78
UD
108{
109 /* Walk through all the active blocks and test whether they were tempered
110 with. */
111 struct hdr *runp = root;
112
30e0f9c3
UD
113 /* Temporarily turn off the checks. */
114 pedantic = 0;
115
8e605e78
UD
116 while (runp != NULL)
117 {
118 (void) checkhdr (runp);
119
120 runp = runp->next;
121 }
30e0f9c3
UD
122
123 /* Turn checks on again. */
124 pedantic = 1;
8e605e78
UD
125}
126
127static void unlink_blk __P ((struct hdr *ptr));
128static void
129unlink_blk (ptr)
130 struct hdr *ptr;
131{
132 if (ptr->next != NULL)
133 {
134 ptr->next->prev = ptr->prev;
135 ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
136 + (uintptr_t) ptr->next->next);
137 }
138 if (ptr->prev != NULL)
139 {
140 ptr->prev->next = ptr->next;
141 ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
142 + (uintptr_t) ptr->prev->next);
143 }
144 else
145 root = ptr->next;
146}
147
148static void link_blk __P ((struct hdr *ptr));
149static void
150link_blk (hdr)
151 struct hdr *hdr;
152{
153 hdr->prev = NULL;
154 hdr->next = root;
155 root = hdr;
156 hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
157
158 /* And the next block. */
159 if (hdr->next != NULL)
160 {
161 hdr->next->prev = hdr;
162 hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
163 + (uintptr_t) hdr->next->next);
164 }
165}
166
a2b08ee5 167static void freehook __P ((__ptr_t, const __ptr_t));
6d52618b 168static void
a2b08ee5 169freehook (ptr, caller)
6d52618b 170 __ptr_t ptr;
a2b08ee5 171 const __ptr_t caller;
6d52618b 172{
8e605e78 173 if (pedantic)
77e1d15a 174 mcheck_check_all ();
6d52618b
UD
175 if (ptr)
176 {
177 struct hdr *hdr = ((struct hdr *) ptr) - 1;
178 checkhdr (hdr);
179 hdr->magic = MAGICFREE;
8e605e78
UD
180 unlink_blk (hdr);
181 hdr->prev = hdr->next = NULL;
6d52618b
UD
182 flood (ptr, FREEFLOOD, hdr->size);
183 ptr = (__ptr_t) hdr;
184 }
185 __free_hook = old_free_hook;
a2b08ee5
UD
186 if (old_free_hook != NULL)
187 (*old_free_hook) (ptr, caller);
188 else
189 free (ptr);
6d52618b
UD
190 __free_hook = freehook;
191}
192
a2b08ee5 193static __ptr_t mallochook __P ((__malloc_size_t, const __ptr_t));
6d52618b 194static __ptr_t
a2b08ee5 195mallochook (size, caller)
6d52618b 196 __malloc_size_t size;
a2b08ee5 197 const __ptr_t caller;
6d52618b
UD
198{
199 struct hdr *hdr;
200
8e605e78 201 if (pedantic)
77e1d15a 202 mcheck_check_all ();
8e605e78 203
6d52618b 204 __malloc_hook = old_malloc_hook;
a2b08ee5
UD
205 if (old_malloc_hook != NULL)
206 hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
207 caller);
208 else
209 hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
6d52618b
UD
210 __malloc_hook = mallochook;
211 if (hdr == NULL)
212 return NULL;
213
214 hdr->size = size;
8e605e78 215 link_blk (hdr);
6d52618b
UD
216 ((char *) &hdr[1])[size] = MAGICBYTE;
217 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
218 return (__ptr_t) (hdr + 1);
219}
220
a2b08ee5 221static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t));
6d52618b 222static __ptr_t
a2b08ee5 223reallochook (ptr, size, caller)
6d52618b
UD
224 __ptr_t ptr;
225 __malloc_size_t size;
a2b08ee5 226 const __ptr_t caller;
6d52618b
UD
227{
228 struct hdr *hdr;
229 __malloc_size_t osize;
230
8e605e78 231 if (pedantic)
77e1d15a 232 mcheck_check_all ();
8e605e78 233
6d52618b
UD
234 if (ptr)
235 {
236 hdr = ((struct hdr *) ptr) - 1;
237 osize = hdr->size;
238
239 checkhdr (hdr);
8e605e78 240 unlink_blk (hdr);
6d52618b
UD
241 if (size < osize)
242 flood ((char *) ptr + size, FREEFLOOD, osize - size);
243 }
244 else
245 {
246 osize = 0;
247 hdr = NULL;
248 }
249 __free_hook = old_free_hook;
250 __malloc_hook = old_malloc_hook;
251 __realloc_hook = old_realloc_hook;
a2b08ee5
UD
252 if (old_realloc_hook != NULL)
253 hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
254 sizeof (struct hdr) + size + 1,
255 caller);
256 else
257 hdr = (struct hdr *) realloc ((__ptr_t) hdr,
258 sizeof (struct hdr) + size + 1);
6d52618b
UD
259 __free_hook = freehook;
260 __malloc_hook = mallochook;
261 __realloc_hook = reallochook;
262 if (hdr == NULL)
263 return NULL;
264
265 hdr->size = size;
8e605e78 266 link_blk (hdr);
6d52618b
UD
267 ((char *) &hdr[1])[size] = MAGICBYTE;
268 if (size > osize)
269 flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
270 return (__ptr_t) (hdr + 1);
271}
272
159a2e1a
AJ
273static void mabort __P ((enum mcheck_status status))
274 __attribute__ ((noreturn));
6d52618b
UD
275static void
276mabort (status)
277 enum mcheck_status status;
278{
279 const char *msg;
280 switch (status)
281 {
282 case MCHECK_OK:
9756dfe1 283 msg = _("memory is consistent, library is buggy\n");
6d52618b
UD
284 break;
285 case MCHECK_HEAD:
9756dfe1 286 msg = _("memory clobbered before allocated block\n");
6d52618b
UD
287 break;
288 case MCHECK_TAIL:
9756dfe1 289 msg = _("memory clobbered past end of allocated block\n");
6d52618b
UD
290 break;
291 case MCHECK_FREE:
9756dfe1 292 msg = _("block freed twice\n");
6d52618b
UD
293 break;
294 default:
9756dfe1 295 msg = _("bogus mcheck_status, library is buggy\n");
6d52618b
UD
296 break;
297 }
298#ifdef _LIBC
299 __libc_fatal (msg);
300#else
9756dfe1 301 fprintf (stderr, "mcheck: %s", msg);
6d52618b
UD
302 fflush (stderr);
303 abort ();
304#endif
305}
306
c4563d2d 307static int mcheck_used;
6d52618b
UD
308
309int
310mcheck (func)
311 void (*func) __P ((enum mcheck_status));
312{
313 abortfunc = (func != NULL) ? func : &mabort;
314
315 /* These hooks may not be safely inserted if malloc is already in use. */
9756dfe1 316 if (__malloc_initialized <= 0 && !mcheck_used)
6d52618b
UD
317 {
318 old_free_hook = __free_hook;
319 __free_hook = freehook;
320 old_malloc_hook = __malloc_hook;
321 __malloc_hook = mallochook;
322 old_realloc_hook = __realloc_hook;
323 __realloc_hook = reallochook;
324 mcheck_used = 1;
325 }
326
327 return mcheck_used ? 0 : -1;
328}
329
8e605e78
UD
330int
331mcheck_pedantic (func)
332 void (*func) __P ((enum mcheck_status));
333{
77e1d15a
UD
334 int res = mcheck (func);
335 if (res == 0)
336 pedantic = 1;
337 return res;
8e605e78
UD
338}
339
6d52618b
UD
340enum mcheck_status
341mprobe (__ptr_t ptr)
342{
997a4165 343 return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
6d52618b 344}