Home | History | Annotate | Line # | Download | only in dist
mcheck.c revision 1.1.1.1
      1 /*	$NetBSD: mcheck.c,v 1.1.1.1 2016/01/13 21:42:18 christos Exp $	*/
      2 
      3 /* Standard debugging hooks for `malloc'.
      4    Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
      5    Written May 1989 by Mike Haertel.
      6 
      7 This library is free software; you can redistribute it and/or
      8 modify it under the terms of the GNU Library General Public License as
      9 published by the Free Software Foundation; either version 2 of the
     10 License, or (at your option) any later version.
     11 
     12 This 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 Library General Public License for more details.
     16 
     17 You should have received a copy of the GNU Library General Public
     18 License along with this library; see the file COPYING.LIB.  If
     19 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
     20 Cambridge, MA 02139, USA.
     21 
     22    The author may be reached (Email) at the address mike (at) ai.mit.edu,
     23    or (US mail) as Mike Haertel c/o Free Software Foundation.  */
     24 
     25 #ifndef	_MALLOC_INTERNAL
     26 #define	_MALLOC_INTERNAL
     27 #include <malloc.h>
     28 #include <stdio.h>
     29 #endif
     30 
     31 /* Old hook values.  */
     32 static void (*old_free_hook) __P ((__ptr_t ptr));
     33 static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size));
     34 static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
     35 
     36 /* Function to call when something awful happens.  */
     37 static void (*abortfunc) __P ((enum mcheck_status));
     38 
     39 /* Arbitrary magical numbers.  */
     40 #define MAGICWORD	0xfedabeeb
     41 #define MAGICFREE	0xd8675309
     42 #define MAGICBYTE	((char) 0xd7)
     43 #define MALLOCFLOOD	((char) 0x93)
     44 #define FREEFLOOD	((char) 0x95)
     45 
     46 struct hdr
     47   {
     48     __malloc_size_t size;		/* Exact size requested by user.  */
     49     unsigned long int magic;	/* Magic number to check header integrity.  */
     50   };
     51 
     52 #if	defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
     53 #define flood memset
     54 #else
     55 static void flood __P ((__ptr_t, int, __malloc_size_t));
     56 static void
     57 flood (ptr, val, size)
     58      __ptr_t ptr;
     59      int val;
     60      __malloc_size_t size;
     61 {
     62   char *cp = ptr;
     63   while (size--)
     64     *cp++ = val;
     65 }
     66 #endif
     67 
     68 static enum mcheck_status checkhdr __P ((const struct hdr *));
     69 static enum mcheck_status
     70 checkhdr (hdr)
     71      const struct hdr *hdr;
     72 {
     73   enum mcheck_status status;
     74   switch (hdr->magic)
     75     {
     76     default:
     77       status = MCHECK_HEAD;
     78       break;
     79     case MAGICFREE:
     80       status = MCHECK_FREE;
     81       break;
     82     case MAGICWORD:
     83       if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
     84 	status = MCHECK_TAIL;
     85       else
     86 	status = MCHECK_OK;
     87       break;
     88     }
     89   if (status != MCHECK_OK)
     90     (*abortfunc) (status);
     91   return status;
     92 }
     93 
     94 static void freehook __P ((__ptr_t));
     95 static void
     96 freehook (ptr)
     97      __ptr_t ptr;
     98 {
     99   struct hdr *hdr = ((struct hdr *) ptr) - 1;
    100   checkhdr (hdr);
    101   hdr->magic = MAGICFREE;
    102   flood (ptr, FREEFLOOD, hdr->size);
    103   __free_hook = old_free_hook;
    104   free (hdr);
    105   __free_hook = freehook;
    106 }
    107 
    108 static __ptr_t mallochook __P ((__malloc_size_t));
    109 static __ptr_t
    110 mallochook (size)
    111      __malloc_size_t size;
    112 {
    113   struct hdr *hdr;
    114 
    115   __malloc_hook = old_malloc_hook;
    116   hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
    117   __malloc_hook = mallochook;
    118   if (hdr == NULL)
    119     return NULL;
    120 
    121   hdr->size = size;
    122   hdr->magic = MAGICWORD;
    123   ((char *) &hdr[1])[size] = MAGICBYTE;
    124   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
    125   return (__ptr_t) (hdr + 1);
    126 }
    127 
    128 static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t));
    129 static __ptr_t
    130 reallochook (ptr, size)
    131      __ptr_t ptr;
    132      __malloc_size_t size;
    133 {
    134   struct hdr *hdr = ((struct hdr *) ptr) - 1;
    135   __malloc_size_t osize = hdr->size;
    136 
    137   checkhdr (hdr);
    138   if (size < osize)
    139     flood ((char *) ptr + size, FREEFLOOD, osize - size);
    140   __free_hook = old_free_hook;
    141   __malloc_hook = old_malloc_hook;
    142   __realloc_hook = old_realloc_hook;
    143   hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1);
    144   __free_hook = freehook;
    145   __malloc_hook = mallochook;
    146   __realloc_hook = reallochook;
    147   if (hdr == NULL)
    148     return NULL;
    149 
    150   hdr->size = size;
    151   hdr->magic = MAGICWORD;
    152   ((char *) &hdr[1])[size] = MAGICBYTE;
    153   if (size > osize)
    154     flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
    155   return (__ptr_t) (hdr + 1);
    156 }
    157 
    158 static void
    159 mabort (status)
    160      enum mcheck_status status;
    161 {
    162   const char *msg;
    163   switch (status)
    164     {
    165     case MCHECK_OK:
    166       msg = "memory is consistent, library is buggy";
    167       break;
    168     case MCHECK_HEAD:
    169       msg = "memory clobbered before allocated block";
    170       break;
    171     case MCHECK_TAIL:
    172       msg = "memory clobbered past end of allocated block";
    173       break;
    174     case MCHECK_FREE:
    175       msg = "block freed twice";
    176       break;
    177     default:
    178       msg = "bogus mcheck_status, library is buggy";
    179       break;
    180     }
    181 #ifdef __GNU_LIBRARY__
    182   __libc_fatal (msg);
    183 #else
    184   fprintf (stderr, "mcheck: %s\n", msg);
    185   fflush (stderr);
    186   abort ();
    187 #endif
    188 }
    189 
    190 static int mcheck_used = 0;
    191 
    192 int
    193 mcheck (func)
    194      void (*func) __P ((enum mcheck_status));
    195 {
    196   abortfunc = (func != NULL) ? func : &mabort;
    197 
    198   /* These hooks may not be safely inserted if malloc is already in use.  */
    199   if (!__malloc_initialized && !mcheck_used)
    200     {
    201       old_free_hook = __free_hook;
    202       __free_hook = freehook;
    203       old_malloc_hook = __malloc_hook;
    204       __malloc_hook = mallochook;
    205       old_realloc_hook = __realloc_hook;
    206       __realloc_hook = reallochook;
    207       mcheck_used = 1;
    208     }
    209 
    210   return mcheck_used ? 0 : -1;
    211 }
    212 
    213 enum mcheck_status
    214 mprobe (__ptr_t ptr)
    215 {
    216   return mcheck_used ? checkhdr (ptr) : MCHECK_DISABLED;
    217 }
    218