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