Commit | Line | Data |
---|---|---|
d81f5d5d C |
1 | /* |
2 | C K C M D B . C -- malloc debugger. | |
3 | */ | |
4 | ||
5 | /* | |
6 | Author: Howie Kaye, Columbia University Center for Computing Activities. | |
7 | Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New | |
8 | York. Permission is granted to any individual or institution to use this | |
9 | software as long as it is not sold for profit. This copyright notice must be | |
10 | retained. This software may not be included in commercial products without | |
11 | written permission of Columbia University. | |
12 | */ | |
13 | #include <stdio.h> | |
14 | #include "ckcdeb.h" | |
15 | /* | |
16 | memdebug: | |
17 | variable to control memory debugging. | |
18 | if memdebug == 1, then action is always taken. | |
19 | if memdebug == 0, then no action is taken. | |
20 | if memdebug == -1, then the user is asked (works well with gdb). | |
21 | */ | |
22 | int memdebug = -1; | |
23 | int disabled = 0; | |
24 | int inited = 0; | |
25 | /* | |
26 | To use this package, compile your program with: | |
27 | -Dmalloc=dmalloc -Dfree=dfree =Dcalloc=dcalloc ... -DMDEBUG | |
28 | and then link it with ckcmdb.c. | |
29 | */ | |
30 | #ifdef MDEBUG | |
31 | /* Use the real ones in this module! */ | |
32 | #ifdef malloc | |
33 | #undef malloc | |
34 | #endif /* malloc */ | |
35 | #ifdef calloc | |
36 | #undef calloc | |
37 | #endif /* calloc */ | |
38 | #ifdef realloc | |
39 | #undef realloc | |
40 | #endif /* realloc */ | |
41 | #ifdef free | |
42 | #undef free | |
43 | #endif /* free */ | |
44 | ||
45 | char *malloc(), *realloc(); | |
46 | char *set_range_check(); | |
47 | char *check_range(); | |
48 | char *maybe_check_range(); | |
49 | ||
50 | #define min(x,y) ((x) < (y) ? (x) : (y)) | |
51 | #define RANGE "ABCDEFGHIJKLMNOP" | |
52 | #define INTSIZE sizeof(int) | |
53 | #define LONGSIZE sizeof(long) | |
54 | #define RSIZE sizeof(RANGE) | |
55 | #define RFRONT min((RSIZE/2),LONGSIZE) | |
56 | #define RBACK min((RSIZE-RFRONT),LONGSIZE) | |
57 | ||
58 | char * | |
59 | dmalloc(size) int size; { | |
60 | char *cp; | |
61 | ||
62 | cp = malloc(size + RSIZE + INTSIZE); | |
63 | if (cp) { | |
64 | cp = set_range_check(cp, size); | |
65 | m_insert(cp); | |
66 | } | |
67 | return(cp); | |
68 | } | |
69 | ||
70 | char * | |
71 | dcalloc(nelem, elsize) int nelem, elsize; { | |
72 | char *cp; | |
73 | ||
74 | cp = dmalloc(nelem * elsize); | |
75 | if (cp) | |
76 | bzero(cp, nelem * elsize); | |
77 | return(cp); | |
78 | } | |
79 | ||
80 | char * | |
81 | drealloc(bp,size) char *bp; int size; { | |
82 | char *cp; | |
83 | ||
84 | if (bp == NULL) { | |
85 | maybe_quit("Freeing NULL pointer"); | |
86 | } else { | |
87 | m_delete(bp); | |
88 | cp = check_range(bp); | |
89 | } | |
90 | cp = realloc(cp, size + RSIZE + INTSIZE); | |
91 | if (cp) { | |
92 | cp = set_range_check(cp, size); | |
93 | m_insert(cp); | |
94 | } | |
95 | return(cp); | |
96 | } | |
97 | ||
98 | dfree(cp) char *cp; { | |
99 | if (cp == NULL) | |
100 | maybe_quit("Freeing NULL pointer"); | |
101 | else { | |
102 | switch(m_delete(cp)) { | |
103 | case 0: | |
104 | cp = maybe_check_range(cp); | |
105 | break; | |
106 | case 1: | |
107 | cp = check_range(cp); | |
108 | break; | |
109 | case 2: | |
110 | break; | |
111 | } | |
112 | } | |
113 | return(free(cp)); | |
114 | } | |
115 | ||
116 | char * | |
117 | set_range_check(cp,size) char *cp; int size; { | |
118 | register int i; | |
119 | int tmp = size; | |
120 | ||
121 | for(i = 0; i < INTSIZE; i++) { /* set the size in the string */ | |
122 | cp[i] = tmp & 0xff; | |
123 | tmp >>= 8; | |
124 | } | |
125 | cp += INTSIZE; /* skip the size */ | |
126 | ||
127 | for(i = 0; i < RFRONT; i++) /* set the front of the range check */ | |
128 | cp[i] = RANGE[i]; /* string */ | |
129 | ||
130 | cp += RFRONT; /* skip the front range check */ | |
131 | ||
132 | for(i = 0; i < RBACK; i++) /* set the back odf the range check */ | |
133 | cp[i+size] = RANGE[i+RFRONT]; | |
134 | ||
135 | return(cp); | |
136 | } | |
137 | ||
138 | /* | |
139 | Put calls to this routine in your code any place where you want to | |
140 | check whether you've copied too many characters into a malloc'd space. | |
141 | */ | |
142 | char * | |
143 | check_range(cp) char *cp; { | |
144 | register char *bp = cp - RFRONT - INTSIZE; | |
145 | char *xp = bp; | |
146 | register int i; | |
147 | int size = 0; | |
148 | ||
149 | for(i = 0 ; i < INTSIZE; i++) { /* get the size out of the string */ | |
150 | size <<= 8; | |
151 | size |= bp[INTSIZE-i-1] & 0xff; | |
152 | } | |
153 | bp += INTSIZE; | |
154 | ||
155 | for(i = 0; i < RFRONT; i++) /* check front range check */ | |
156 | if (bp[i] != RANGE[i]) { | |
157 | maybe_quit("leftside malloc buffer overrun"); | |
158 | break; | |
159 | } | |
160 | bp += RFRONT; /* skip front range check */ | |
161 | ||
162 | for(i = 0; i < RBACK; i++) /* check back range check */ | |
163 | if (bp[i+size] != RANGE[i+RFRONT]) { | |
164 | maybe_quit("rightside malloc buffer overrun"); | |
165 | break; | |
166 | } | |
167 | return(xp); | |
168 | } | |
169 | ||
170 | static char * | |
171 | maybe_check_range(cp) char *cp; { | |
172 | register char *bp = cp - RFRONT - INTSIZE; | |
173 | char *xp = bp; | |
174 | register int i; | |
175 | int size = 0; | |
176 | ||
177 | for(i = 0 ; i < INTSIZE; i++) { /* get the size out of the string */ | |
178 | size <<= 8; | |
179 | size |= bp[INTSIZE-i-1] & 0xff; | |
180 | } | |
181 | bp += INTSIZE; | |
182 | ||
183 | for(i = 0; i < RFRONT; i++) /* check front range check */ | |
184 | if (bp[i] != RANGE[i]) { | |
185 | return(cp); | |
186 | } | |
187 | bp += RFRONT; /* skip front range check */ | |
188 | ||
189 | for(i = 0; i < RBACK; i++) /* check back range check */ | |
190 | if (bp[i+size] != RANGE[i+RFRONT]) { | |
191 | fprintf(stderr,"rightside malloc buffer overrun\n"); | |
192 | abort(); | |
193 | break; | |
194 | } | |
195 | return(xp); | |
196 | } | |
197 | ||
198 | #define BUCKETS 10000 | |
199 | char *m_used[BUCKETS]; | |
200 | char *m_used2[BUCKETS]; | |
201 | ||
202 | VOID | |
203 | m_insert(cp) register char *cp; { | |
204 | register int i; | |
205 | ||
206 | if (disabled) | |
207 | return; | |
208 | ||
209 | for(i = 0; i < BUCKETS; i++) | |
210 | if (m_used[i] == 0) { | |
211 | m_used[i] = cp; | |
212 | return; | |
213 | } | |
214 | disabled ++; | |
215 | } | |
216 | ||
217 | static | |
218 | m_insert2(cp) register char *cp; { | |
219 | register int i; | |
220 | ||
221 | if (disabled) | |
222 | return; | |
223 | for(i = 0; i < BUCKETS; i++) | |
224 | if (m_used2[i] == 0) { | |
225 | m_used2[i] = cp; | |
226 | return; | |
227 | } | |
228 | disabled ++; | |
229 | } | |
230 | ||
231 | VOID | |
232 | m_delete(cp) register char *cp; { | |
233 | register int i; | |
234 | ||
235 | for(i = 0; i < BUCKETS; i++) | |
236 | if (m_used[i] == cp) { | |
237 | m_used[i] = 0; | |
238 | return(1); | |
239 | } | |
240 | for(i = 0; i < BUCKETS; i++) | |
241 | if (m_used2[i] == cp) { | |
242 | m_used2[i] = 0; | |
243 | return(2); | |
244 | } | |
245 | if (disabled) | |
246 | return(0); | |
247 | ||
248 | maybe_quit("Freeing unmalloc'ed pointer"); | |
249 | return(0); | |
250 | } | |
251 | ||
252 | VOID | |
253 | m_init() { | |
254 | register int i; | |
255 | ||
256 | inited = 1; | |
257 | disabled = 0; | |
258 | for(i = 0; i < BUCKETS; i++) | |
259 | m_used[i] = 0; | |
260 | } | |
261 | ||
262 | VOID | |
263 | m_done() { | |
264 | register int i,j=0; | |
265 | ||
266 | if (disabled) | |
267 | return; | |
268 | for(i = 0; i < BUCKETS; i++) | |
269 | if (m_used[i] != 0) { | |
270 | if (memdebug) { | |
271 | if (j == 0) | |
272 | fprintf(stderr,"unfree'ed buffers, indices: "); | |
273 | fprintf(stderr,"%d, ", i); | |
274 | j++; | |
275 | } | |
276 | } | |
277 | if (j) | |
278 | fprintf(stderr,"\n"); | |
279 | for(i = 0; i < BUCKETS; i++) | |
280 | if (m_used2[i] != 0) { | |
281 | if (memdebug) { | |
282 | if (j == 0) | |
283 | fprintf(stderr,"unfree'ed registered buffers, indices: "); | |
284 | fprintf(stderr,"%d, ", i); | |
285 | j++; | |
286 | } | |
287 | } | |
288 | if (j) | |
289 | fprintf(stderr,"\n"); | |
290 | if (j) | |
291 | maybe_quit("Unfree'ed malloc buffers"); | |
292 | } | |
293 | ||
294 | VOID | |
295 | m_checkranges() { | |
296 | int i; | |
297 | ||
298 | for ( i = 0; i < BUCKETS; i++) | |
299 | if (m_used[i]) | |
300 | check_range(m_used[i]); | |
301 | } | |
302 | ||
303 | static VOID | |
304 | maybe_quit(str) char *str; { | |
305 | debug(F100,"mdebug maybe_quit","",0); | |
306 | if (memdebug == 0) | |
307 | return; | |
308 | fprintf(stderr,"%s\n",str); | |
309 | if (memdebug == 1) | |
310 | abort(); | |
311 | if (memdebug == -1) | |
312 | if (ask("Quit? ")) | |
313 | abort(); | |
314 | } | |
315 | ||
316 | static int | |
317 | ask(str) char *str; { | |
318 | char buf[100]; | |
319 | FILE *in; | |
320 | int fd; | |
321 | ||
322 | fd = dup(fileno(stdin)); | |
323 | in = fdopen(fd, "r"); | |
324 | while(1) { | |
325 | fprintf(stderr,str); | |
326 | fflush(stderr); | |
327 | if (fgets(buf, 99, in) == NULL) /* EOF? */ | |
328 | return(0); | |
329 | if (buf[0] == 'n' || buf[0] == 'N') { | |
330 | fclose(in); | |
331 | return(0); | |
332 | } | |
333 | if (buf[0] == 'y' || buf[0] == 'Y') { | |
334 | fclose(in); | |
335 | return(1); | |
336 | } | |
337 | fprintf(stderr,"please answer y/n.\n"); | |
338 | } | |
339 | } | |
340 | #endif /* MDEBUG */ |