]>
Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* Standard debugging hooks for `mmalloc'. |
2 | Copyright 1990, 1991, 1992 Free Software Foundation | |
3 | ||
4 | Written May 1989 by Mike Haertel. | |
5 | Heavily modified Mar 1992 by Fred Fish ([email protected]) | |
6 | ||
7 | The GNU C 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 | The GNU C 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 the GNU C Library; see the file COPYING.LIB. If | |
19 | not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, USA. | |
21 | ||
22 | The author may be reached (Email) at the address [email protected], | |
23 | or (US mail) as Mike Haertel c/o Free Software Foundation. */ | |
24 | ||
25 | #include "mmprivate.h" | |
26 | ||
27 | /* Default function to call when something awful happens. The application | |
28 | can specify an alternate function to be called instead (and probably will | |
29 | want to). */ | |
30 | ||
31 | extern void abort PARAMS ((void)); | |
32 | ||
33 | /* Arbitrary magical numbers. */ | |
34 | ||
35 | #define MAGICWORD (unsigned int) 0xfedabeeb /* Active chunk */ | |
36 | #define MAGICWORDFREE (unsigned int) 0xdeadbeef /* Inactive chunk */ | |
37 | #define MAGICBYTE ((char) 0xd7) | |
38 | ||
39 | /* Each memory allocation is bounded by a header structure and a trailer | |
40 | byte. I.E. | |
41 | ||
42 | <size><magicword><user's allocation><magicbyte> | |
43 | ||
44 | The pointer returned to the user points to the first byte in the | |
45 | user's allocation area. The magic word can be tested to detect | |
46 | buffer underruns and the magic byte can be tested to detect overruns. */ | |
47 | ||
48 | struct hdr | |
49 | { | |
50 | size_t size; /* Exact size requested by user. */ | |
51 | unsigned long int magic; /* Magic number to check header integrity. */ | |
52 | }; | |
53 | ||
54 | static void checkhdr PARAMS ((struct mdesc *, CONST struct hdr *)); | |
55 | static void mfree_check PARAMS ((PTR, PTR)); | |
56 | static PTR mmalloc_check PARAMS ((PTR, size_t)); | |
57 | static PTR mrealloc_check PARAMS ((PTR, PTR, size_t)); | |
58 | ||
59 | /* Check the magicword and magicbyte, and if either is corrupted then | |
60 | call the emergency abort function specified for the heap in use. */ | |
61 | ||
62 | static void | |
63 | checkhdr (mdp, hdr) | |
64 | struct mdesc *mdp; | |
65 | CONST struct hdr *hdr; | |
66 | { | |
67 | if (hdr -> magic != MAGICWORD || | |
68 | ((char *) &hdr[1])[hdr -> size] != MAGICBYTE) | |
69 | { | |
70 | (*mdp -> abortfunc)(); | |
71 | } | |
72 | } | |
73 | ||
74 | static void | |
75 | mfree_check (md, ptr) | |
76 | PTR md; | |
77 | PTR ptr; | |
78 | { | |
79 | struct hdr *hdr = ((struct hdr *) ptr) - 1; | |
80 | struct mdesc *mdp; | |
81 | ||
82 | mdp = MD_TO_MDP (md); | |
83 | checkhdr (mdp, hdr); | |
84 | hdr -> magic = MAGICWORDFREE; | |
85 | mdp -> mfree_hook = NULL; | |
86 | mfree (md, (PTR)hdr); | |
87 | mdp -> mfree_hook = mfree_check; | |
88 | } | |
89 | ||
90 | static PTR | |
91 | mmalloc_check (md, size) | |
92 | PTR md; | |
93 | size_t size; | |
94 | { | |
95 | struct hdr *hdr; | |
96 | struct mdesc *mdp; | |
97 | size_t nbytes; | |
98 | ||
99 | mdp = MD_TO_MDP (md); | |
100 | mdp -> mmalloc_hook = NULL; | |
101 | nbytes = sizeof (struct hdr) + size + 1; | |
102 | hdr = (struct hdr *) mmalloc (md, nbytes); | |
103 | mdp -> mmalloc_hook = mmalloc_check; | |
104 | if (hdr != NULL) | |
105 | { | |
106 | hdr -> size = size; | |
107 | hdr -> magic = MAGICWORD; | |
108 | hdr++; | |
109 | *((char *) hdr + size) = MAGICBYTE; | |
110 | } | |
111 | return ((PTR) hdr); | |
112 | } | |
113 | ||
114 | static PTR | |
115 | mrealloc_check (md, ptr, size) | |
116 | PTR md; | |
117 | PTR ptr; | |
118 | size_t size; | |
119 | { | |
120 | struct hdr *hdr = ((struct hdr *) ptr) - 1; | |
121 | struct mdesc *mdp; | |
122 | size_t nbytes; | |
123 | ||
124 | mdp = MD_TO_MDP (md); | |
125 | checkhdr (mdp, hdr); | |
126 | mdp -> mfree_hook = NULL; | |
127 | mdp -> mmalloc_hook = NULL; | |
128 | mdp -> mrealloc_hook = NULL; | |
129 | nbytes = sizeof (struct hdr) + size + 1; | |
130 | hdr = (struct hdr *) mrealloc (md, (PTR) hdr, nbytes); | |
131 | mdp -> mfree_hook = mfree_check; | |
132 | mdp -> mmalloc_hook = mmalloc_check; | |
133 | mdp -> mrealloc_hook = mrealloc_check; | |
134 | if (hdr != NULL) | |
135 | { | |
136 | hdr -> size = size; | |
137 | hdr++; | |
138 | *((char *) hdr + size) = MAGICBYTE; | |
139 | } | |
140 | return ((PTR) hdr); | |
141 | } | |
142 | ||
143 | /* Turn on default checking for mmalloc/mrealloc/mfree, for the heap specified | |
144 | by MD. If FUNC is non-NULL, it is a pointer to the function to call | |
145 | to abort whenever memory corruption is detected. By default, this is the | |
146 | standard library function abort(). | |
147 | ||
148 | Note that we disallow installation of initial checking hooks if mmalloc | |
149 | has been called at any time for this particular heap, since if any region | |
150 | that is allocated prior to installation of the hooks is subsequently | |
151 | reallocated or freed after installation of the hooks, it is guaranteed | |
152 | to trigger a memory corruption error. We do this by checking the state | |
153 | of the MMALLOC_INITIALIZED flag. If the FORCE argument is non-zero, this | |
154 | checking is disabled and it is allowed to install the checking hooks at any | |
155 | time. This is useful on systems where the C runtime makes one or more | |
156 | malloc calls before the user code had a chance to call mmcheck or mmcheckf, | |
157 | but never calls free with these values. Thus if we are certain that only | |
158 | values obtained from mallocs after an mmcheck/mmcheckf will ever be passed | |
159 | to free(), we can go ahead and force installation of the useful checking | |
160 | hooks. | |
161 | ||
162 | However, we can call this function at any time after the initial call, | |
163 | to update the function pointers to the checking routines and to the | |
164 | user defined corruption handler routine, as long as these function pointers | |
165 | have been previously extablished by the initial call. Note that we | |
166 | do this automatically when remapping a previously used heap, to ensure | |
167 | that the hooks get updated to the correct values, although the corruption | |
168 | handler pointer gets set back to the default. The application can then | |
169 | call mmcheck to use a different corruption handler if desired. | |
170 | ||
171 | Returns non-zero if checking is successfully enabled, zero otherwise. */ | |
172 | ||
173 | int | |
174 | mmcheckf (md, func, force) | |
175 | PTR md; | |
176 | void (*func) PARAMS ((void)); | |
177 | int force; | |
178 | { | |
179 | struct mdesc *mdp; | |
180 | int rtnval; | |
181 | ||
182 | mdp = MD_TO_MDP (md); | |
183 | ||
184 | /* We can safely set or update the abort function at any time, regardless | |
185 | of whether or not we successfully do anything else. */ | |
186 | ||
187 | mdp -> abortfunc = (func != NULL ? func : abort); | |
188 | ||
189 | /* If we haven't yet called mmalloc the first time for this heap, or if we | |
190 | have hooks that were previously installed, then allow the hooks to be | |
191 | initialized or updated. */ | |
192 | ||
193 | if (force || | |
194 | !(mdp -> flags & MMALLOC_INITIALIZED) || | |
195 | (mdp -> mfree_hook != NULL)) | |
196 | { | |
197 | mdp -> mfree_hook = mfree_check; | |
198 | mdp -> mmalloc_hook = mmalloc_check; | |
199 | mdp -> mrealloc_hook = mrealloc_check; | |
200 | mdp -> flags |= MMALLOC_MMCHECK_USED; | |
201 | rtnval = 1; | |
202 | } | |
203 | else | |
204 | { | |
205 | rtnval = 0; | |
206 | } | |
207 | ||
208 | return (rtnval); | |
209 | } | |
210 | ||
211 | /* This routine is for backwards compatibility only, in case there are | |
212 | still callers to the original mmcheck function. */ | |
213 | ||
214 | int | |
215 | mmcheck (md, func) | |
216 | PTR md; | |
217 | void (*func) PARAMS ((void)); | |
218 | { | |
219 | int rtnval; | |
220 | ||
221 | rtnval = mmcheckf (md, func, 0); | |
222 | return (rtnval); | |
223 | } |