malloc: Add posix_memalign test.
[platform/upstream/glibc.git] / malloc / mcheck.c
1 /* Standard debugging hooks for `malloc'.
2    Copyright (C) 1990-2013 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, see
18    <http://www.gnu.org/licenses/>.  */
19
20 #ifndef _MALLOC_INTERNAL
21 # define _MALLOC_INTERNAL
22 # include <malloc.h>
23 # include <mcheck.h>
24 # include <stdint.h>
25 # include <stdio.h>
26 # include <libintl.h>
27 # include <errno.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) (size_t size, const __ptr_t);
33 static __ptr_t (*old_memalign_hook) (size_t alignment, size_t size,
34                                      const __ptr_t);
35 static __ptr_t (*old_realloc_hook) (__ptr_t ptr, size_t size,
36                                     const __ptr_t);
37
38 /* Function to call when something awful happens.  */
39 static void (*abortfunc) (enum mcheck_status);
40
41 /* Arbitrary magical numbers.  */
42 #define MAGICWORD       0xfedabeeb
43 #define MAGICFREE       0xd8675309
44 #define MAGICBYTE       ((char) 0xd7)
45 #define MALLOCFLOOD     ((char) 0x93)
46 #define FREEFLOOD       ((char) 0x95)
47
48 struct hdr
49   {
50     size_t size;                /* Exact size requested by user.  */
51     unsigned long int magic;    /* Magic number to check header integrity.  */
52     struct hdr *prev;
53     struct hdr *next;
54     __ptr_t block;              /* Real block allocated, for memalign.  */
55     unsigned long int magic2;   /* Extra, keeps us doubleword aligned.  */
56   };
57
58 /* This is the beginning of the list of all memory blocks allocated.
59    It is only constructed if the pedantic testing is requested.  */
60 static struct hdr *root;
61
62 static int mcheck_used;
63
64 /* Nonzero if pedentic checking of all blocks is requested.  */
65 static int pedantic;
66
67 #if defined _LIBC || defined STDC_HEADERS || defined USG
68 # include <string.h>
69 # define flood memset
70 #else
71 static void flood (__ptr_t, int, size_t);
72 static void
73 flood (ptr, val, size)
74      __ptr_t ptr;
75      int val;
76      size_t size;
77 {
78   char *cp = ptr;
79   while (size--)
80     *cp++ = val;
81 }
82 #endif
83
84 static enum mcheck_status
85 checkhdr (const struct hdr *hdr)
86 {
87   enum mcheck_status status;
88
89   if (!mcheck_used)
90     /* Maybe the mcheck used is disabled?  This happens when we find
91        an error and report it.  */
92     return MCHECK_OK;
93
94   switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
95     {
96     default:
97       status = MCHECK_HEAD;
98       break;
99     case MAGICFREE:
100       status = MCHECK_FREE;
101       break;
102     case MAGICWORD:
103       if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
104         status = MCHECK_TAIL;
105       else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
106         status = MCHECK_HEAD;
107       else
108         status = MCHECK_OK;
109       break;
110     }
111   if (status != MCHECK_OK)
112     {
113       mcheck_used = 0;
114       (*abortfunc) (status);
115       mcheck_used = 1;
116     }
117   return status;
118 }
119
120 void
121 mcheck_check_all (void)
122 {
123   /* Walk through all the active blocks and test whether they were tampered
124      with.  */
125   struct hdr *runp = root;
126
127   /* Temporarily turn off the checks.  */
128   pedantic = 0;
129
130   while (runp != NULL)
131     {
132       (void) checkhdr (runp);
133
134       runp = runp->next;
135     }
136
137   /* Turn checks on again.  */
138   pedantic = 1;
139 }
140 #ifdef _LIBC
141 libc_hidden_def (mcheck_check_all)
142 #endif
143
144 static void
145 unlink_blk (struct hdr *ptr)
146 {
147   if (ptr->next != NULL)
148     {
149       ptr->next->prev = ptr->prev;
150       ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
151                                       + (uintptr_t) ptr->next->next);
152     }
153   if (ptr->prev != NULL)
154     {
155       ptr->prev->next = ptr->next;
156       ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
157                                       + (uintptr_t) ptr->prev->next);
158     }
159   else
160     root = ptr->next;
161 }
162
163 static void
164 link_blk (struct hdr *hdr)
165 {
166   hdr->prev = NULL;
167   hdr->next = root;
168   root = hdr;
169   hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
170
171   /* And the next block.  */
172   if (hdr->next != NULL)
173     {
174       hdr->next->prev = hdr;
175       hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
176                                       + (uintptr_t) hdr->next->next);
177     }
178 }
179 static void
180 freehook (__ptr_t ptr, const __ptr_t caller)
181 {
182   if (pedantic)
183     mcheck_check_all ();
184   if (ptr)
185     {
186       struct hdr *hdr = ((struct hdr *) ptr) - 1;
187       checkhdr (hdr);
188       hdr->magic = MAGICFREE;
189       hdr->magic2 = MAGICFREE;
190       unlink_blk (hdr);
191       hdr->prev = hdr->next = NULL;
192       flood (ptr, FREEFLOOD, hdr->size);
193       ptr = hdr->block;
194     }
195   __free_hook = old_free_hook;
196   if (old_free_hook != NULL)
197     (*old_free_hook) (ptr, caller);
198   else
199     free (ptr);
200   __free_hook = freehook;
201 }
202
203 static __ptr_t
204 mallochook (size_t size, const __ptr_t caller)
205 {
206   struct hdr *hdr;
207
208   if (pedantic)
209     mcheck_check_all ();
210
211   if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
212     {
213       __set_errno (ENOMEM);
214       return NULL;
215     }
216
217   __malloc_hook = old_malloc_hook;
218   if (old_malloc_hook != NULL)
219     hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
220                                              caller);
221   else
222     hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
223   __malloc_hook = mallochook;
224   if (hdr == NULL)
225     return NULL;
226
227   hdr->size = size;
228   link_blk (hdr);
229   hdr->block = hdr;
230   hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
231   ((char *) &hdr[1])[size] = MAGICBYTE;
232   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
233   return (__ptr_t) (hdr + 1);
234 }
235
236 static __ptr_t
237 memalignhook (size_t alignment, size_t size,
238               const __ptr_t caller)
239 {
240   struct hdr *hdr;
241   size_t slop;
242   char *block;
243
244   if (pedantic)
245     mcheck_check_all ();
246
247   slop = (sizeof *hdr + alignment - 1) & -alignment;
248
249   if (size > ~((size_t) 0) - (slop + 1))
250     {
251       __set_errno (ENOMEM);
252       return NULL;
253     }
254
255   __memalign_hook = old_memalign_hook;
256   if (old_memalign_hook != NULL)
257     block = (*old_memalign_hook) (alignment, slop + size + 1, caller);
258   else
259     block = memalign (alignment, slop + size + 1);
260   __memalign_hook = memalignhook;
261   if (block == NULL)
262     return NULL;
263
264   hdr = ((struct hdr *) (block + slop)) - 1;
265
266   hdr->size = size;
267   link_blk (hdr);
268   hdr->block = (__ptr_t) block;
269   hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
270   ((char *) &hdr[1])[size] = MAGICBYTE;
271   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
272   return (__ptr_t) (hdr + 1);
273 }
274
275 static __ptr_t
276 reallochook (__ptr_t ptr, size_t size, const __ptr_t caller)
277 {
278   if (size == 0)
279     {
280       freehook (ptr, caller);
281       return NULL;
282     }
283
284   struct hdr *hdr;
285   size_t osize;
286
287   if (pedantic)
288     mcheck_check_all ();
289
290   if (size > ~((size_t) 0) - (sizeof (struct hdr) + 1))
291     {
292       __set_errno (ENOMEM);
293       return NULL;
294     }
295
296   if (ptr)
297     {
298       hdr = ((struct hdr *) ptr) - 1;
299       osize = hdr->size;
300
301       checkhdr (hdr);
302       unlink_blk (hdr);
303       if (size < osize)
304         flood ((char *) ptr + size, FREEFLOOD, osize - size);
305     }
306   else
307     {
308       osize = 0;
309       hdr = NULL;
310     }
311   __free_hook = old_free_hook;
312   __malloc_hook = old_malloc_hook;
313   __memalign_hook = old_memalign_hook;
314   __realloc_hook = old_realloc_hook;
315   if (old_realloc_hook != NULL)
316     hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
317                                               sizeof (struct hdr) + size + 1,
318                                               caller);
319   else
320     hdr = (struct hdr *) realloc ((__ptr_t) hdr,
321                                   sizeof (struct hdr) + size + 1);
322   __free_hook = freehook;
323   __malloc_hook = mallochook;
324   __memalign_hook = memalignhook;
325   __realloc_hook = reallochook;
326   if (hdr == NULL)
327     return NULL;
328
329   hdr->size = size;
330   link_blk (hdr);
331   hdr->block = hdr;
332   hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
333   ((char *) &hdr[1])[size] = MAGICBYTE;
334   if (size > osize)
335     flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
336   return (__ptr_t) (hdr + 1);
337 }
338
339 __attribute__ ((noreturn))
340 static void
341 mabort (enum mcheck_status status)
342 {
343   const char *msg;
344   switch (status)
345     {
346     case MCHECK_OK:
347       msg = _("memory is consistent, library is buggy\n");
348       break;
349     case MCHECK_HEAD:
350       msg = _("memory clobbered before allocated block\n");
351       break;
352     case MCHECK_TAIL:
353       msg = _("memory clobbered past end of allocated block\n");
354       break;
355     case MCHECK_FREE:
356       msg = _("block freed twice\n");
357       break;
358     default:
359       msg = _("bogus mcheck_status, library is buggy\n");
360       break;
361     }
362 #ifdef _LIBC
363   __libc_fatal (msg);
364 #else
365   fprintf (stderr, "mcheck: %s", msg);
366   fflush (stderr);
367   abort ();
368 #endif
369 }
370
371 /* Memory barrier so that GCC does not optimize out the argument.  */
372 #define malloc_opt_barrier(x) \
373 ({ __typeof (x) __x = x; __asm ("" : "+m" (__x)); __x; })
374
375 int
376 mcheck (func)
377      void (*func) (enum mcheck_status);
378 {
379   abortfunc = (func != NULL) ? func : &mabort;
380
381   /* These hooks may not be safely inserted if malloc is already in use.  */
382   if (__malloc_initialized <= 0 && !mcheck_used)
383     {
384       /* We call malloc() once here to ensure it is initialized.  */
385       void *p = malloc (0);
386       /* GCC might optimize out the malloc/free pair without a barrier.  */
387       p = malloc_opt_barrier (p);
388       free (p);
389
390       old_free_hook = __free_hook;
391       __free_hook = freehook;
392       old_malloc_hook = __malloc_hook;
393       __malloc_hook = mallochook;
394       old_memalign_hook = __memalign_hook;
395       __memalign_hook = memalignhook;
396       old_realloc_hook = __realloc_hook;
397       __realloc_hook = reallochook;
398       mcheck_used = 1;
399     }
400
401   return mcheck_used ? 0 : -1;
402 }
403 #ifdef _LIBC
404 libc_hidden_def (mcheck)
405 #endif
406
407 int
408 mcheck_pedantic (func)
409       void (*func) (enum mcheck_status);
410 {
411   int res = mcheck (func);
412   if (res == 0)
413     pedantic = 1;
414   return res;
415 }
416
417 enum mcheck_status
418 mprobe (__ptr_t ptr)
419 {
420   return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
421 }