home *** CD-ROM | disk | FTP | other *** search
- /***
- *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 <stdlib.h>
- #include <malloc.h>
-
- #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];
- }
-