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