]>
Commit | Line | Data |
---|---|---|
01fb5bca FF |
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., 675 Mass Ave, | |
20 | Cambridge, MA 02139, 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 "mmalloc.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 0xfedabeeb /* Magic word for active chunk */ | |
36 | #define MAGICWORDFREE 0xdeadbeef /* Magic word for 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 | /* Check the magicword and magicbyte, and if either is corrupted then | |
55 | call the emergency abort function specified for the heap in use. */ | |
56 | ||
57 | static void | |
58 | checkhdr (mdp, hdr) | |
59 | struct mdesc *mdp; | |
60 | CONST struct hdr *hdr; | |
61 | { | |
62 | if (hdr -> magic != MAGICWORD || | |
63 | ((char *) &hdr[1])[hdr -> size] != MAGICBYTE) | |
64 | { | |
65 | (*mdp -> abortfunc)(); | |
66 | } | |
67 | } | |
68 | ||
69 | static void | |
70 | mfree_check (md, ptr) | |
71 | PTR md; | |
72 | PTR ptr; | |
73 | { | |
74 | struct hdr *hdr = ((struct hdr *) ptr) - 1; | |
75 | struct mdesc *mdp; | |
76 | ||
77 | mdp = MD_TO_MDP (md); | |
78 | checkhdr (mdp, hdr); | |
79 | hdr -> magic = MAGICWORDFREE; | |
80 | mdp -> mfree_hook = NULL; | |
81 | mfree (md, hdr); | |
82 | mdp -> mfree_hook = mfree_check; | |
83 | } | |
84 | ||
85 | static PTR | |
86 | mmalloc_check (md, size) | |
87 | PTR md; | |
88 | size_t size; | |
89 | { | |
90 | struct hdr *hdr; | |
91 | struct mdesc *mdp; | |
92 | size_t nbytes; | |
93 | ||
94 | mdp = MD_TO_MDP (md); | |
95 | mdp -> mmalloc_hook = NULL; | |
96 | nbytes = sizeof (struct hdr) + size + 1; | |
97 | hdr = (struct hdr *) mmalloc (md, nbytes); | |
98 | mdp -> mmalloc_hook = mmalloc_check; | |
99 | if (hdr != NULL) | |
100 | { | |
101 | hdr -> size = size; | |
102 | hdr -> magic = MAGICWORD; | |
103 | hdr++; | |
104 | *((char *) hdr + size) = MAGICBYTE; | |
105 | } | |
106 | return ((PTR) hdr); | |
107 | } | |
108 | ||
109 | static PTR | |
110 | mrealloc_check (md, ptr, size) | |
111 | PTR md; | |
112 | PTR ptr; | |
113 | size_t size; | |
114 | { | |
115 | struct hdr *hdr = ((struct hdr *) ptr) - 1; | |
116 | struct mdesc *mdp; | |
117 | size_t nbytes; | |
118 | ||
119 | mdp = MD_TO_MDP (md); | |
120 | checkhdr (mdp, hdr); | |
121 | mdp -> mfree_hook = NULL; | |
122 | mdp -> mmalloc_hook = NULL; | |
123 | mdp -> mrealloc_hook = NULL; | |
124 | nbytes = sizeof (struct hdr) + size + 1; | |
125 | hdr = (struct hdr *) mrealloc (md, (PTR) hdr, nbytes); | |
126 | mdp -> mfree_hook = mfree_check; | |
127 | mdp -> mmalloc_hook = mmalloc_check; | |
128 | mdp -> mrealloc_hook = mrealloc_check; | |
129 | if (hdr != NULL) | |
130 | { | |
131 | hdr -> size = size; | |
132 | hdr++; | |
133 | *((char *) hdr + size) = MAGICBYTE; | |
134 | } | |
135 | return ((PTR) hdr); | |
136 | } | |
137 | ||
138 | /* Turn on default checking for mmalloc/mrealloc/mfree, for the heap specified | |
139 | by MD. If FUNC is non-NULL, it is a pointer to the function to call | |
140 | to abort whenever memory corruption is detected. By default, this is the | |
141 | standard library function abort(). | |
142 | ||
143 | Note that we disallow installation of initial checking hooks if mmalloc | |
144 | has been called at any time for this particular heap, since if any region | |
145 | that is allocated prior to installation of the hooks is subsequently | |
146 | reallocated or freed after installation of the hooks, it is guaranteed | |
147 | to trigger a memory corruption error. We do this by checking the state | |
148 | of the MMALLOC_INITIALIZED flag. | |
149 | ||
150 | However, we can call this function at any time after the initial call, | |
151 | to update the function pointers to the checking routines and to the | |
152 | user defined corruption handler routine, as long as these function pointers | |
153 | have been previously extablished by the initial call. Note that we | |
154 | do this automatically when remapping an previously used heap, to ensure | |
155 | that the hooks get updated to the correct values, although the corruption | |
156 | handler pointer gets set back to the default. The application can then | |
157 | call mmcheck to use a different corruption handler if desired. | |
158 | ||
159 | Returns non-zero if checking is successfully enabled, zero otherwise. */ | |
160 | ||
161 | int | |
162 | mmcheck (md, func) | |
163 | PTR md; | |
164 | void (*func) PARAMS ((void)); | |
165 | { | |
166 | struct mdesc *mdp; | |
167 | int rtnval; | |
168 | ||
169 | mdp = MD_TO_MDP (md); | |
170 | ||
171 | /* We can safely set or update the abort function at any time, regardless | |
172 | of whether or not we successfully do anything else. */ | |
173 | ||
174 | mdp -> abortfunc = (func != NULL ? func : abort); | |
175 | ||
176 | /* If we haven't yet called mmalloc the first time for this heap, or if we | |
177 | have hooks that were previously installed, then allow the hooks to be | |
178 | initialized or updated. */ | |
179 | ||
180 | if (1 /* FIXME: Always allow installation for now. */ || | |
181 | !(mdp -> flags & MMALLOC_INITIALIZED) || | |
182 | (mdp -> mfree_hook != NULL)) | |
183 | { | |
184 | mdp -> mfree_hook = mfree_check; | |
185 | mdp -> mmalloc_hook = mmalloc_check; | |
186 | mdp -> mrealloc_hook = mrealloc_check; | |
187 | mdp -> flags |= MMALLOC_MMCHECK_USED; | |
188 | rtnval = 1; | |
189 | } | |
190 | else | |
191 | { | |
192 | rtnval = 0; | |
193 | } | |
194 | ||
195 | return (rtnval); | |
196 | } |