home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
vc98
/
crt
/
src
/
heapchk.c
< prev
next >
Wrap
C/C++ Source or Header
|
1998-06-17
|
7KB
|
349 lines
/***
*heapchk.c - perform a consistency check on the heap
*
* Copyright (c) 1989-1997, Microsoft Corporation. All rights reserved.
*
*Purpose:
* Defines the _heapchk() and _heapset() functions
*
*******************************************************************************/
#ifdef WINHEAP
#include <cruntime.h>
#include <windows.h>
#include <errno.h>
#include <malloc.h>
#include <mtdll.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <winheap.h>
/***
*int _heapchk() - Validate the heap
*int _heapset(_fill) - Obsolete function!
*
*Purpose:
* Both functions perform a consistency check on the heap. The old
* _heapset used to fill free blocks with _fill, in addition to
* performing the consistency check. The current _heapset ignores the
* passed parameter and just returns _heapchk.
*
*Entry:
* For heapchk()
* No arguments
* For heapset()
* int _fill - ignored
*
*Exit:
* Returns one of the following values:
*
* _HEAPOK - completed okay
* _HEAPEMPTY - heap not initialized
* _HEAPBADBEGIN - can't find initial header info
* _HEAPBADNODE - malformed node somewhere
*
* Debug version prints out a diagnostic message if an error is found
* (see errmsg[] above).
*
* NOTE: Add code to support memory regions.
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/
int __cdecl _heapchk (void)
{
int retcode = _HEAPOK;
_mlock(_HEAP_LOCK);
if ( __sbh_heap_check() < 0 )
retcode = _HEAPBADNODE;
_munlock(_HEAP_LOCK);
if (!HeapValidate(_crtheap, 0, NULL))
{
if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
{
_doserrno = ERROR_CALL_NOT_IMPLEMENTED;
errno = ENOSYS;
}
else
retcode = _HEAPBADNODE;
}
return retcode;
}
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
int __cdecl _heapset (
unsigned int _fill
)
{
return _heapchk();
}
#else /* WINHEAP */
#include <cruntime.h>
#include <heap.h>
#include <malloc.h>
#include <mtdll.h>
#include <stddef.h>
#include <string.h>
static int __cdecl _heap_checkset(unsigned int _fill);
/* Debug error values */
#define _EMPTYHEAP 0
#define _BADROVER 1
#define _BADRANGE 2
#define _BADSENTINEL 3
#define _BADEMPTY 4
#define _EMPTYLOOP 5
#define _BADFREE 6
#define _BADORDER 7
#define _PRINTERR(msg)
/***
*int _heapchk() - Validate the heap
*int _heapset(_fill) - Validate the heap and fill in free entries
*
*Purpose:
* Performs a consistency check on the heap.
*
*Entry:
* For heapchk()
* No arguments
* For heapset()
* int _fill - value to be used as filler in free entries
*
*Exit:
* Returns one of the following values:
*
* _HEAPOK - completed okay
* _HEAPEMPTY - heap not initialized
* _HEAPBADBEGIN - can't find initial header info
* _HEAPBADNODE - malformed node somewhere
*
* Debug version prints out a diagnostic message if an error is found
* (see errmsg[] above).
*
* NOTE: Add code to support memory regions.
*
*Uses:
*
*Exceptions:
*
*******************************************************************************/
int __cdecl _heapchk(void)
{
return(_heap_checkset((unsigned int)_HEAP_NOFILL));
}
int __cdecl _heapset (
unsigned int _fill
)
{
return(_heap_checkset(_fill));
}
/***
*static int _heap_checkset(_fill) - check the heap and fill in the
* free entries
*
*Purpose:
* Workhorse routine for both _heapchk() and _heapset().
*
*Entry:
* int _fill - either _HEAP_NOFILL or a value to be used as filler in
* free entries
*
*Exit:
* See description of _heapchk()/_heapset()
*
*******************************************************************************/
static int __cdecl _heap_checkset (
unsigned int _fill
)
{
REG1 _PBLKDESC pdesc;
REG2 _PBLKDESC pnext;
int roverfound=0;
int retval = _HEAPOK;
/*
* lock the heap
*/
_mlock(_HEAP_LOCK);
/*
* Validate the sentinel
*/
if (_heap_desc.sentinel.pnextdesc != NULL) {
_PRINTERR(_BADSENTINEL);
retval = _HEAPBADNODE;
goto done;
}
/*
* Test for an empty heap
*/
if ( (_heap_desc.pfirstdesc == &_heap_desc.sentinel) &&
(_heap_desc.proverdesc == &_heap_desc.sentinel) ) {
retval = _HEAPEMPTY;
goto done;
}
/*
* Get and validate the first descriptor
*/
if ((pdesc = _heap_desc.pfirstdesc) == NULL) {
_PRINTERR(_EMPTYHEAP);
retval = _HEAPBADBEGIN;
goto done;
}
/*
* Walk the heap descriptor list
*/
while (pdesc != &_heap_desc.sentinel) {
/*
* Make sure address for this entry is in range.
*/
if ( (_ADDRESS(pdesc) < _ADDRESS(_heap_desc.pfirstdesc)) ||
(_ADDRESS(pdesc) > _heap_desc.sentinel.pblock) ) {
_PRINTERR(_BADRANGE);
retval = _HEAPBADNODE;
goto done;
}
pnext = pdesc->pnextdesc;
/*
* Make sure the blocks corresponding to pdesc and pnext are
* in proper order.
*/
if ( _ADDRESS(pdesc) >= _ADDRESS(pnext) ) {
_PRINTERR(_BADORDER);
retval = _HEAPBADNODE;
goto done;
}
/*
* Check the backpointer.
*/
if (_IS_INUSE(pdesc) || _IS_FREE(pdesc)) {
if (!_CHECK_PDESC(pdesc)) {
retval = _HEAPBADPTR;
goto done;
}
}
/*
* Check for proverdesc
*/
if (pdesc == _heap_desc.proverdesc)
roverfound++;
/*
* If it is free, fill it in if appropriate
*/
if ( _IS_FREE(pdesc) && (_fill != _HEAP_NOFILL) )
memset( (void *)((unsigned)_ADDRESS(pdesc)+_HDRSIZE),
_fill, _BLKSIZE(pdesc) );
/*
* Onto the next block
*/
pdesc = pnext;
}
/*
* Make sure we found 1 and only 1 rover
*/
if (_heap_desc.proverdesc == &_heap_desc.sentinel)
roverfound++;
if (roverfound != 1) {
_PRINTERR(_BADROVER);
retval = _HEAPBADBEGIN;
goto done;
}
/*
* Walk the empty list. We can't really compare values against
* anything but we may loop forever or may cause a fault.
*/
pdesc = _heap_desc.emptylist;
while (pdesc != NULL) {
pnext = pdesc->pnextdesc;
/*
* Header should only appear once
*/
if (pnext == _heap_desc.emptylist) {
_PRINTERR(_EMPTYLOOP)
retval = _HEAPBADPTR;
goto done;
}
pdesc = pnext;
}
/*
* Common return
*/
done:
/*
* release the heap lock
*/
_munlock(_HEAP_LOCK);
return(retval);
}
#endif /* WINHEAP */