]>
Commit | Line | Data |
---|---|---|
6d52618b | 1 | /* Standard debugging hooks for `malloc'. |
159a2e1a | 2 | Copyright (C) 1990-1997, 1999, 2000, 2001 Free Software Foundation, Inc. |
6d52618b UD |
3 | Written May 1989 by Mike Haertel. |
4 | ||
5 | This library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Library General Public License as | |
7 | published by the Free Software Foundation; either version 2 of the | |
8 | License, or (at your option) any later version. | |
9 | ||
10 | This library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Library General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Library General Public | |
16 | License along with this library; see the file COPYING.LIB. If not, | |
17 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
18 | Boston, MA 02111-1307, USA. | |
19 | ||
20 | The author may be reached (Email) at the address mike@ai.mit.edu, | |
21 | or (US mail) as Mike Haertel c/o Free Software Foundation. */ | |
22 | ||
23 | #ifndef _MALLOC_INTERNAL | |
9756dfe1 UD |
24 | # define _MALLOC_INTERNAL |
25 | # include <malloc.h> | |
26 | # include <mcheck.h> | |
8e605e78 | 27 | # include <stdint.h> |
9756dfe1 | 28 | # include <stdio.h> |
4360eafd | 29 | # include <libintl.h> |
6d52618b UD |
30 | #endif |
31 | ||
32 | /* Old hook values. */ | |
a2b08ee5 UD |
33 | static void (*old_free_hook) __P ((__ptr_t ptr, __const __ptr_t)); |
34 | static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size, const __ptr_t)); | |
35 | static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size, | |
36 | __const __ptr_t)); | |
6d52618b UD |
37 | |
38 | /* Function to call when something awful happens. */ | |
39 | static void (*abortfunc) __P ((enum mcheck_status)); | |
40 | ||
41 | /* Arbitrary magical numbers. */ | |
42 | #define MAGICWORD 0xfedabeeb | |
43 | #define MAGICFREE 0xd8675309 | |
44 | #define MAGICBYTE ((char) 0xd7) | |
45 | #define MALLOCFLOOD ((char) 0x93) | |
46 | #define FREEFLOOD ((char) 0x95) | |
47 | ||
48 | struct hdr | |
49 | { | |
8e605e78 | 50 | __malloc_size_t size; /* Exact size requested by user. */ |
6d52618b | 51 | unsigned long int magic; /* Magic number to check header integrity. */ |
8e605e78 UD |
52 | struct hdr *prev; |
53 | struct hdr *next; | |
6d52618b UD |
54 | }; |
55 | ||
8e605e78 UD |
56 | /* This is the beginning of the list of all memory blocks allocated. |
57 | It is only constructed if the pedantic testing is requested. */ | |
58 | static struct hdr *root; | |
59 | ||
60 | /* Nonzero if pedentic checking of all blocks is requested. */ | |
61 | static int pedantic; | |
62 | ||
9756dfe1 UD |
63 | #if defined _LIBC || defined STDC_HEADERS || defined USG |
64 | # include <string.h> | |
65 | # define flood memset | |
6d52618b UD |
66 | #else |
67 | static void flood __P ((__ptr_t, int, __malloc_size_t)); | |
68 | static void | |
69 | flood (ptr, val, size) | |
70 | __ptr_t ptr; | |
71 | int val; | |
72 | __malloc_size_t size; | |
73 | { | |
74 | char *cp = ptr; | |
75 | while (size--) | |
76 | *cp++ = val; | |
77 | } | |
78 | #endif | |
79 | ||
80 | static enum mcheck_status checkhdr __P ((const struct hdr *)); | |
81 | static enum mcheck_status | |
82 | checkhdr (hdr) | |
83 | const struct hdr *hdr; | |
84 | { | |
85 | enum mcheck_status status; | |
8e605e78 | 86 | switch (hdr->magic ^ ((uintptr_t) hdr->prev + (uintptr_t) hdr->next)) |
6d52618b UD |
87 | { |
88 | default: | |
89 | status = MCHECK_HEAD; | |
90 | break; | |
91 | case MAGICFREE: | |
92 | status = MCHECK_FREE; | |
93 | break; | |
94 | case MAGICWORD: | |
95 | if (((char *) &hdr[1])[hdr->size] != MAGICBYTE) | |
96 | status = MCHECK_TAIL; | |
97 | else | |
98 | status = MCHECK_OK; | |
99 | break; | |
100 | } | |
101 | if (status != MCHECK_OK) | |
102 | (*abortfunc) (status); | |
103 | return status; | |
104 | } | |
105 | ||
77e1d15a UD |
106 | void |
107 | mcheck_check_all () | |
8e605e78 UD |
108 | { |
109 | /* Walk through all the active blocks and test whether they were tempered | |
110 | with. */ | |
111 | struct hdr *runp = root; | |
112 | ||
30e0f9c3 UD |
113 | /* Temporarily turn off the checks. */ |
114 | pedantic = 0; | |
115 | ||
8e605e78 UD |
116 | while (runp != NULL) |
117 | { | |
118 | (void) checkhdr (runp); | |
119 | ||
120 | runp = runp->next; | |
121 | } | |
30e0f9c3 UD |
122 | |
123 | /* Turn checks on again. */ | |
124 | pedantic = 1; | |
8e605e78 UD |
125 | } |
126 | ||
127 | static void unlink_blk __P ((struct hdr *ptr)); | |
128 | static void | |
129 | unlink_blk (ptr) | |
130 | struct hdr *ptr; | |
131 | { | |
132 | if (ptr->next != NULL) | |
133 | { | |
134 | ptr->next->prev = ptr->prev; | |
135 | ptr->next->magic = MAGICWORD ^ ((uintptr_t) ptr->next->prev | |
136 | + (uintptr_t) ptr->next->next); | |
137 | } | |
138 | if (ptr->prev != NULL) | |
139 | { | |
140 | ptr->prev->next = ptr->next; | |
141 | ptr->prev->magic = MAGICWORD ^ ((uintptr_t) ptr->prev->prev | |
142 | + (uintptr_t) ptr->prev->next); | |
143 | } | |
144 | else | |
145 | root = ptr->next; | |
146 | } | |
147 | ||
148 | static void link_blk __P ((struct hdr *ptr)); | |
149 | static void | |
150 | link_blk (hdr) | |
151 | struct hdr *hdr; | |
152 | { | |
153 | hdr->prev = NULL; | |
154 | hdr->next = root; | |
155 | root = hdr; | |
156 | hdr->magic = MAGICWORD ^ (uintptr_t) hdr->next; | |
157 | ||
158 | /* And the next block. */ | |
159 | if (hdr->next != NULL) | |
160 | { | |
161 | hdr->next->prev = hdr; | |
162 | hdr->next->magic = MAGICWORD ^ ((uintptr_t) hdr | |
163 | + (uintptr_t) hdr->next->next); | |
164 | } | |
165 | } | |
166 | ||
a2b08ee5 | 167 | static void freehook __P ((__ptr_t, const __ptr_t)); |
6d52618b | 168 | static void |
a2b08ee5 | 169 | freehook (ptr, caller) |
6d52618b | 170 | __ptr_t ptr; |
a2b08ee5 | 171 | const __ptr_t caller; |
6d52618b | 172 | { |
8e605e78 | 173 | if (pedantic) |
77e1d15a | 174 | mcheck_check_all (); |
6d52618b UD |
175 | if (ptr) |
176 | { | |
177 | struct hdr *hdr = ((struct hdr *) ptr) - 1; | |
178 | checkhdr (hdr); | |
179 | hdr->magic = MAGICFREE; | |
8e605e78 UD |
180 | unlink_blk (hdr); |
181 | hdr->prev = hdr->next = NULL; | |
6d52618b UD |
182 | flood (ptr, FREEFLOOD, hdr->size); |
183 | ptr = (__ptr_t) hdr; | |
184 | } | |
185 | __free_hook = old_free_hook; | |
a2b08ee5 UD |
186 | if (old_free_hook != NULL) |
187 | (*old_free_hook) (ptr, caller); | |
188 | else | |
189 | free (ptr); | |
6d52618b UD |
190 | __free_hook = freehook; |
191 | } | |
192 | ||
a2b08ee5 | 193 | static __ptr_t mallochook __P ((__malloc_size_t, const __ptr_t)); |
6d52618b | 194 | static __ptr_t |
a2b08ee5 | 195 | mallochook (size, caller) |
6d52618b | 196 | __malloc_size_t size; |
a2b08ee5 | 197 | const __ptr_t caller; |
6d52618b UD |
198 | { |
199 | struct hdr *hdr; | |
200 | ||
8e605e78 | 201 | if (pedantic) |
77e1d15a | 202 | mcheck_check_all (); |
8e605e78 | 203 | |
6d52618b | 204 | __malloc_hook = old_malloc_hook; |
a2b08ee5 UD |
205 | if (old_malloc_hook != NULL) |
206 | hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1, | |
207 | caller); | |
208 | else | |
209 | hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1); | |
6d52618b UD |
210 | __malloc_hook = mallochook; |
211 | if (hdr == NULL) | |
212 | return NULL; | |
213 | ||
214 | hdr->size = size; | |
8e605e78 | 215 | link_blk (hdr); |
6d52618b UD |
216 | ((char *) &hdr[1])[size] = MAGICBYTE; |
217 | flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size); | |
218 | return (__ptr_t) (hdr + 1); | |
219 | } | |
220 | ||
a2b08ee5 | 221 | static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t)); |
6d52618b | 222 | static __ptr_t |
a2b08ee5 | 223 | reallochook (ptr, size, caller) |
6d52618b UD |
224 | __ptr_t ptr; |
225 | __malloc_size_t size; | |
a2b08ee5 | 226 | const __ptr_t caller; |
6d52618b UD |
227 | { |
228 | struct hdr *hdr; | |
229 | __malloc_size_t osize; | |
230 | ||
8e605e78 | 231 | if (pedantic) |
77e1d15a | 232 | mcheck_check_all (); |
8e605e78 | 233 | |
6d52618b UD |
234 | if (ptr) |
235 | { | |
236 | hdr = ((struct hdr *) ptr) - 1; | |
237 | osize = hdr->size; | |
238 | ||
239 | checkhdr (hdr); | |
8e605e78 | 240 | unlink_blk (hdr); |
6d52618b UD |
241 | if (size < osize) |
242 | flood ((char *) ptr + size, FREEFLOOD, osize - size); | |
243 | } | |
244 | else | |
245 | { | |
246 | osize = 0; | |
247 | hdr = NULL; | |
248 | } | |
249 | __free_hook = old_free_hook; | |
250 | __malloc_hook = old_malloc_hook; | |
251 | __realloc_hook = old_realloc_hook; | |
a2b08ee5 UD |
252 | if (old_realloc_hook != NULL) |
253 | hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr, | |
254 | sizeof (struct hdr) + size + 1, | |
255 | caller); | |
256 | else | |
257 | hdr = (struct hdr *) realloc ((__ptr_t) hdr, | |
258 | sizeof (struct hdr) + size + 1); | |
6d52618b UD |
259 | __free_hook = freehook; |
260 | __malloc_hook = mallochook; | |
261 | __realloc_hook = reallochook; | |
262 | if (hdr == NULL) | |
263 | return NULL; | |
264 | ||
265 | hdr->size = size; | |
8e605e78 | 266 | link_blk (hdr); |
6d52618b UD |
267 | ((char *) &hdr[1])[size] = MAGICBYTE; |
268 | if (size > osize) | |
269 | flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize); | |
270 | return (__ptr_t) (hdr + 1); | |
271 | } | |
272 | ||
159a2e1a AJ |
273 | static void mabort __P ((enum mcheck_status status)) |
274 | __attribute__ ((noreturn)); | |
6d52618b UD |
275 | static void |
276 | mabort (status) | |
277 | enum mcheck_status status; | |
278 | { | |
279 | const char *msg; | |
280 | switch (status) | |
281 | { | |
282 | case MCHECK_OK: | |
9756dfe1 | 283 | msg = _("memory is consistent, library is buggy\n"); |
6d52618b UD |
284 | break; |
285 | case MCHECK_HEAD: | |
9756dfe1 | 286 | msg = _("memory clobbered before allocated block\n"); |
6d52618b UD |
287 | break; |
288 | case MCHECK_TAIL: | |
9756dfe1 | 289 | msg = _("memory clobbered past end of allocated block\n"); |
6d52618b UD |
290 | break; |
291 | case MCHECK_FREE: | |
9756dfe1 | 292 | msg = _("block freed twice\n"); |
6d52618b UD |
293 | break; |
294 | default: | |
9756dfe1 | 295 | msg = _("bogus mcheck_status, library is buggy\n"); |
6d52618b UD |
296 | break; |
297 | } | |
298 | #ifdef _LIBC | |
299 | __libc_fatal (msg); | |
300 | #else | |
9756dfe1 | 301 | fprintf (stderr, "mcheck: %s", msg); |
6d52618b UD |
302 | fflush (stderr); |
303 | abort (); | |
304 | #endif | |
305 | } | |
306 | ||
c4563d2d | 307 | static int mcheck_used; |
6d52618b UD |
308 | |
309 | int | |
310 | mcheck (func) | |
311 | void (*func) __P ((enum mcheck_status)); | |
312 | { | |
313 | abortfunc = (func != NULL) ? func : &mabort; | |
314 | ||
315 | /* These hooks may not be safely inserted if malloc is already in use. */ | |
9756dfe1 | 316 | if (__malloc_initialized <= 0 && !mcheck_used) |
6d52618b UD |
317 | { |
318 | old_free_hook = __free_hook; | |
319 | __free_hook = freehook; | |
320 | old_malloc_hook = __malloc_hook; | |
321 | __malloc_hook = mallochook; | |
322 | old_realloc_hook = __realloc_hook; | |
323 | __realloc_hook = reallochook; | |
324 | mcheck_used = 1; | |
325 | } | |
326 | ||
327 | return mcheck_used ? 0 : -1; | |
328 | } | |
329 | ||
8e605e78 UD |
330 | int |
331 | mcheck_pedantic (func) | |
332 | void (*func) __P ((enum mcheck_status)); | |
333 | { | |
77e1d15a UD |
334 | int res = mcheck (func); |
335 | if (res == 0) | |
336 | pedantic = 1; | |
337 | return res; | |
8e605e78 UD |
338 | } |
339 | ||
6d52618b UD |
340 | enum mcheck_status |
341 | mprobe (__ptr_t ptr) | |
342 | { | |
997a4165 | 343 | return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED; |
6d52618b | 344 | } |