(install-bin): Remove memusage.
[kopensolaris-gnu/glibc.git] / malloc / mcheck.c
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.
5
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.
10
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.
15
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.  */
20
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
29
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);
38
39 /* Function to call when something awful happens.  */
40 static void (*abortfunc) (enum mcheck_status);
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
49 struct hdr
50   {
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.  */
57   };
58
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;
62
63 static int mcheck_used;
64
65 /* Nonzero if pedentic checking of all blocks is requested.  */
66 static int pedantic;
67
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;
78 {
79   char *cp = ptr;
80   while (size--)
81     *cp++ = val;
82 }
83 #endif
84
85 static enum mcheck_status
86 checkhdr (const struct hdr *hdr)
87 {
88   enum mcheck_status status;
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
95   switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
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;
106       else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
107         status = MCHECK_HEAD;
108       else
109         status = MCHECK_OK;
110       break;
111     }
112   if (status != MCHECK_OK)
113     {
114       mcheck_used = 0;
115       (*abortfunc) (status);
116       mcheck_used = 1;
117     }
118   return status;
119 }
120
121 void
122 mcheck_check_all (void)
123 {
124   /* Walk through all the active blocks and test whether they were tempered
125      with.  */
126   struct hdr *runp = root;
127
128   /* Temporarily turn off the checks.  */
129   pedantic = 0;
130
131   while (runp != NULL)
132     {
133       (void) checkhdr (runp);
134
135       runp = runp->next;
136     }
137
138   /* Turn checks on again.  */
139   pedantic = 1;
140 }
141 #ifdef _LIBC
142 libc_hidden_def (mcheck_check_all)
143 #endif
144
145 static void
146 unlink_blk (struct hdr *ptr)
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
164 static void
165 link_blk (struct hdr *hdr)
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 }
180 static void
181 freehook (__ptr_t ptr, const __ptr_t caller)
182 {
183   if (pedantic)
184     mcheck_check_all ();
185   if (ptr)
186     {
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;
195     }
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;
202 }
203
204 static __ptr_t
205 mallochook (__malloc_size_t size, const __ptr_t caller)
206 {
207   struct hdr *hdr;
208
209   if (pedantic)
210     mcheck_check_all ();
211
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;
221
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);
229 }
230
231 static __ptr_t
232 memalignhook (__malloc_size_t alignment, __malloc_size_t size,
233               const __ptr_t caller)
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
248     block = memalign (alignment, slop + size + 1);
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;
259   ((char *) &hdr[1])[size] = MAGICBYTE;
260   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
261   return (__ptr_t) (hdr + 1);
262 }
263
264 static __ptr_t
265 reallochook (__ptr_t ptr, __malloc_size_t size, const __ptr_t caller)
266 {
267   struct hdr *hdr;
268   __malloc_size_t osize;
269
270   if (pedantic)
271     mcheck_check_all ();
272
273   if (ptr)
274     {
275       hdr = ((struct hdr *) ptr) - 1;
276       osize = hdr->size;
277
278       checkhdr (hdr);
279       unlink_blk (hdr);
280       if (size < osize)
281         flood ((char *) ptr + size, FREEFLOOD, osize - size);
282     }
283   else
284     {
285       osize = 0;
286       hdr = NULL;
287     }
288   __free_hook = old_free_hook;
289   __malloc_hook = old_malloc_hook;
290   __memalign_hook = old_memalign_hook;
291   __realloc_hook = old_realloc_hook;
292   if (old_realloc_hook != NULL)
293     hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
294                                               sizeof (struct hdr) + size + 1,
295                                               caller);
296   else
297     hdr = (struct hdr *) realloc ((__ptr_t) hdr,
298                                   sizeof (struct hdr) + size + 1);
299   __free_hook = freehook;
300   __malloc_hook = mallochook;
301   __memalign_hook = memalignhook;
302   __realloc_hook = reallochook;
303   if (hdr == NULL)
304     return NULL;
305
306   hdr->size = size;
307   link_blk (hdr);
308   hdr->block = hdr;
309   hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
310   ((char *) &hdr[1])[size] = MAGICBYTE;
311   if (size > osize)
312     flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
313   return (__ptr_t) (hdr + 1);
314 }
315
316 __attribute__ ((noreturn))
317 static void
318 mabort (enum mcheck_status status)
319 {
320   const char *msg;
321   switch (status)
322     {
323     case MCHECK_OK:
324       msg = _("memory is consistent, library is buggy\n");
325       break;
326     case MCHECK_HEAD:
327       msg = _("memory clobbered before allocated block\n");
328       break;
329     case MCHECK_TAIL:
330       msg = _("memory clobbered past end of allocated block\n");
331       break;
332     case MCHECK_FREE:
333       msg = _("block freed twice\n");
334       break;
335     default:
336       msg = _("bogus mcheck_status, library is buggy\n");
337       break;
338     }
339 #ifdef _LIBC
340   __libc_fatal (msg);
341 #else
342   fprintf (stderr, "mcheck: %s", msg);
343   fflush (stderr);
344   abort ();
345 #endif
346 }
347
348 int
349 mcheck (func)
350      void (*func) (enum mcheck_status);
351 {
352   abortfunc = (func != NULL) ? func : &mabort;
353
354   /* These hooks may not be safely inserted if malloc is already in use.  */
355   if (__malloc_initialized <= 0 && !mcheck_used)
356     {
357       /* We call malloc() once here to ensure it is initialized.  */
358       void *p = malloc (0);
359       free (p);
360
361       old_free_hook = __free_hook;
362       __free_hook = freehook;
363       old_malloc_hook = __malloc_hook;
364       __malloc_hook = mallochook;
365       old_memalign_hook = __memalign_hook;
366       __memalign_hook = memalignhook;
367       old_realloc_hook = __realloc_hook;
368       __realloc_hook = reallochook;
369       mcheck_used = 1;
370     }
371
372   return mcheck_used ? 0 : -1;
373 }
374 #ifdef _LIBC
375 libc_hidden_def (mcheck)
376 #endif
377
378 int
379 mcheck_pedantic (func)
380       void (*func) (enum mcheck_status);
381 {
382   int res = mcheck (func);
383   if (res == 0)
384     pedantic = 1;
385   return res;
386 }
387
388 enum mcheck_status
389 mprobe (__ptr_t ptr)
390 {
391   return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
392 }