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