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