/*** *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 #include #include #include #include #include #include #include #include /*** *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 #include #include #include #include #include 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 */