fdwalk should return 0 on an empty directory
[kopensolaris-gnu/glibc.git] / malloc / mcheck.c
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.
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   if (size == 0)
268     {
269       freehook (ptr, caller);
270       return NULL;
271     }
272
273   struct hdr *hdr;
274   __malloc_size_t osize;
275
276   if (pedantic)
277     mcheck_check_all ();
278
279   if (ptr)
280     {
281       hdr = ((struct hdr *) ptr) - 1;
282       osize = hdr->size;
283
284       checkhdr (hdr);
285       unlink_blk (hdr);
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;
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;
311
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);
320 }
321
322 __attribute__ ((noreturn))
323 static void
324 mabort (enum mcheck_status status)
325 {
326   const char *msg;
327   switch (status)
328     {
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;
344     }
345 #ifdef _LIBC
346   __libc_fatal (msg);
347 #else
348   fprintf (stderr, "mcheck: %s", msg);
349   fflush (stderr);
350   abort ();
351 #endif
352 }
353
354 int
355 mcheck (func)
356      void (*func) (enum mcheck_status);
357 {
358   abortfunc = (func != NULL) ? func : &mabort;
359
360   /* These hooks may not be safely inserted if malloc is already in use.  */
361   if (__malloc_initialized <= 0 && !mcheck_used)
362     {
363       /* We call malloc() once here to ensure it is initialized.  */
364       void *p = malloc (0);
365       free (p);
366
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;
376     }
377
378   return mcheck_used ? 0 : -1;
379 }
380 #ifdef _LIBC
381 libc_hidden_def (mcheck)
382 #endif
383
384 int
385 mcheck_pedantic (func)
386       void (*func) (enum mcheck_status);
387 {
388   int res = mcheck (func);
389   if (res == 0)
390     pedantic = 1;
391   return res;
392 }
393
394 enum mcheck_status
395 mprobe (__ptr_t ptr)
396 {
397   return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
398 }