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
flood(ptr,val,size)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
checkhdr(hdr)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
freehook(ptr)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
mallochook(size)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
reallochook(ptr,size)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
mabort(status)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
mprobe(__ptr_t ptr)215 mprobe (__ptr_t ptr)
216 {
217 return mcheck_used ? checkhdr (ptr) : MCHECK_DISABLED;
218 }
219