]>
Commit | Line | Data |
---|---|---|
6d52618b | 1 | /* Standard debugging hooks for `malloc'. |
c4563d2d | 2 | Copyright (C) 1990,91,92,93,94,95,96,97,99 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> | |
27 | # include <stdio.h> | |
4360eafd | 28 | # include <libintl.h> |
6d52618b UD |
29 | #endif |
30 | ||
31 | /* Old hook values. */ | |
a2b08ee5 UD |
32 | static void (*old_free_hook) __P ((__ptr_t ptr, __const __ptr_t)); |
33 | static __ptr_t (*old_malloc_hook) __P ((__malloc_size_t size, const __ptr_t)); | |
34 | static __ptr_t (*old_realloc_hook) __P ((__ptr_t ptr, __malloc_size_t size, | |
35 | __const __ptr_t)); | |
6d52618b UD |
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 | ||
9756dfe1 UD |
53 | #if defined _LIBC || defined STDC_HEADERS || defined USG |
54 | # include <string.h> | |
55 | # define flood memset | |
6d52618b UD |
56 | #else |
57 | static void flood __P ((__ptr_t, int, __malloc_size_t)); | |
58 | static void | |
59 | flood (ptr, val, size) | |
60 | __ptr_t ptr; | |
61 | int val; | |
62 | __malloc_size_t size; | |
63 | { | |
64 | char *cp = ptr; | |
65 | while (size--) | |
66 | *cp++ = val; | |
67 | } | |
68 | #endif | |
69 | ||
70 | static enum mcheck_status checkhdr __P ((const struct hdr *)); | |
71 | static enum mcheck_status | |
72 | checkhdr (hdr) | |
73 | const struct hdr *hdr; | |
74 | { | |
75 | enum mcheck_status status; | |
76 | switch (hdr->magic) | |
77 | { | |
78 | default: | |
79 | status = MCHECK_HEAD; | |
80 | break; | |
81 | case MAGICFREE: | |
82 | status = MCHECK_FREE; | |
83 | break; | |
84 | case MAGICWORD: | |
85 | if (((char *) &hdr[1])[hdr->size] != MAGICBYTE) | |
86 | status = MCHECK_TAIL; | |
87 | else | |
88 | status = MCHECK_OK; | |
89 | break; | |
90 | } | |
91 | if (status != MCHECK_OK) | |
92 | (*abortfunc) (status); | |
93 | return status; | |
94 | } | |
95 | ||
a2b08ee5 | 96 | static void freehook __P ((__ptr_t, const __ptr_t)); |
6d52618b | 97 | static void |
a2b08ee5 | 98 | freehook (ptr, caller) |
6d52618b | 99 | __ptr_t ptr; |
a2b08ee5 | 100 | const __ptr_t caller; |
6d52618b UD |
101 | { |
102 | if (ptr) | |
103 | { | |
104 | struct hdr *hdr = ((struct hdr *) ptr) - 1; | |
105 | checkhdr (hdr); | |
106 | hdr->magic = MAGICFREE; | |
107 | flood (ptr, FREEFLOOD, hdr->size); | |
108 | ptr = (__ptr_t) hdr; | |
109 | } | |
110 | __free_hook = old_free_hook; | |
a2b08ee5 UD |
111 | if (old_free_hook != NULL) |
112 | (*old_free_hook) (ptr, caller); | |
113 | else | |
114 | free (ptr); | |
6d52618b UD |
115 | __free_hook = freehook; |
116 | } | |
117 | ||
a2b08ee5 | 118 | static __ptr_t mallochook __P ((__malloc_size_t, const __ptr_t)); |
6d52618b | 119 | static __ptr_t |
a2b08ee5 | 120 | mallochook (size, caller) |
6d52618b | 121 | __malloc_size_t size; |
a2b08ee5 | 122 | const __ptr_t caller; |
6d52618b UD |
123 | { |
124 | struct hdr *hdr; | |
125 | ||
126 | __malloc_hook = old_malloc_hook; | |
a2b08ee5 UD |
127 | if (old_malloc_hook != NULL) |
128 | hdr = (struct hdr *) (*old_malloc_hook) (sizeof (struct hdr) + size + 1, | |
129 | caller); | |
130 | else | |
131 | hdr = (struct hdr *) malloc (sizeof (struct hdr) + size + 1); | |
6d52618b UD |
132 | __malloc_hook = mallochook; |
133 | if (hdr == NULL) | |
134 | return NULL; | |
135 | ||
136 | hdr->size = size; | |
137 | hdr->magic = MAGICWORD; | |
138 | ((char *) &hdr[1])[size] = MAGICBYTE; | |
139 | flood ((__ptr_t) (hdr + 1), MALLOCFLOOD, size); | |
140 | return (__ptr_t) (hdr + 1); | |
141 | } | |
142 | ||
a2b08ee5 | 143 | static __ptr_t reallochook __P ((__ptr_t, __malloc_size_t, const __ptr_t)); |
6d52618b | 144 | static __ptr_t |
a2b08ee5 | 145 | reallochook (ptr, size, caller) |
6d52618b UD |
146 | __ptr_t ptr; |
147 | __malloc_size_t size; | |
a2b08ee5 | 148 | const __ptr_t caller; |
6d52618b UD |
149 | { |
150 | struct hdr *hdr; | |
151 | __malloc_size_t osize; | |
152 | ||
153 | if (ptr) | |
154 | { | |
155 | hdr = ((struct hdr *) ptr) - 1; | |
156 | osize = hdr->size; | |
157 | ||
158 | checkhdr (hdr); | |
159 | if (size < osize) | |
160 | flood ((char *) ptr + size, FREEFLOOD, osize - size); | |
161 | } | |
162 | else | |
163 | { | |
164 | osize = 0; | |
165 | hdr = NULL; | |
166 | } | |
167 | __free_hook = old_free_hook; | |
168 | __malloc_hook = old_malloc_hook; | |
169 | __realloc_hook = old_realloc_hook; | |
a2b08ee5 UD |
170 | if (old_realloc_hook != NULL) |
171 | hdr = (struct hdr *) (*old_realloc_hook) ((__ptr_t) hdr, | |
172 | sizeof (struct hdr) + size + 1, | |
173 | caller); | |
174 | else | |
175 | hdr = (struct hdr *) realloc ((__ptr_t) hdr, | |
176 | sizeof (struct hdr) + size + 1); | |
6d52618b UD |
177 | __free_hook = freehook; |
178 | __malloc_hook = mallochook; | |
179 | __realloc_hook = reallochook; | |
180 | if (hdr == NULL) | |
181 | return NULL; | |
182 | ||
183 | hdr->size = size; | |
184 | hdr->magic = MAGICWORD; | |
185 | ((char *) &hdr[1])[size] = MAGICBYTE; | |
186 | if (size > osize) | |
187 | flood ((char *) (hdr + 1) + osize, MALLOCFLOOD, size - osize); | |
188 | return (__ptr_t) (hdr + 1); | |
189 | } | |
190 | ||
191 | static void mabort __P ((enum mcheck_status status)); | |
192 | static void | |
193 | mabort (status) | |
194 | enum mcheck_status status; | |
195 | { | |
196 | const char *msg; | |
197 | switch (status) | |
198 | { | |
199 | case MCHECK_OK: | |
9756dfe1 | 200 | msg = _("memory is consistent, library is buggy\n"); |
6d52618b UD |
201 | break; |
202 | case MCHECK_HEAD: | |
9756dfe1 | 203 | msg = _("memory clobbered before allocated block\n"); |
6d52618b UD |
204 | break; |
205 | case MCHECK_TAIL: | |
9756dfe1 | 206 | msg = _("memory clobbered past end of allocated block\n"); |
6d52618b UD |
207 | break; |
208 | case MCHECK_FREE: | |
9756dfe1 | 209 | msg = _("block freed twice\n"); |
6d52618b UD |
210 | break; |
211 | default: | |
9756dfe1 | 212 | msg = _("bogus mcheck_status, library is buggy\n"); |
6d52618b UD |
213 | break; |
214 | } | |
215 | #ifdef _LIBC | |
216 | __libc_fatal (msg); | |
217 | #else | |
9756dfe1 | 218 | fprintf (stderr, "mcheck: %s", msg); |
6d52618b UD |
219 | fflush (stderr); |
220 | abort (); | |
221 | #endif | |
222 | } | |
223 | ||
c4563d2d | 224 | static int mcheck_used; |
6d52618b UD |
225 | |
226 | int | |
227 | mcheck (func) | |
228 | void (*func) __P ((enum mcheck_status)); | |
229 | { | |
230 | abortfunc = (func != NULL) ? func : &mabort; | |
231 | ||
232 | /* These hooks may not be safely inserted if malloc is already in use. */ | |
9756dfe1 | 233 | if (__malloc_initialized <= 0 && !mcheck_used) |
6d52618b UD |
234 | { |
235 | old_free_hook = __free_hook; | |
236 | __free_hook = freehook; | |
237 | old_malloc_hook = __malloc_hook; | |
238 | __malloc_hook = mallochook; | |
239 | old_realloc_hook = __realloc_hook; | |
240 | __realloc_hook = reallochook; | |
241 | mcheck_used = 1; | |
242 | } | |
243 | ||
244 | return mcheck_used ? 0 : -1; | |
245 | } | |
246 | ||
247 | enum mcheck_status | |
248 | mprobe (__ptr_t ptr) | |
249 | { | |
997a4165 | 250 | return mcheck_used ? checkhdr (((struct hdr *) ptr) - 1) : MCHECK_DISABLED; |
6d52618b | 251 | } |