/***
*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];
}