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 */