/*** *alloc.c - disked malloc/free front-end. * *Copyright (c) 1993-1995, Gregg Jennings. All wrongs reserved. * P O Box 200, Falmouth, MA 02541-0200 * *Purpose: * Debugging support. * *Notice: * This progam may be freely used and distributed. Any distrubution * with modifications must retain the above copyright statement and * modifications noted. * No pulp-publication, in whole or in part, permitted without * permission (magazines or books). *******************************************************************************/ /* Version 2.6 20-Dec-1994 converted error references to function calls 2.5 18-Nov-1994 alloc_handler() 2.4 11-Sep-1994 removed DISKED ifdefs fixed heapstat() 2.3 25-Feb-1994 hugealloc(),hugefree(), etc 2.2 21-Feb-1994 fixed heapstat 2.1 13-Jan-1994 Borland stuff, heaptest was heapcheck 2.0 28-Nov-1993 malloc() and free() front end or "wrappers". This family of functions can be called explicitly (as DISKED does) or via macros: #define malloc(s) alloc(1,s) #define free(p) freep(p) etc. which will enable them to be used if needed for debugging. The heaptest() function can find bounds errors; just add this in your code to find it: if (heaptest() < 1) printf("%s%d",__FILE__,__LINE__); Notes: This unit can be a separate unit. The only globals referenced are the error message enums in ERROR.H. The ERROR.C error message calls can be removed without effect. Borland does not have a near heap in Large Memory model. */ #include #include #include "alloc.h" #include "error.h" /* globals referenced here error number definitions (enum ERROR_MSG, ERROR.H) */ /* globals defined here */ unsigned int blocks = 0; /* statistics only */ unsigned int nblocks = 0; /* used by DEBUG.C */ unsigned int hblocks = 0; unsigned int frees = 0; unsigned int nfrees = 0; unsigned int hfrees = 0; /* internal functions */ static void default_alloc_handler(void); /*** *alloc_handler - got the idea from C++, this is called * for alloc failures * ***/ void (*alloc_handler)(void) = default_alloc_handler; /*** *default_alloc_handler - handles memory allocation failure * * So far only sets error message information. * ****/ static void default_alloc_handler(void) { set_err_num(ALLOC_FAIL); /* set error number */ /* the module, function error */ /* arg are set by the caller */ set_err_info("memavail: %lu",memavail()); /* set avail. mem. info */ } /*** *set_alloc_handler - set the function to call upon malloc * failure * ****/ extern void set_alloc_handler(void (*func)(void)) { alloc_handler = (func) ? func : default_alloc_handler; } /*** *alloc - malloc/calloc replacement * ****/ extern void *alloc(size_t num, size_t size) { void *t; if (size == 0) { set_err_num(ALLOC_ZERO); return NULL; } if ((t = calloc(num,size)) == NULL) alloc_handler(); ++blocks; return t; } #ifndef __BORLANDC__ extern void _near *nalloc(size_t num, size_t size) { void _near *t; if (size == 0) { set_err_num(ALLOC_ZERO); return NULL; } if ((t = _ncalloc(num,size)) == NULL) alloc_handler(); ++nblocks; return t; } #endif /* !__BORLANDC__ */ extern void _huge *hugealloc(long num, long size) { void _huge *t; if (size == 0) { set_err_num(ALLOC_ZERO); return NULL; } if ((t = huge_alloc(num,size)) == NULL) alloc_handler(); ++hblocks; return t; } /* realloc() */ extern void *newalloc(void *p, size_t size) { if (p != NULL) freep(p); return alloc(1,size); } extern void freep(void *addr) { int h; if (addr != NULL) { free(addr); if ((h = _fheapset(254)) != _HEAPOK) { set_error(NULL,"alloc",HEAP_ERROR,"freep"); set_err_arg(heapstat(h)); } addr = NULL; ++frees; } else set_err_num(FREE_NULL); } #if !defined(__BORLANDC__) extern void nfreep(void _near *addr) { int h; if (addr != NULL) { _nfree(addr); if ((h = _nheapset(254)) != _HEAPOK) { set_error(NULL,"alloc",HEAP_ERROR,"nfreep"); set_err_arg(heapstat(h)); } addr = NULL; ++nfrees; } else set_err_num(FREE_NULL); } #endif extern void hugefreep(void _huge *addr) { if (addr != NULL) { huge_free(addr); addr = NULL; ++hfrees; } else set_err_num(FREE_NULL); } /*** *heaptest() * * putting calls to this throughout the program can help find were the * heap is getting corrupted: * * if (heaptest() < 1) * printf("%s%d",__FILE__,__LINE__); ***/ extern int heaptest(void) { int h; #if !defined(__BORLANDC__) if ((h = _fheapchk()) != _HEAPOK || (h = _nheapchk()) != _HEAPOK) #else if ((h = _heapchk()) != _HEAPOK) #endif return h; else return 1; } /* AS IN MALLOC.H: constants for _heapchk/_heapset/_heapwalk routines Borland: #define _HEAPEMPTY 1 // 0 #define _HEAPOK 2 // 1 #define _HEAPEND 5 // 4 #define _HEAPCORRUPT -1 // 5 #define _BADNODE -2 // 2 #define _BADVALUE -3 // 3 #define _FREEENTRY 3 #define _USEDENTRY 4 Microsoft: #define _HEAPEMPTY (-1) #define _HEAPOK (-2) // _heapchk/_heapset only #define _HEAPBADBEGIN (-3) #define _HEAPBADNODE (-4) #define _HEAPEND (-5) // _heapwalk only #define _HEAPBADPTR (-6) #define _FREEENTRY 0 #define _USEDENTRY 1 Watcom: #define _HEAPOK 0 #define _HEAPEMPTY 1 // heap isn't initialized #define _HEAPBADBEGIN 2 // heap header is corrupted #define _HEAPBADNODE 3 // heap entry is corrupted #define _HEAPEND 4 // end of heap entries (_heapwalk) #define _HEAPBADPTR 5 // invalid heap entry pointer (_heapwalk) #define _FREEENTRY 1 #define _USEDENTRY 0 You can see the dificulty with these compiler library functions! */ /* heap status message - values are normalized to 0-N */ static char *heap_msg[] = { #ifdef _MSC_VER "empty heap", "heap is fine", "bad start of heap", "bad node in heap", "end of heap", "bad pointer to heap", "bad heap", /* unknown value */ #elif __WATCOMC__ "heap is fine", "empty heap", "bad start of heap", "bad node in heap", "end of heap", "bad pointer to heap", "bad heap", /* unknown value */ #elif __BORLANDC__ "empty heap", "heap is fine", "bad node in heap", "bad pointer to heap", "end of heap", "bad heap", /* unknown value */ #else #error put Your compiler messages here #endif }; /* get heap status message */ extern char *heapstat(int status) { #ifdef _MSC_VER status = -status-1; /* make offset into message array */ #elif defined(__BORLANDC__) if (status < 0) { if (status == -1) status = 5; else status = -status; } else --status; #endif if (status < 0 || status > (sizeof(heap_msg)/sizeof(char *))-1) status = (sizeof(heap_msg)/sizeof(char *))-1; return heap_msg[status]; }