/*** *heapchk.c - perform a consistency check on the heap * * Copyright (c) 1989-1991, Microsoft Corporation. All rights reserved. * *Purpose: * Defines the _heapchk() and _heapset() functions * *Revision History: * 06-30-89 JCR Module created. * 07-28-89 GJF Added check for free block preceding the rover * 11-13-89 GJF Added MTHREAD support, also fixed copyright * 12-13-89 GJF Added check for descriptor order, did some tuning, * changed header file name to heap.h * 12-15-89 GJF Purged DEBUG286 stuff. Also added explicit _cdecl to * function definitions. * 12-19-89 GJF Got rid of checks involving plastdesc (revised check * of proverdesc and DEBUG errors accordingly) * 03-09-90 GJF Replaced _cdecl with _CALLTYPE1, added #include * and removed #include . * 03-29-90 GJF Made _heap_checkset() _CALLTYPE4. * 09-27-90 GJF New-style function declarators. * 03-05-91 GJF Changed strategy for rover - old version available * by #define-ing _OLDROVER_. * *******************************************************************************/ #include #include #include #include #include #include #ifdef DEBUG #include #endif static int _CALLTYPE4 _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 #ifdef DEBUG static char *errmsgs[] = { "_heap_desc.pfirstdesc == NULL", "_heap_desc.proverdesc not found in desc list", "address is outside the heap", "sentinel descriptor corrupted", "empty desc pblock != NULL (debug version)", "header ptr found twice in emptylist", "free block precedes rover", "adjacent descriptors in reverse order from heap blocks" }; #define _PRINTERR(msg) \ printf("\n*** HEAP ERROR: %s ***\n", errmsgs[(msg)]); \ fflush(stdout); #else /* !DEBUG */ #define _PRINTERR(msg) #endif /* DEBUG */ /*** *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 _CALLTYPE1 _heapchk(void) { return(_heap_checkset((unsigned int)_HEAP_NOFILL)); } /******************************************************************************/ int _CALLTYPE1 _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 _CALLTYPE4 _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++; #ifdef _OLDROVER_ /* * If it is free, make sure it doesn't precede the rover * block and fill it in if appropriate */ if ( _IS_FREE(pdesc) ) { if ( roverfound == 0 ) { _PRINTERR(_BADFREE); retval = _HEAPBADNODE; goto done; } if ( _fill != _HEAP_NOFILL ) memset( (void *)((unsigned)_ADDRESS(pdesc)+_HDRSIZE), _fill, _BLKSIZE(pdesc) ); } #else /* ndef _OLDROVER_ */ /* * 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) ); #endif /* _OLDROVER_ */ /* * 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) { #ifdef DEBUG if (pdesc->pblock != NULL) { _PRINTERR(_BADEMPTY) retval = _HEAPBADPTR; goto done; } #endif 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); }