BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / kermit-5A.188 / ckcmdb.c
CommitLineData
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*/
22int memdebug = -1;
23int disabled = 0;
24int 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
45char *malloc(), *realloc();
46char *set_range_check();
47char *check_range();
48char *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
58char *
59dmalloc(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
70char *
71dcalloc(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
80char *
81drealloc(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
98dfree(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
116char *
117set_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*/
142char *
143check_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
170static char *
171maybe_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
199char *m_used[BUCKETS];
200char *m_used2[BUCKETS];
201
202VOID
203m_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
217static
218m_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
231VOID
232m_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
252VOID
253m_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
262VOID
263m_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
294VOID
295m_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
303static VOID
304maybe_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
316static int
317ask(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 */