]> git.ipfire.org Git - thirdparty/glibc.git/blame - malloc/mcheck.c
* malloc/mcheck.c (reallochook): If size==0, free the block.
[thirdparty/glibc.git] / malloc / mcheck.c
CommitLineData
6d52618b 1/* Standard debugging hooks for `malloc'.
129abdd3 2 Copyright (C) 1990-1997,1999,2000-2002,2007 Free Software Foundation, Inc.
41bdb6e2 3 This file is part of the GNU C Library.
6d52618b
UD
4 Written May 1989 by Mike Haertel.
5
41bdb6e2
AJ
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.
6d52618b 10
41bdb6e2 11 The GNU C Library is distributed in the hope that it will be useful,
6d52618b
UD
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 14 Lesser General Public License for more details.
6d52618b 15
41bdb6e2
AJ
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. */
6d52618b
UD
20
21#ifndef _MALLOC_INTERNAL
9756dfe1
UD
22# define _MALLOC_INTERNAL
23# include <malloc.h>
24# include <mcheck.h>
8e605e78 25# include <stdint.h>
9756dfe1 26# include <stdio.h>
4360eafd 27# include <libintl.h>
6d52618b
UD
28#endif
29
30/* Old hook values. */
b80163bd
RM
31static void (*old_free_hook) (__ptr_t ptr, __const __ptr_t);
32static __ptr_t (*old_malloc_hook) (__malloc_size_t size, const __ptr_t);
33static __ptr_t (*old_memalign_hook) (__malloc_size_t alignment,
34 __malloc_size_t size,
35 const __ptr_t);
36static __ptr_t (*old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
37 __const __ptr_t);
6d52618b
UD
38
39/* Function to call when something awful happens. */
b80163bd 40static void (*abortfunc) (enum mcheck_status);
6d52618b
UD
41
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)
48
49struct hdr
50 {
8e605e78 51 __malloc_size_t size; /* Exact size requested by user. */
6d52618b 52 unsigned long int magic; /* Magic number to check header integrity. */
8e605e78
UD
53 struct hdr *prev;
54 struct hdr *next;
6e3d59bc
RM
55 __ptr_t block; /* Real block allocated, for memalign. */
56 unsigned long int magic2; /* Extra, keeps us doubleword aligned. */
6d52618b
UD
57 };
58
8e605e78
UD
59/* This is the beginning of the list of all memory blocks allocated.
60 It is only constructed if the pedantic testing is requested. */
61static struct hdr *root;
62
adef3744
UD
63static int mcheck_used;
64
8e605e78
UD
65/* Nonzero if pedentic checking of all blocks is requested. */
66static int pedantic;
67
9756dfe1
UD
68#if defined _LIBC || defined STDC_HEADERS || defined USG
69# include <string.h>
70# define flood memset
6d52618b 71#else
b80163bd 72static void flood (__ptr_t, int, __malloc_size_t);
6d52618b
UD
73static void
74flood (ptr, val, size)
75 __ptr_t ptr;
76 int val;
77 __malloc_size_t size;
78{
79 char *cp = ptr;
80 while (size--)
81 *cp++ = val;
82}
83#endif
84
6d52618b 85static enum mcheck_status
b80163bd 86checkhdr (const struct hdr *hdr)
6d52618b
UD
87{
88 enum mcheck_status status;
adef3744
UD
89
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;
94
8e605e78 95 switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
6d52618b
UD
96 {
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;
6e3d59bc
RM
106 else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
107 status = MCHECK_HEAD;
6d52618b
UD
108 else
109 status = MCHECK_OK;
110 break;
111 }
112 if (status != MCHECK_OK)
adef3744
UD
113 {
114 mcheck_used = 0;
115 (*abortfunc) (status);
116 mcheck_used = 1;
117 }
6d52618b
UD
118 return status;
119}
120
77e1d15a 121void
b80163bd 122mcheck_check_all (void)
8e605e78
UD
123{
124 /* Walk through all the active blocks and test whether they were tempered
125 with. */
126 struct hdr *runp = root;
127
30e0f9c3
UD
128 /* Temporarily turn off the checks. */
129 pedantic = 0;
130
8e605e78
UD
131 while (runp != NULL)
132 {
133 (void) checkhdr (runp);
134
135 runp = runp->next;
136 }
30e0f9c3
UD
137
138 /* Turn checks on again. */
139 pedantic = 1;
8e605e78 140}
a14f26ef
RM
141#ifdef _LIBC
142libc_hidden_def (mcheck_check_all)
143#endif
8e605e78 144
8e605e78 145static void
b80163bd 146unlink_blk (struct hdr *ptr)
8e605e78
UD
147{
148 if (ptr->next != NULL)
149 {
150 ptr->next->prev = ptr->prev;
151 ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
152 + (uintptr_t) ptr->next->next);
153 }
154 if (ptr->prev != NULL)
155 {
156 ptr->prev->next = ptr->next;
157 ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
158 + (uintptr_t) ptr->prev->next);
159 }
160 else
161 root = ptr->next;
162}
163
8e605e78 164static void
b80163bd 165link_blk (struct hdr *hdr)
8e605e78
UD
166{
167 hdr->prev = NULL;
168 hdr->next = root;
169 root = hdr;
170 hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
171
172 /* And the next block. */
173 if (hdr->next != NULL)
174 {
175 hdr->next->prev = hdr;
176 hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
177 + (uintptr_t) hdr->next->next);
178 }
179}
6d52618b 180static void
b80163bd 181freehook (__ptr_t ptr, const __ptr_t caller)
6d52618b 182{
8e605e78 183 if (pedantic)
77e1d15a 184 mcheck_check_all ();
6d52618b
UD
185 if (ptr)
186 {
187 struct hdr *hdr = ((struct hdr *) ptr) - 1;
188 checkhdr (hdr);
189 hdr->magic = MAGICFREE;
6e3d59bc 190 hdr->magic2 = MAGICFREE;
8e605e78
UD
191 unlink_blk (hdr);
192 hdr->prev = hdr->next = NULL;
6d52618b 193 flood (ptr, FREEFLOOD, hdr->size);
6e3d59bc 194 ptr = hdr->block;
6d52618b
UD
195 }
196 __free_hook = old_free_hook;
a2b08ee5
UD
197 if (old_free_hook != NULL)
198 (*old_free_hook) (ptr, caller);
199 else
a334319f 200 free (ptr);
6d52618b
UD
201 __free_hook = freehook;
202}
203
6d52618b 204static __ptr_t
b80163bd 205mallochook (__malloc_size_t size, const __ptr_t caller)
6d52618b
UD
206{
207 struct hdr *hdr;
208
8e605e78 209 if (pedantic)
77e1d15a 210 mcheck_check_all ();
8e605e78 211
6d52618b 212 __malloc_hook = old_malloc_hook;
a2b08ee5
UD
213 if (old_malloc_hook != NULL)
214 hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
215 caller);
216 else
a334319f 217 hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
6d52618b
UD
218 __malloc_hook = mallochook;
219 if (hdr == NULL)
220 return NULL;
221
222 hdr->size = size;
8e605e78 223 link_blk (hdr);
6e3d59bc
RM
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);
229}
230
6e3d59bc 231static __ptr_t
b80163bd
RM
232memalignhook (__malloc_size_t alignment, __malloc_size_t size,
233 const __ptr_t caller)
6e3d59bc
RM
234{
235 struct hdr *hdr;
236 __malloc_size_t slop;
237 char *block;
238
239 if (pedantic)
240 mcheck_check_all ();
241
242 slop = (sizeof *hdr + alignment - 1) & -alignment;
243
244 __memalign_hook = old_memalign_hook;
245 if (old_memalign_hook != NULL)
246 block = (*old_memalign_hook) (alignment, slop + size + 1, caller);
247 else
a334319f 248 block = memalign (alignment, slop + size + 1);
6e3d59bc
RM
249 __memalign_hook = memalignhook;
250 if (block == NULL)
251 return NULL;
252
253 hdr = ((struct hdr *) (block + slop)) - 1;
254
255 hdr->size = size;
256 link_blk (hdr);
257 hdr->block = (__ptr_t) block;
258 hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
6d52618b
UD
259 ((char *) &hdr[1])[size] = MAGICBYTE;
260 flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
261 return (__ptr_t) (hdr + 1);
262}
263
6d52618b 264static __ptr_t
b80163bd 265reallochook (__ptr_t ptr, __malloc_size_t size, const __ptr_t caller)
6d52618b 266{
129abdd3
UD
267 if (size == 0)
268 {
269 freehook (ptr, caller);
270 return;
271 }
272
6d52618b
UD
273 struct hdr *hdr;
274 __malloc_size_t osize;
275
8e605e78 276 if (pedantic)
77e1d15a 277 mcheck_check_all ();
8e605e78 278
6d52618b
UD
279 if (ptr)
280 {
281 hdr = ((struct hdr *) ptr) - 1;
282 osize = hdr->size;
283
284 checkhdr (hdr);
8e605e78 285 unlink_blk (hdr);
6d52618b
UD
286 if (size < osize)
287 flood ((char *) ptr + size, FREEFLOOD, osize - size);
288 }
289 else
290 {
291 osize = 0;
292 hdr = NULL;
293 }
294 __free_hook = old_free_hook;
295 __malloc_hook = old_malloc_hook;
6e3d59bc 296 __memalign_hook = old_memalign_hook;
6d52618b 297 __realloc_hook = old_realloc_hook;
a2b08ee5
UD
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
a334319f
UD
303 hdr = (struct hdr *) realloc ((__ptr_t) hdr,
304 sizeof (struct hdr) + size + 1);
6d52618b
UD
305 __free_hook = freehook;
306 __malloc_hook = mallochook;
6e3d59bc 307 __memalign_hook = memalignhook;
6d52618b
UD
308 __realloc_hook = reallochook;
309 if (hdr == NULL)
310 return NULL;
311
312 hdr->size = size;
8e605e78 313 link_blk (hdr);
6e3d59bc
RM
314 hdr->block = hdr;
315 hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
6d52618b
UD
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);
320}
321
b80163bd 322__attribute__ ((noreturn))
6d52618b 323static void
b80163bd 324mabort (enum mcheck_status status)
6d52618b
UD
325{
326 const char *msg;
327 switch (status)
328 {
329 case MCHECK_OK:
9756dfe1 330 msg = _("memory is consistent, library is buggy\n");
6d52618b
UD
331 break;
332 case MCHECK_HEAD:
9756dfe1 333 msg = _("memory clobbered before allocated block\n");
6d52618b
UD
334 break;
335 case MCHECK_TAIL:
9756dfe1 336 msg = _("memory clobbered past end of allocated block\n");
6d52618b
UD
337 break;
338 case MCHECK_FREE:
9756dfe1 339 msg = _("block freed twice\n");
6d52618b
UD
340 break;
341 default:
9756dfe1 342 msg = _("bogus mcheck_status, library is buggy\n");
6d52618b
UD
343 break;
344 }
345#ifdef _LIBC
346 __libc_fatal (msg);
347#else
9756dfe1 348 fprintf (stderr, "mcheck: %s", msg);
6d52618b
UD
349 fflush (stderr);
350 abort ();
351#endif
352}
353
6d52618b
UD
354int
355mcheck (func)
b80163bd 356 void (*func) (enum mcheck_status);
6d52618b
UD
357{
358 abortfunc = (func != NULL) ? func : &mabort;
359
360 /* These hooks may not be safely inserted if malloc is already in use. */
9756dfe1 361 if (__malloc_initialized <= 0 && !mcheck_used)
6d52618b 362 {
1b20d937 363 /* We call malloc() once here to ensure it is initialized. */
a334319f
UD
364 void *p = malloc (0);
365 free (p);
1b20d937 366
6d52618b
UD
367 old_free_hook = __free_hook;
368 __free_hook = freehook;
369 old_malloc_hook = __malloc_hook;
370 __malloc_hook = mallochook;
6e3d59bc
RM
371 old_memalign_hook = __memalign_hook;
372 __memalign_hook = memalignhook;
6d52618b
UD
373 old_realloc_hook = __realloc_hook;
374 __realloc_hook = reallochook;
375 mcheck_used = 1;
376 }
377
378 return mcheck_used ? 0 : -1;
379}
509d1b68
RM
380#ifdef _LIBC
381libc_hidden_def (mcheck)
382#endif
6d52618b 383
8e605e78
UD
384int
385mcheck_pedantic (func)
b80163bd 386 void (*func) (enum mcheck_status);
8e605e78 387{
77e1d15a
UD
388 int res = mcheck (func);
389 if (res == 0)
390 pedantic = 1;
391 return res;
8e605e78
UD
392}
393
6d52618b
UD
394enum mcheck_status
395mprobe (__ptr_t ptr)
396{
997a4165 397 return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
6d52618b 398}