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