Back to index

glibc  2.9
mcheck.c
Go to the documentation of this file.
00001 /* Standard debugging hooks for `malloc'.
00002    Copyright (C) 1990-1997,1999,2000-2002,2007 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Written May 1989 by Mike Haertel.
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #ifndef       _MALLOC_INTERNAL
00022 # define _MALLOC_INTERNAL
00023 # include <malloc.h>
00024 # include <mcheck.h>
00025 # include <stdint.h>
00026 # include <stdio.h>
00027 # include <libintl.h>
00028 #endif
00029 
00030 /* Old hook values.  */
00031 static void (*old_free_hook) (__ptr_t ptr, __const __ptr_t);
00032 static __ptr_t (*old_malloc_hook) (__malloc_size_t size, const __ptr_t);
00033 static __ptr_t (*old_memalign_hook) (__malloc_size_t alignment,
00034                                  __malloc_size_t size,
00035                                  const __ptr_t);
00036 static __ptr_t (*old_realloc_hook) (__ptr_t ptr, __malloc_size_t size,
00037                                 __const __ptr_t);
00038 
00039 /* Function to call when something awful happens.  */
00040 static void (*abortfunc) (enum mcheck_status);
00041 
00042 /* Arbitrary magical numbers.  */
00043 #define MAGICWORD    0xfedabeeb
00044 #define MAGICFREE    0xd8675309
00045 #define MAGICBYTE    ((char) 0xd7)
00046 #define MALLOCFLOOD  ((char) 0x93)
00047 #define FREEFLOOD    ((char) 0x95)
00048 
00049 struct hdr
00050   {
00051     __malloc_size_t size;   /* Exact size requested by user.  */
00052     unsigned long int magic;       /* Magic number to check header integrity.  */
00053     struct hdr *prev;
00054     struct hdr *next;
00055     __ptr_t block;          /* Real block allocated, for memalign.  */
00056     unsigned long int magic2;      /* Extra, keeps us doubleword aligned.  */
00057   };
00058 
00059 /* This is the beginning of the list of all memory blocks allocated.
00060    It is only constructed if the pedantic testing is requested.  */
00061 static struct hdr *root;
00062 
00063 static int mcheck_used;
00064 
00065 /* Nonzero if pedentic checking of all blocks is requested.  */
00066 static int pedantic;
00067 
00068 #if defined _LIBC || defined STDC_HEADERS || defined USG
00069 # include <string.h>
00070 # define flood memset
00071 #else
00072 static void flood (__ptr_t, int, __malloc_size_t);
00073 static void
00074 flood (ptr, val, size)
00075      __ptr_t ptr;
00076      int val;
00077      __malloc_size_t size;
00078 {
00079   char *cp = ptr;
00080   while (size--)
00081     *cp++ = val;
00082 }
00083 #endif
00084 
00085 static enum mcheck_status
00086 checkhdr (const struct hdr *hdr)
00087 {
00088   enum mcheck_status status;
00089 
00090   if (!mcheck_used)
00091     /* Maybe the mcheck used is disabled?  This happens when we find
00092        an error and report it.  */
00093     return MCHECK_OK;
00094 
00095   switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next))
00096     {
00097     default:
00098       status = MCHECK_HEAD;
00099       break;
00100     case MAGICFREE:
00101       status = MCHECK_FREE;
00102       break;
00103     case MAGICWORD:
00104       if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
00105        status = MCHECK_TAIL;
00106       else if ((hdr->magic2 ^ (uintptr_t) hdr->block) != MAGICWORD)
00107        status = MCHECK_HEAD;
00108       else
00109        status = MCHECK_OK;
00110       break;
00111     }
00112   if (status != MCHECK_OK)
00113     {
00114       mcheck_used = 0;
00115       (*abortfunc) (status);
00116       mcheck_used = 1;
00117     }
00118   return status;
00119 }
00120 
00121 void
00122 mcheck_check_all (void)
00123 {
00124   /* Walk through all the active blocks and test whether they were tempered
00125      with.  */
00126   struct hdr *runp = root;
00127 
00128   /* Temporarily turn off the checks.  */
00129   pedantic = 0;
00130 
00131   while (runp != NULL)
00132     {
00133       (void) checkhdr (runp);
00134 
00135       runp = runp->next;
00136     }
00137 
00138   /* Turn checks on again.  */
00139   pedantic = 1;
00140 }
00141 #ifdef _LIBC
00142 libc_hidden_def (mcheck_check_all)
00143 #endif
00144 
00145 static void
00146 unlink_blk (struct hdr *ptr)
00147 {
00148   if (ptr->next != NULL)
00149     {
00150       ptr->next->prev = ptr->prev;
00151       ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev
00152                                   + (uintptr_t) ptr->next->next);
00153     }
00154   if (ptr->prev != NULL)
00155     {
00156       ptr->prev->next = ptr->next;
00157       ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev
00158                                   + (uintptr_t) ptr->prev->next);
00159     }
00160   else
00161     root = ptr->next;
00162 }
00163 
00164 static void
00165 link_blk (struct hdr *hdr)
00166 {
00167   hdr->prev = NULL;
00168   hdr->next = root;
00169   root = hdr;
00170   hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next;
00171 
00172   /* And the next block.  */
00173   if (hdr->next != NULL)
00174     {
00175       hdr->next->prev = hdr;
00176       hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr
00177                                   + (uintptr_t) hdr->next->next);
00178     }
00179 }
00180 static void
00181 freehook (__ptr_t ptr, const __ptr_t caller)
00182 {
00183   if (pedantic)
00184     mcheck_check_all ();
00185   if (ptr)
00186     {
00187       struct hdr *hdr = ((struct hdr *) ptr) - 1;
00188       checkhdr (hdr);
00189       hdr->magic = MAGICFREE;
00190       hdr->magic2 = MAGICFREE;
00191       unlink_blk (hdr);
00192       hdr->prev = hdr->next = NULL;
00193       flood (ptr, FREEFLOOD, hdr->size);
00194       ptr = hdr->block;
00195     }
00196   __free_hook = old_free_hook;
00197   if (old_free_hook != NULL)
00198     (*old_free_hook) (ptr, caller);
00199   else
00200     free (ptr);
00201   __free_hook = freehook;
00202 }
00203 
00204 static __ptr_t
00205 mallochook (__malloc_size_t size, const __ptr_t caller)
00206 {
00207   struct hdr *hdr;
00208 
00209   if (pedantic)
00210     mcheck_check_all ();
00211 
00212   __malloc_hook = old_malloc_hook;
00213   if (old_malloc_hook != NULL)
00214     hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1,
00215                                         caller);
00216   else
00217     hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
00218   __malloc_hook = mallochook;
00219   if (hdr == NULL)
00220     return NULL;
00221 
00222   hdr->size = size;
00223   link_blk (hdr);
00224   hdr->block = hdr;
00225   hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
00226   ((char *) &hdr[1])[size] = MAGICBYTE;
00227   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
00228   return (__ptr_t) (hdr + 1);
00229 }
00230 
00231 static __ptr_t
00232 memalignhook (__malloc_size_t alignment, __malloc_size_t size,
00233              const __ptr_t caller)
00234 {
00235   struct hdr *hdr;
00236   __malloc_size_t slop;
00237   char *block;
00238 
00239   if (pedantic)
00240     mcheck_check_all ();
00241 
00242   slop = (sizeof *hdr + alignment - 1) & -alignment;
00243 
00244   __memalign_hook = old_memalign_hook;
00245   if (old_memalign_hook != NULL)
00246     block = (*old_memalign_hook) (alignment, slop + size + 1, caller);
00247   else
00248     block = memalign (alignment, slop + size + 1);
00249   __memalign_hook = memalignhook;
00250   if (block == NULL)
00251     return NULL;
00252 
00253   hdr = ((struct hdr *) (block + slop)) - 1;
00254 
00255   hdr->size = size;
00256   link_blk (hdr);
00257   hdr->block = (__ptr_t) block;
00258   hdr->magic2 = (uintptr_t) block ^ MAGICWORD;
00259   ((char *) &hdr[1])[size] = MAGICBYTE;
00260   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
00261   return (__ptr_t) (hdr + 1);
00262 }
00263 
00264 static __ptr_t
00265 reallochook (__ptr_t ptr, __malloc_size_t size, const __ptr_t caller)
00266 {
00267   if (size == 0)
00268     {
00269       freehook (ptr, caller);
00270       return NULL;
00271     }
00272 
00273   struct hdr *hdr;
00274   __malloc_size_t osize;
00275 
00276   if (pedantic)
00277     mcheck_check_all ();
00278 
00279   if (ptr)
00280     {
00281       hdr = ((struct hdr *) ptr) - 1;
00282       osize = hdr->size;
00283 
00284       checkhdr (hdr);
00285       unlink_blk (hdr);
00286       if (size < osize)
00287        flood ((char *) ptr + size, FREEFLOOD, osize - size);
00288     }
00289   else
00290     {
00291       osize = 0;
00292       hdr = NULL;
00293     }
00294   __free_hook = old_free_hook;
00295   __malloc_hook = old_malloc_hook;
00296   __memalign_hook = old_memalign_hook;
00297   __realloc_hook = old_realloc_hook;
00298   if (old_realloc_hook != NULL)
00299     hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr,
00300                                          sizeof (struct hdr) + size + 1,
00301                                          caller);
00302   else
00303     hdr = (struct hdr *) realloc ((__ptr_t) hdr,
00304                               sizeof (struct hdr) + size + 1);
00305   __free_hook = freehook;
00306   __malloc_hook = mallochook;
00307   __memalign_hook = memalignhook;
00308   __realloc_hook = reallochook;
00309   if (hdr == NULL)
00310     return NULL;
00311 
00312   hdr->size = size;
00313   link_blk (hdr);
00314   hdr->block = hdr;
00315   hdr->magic2 = (uintptr_t) hdr ^ MAGICWORD;
00316   ((char *) &hdr[1])[size] = MAGICBYTE;
00317   if (size > osize)
00318     flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
00319   return (__ptr_t) (hdr + 1);
00320 }
00321 
00322 __attribute__ ((noreturn))
00323 static void
00324 mabort (enum mcheck_status status)
00325 {
00326   const char *msg;
00327   switch (status)
00328     {
00329     case MCHECK_OK:
00330       msg = _("memory is consistent, library is buggy\n");
00331       break;
00332     case MCHECK_HEAD:
00333       msg = _("memory clobbered before allocated block\n");
00334       break;
00335     case MCHECK_TAIL:
00336       msg = _("memory clobbered past end of allocated block\n");
00337       break;
00338     case MCHECK_FREE:
00339       msg = _("block freed twice\n");
00340       break;
00341     default:
00342       msg = _("bogus mcheck_status, library is buggy\n");
00343       break;
00344     }
00345 #ifdef _LIBC
00346   __libc_fatal (msg);
00347 #else
00348   fprintf (stderr, "mcheck: %s", msg);
00349   fflush (stderr);
00350   abort ();
00351 #endif
00352 }
00353 
00354 int
00355 mcheck (func)
00356      void (*func) (enum mcheck_status);
00357 {
00358   abortfunc = (func != NULL) ? func : &mabort;
00359 
00360   /* These hooks may not be safely inserted if malloc is already in use.  */
00361   if (__malloc_initialized <= 0 && !mcheck_used)
00362     {
00363       /* We call malloc() once here to ensure it is initialized.  */
00364       void *p = malloc (0);
00365       free (p);
00366 
00367       old_free_hook = __free_hook;
00368       __free_hook = freehook;
00369       old_malloc_hook = __malloc_hook;
00370       __malloc_hook = mallochook;
00371       old_memalign_hook = __memalign_hook;
00372       __memalign_hook = memalignhook;
00373       old_realloc_hook = __realloc_hook;
00374       __realloc_hook = reallochook;
00375       mcheck_used = 1;
00376     }
00377 
00378   return mcheck_used ? 0 : -1;
00379 }
00380 #ifdef _LIBC
00381 libc_hidden_def (mcheck)
00382 #endif
00383 
00384 int
00385 mcheck_pedantic (func)
00386       void (*func) (enum mcheck_status);
00387 {
00388   int res = mcheck (func);
00389   if (res == 0)
00390     pedantic = 1;
00391   return res;
00392 }
00393 
00394 enum mcheck_status
00395 mprobe (__ptr_t ptr)
00396 {
00397   return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED;
00398 }