Home | History | Annotate | Line # | Download | only in dist
      1  1.2  christos /*	$NetBSD: mcheck.c,v 1.2 2016/01/13 21:56:38 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.2  christos #include <stdlib.h>
     29  1.1  christos #include <stdio.h>
     30  1.1  christos #endif
     31  1.1  christos 
     32  1.1  christos /* Old hook values.  */
     33  1.1  christos static void (*old_free_hook) __P ((__ptr_t ptr));
     34  1.1  christos static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size));
     35  1.1  christos static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size));
     36  1.1  christos 
     37  1.1  christos /* Function to call when something awful happens.  */
     38  1.1  christos static void (*abortfunc) __P ((enum mcheck_status));
     39  1.1  christos 
     40  1.1  christos /* Arbitrary magical numbers.  */
     41  1.1  christos #define MAGICWORD	0xfedabeeb
     42  1.1  christos #define MAGICFREE	0xd8675309
     43  1.1  christos #define MAGICBYTE	((char) 0xd7)
     44  1.1  christos #define MALLOCFLOOD	((char) 0x93)
     45  1.1  christos #define FREEFLOOD	((char) 0x95)
     46  1.1  christos 
     47  1.1  christos struct hdr
     48  1.1  christos   {
     49  1.1  christos     __malloc_size_t size;		/* Exact size requested by user.  */
     50  1.1  christos     unsigned long int magic;	/* Magic number to check header integrity.  */
     51  1.1  christos   };
     52  1.1  christos 
     53  1.1  christos #if	defined(_LIBC) || defined(STDC_HEADERS) || defined(USG)
     54  1.1  christos #define flood memset
     55  1.1  christos #else
     56  1.1  christos static void flood __P ((__ptr_t, int, __malloc_size_t));
     57  1.1  christos static void
     58  1.1  christos flood (ptr, val, size)
     59  1.1  christos      __ptr_t ptr;
     60  1.1  christos      int val;
     61  1.1  christos      __malloc_size_t size;
     62  1.1  christos {
     63  1.1  christos   char *cp = ptr;
     64  1.1  christos   while (size--)
     65  1.1  christos     *cp++ = val;
     66  1.1  christos }
     67  1.1  christos #endif
     68  1.1  christos 
     69  1.1  christos static enum mcheck_status checkhdr __P ((const struct hdr *));
     70  1.1  christos static enum mcheck_status
     71  1.1  christos checkhdr (hdr)
     72  1.1  christos      const struct hdr *hdr;
     73  1.1  christos {
     74  1.1  christos   enum mcheck_status status;
     75  1.1  christos   switch (hdr->magic)
     76  1.1  christos     {
     77  1.1  christos     default:
     78  1.1  christos       status = MCHECK_HEAD;
     79  1.1  christos       break;
     80  1.1  christos     case MAGICFREE:
     81  1.1  christos       status = MCHECK_FREE;
     82  1.1  christos       break;
     83  1.1  christos     case MAGICWORD:
     84  1.1  christos       if (((char *) &hdr[1])[hdr->size] != MAGICBYTE)
     85  1.1  christos 	status = MCHECK_TAIL;
     86  1.1  christos       else
     87  1.1  christos 	status = MCHECK_OK;
     88  1.1  christos       break;
     89  1.1  christos     }
     90  1.1  christos   if (status != MCHECK_OK)
     91  1.1  christos     (*abortfunc) (status);
     92  1.1  christos   return status;
     93  1.1  christos }
     94  1.1  christos 
     95  1.1  christos static void freehook __P ((__ptr_t));
     96  1.1  christos static void
     97  1.1  christos freehook (ptr)
     98  1.1  christos      __ptr_t ptr;
     99  1.1  christos {
    100  1.1  christos   struct hdr *hdr = ((struct hdr *) ptr) - 1;
    101  1.1  christos   checkhdr (hdr);
    102  1.1  christos   hdr->magic = MAGICFREE;
    103  1.1  christos   flood (ptr, FREEFLOOD, hdr->size);
    104  1.1  christos   __free_hook = old_free_hook;
    105  1.1  christos   free (hdr);
    106  1.1  christos   __free_hook = freehook;
    107  1.1  christos }
    108  1.1  christos 
    109  1.1  christos static __ptr_t mallochook __P ((__malloc_size_t));
    110  1.1  christos static __ptr_t
    111  1.1  christos mallochook (size)
    112  1.1  christos      __malloc_size_t size;
    113  1.1  christos {
    114  1.1  christos   struct hdr *hdr;
    115  1.1  christos 
    116  1.1  christos   __malloc_hook = old_malloc_hook;
    117  1.1  christos   hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1);
    118  1.1  christos   __malloc_hook = mallochook;
    119  1.1  christos   if (hdr == NULL)
    120  1.1  christos     return NULL;
    121  1.1  christos 
    122  1.1  christos   hdr->size = size;
    123  1.1  christos   hdr->magic = MAGICWORD;
    124  1.1  christos   ((char *) &hdr[1])[size] = MAGICBYTE;
    125  1.1  christos   flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size);
    126  1.1  christos   return (__ptr_t) (hdr + 1);
    127  1.1  christos }
    128  1.1  christos 
    129  1.1  christos static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t));
    130  1.1  christos static __ptr_t
    131  1.1  christos reallochook (ptr, size)
    132  1.1  christos      __ptr_t ptr;
    133  1.1  christos      __malloc_size_t size;
    134  1.1  christos {
    135  1.1  christos   struct hdr *hdr = ((struct hdr *) ptr) - 1;
    136  1.1  christos   __malloc_size_t osize = hdr->size;
    137  1.1  christos 
    138  1.1  christos   checkhdr (hdr);
    139  1.1  christos   if (size < osize)
    140  1.1  christos     flood ((char *) ptr + size, FREEFLOOD, osize - size);
    141  1.1  christos   __free_hook = old_free_hook;
    142  1.1  christos   __malloc_hook = old_malloc_hook;
    143  1.1  christos   __realloc_hook = old_realloc_hook;
    144  1.1  christos   hdr = (struct hdr *) realloc ((__ptr_t) hdr, sizeof (struct hdr) + size + 1);
    145  1.1  christos   __free_hook = freehook;
    146  1.1  christos   __malloc_hook = mallochook;
    147  1.1  christos   __realloc_hook = reallochook;
    148  1.1  christos   if (hdr == NULL)
    149  1.1  christos     return NULL;
    150  1.1  christos 
    151  1.1  christos   hdr->size = size;
    152  1.1  christos   hdr->magic = MAGICWORD;
    153  1.1  christos   ((char *) &hdr[1])[size] = MAGICBYTE;
    154  1.1  christos   if (size > osize)
    155  1.1  christos     flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize);
    156  1.1  christos   return (__ptr_t) (hdr + 1);
    157  1.1  christos }
    158  1.1  christos 
    159  1.1  christos static void
    160  1.1  christos mabort (status)
    161  1.1  christos      enum mcheck_status status;
    162  1.1  christos {
    163  1.1  christos   const char *msg;
    164  1.1  christos   switch (status)
    165  1.1  christos     {
    166  1.1  christos     case MCHECK_OK:
    167  1.1  christos       msg = "memory is consistent, library is buggy";
    168  1.1  christos       break;
    169  1.1  christos     case MCHECK_HEAD:
    170  1.1  christos       msg = "memory clobbered before allocated block";
    171  1.1  christos       break;
    172  1.1  christos     case MCHECK_TAIL:
    173  1.1  christos       msg = "memory clobbered past end of allocated block";
    174  1.1  christos       break;
    175  1.1  christos     case MCHECK_FREE:
    176  1.1  christos       msg = "block freed twice";
    177  1.1  christos       break;
    178  1.1  christos     default:
    179  1.1  christos       msg = "bogus mcheck_status, library is buggy";
    180  1.1  christos       break;
    181  1.1  christos     }
    182  1.1  christos #ifdef __GNU_LIBRARY__
    183  1.1  christos   __libc_fatal (msg);
    184  1.1  christos #else
    185  1.1  christos   fprintf (stderr, "mcheck: %s\n", msg);
    186  1.1  christos   fflush (stderr);
    187  1.1  christos   abort ();
    188  1.1  christos #endif
    189  1.1  christos }
    190  1.1  christos 
    191  1.1  christos static int mcheck_used = 0;
    192  1.1  christos 
    193  1.1  christos int
    194  1.1  christos mcheck (func)
    195  1.1  christos      void (*func) __P ((enum mcheck_status));
    196  1.1  christos {
    197  1.1  christos   abortfunc = (func != NULL) ? func : &mabort;
    198  1.1  christos 
    199  1.1  christos   /* These hooks may not be safely inserted if malloc is already in use.  */
    200  1.1  christos   if (!__malloc_initialized && !mcheck_used)
    201  1.1  christos     {
    202  1.1  christos       old_free_hook = __free_hook;
    203  1.1  christos       __free_hook = freehook;
    204  1.1  christos       old_malloc_hook = __malloc_hook;
    205  1.1  christos       __malloc_hook = mallochook;
    206  1.1  christos       old_realloc_hook = __realloc_hook;
    207  1.1  christos       __realloc_hook = reallochook;
    208  1.1  christos       mcheck_used = 1;
    209  1.1  christos     }
    210  1.1  christos 
    211  1.1  christos   return mcheck_used ? 0 : -1;
    212  1.1  christos }
    213  1.1  christos 
    214  1.1  christos enum mcheck_status
    215  1.1  christos mprobe (__ptr_t ptr)
    216  1.1  christos {
    217  1.1  christos   return mcheck_used ? checkhdr (ptr) : MCHECK_DISABLED;
    218  1.1  christos }
    219