Upload Tizen:Base source
[external/eglibc.git] / malloc / mcheck.c
1 /* Standard debugging hooks for `malloc'.
2    Copyright (C) 1990-1997,1999,2000-2002,2007,2010
3    Free Software Foundation, Inc.
4    This file is part of the GNU C Library.
5    Written May 1989 by Mike Haertel.
6
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.
11
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16
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.  */
21
22 #ifndef _MALLOC_INTERNAL
23 # define _MALLOC_INTERNAL
24 # include <malloc.h>
25 # include <mcheck.h>
26 # include <stdint.h>
27 # include <stdio.h>
28 # include <libintl.h>
29 # include <errno.h>
30 #endif
31
32 /* Old hook values.  */
33 static void (*old_free_hook) (__ptr_t ptr, __const __ptr_t);
34 static __ptr_t (*old_malloc_hook) (__malloc_size_t size, const __ptr_t);
35 static __ptr_t (*old_memalign_hook) (__malloc_size_t alignment,
36                                      __malloc_size_t size,
37                                      const __ptr_t);
38 static __ptr_t (*old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
39                                     __const __ptr_t);
40
41 /* Function to call when something awful happens.  */
42 static void (*abortfunc) (enum mcheck_status);
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
51 struct hdr
52   {
53     __malloc_size_t size;       /* Exact size requested by user.  */
54     unsigned long int magic;    /* Magic number to check header integrity.  */
55     struct hdr *prev;
56     struct hdr *next;
57     __ptr_t block;              /* Real block allocated, for memalign.  */
58     unsigned long int magic2;   /* Extra, keeps us doubleword aligned.  */
59   };
60
61 /* This is the beginning of the list of all memory blocks allocated.
62    It is only constructed if the pedantic testing is requested.  */
63 static struct hdr *root;
64
65 static int mcheck_used;
66
67 /* Nonzero if pedentic checking of all blocks is requested.  */
68 static int pedantic;
69
70 #if defined _LIBC || defined STDC_HEADERS || defined USG
71 # include <string.h>
72 # define flood memset
73 #else
74 static void flood (__ptr_t, int, __malloc_size_t);
75 static void
76 flood (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
87 static enum mcheck_status
88 checkhdr (const struct hdr *hdr)
89 {
90   enum mcheck_status status;
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
97   switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
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;
108       else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
109         status = MCHECK_HEAD;
110       else
111         status = MCHECK_OK;
112       break;
113     }
114   if (status != MCHECK_OK)
115     {
116       mcheck_used = 0;
117       (*abortfunc) (status);
118       mcheck_used = 1;
119     }
120   return status;
121 }
122
123 void
124 mcheck_check_all (void)
125 {
126   /* Walk through all the active blocks and test whether they were tempered
127      with.  */
128   struct hdr *runp = root;
129
130   /* Temporarily turn off the checks.  */
131   pedantic = 0;
132
133   while (runp != NULL)
134     {
135       (void) checkhdr (runp);
136
137       runp = runp->next;
138     }
139
140   /* Turn checks on again.  */
141   pedantic = 1;
142 }
143 #ifdef _LIBC
144 libc_hidden_def (mcheck_check_all)
145 #endif
146
147 static void
148 unlink_blk (struct hdr *ptr)
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
166 static void
167 link_blk (struct hdr *hdr)
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 }
182 static void
183 freehook (__ptr_t ptr, const __ptr_t caller)
184 {
185   if (pedantic)
186     mcheck_check_all ();
187   if (ptr)
188     {
189       struct hdr *hdr = ((struct hdr *) ptr) - 1;
190       checkhdr (hdr);
191       hdr->magic = MAGICFREE;
192       hdr->magic2 = MAGICFREE;
193       unlink_blk (hdr);
194       hdr->prev = hdr->next = NULL;
195       flood (ptr, FREEFLOOD, hdr->size);
196       ptr = hdr->block;
197     }
198   __free_hook = old_free_hook;
199   if (old_free_hook != NULL)
200     (*old_free_hook) (ptr, caller);
201   else
202     free (ptr);
203   __free_hook = freehook;
204 }
205
206 static __ptr_t
207 mallochook (__malloc_size_t size, const __ptr_t caller)
208 {
209   struct hdr *hdr;
210
211   if (pedantic)
212     mcheck_check_all ();
213
214   if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
215     {
216       __set_errno (ENOMEM);
217       return NULL;
218     }
219
220   __malloc_hook = old_malloc_hook;
221   if (old_malloc_hook != NULL)
222     hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
223                                              caller);
224   else
225     hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
226   __malloc_hook = mallochook;
227   if (hdr == NULL)
228     return NULL;
229
230   hdr->size = size;
231   link_blk (hdr);
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
239 static __ptr_t
240 memalignhook (__malloc_size_t alignment, __malloc_size_t size,
241               const __ptr_t caller)
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
252   if (size > ~((size_t) 0) - (slop + 1))
253     {
254       __set_errno (ENOMEM);
255       return NULL;
256     }
257
258   __memalign_hook = old_memalign_hook;
259   if (old_memalign_hook != NULL)
260     block = (*old_memalign_hook) (alignment, slop + size + 1, caller);
261   else
262     block = memalign (alignment, slop + size + 1);
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;
273   ((char *) &hdr[1])[size] = MAGICBYTE;
274   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
275   return (__ptr_t) (hdr + 1);
276 }
277
278 static __ptr_t
279 reallochook (__ptr_t ptr, __malloc_size_t size, const __ptr_t caller)
280 {
281   if (size == 0)
282     {
283       freehook (ptr, caller);
284       return NULL;
285     }
286
287   struct hdr *hdr;
288   __malloc_size_t osize;
289
290   if (pedantic)
291     mcheck_check_all ();
292
293   if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
294     {
295       __set_errno (ENOMEM);
296       return NULL;
297     }
298
299   if (ptr)
300     {
301       hdr = ((struct hdr *) ptr) - 1;
302       osize = hdr->size;
303
304       checkhdr (hdr);
305       unlink_blk (hdr);
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;
316   __memalign_hook = old_memalign_hook;
317   __realloc_hook = old_realloc_hook;
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
323     hdr = (struct hdr *) realloc ((__ptr_t) hdr,
324                                   sizeof (struct hdr) + size + 1);
325   __free_hook = freehook;
326   __malloc_hook = mallochook;
327   __memalign_hook = memalignhook;
328   __realloc_hook = reallochook;
329   if (hdr == NULL)
330     return NULL;
331
332   hdr->size = size;
333   link_blk (hdr);
334   hdr->block = hdr;
335   hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
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
342 __attribute__ ((noreturn))
343 static void
344 mabort (enum mcheck_status status)
345 {
346   const char *msg;
347   switch (status)
348     {
349     case MCHECK_OK:
350       msg = _("memory is consistent, library is buggy\n");
351       break;
352     case MCHECK_HEAD:
353       msg = _("memory clobbered before allocated block\n");
354       break;
355     case MCHECK_TAIL:
356       msg = _("memory clobbered past end of allocated block\n");
357       break;
358     case MCHECK_FREE:
359       msg = _("block freed twice\n");
360       break;
361     default:
362       msg = _("bogus mcheck_status, library is buggy\n");
363       break;
364     }
365 #ifdef _LIBC
366   __libc_fatal (msg);
367 #else
368   fprintf (stderr, "mcheck: %s", msg);
369   fflush (stderr);
370   abort ();
371 #endif
372 }
373
374 int
375 mcheck (func)
376      void (*func) (enum mcheck_status);
377 {
378   abortfunc = (func != NULL) ? func : &mabort;
379
380   /* These hooks may not be safely inserted if malloc is already in use.  */
381   if (__malloc_initialized <= 0 && !mcheck_used)
382     {
383       /* We call malloc() once here to ensure it is initialized.  */
384       void *p = malloc (0);
385       free (p);
386
387       old_free_hook = __free_hook;
388       __free_hook = freehook;
389       old_malloc_hook = __malloc_hook;
390       __malloc_hook = mallochook;
391       old_memalign_hook = __memalign_hook;
392       __memalign_hook = memalignhook;
393       old_realloc_hook = __realloc_hook;
394       __realloc_hook = reallochook;
395       mcheck_used = 1;
396     }
397
398   return mcheck_used ? 0 : -1;
399 }
400 #ifdef _LIBC
401 libc_hidden_def (mcheck)
402 #endif
403
404 int
405 mcheck_pedantic (func)
406       void (*func) (enum mcheck_status);
407 {
408   int res = mcheck (func);
409   if (res == 0)
410     pedantic = 1;
411   return res;
412 }
413
414 enum mcheck_status
415 mprobe (__ptr_t ptr)
416 {
417   return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
418 }