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