home *** CD-ROM | disk | FTP | other *** search
- /***
- *dbgheap.c - Debug CRT Heap Functions
- *
- * Copyright (c) 1988-1997, Microsoft Corporation. All rights reserved.
- *
- *Purpose:
- * Defines debug versions of heap functions.
- *
- *******************************************************************************/
-
- #ifdef _DEBUG
-
- #ifdef _WIN32
- #include <windows.h>
- #include <winheap.h>
- #else /* _WIN32 */
- #include <memory.h>
- #include <string.h>
- #define FALSE 0
- #define TRUE 1
- #define BYTE char
- #endif /* _WIN32 */
-
- #include <ctype.h>
- #include <dbgint.h>
- #ifndef WINHEAP
- #include <heap.h>
- #endif /* WINHEAP */
- #include <internal.h>
- #include <limits.h>
- #include <malloc.h>
- #include <mtdll.h>
- #include <stdio.h>
- #include <stdlib.h>
-
-
- /*---------------------------------------------------------------------------
- *
- * Heap management
- *
- --------------------------------------------------------------------------*/
-
- #ifdef _MAC
- extern Handle hHeapRegions;
- #endif /* _MAC */
-
- #define IGNORE_REQ 0L /* Request number for ignore block */
- #define IGNORE_LINE 0xFEDCBABC /* Line number for ignore block */
-
-
- /*
- * Bitfield flag that controls CRT heap behavior --
- * default is to record all allocations (_CRTDBG_ALLOC_MEM_DF)
- */
- int _crtDbgFlag = _CRTDBG_ALLOC_MEM_DF;
-
- static long _lRequestCurr = 1; /* Current request number */
-
- _CRTIMP long _crtBreakAlloc = -1L; /* Break on allocation by request number */
-
- static unsigned long _lTotalAlloc; /* Grand total - sum of all allocations */
- static unsigned long _lCurAlloc; /* Total amount currently allocated */
- static unsigned long _lMaxAlloc; /* Largest ever allocated at once */
-
- /*
- * The following values are non-zero, constant, odd, large, and atypical
- * Non-zero values help find bugs assuming zero filled data.
- * Constant values are good so that memory filling is deterministic
- * (to help make bugs reproducable). Of course it is bad if
- * the constant filling of weird values masks a bug.
- * Mathematically odd numbers are good for finding bugs assuming a cleared
- * lower bit, as well as useful for trapping on the Mac.
- * Large numbers (byte values at least) are less typical, and are good
- * at finding bad addresses.
- * Atypical values (i.e. not too often) are good since they typically
- * cause early detection in code.
- * For the case of no-man's land and free blocks, if you store to any
- * of these locations, the memory integrity checker will detect it.
- */
-
- static unsigned char _bNoMansLandFill = 0xFD; /* fill no-man's land with this */
- static unsigned char _bDeadLandFill = 0xDD; /* fill free objects with this */
- static unsigned char _bCleanLandFill = 0xCD; /* fill new objects with this */
-
- static _CrtMemBlockHeader * _pFirstBlock;
- static _CrtMemBlockHeader * _pLastBlock;
-
- _CRT_DUMP_CLIENT _pfnDumpClient;
-
-
- #if _FREE_BLOCK != 0 || _NORMAL_BLOCK != 1 || _CRT_BLOCK != 2 || _IGNORE_BLOCK != 3 || _CLIENT_BLOCK != 4
- #error Block numbers have changed !
- #endif /* _FREE_BLOCK != 0 || _NORMAL_BLOCK != 1 || _CRT_BLOCK != 2 || _IGNORE_BLOCK != 3 || _CLIENT_BLOCK != 4 */
-
- static char * szBlockUseName[_MAX_BLOCKS] = {
- "Free",
- "Normal",
- "CRT",
- "Ignore",
- "Client",
- };
-
- int __cdecl CheckBytes(unsigned char *, unsigned char, size_t);
-
-
- /***
- *void *malloc() - Get a block of memory from the debug heap
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the heap and
- * return a pointer to it.
- *
- * Allocates 'normal' memory block.
- *
- *Entry:
- * size_t nSize - size of block requested
- *
- *Exit:
- * Success: Pointer to memory block
- * Failure: NULL (or some error value)
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- _CRTIMP void * __cdecl malloc (
- size_t nSize
- )
- {
- return _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);
- }
-
- /***
- *void * _malloc_dbg() - Get a block of memory from the debug heap
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the heap and
- * return a pointer to it.
- *
- * Allocates any type of supported memory block.
- *
- *Entry:
- * size_t nSize - size of block requested
- * int nBlockUse - block type
- * char * szFileName - file name
- * int nLine - line number
- *
- *Exit:
- * Success: Pointer to memory block
- * Failure: NULL (or some error value)
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- _CRTIMP void * __cdecl _malloc_dbg (
- size_t nSize,
- int nBlockUse,
- const char * szFileName,
- int nLine
- )
- {
- return _nh_malloc_dbg(nSize, _newmode, nBlockUse, szFileName, nLine);
- }
-
- /***
- *void * _nh_malloc() - Get a block of memory from the debug heap
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the debug
- * heap and return a pointer to it. Assumes heap already locked.
- *
- * If no blocks available, call new handler.
- *
- * Allocates 'normal' memory block.
- *
- *Entry:
- * size_t nSize - size of block requested
- * int nhFlag - TRUE if new handler function
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void * __cdecl _nh_malloc (
- size_t nSize,
- int nhFlag
- )
- {
- return _nh_malloc_dbg(nSize, nhFlag, _NORMAL_BLOCK, NULL, 0);
- }
-
-
- /***
- *void * _nh_malloc_dbg() - Get a block of memory from the debug heap
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the debug
- * heap and return a pointer to it. Assumes heap already locked.
- *
- * If no blocks available, call new handler.
- *
- * Allocates any type of supported memory block.
- *
- *Entry:
- * size_t nSize - size of block requested
- * int nhFlag - TRUE if new handler function
- * int nBlockUse - block type
- * char * szFileName - file name
- * int nLine - line number
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void * __cdecl _nh_malloc_dbg (
- size_t nSize,
- int nhFlag,
- int nBlockUse,
- const char * szFileName,
- int nLine
- )
- {
- void * pvBlk;
-
- for (;;)
- {
- /* lock the heap
- */
- _mlock(_HEAP_LOCK);
-
- /* do the allocation
- */
- pvBlk = _heap_alloc_dbg(nSize, nBlockUse, szFileName, nLine);
-
- /* unlock the heap
- */
- _munlock(_HEAP_LOCK);
-
- if (pvBlk || nhFlag == 0)
- return pvBlk;
-
- /* call installed new handler */
- if (!_callnewh(nSize))
- return NULL;
-
- /* new handler was successful -- try to allocate again */
- }
- }
-
- /***
- *void * _heap_alloc() - does actual allocation
- *
- *Purpose:
- * Does heap allocation.
- *
- * Allocates 'normal' memory block.
- *
- *Entry:
- * size_t nSize - size of block requested
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void * __cdecl _heap_alloc(
- size_t nSize
- )
- {
- return _heap_alloc_dbg(nSize, _NORMAL_BLOCK, NULL, 0);
- }
-
- /***
- *void * _heap_alloc_dbg() - does actual allocation
- *
- *Purpose:
- * Does heap allocation.
- *
- * Allocates any type of supported memory block.
- *
- *Entry:
- * size_t nSize - size of block requested
- * int nBlockUse - block type
- * char * szFileName - file name
- * int nLine - line number
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- void * __cdecl _heap_alloc_dbg(
- size_t nSize,
- int nBlockUse,
- const char * szFileName,
- int nLine
- )
- {
- long lRequest;
- size_t blockSize;
- int fIgnore = FALSE;
- _CrtMemBlockHeader * pHead;
-
- /* verify heap before allocation */
- if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
- _ASSERTE(_CrtCheckMemory());
-
- lRequest = _lRequestCurr;
-
- /* break into debugger at specific memory allocation */
- if (lRequest == _crtBreakAlloc)
- _CrtDbgBreak();
-
- /* forced failure */
- if (!(*_pfnAllocHook)(_HOOK_ALLOC, NULL, nSize, nBlockUse, lRequest, szFileName, nLine))
- {
- if (szFileName)
- _RPT2(_CRT_WARN, "Client hook allocation failure at file %hs line %d.\n",
- szFileName, nLine);
- else
- _RPT0(_CRT_WARN, "Client hook allocation failure.\n");
-
- return NULL;
- }
-
- /* cannot ignore CRT allocations */
- if (_BLOCK_TYPE(nBlockUse) != _CRT_BLOCK &&
- !(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF))
- fIgnore = TRUE;
-
- /* Diagnostic memory allocation from this point on */
-
- if (nSize > (size_t)_HEAP_MAXREQ ||
- nSize + nNoMansLandSize + sizeof(_CrtMemBlockHeader) > (size_t)_HEAP_MAXREQ)
- {
- _RPT1(_CRT_ERROR, "Invalid allocation size: %u bytes.\n", nSize);
- return NULL;
- }
-
- if (!_BLOCK_TYPE_IS_VALID(nBlockUse))
- {
- _RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type.\n");
- }
-
- blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;
-
- #ifndef WINHEAP
- /* round requested size */
- blockSize = _ROUND2(blockSize, _GRANULARITY);
- #endif /* WINHEAP */
-
- pHead = (_CrtMemBlockHeader *)_heap_alloc_base(blockSize);
-
- if (pHead == NULL)
- return NULL;
-
- /* commit allocation */
- ++_lRequestCurr;
-
- if (fIgnore)
- {
- pHead->pBlockHeaderNext = NULL;
- pHead->pBlockHeaderPrev = NULL;
- pHead->szFileName = NULL;
- pHead->nLine = IGNORE_LINE;
- pHead->nDataSize = nSize;
- pHead->nBlockUse = _IGNORE_BLOCK;
- pHead->lRequest = IGNORE_REQ;
- }
- else {
- /* keep track of total amount of memory allocated */
- _lTotalAlloc += nSize;
- _lCurAlloc += nSize;
-
- if (_lCurAlloc > _lMaxAlloc)
- _lMaxAlloc = _lCurAlloc;
-
- if (_pFirstBlock)
- _pFirstBlock->pBlockHeaderPrev = pHead;
- else
- _pLastBlock = pHead;
-
- pHead->pBlockHeaderNext = _pFirstBlock;
- pHead->pBlockHeaderPrev = NULL;
- pHead->szFileName = (char *)szFileName;
- pHead->nLine = nLine;
- pHead->nDataSize = nSize;
- pHead->nBlockUse = nBlockUse;
- pHead->lRequest = lRequest;
-
- /* link blocks together */
- _pFirstBlock = pHead;
- }
-
- /* fill in gap before and after real block */
- memset((void *)pHead->gap, _bNoMansLandFill, nNoMansLandSize);
- memset((void *)(pbData(pHead) + nSize), _bNoMansLandFill, nNoMansLandSize);
-
- /* fill data with silly value (but non-zero) */
- memset((void *)pbData(pHead), _bCleanLandFill, nSize);
-
- return (void *)pbData(pHead);
- }
-
-
- /***
- *void * calloc() - Get a block of memory from the debug heap, init to 0
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the debug
- * heap and return a pointer to it.
- *
- * Allocates 'normal' memory block.
- *
- *Entry:
- * size_t nNum - number of elements in the array
- * size_t nSize - size of each element
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
- _CRTIMP void * __cdecl calloc(
- size_t nNum,
- size_t nSize
- )
- {
- return _calloc_dbg(nNum, nSize, _NORMAL_BLOCK, NULL, 0);
- }
-
-
- /***
- *void * _calloc_dbg() - Get a block of memory from the debug heap, init to 0
- * - with info
- *
- *Purpose:
- * Allocate of block of memory of at least size bytes from the debug
- * heap and return a pointer to it.
- *
- * Allocates any type of supported memory block.
- *
- *Entry:
- * size_t nNum - number of elements in the array
- * size_t nSize - size of each element
- * int nBlockUse - block type
- * char * szFileName - file name
- * int nLine - line number
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- _CRTIMP void * __cdecl _calloc_dbg(
- size_t nNum,
- size_t nSize,
- int nBlockUse,
- const char * szFileName,
- int nLine
- )
- {
- void * pvBlk;
- unsigned char *pStart;
- unsigned char *pLast;
-
- nSize *= nNum;
-
- /*
- * try to malloc the requested space
- */
-
- pvBlk = _malloc_dbg(nSize, nBlockUse, szFileName, nLine);
-
- /*
- * If malloc() succeeded, initialize the allocated space to zeros.
- * Note that unlike _calloc_base, exactly nNum bytes are set to zero.
- */
-
- if ( pvBlk != NULL )
- {
- pStart = (unsigned char *)pvBlk;
- pLast = pStart + nSize;
- while ( pStart < pLast )
- *(pStart++) = 0;
- }
-
- return(pvBlk);
- }
-
-
- /***
- *static void * realloc_help() - does all the work for _realloc and _expand
- *
- *Purpose:
- * Helper function for _realloc and _expand.
- *
- *Entry:
- * void * pUserData - pointer previously allocated block
- * size_t nNewSize - requested size for the re-allocated block
- * int nBlockUse - block type
- * char * szFileName - file name
- * int nLine - line number
- * int fRealloc - TRUE when _realloc, FALSE when _expand
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- static void * __cdecl realloc_help(
- void * pUserData,
- size_t nNewSize,
- int nBlockUse,
- const char * szFileName,
- int nLine,
- int fRealloc
- )
- {
- long lRequest;
- int fIgnore = FALSE;
- unsigned char *pUserBlock;
- _CrtMemBlockHeader * pOldBlock;
- _CrtMemBlockHeader * pNewBlock;
-
- /*
- * ANSI: realloc(NULL, newsize) is equivalent to malloc(newsize)
- */
- if (pUserData == NULL)
- {
- return _malloc_dbg(nNewSize, nBlockUse, szFileName, nLine);
- }
-
- /*
- * ANSI: realloc(pUserData, 0) is equivalent to free(pUserData)
- * (except that NULL is returned)
- */
- if (fRealloc && nNewSize == 0)
- {
- _free_dbg(pUserData, nBlockUse);
- return NULL;
- }
-
- /* verify heap before re-allocation */
- if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
- _ASSERTE(_CrtCheckMemory());
-
- lRequest = _lRequestCurr;
-
- if (lRequest == _crtBreakAlloc)
- _CrtDbgBreak(); /* break into debugger at specific memory leak */
-
- /* forced failure */
- if (!(*_pfnAllocHook)(_HOOK_REALLOC, pUserData, nNewSize, nBlockUse, lRequest, szFileName, nLine))
- {
- if (szFileName)
- _RPT2(_CRT_WARN, "Client hook re-allocation failure at file %hs line %d.\n",
- szFileName, nLine);
- else
- _RPT0(_CRT_WARN, "Client hook re-allocation failure.\n");
-
- return NULL;
- }
-
- /* Diagnostic memory allocation from this point on */
-
- if (nNewSize > (size_t)UINT_MAX - nNoMansLandSize - sizeof(_CrtMemBlockHeader))
- {
- _RPT1(_CRT_ERROR, "Allocation too large or negative: %u bytes.\n",
- nNewSize);
- return NULL;
- }
-
- if (nBlockUse != _NORMAL_BLOCK
- && _BLOCK_TYPE(nBlockUse) != _CLIENT_BLOCK
- && _BLOCK_TYPE(nBlockUse) != _CRT_BLOCK)
- {
- _RPT0(_CRT_ERROR, "Error: memory allocation: bad memory block type.\n");
- }
-
- /*
- * If this ASSERT fails, a bad pointer has been passed in. It may be
- * totally bogus, or it may have been allocated from another heap.
- * The pointer MUST come from the 'local' heap.
- */
- _ASSERTE(_CrtIsValidHeapPointer(pUserData));
-
- /* get a pointer to memory block header */
- pOldBlock = pHdr(pUserData);
-
- if (pOldBlock->nBlockUse == _IGNORE_BLOCK)
- fIgnore = TRUE;
-
- if (fIgnore)
- {
- _ASSERTE(pOldBlock->nLine == IGNORE_LINE && pOldBlock->lRequest == IGNORE_REQ);
- }
- else {
- /* Error if freeing incorrect memory type */
- /* CRT blocks can be treated as NORMAL blocks */
- if (_BLOCK_TYPE(pOldBlock->nBlockUse) == _CRT_BLOCK && _BLOCK_TYPE(nBlockUse) == _NORMAL_BLOCK)
- nBlockUse = _CRT_BLOCK;
- _ASSERTE(_BLOCK_TYPE(pOldBlock->nBlockUse)==_BLOCK_TYPE(nBlockUse));
- }
-
- /*
- * note that all header values will remain valid
- * and min(nNewSize,nOldSize) bytes of data will also remain valid
- */
- if (fRealloc)
- {
- if (NULL == (pNewBlock = _realloc_base(pOldBlock,
- sizeof(_CrtMemBlockHeader) + nNewSize + nNoMansLandSize)))
- return NULL;
- }
- else {
- if (NULL == (pNewBlock = _expand_base(pOldBlock,
- sizeof(_CrtMemBlockHeader) + nNewSize + nNoMansLandSize)))
- return NULL;
- }
-
- /* commit allocation */
- ++_lRequestCurr;
-
- if (!fIgnore)
- {
- /* keep track of total amount of memory allocated */
- _lTotalAlloc -= pNewBlock->nDataSize;
- _lTotalAlloc += nNewSize;
-
- _lCurAlloc -= pNewBlock->nDataSize;
- _lCurAlloc += nNewSize;
-
- if (_lCurAlloc > _lMaxAlloc)
- _lMaxAlloc = _lCurAlloc;
- }
-
- pUserBlock = pbData(pNewBlock);
-
- /* if the block grew, put in special value */
- if (nNewSize > pNewBlock->nDataSize)
- memset(pUserBlock + pNewBlock->nDataSize, _bCleanLandFill,
- nNewSize - pNewBlock->nDataSize);
-
- /* fill in gap after real block */
- memset(pUserBlock + nNewSize, _bNoMansLandFill, nNoMansLandSize);
-
- if (!fIgnore)
- {
- pNewBlock->szFileName = (char *)szFileName;
- pNewBlock->nLine = nLine;
- pNewBlock->lRequest = lRequest;
- }
-
- pNewBlock->nDataSize = nNewSize;
-
- _ASSERTE(fRealloc || (!fRealloc && pNewBlock == pOldBlock));
-
- /* if block did not move or ignored, we are done */
- if (pNewBlock == pOldBlock || fIgnore)
- return (void *)pUserBlock;
-
- /* must remove old memory from dbg heap list */
- /* note that new block header pointers still valid */
- if (pNewBlock->pBlockHeaderNext)
- {
- pNewBlock->pBlockHeaderNext->pBlockHeaderPrev
- = pNewBlock->pBlockHeaderPrev;
- }
- else
- {
- _ASSERTE(_pLastBlock == pOldBlock);
- _pLastBlock = pNewBlock->pBlockHeaderPrev;
- }
-
- if (pNewBlock->pBlockHeaderPrev)
- {
- pNewBlock->pBlockHeaderPrev->pBlockHeaderNext
- = pNewBlock->pBlockHeaderNext;
- }
- else
- {
- _ASSERTE(_pFirstBlock == pOldBlock);
- _pFirstBlock = pNewBlock->pBlockHeaderNext;
- }
-
- /* put new memory into list */
- if (_pFirstBlock)
- _pFirstBlock->pBlockHeaderPrev = pNewBlock;
- else
- _pLastBlock = pNewBlock;
-
- pNewBlock->pBlockHeaderNext = _pFirstBlock;
- pNewBlock->pBlockHeaderPrev = NULL;
-
- /* link blocks together */
- _pFirstBlock = pNewBlock;
-
- return (void *)pUserBlock;
- }
-
-
- /***
- *void * realloc() - reallocate a block of memory in the heap
- *
- *Purpose:
- * Re-allocates a block in the heap to nNewSize bytes. nNewSize may be
- * either greater or less than the original size of the block. The
- * re-allocation may result in moving the block as well as changing
- * the size. If the block is moved, the contents of the original block
- * are copied over.
- *
- * Re-allocates 'normal' memory block.
- *
- *Entry:
- * void * pUserData - pointer to previously allocated block
- * size_t nNewSize - requested size for the re-allocated block
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- _CRTIMP void * __cdecl realloc(
- void * pUserData,
- size_t nNewSize
- )
- {
- return _realloc_dbg(pUserData, nNewSize, _NORMAL_BLOCK, NULL, 0);
- }
-
-
- /***
- *void * _realloc_dbg() - reallocate a block of memory in the heap
- * - with info
- *
- *Purpose:
- * Re-allocates a block in the heap to nNewSize bytes. nNewSize may be
- * either greater or less than the original size of the block. The
- * re-allocation may result in moving the block as well as changing
- * the size. If the block is moved, the contents of the original block
- * are copied over.
- *
- * Re-allocates any type of supported memory block.
- *
- *Entry:
- * void * pUserData - pointer previously allocated block
- * size_t nNewSize - requested size for the re-allocated block
- * int nBlockUse - block type
- * char * szFileName - file name
- * int nLine - line number
- *
- *Exit:
- * Success: Pointer to (user portion of) memory block
- * Failure: NULL
- *
- *Exceptions:
- *
- *******************************************************************************/
-
- _CRTIMP void * __cdecl _realloc_dbg(
- void * pUserData,
- size_t nNewSize,
- int nBlockUse,
- const char * szFileName,
- int nLine
- )
- {
- void * pvBlk;
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- /* allocate the block
- */
- pvBlk = realloc_help(pUserData,
- nNewSize,
- nBlockUse,
- szFileName,
- nLine,
- TRUE);
-
- _munlock(_HEAP_LOCK); /* release other threads */
-
- return pvBlk;
- }
-
- /***
- *void * _expand() - expand/contract a block of memory in the heap
- *
- *Purpose:
- * Resizes a block in the heap to newsize bytes. newsize may be either
- * greater (expansion) or less (contraction) than the original size of
- * the block. The block is NOT moved. In the case of expansion, if the
- * block cannot be expanded to newsize bytes, it is expanded as much as
- * possible.
- *
- * Re-allocates 'normal' memory block.
- *
- *Entry:
- * void * pUserData - pointer to block in the heap previously allocated
- * by a call to malloc(), realloc() or _expand().
- *
- * size_t nNewSize - requested size for the resized block
- *
- *Exit:
- * Success: Pointer to the resized memory block (i.e., pUserData)
- * Failure: NULL
- *
- *Uses:
- *
- *Exceptions:
- * If pUserData does not point to a valid allocation block in the heap,
- * _expand() will behave unpredictably and probably corrupt the heap.
- *
- *******************************************************************************/
-
- _CRTIMP void * __cdecl _expand(
- void * pUserData,
- size_t nNewSize
- )
- {
- return _expand_dbg(pUserData, nNewSize, _NORMAL_BLOCK, NULL, 0);
- }
-
-
- /***
- *void * _expand() - expand/contract a block of memory in the heap
- *
- *Purpose:
- * Resizes a block in the heap to newsize bytes. newsize may be either
- * greater (expansion) or less (contraction) than the original size of
- * the block. The block is NOT moved. In the case of expansion, if the
- * block cannot be expanded to newsize bytes, it is expanded as much as
- * possible.
- *
- * Re-allocates any type of supported memory block.
- *
- *Entry:
- * void * pUserData - pointer to block in the heap previously allocated
- * by a call to malloc(), realloc() or _expand().
- *
- * size_t nNewSize - requested size for the resized block
- *
- *Exit:
- * Success: Pointer to the resized memory block (i.e., pUserData)
- * Failure: NULL
- *
- *Uses:
- *
- *Exceptions:
- * If pUserData does not point to a valid allocation block in the heap,
- * _expand() will behave unpredictably and probably corrupt the heap.
- *
- *******************************************************************************/
-
- _CRTIMP void * __cdecl _expand_dbg(
- void * pUserData,
- size_t nNewSize,
- int nBlockUse,
- const char * szFileName,
- int nLine
- )
- {
- void * pvBlk;
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- /* allocate the block
- */
- pvBlk = realloc_help(pUserData,
- nNewSize,
- nBlockUse,
- szFileName,
- nLine,
- FALSE);
-
- _munlock(_HEAP_LOCK); /* release other threads */
-
- return pvBlk;
- }
-
- /***
- *void free() - free a block in the debug heap
- *
- *Purpose:
- * Frees a 'normal' memory block.
- *
- *Entry:
- * void * pUserData - pointer to a (user portion) of memory block in the
- * debug heap
- *
- *Return:
- * <void>
- *
- *******************************************************************************/
- _CRTIMP void __cdecl free(
- void * pUserData
- )
- {
- _free_dbg(pUserData, _NORMAL_BLOCK);
- }
-
- #ifdef _MT
-
- void __cdecl _free_lk(
- void * pUserData
- )
- {
- _free_dbg_lk(pUserData, _NORMAL_BLOCK);
- }
-
- #endif /* _MT */
-
-
- /***
- *void _free_dbg() - free a block in the debug heap
- *
- *Purpose:
- * Frees any type of supported block.
- *
- *Entry:
- * void * pUserData - pointer to a (user portion) of memory block in the
- * debug heap
- * int nBlockUse - block type
- *
- *Return:
- * <void>
- *
- *******************************************************************************/
-
- #ifdef _MT
-
- _CRTIMP void __cdecl _free_dbg(
- void * pUserData,
- int nBlockUse
- )
- {
- /* lock the heap
- */
- _mlock(_HEAP_LOCK);
-
- /* allocate the block
- */
- _free_dbg_lk(pUserData, nBlockUse);
-
- /* unlock the heap
- */
- _munlock(_HEAP_LOCK);
- }
-
- void __cdecl _free_dbg_lk(
-
- #else /* _MT */
-
- _CRTIMP void __cdecl _free_dbg(
-
- #endif /* _MT */
-
- void * pUserData,
- int nBlockUse
- )
- {
- _CrtMemBlockHeader * pHead;
-
- /* verify heap before freeing */
- if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
- _ASSERTE(_CrtCheckMemory());
-
- if (pUserData == NULL)
- return;
-
- /* forced failure */
- if (!(*_pfnAllocHook)(_HOOK_FREE, pUserData, 0, nBlockUse, 0L, NULL, 0))
- {
- _RPT0(_CRT_WARN, "Client hook free failure.\n");
-
- return;
- }
-
- /*
- * If this ASSERT fails, a bad pointer has been passed in. It may be
- * totally bogus, or it may have been allocated from another heap.
- * The pointer MUST come from the 'local' heap.
- */
- _ASSERTE(_CrtIsValidHeapPointer(pUserData));
-
- /* get a pointer to memory block header */
- pHead = pHdr(pUserData);
-
- /* verify block type */
- _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
-
- /* if we didn't already check entire heap, at least check this object */
- if (!(_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF))
- {
- /* check no-mans-land gaps */
- if (!CheckBytes(pHead->gap, _bNoMansLandFill, nNoMansLandSize))
- _RPT3(_CRT_ERROR, "DAMAGE: before %hs block (#%d) at 0x%08X.\n",
- szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)],
- pHead->lRequest,
- (BYTE *) pbData(pHead));
-
- if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill, nNoMansLandSize))
- _RPT3(_CRT_ERROR, "DAMAGE: after %hs block (#%d) at 0x%08X.\n",
- szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)],
- pHead->lRequest,
- (BYTE *) pbData(pHead));
- }
-
- if (pHead->nBlockUse == _IGNORE_BLOCK)
- {
- _ASSERTE(pHead->nLine == IGNORE_LINE && pHead->lRequest == IGNORE_REQ);
- /* fill the entire block including header with dead-land-fill */
- memset(pHead, _bDeadLandFill,
- sizeof(_CrtMemBlockHeader) + pHead->nDataSize + nNoMansLandSize);
- _free_base(pHead);
- return;
- }
-
- /* CRT blocks can be freed as NORMAL blocks */
- if (pHead->nBlockUse == _CRT_BLOCK && nBlockUse == _NORMAL_BLOCK)
- nBlockUse = _CRT_BLOCK;
-
- /* Error if freeing incorrect memory type */
- _ASSERTE(pHead->nBlockUse == nBlockUse);
-
- /* keep track of total amount of memory allocated */
- _lCurAlloc -= pHead->nDataSize;
-
- /* optionally reclaim memory */
- if (!(_crtDbgFlag & _CRTDBG_DELAY_FREE_MEM_DF))
- {
- /* remove from the linked list */
- if (pHead->pBlockHeaderNext)
- {
- pHead->pBlockHeaderNext->pBlockHeaderPrev = pHead->pBlockHeaderPrev;
- }
- else
- {
- _ASSERTE(_pLastBlock == pHead);
- _pLastBlock = pHead->pBlockHeaderPrev;
- }
-
- if (pHead->pBlockHeaderPrev)
- {
- pHead->pBlockHeaderPrev->pBlockHeaderNext = pHead->pBlockHeaderNext;
- }
- else
- {
- _ASSERTE(_pFirstBlock == pHead);
- _pFirstBlock = pHead->pBlockHeaderNext;
- }
-
- /* fill the entire block including header with dead-land-fill */
- memset(pHead, _bDeadLandFill,
- sizeof(_CrtMemBlockHeader) + pHead->nDataSize + nNoMansLandSize);
- _free_base(pHead);
- }
- else
- {
- pHead->nBlockUse = _FREE_BLOCK;
-
- /* keep memory around as dead space */
- memset(pbData(pHead), _bDeadLandFill, pHead->nDataSize);
- }
- }
-
- /***
- *size_t _msize() - calculate the size of specified block in the heap
- *
- *Purpose:
- * Calculates the size of memory block (in the heap) pointed to by
- * pUserData.
- *
- * For 'normal' memory block.
- *
- *Entry:
- * void * pUserData - pointer to a memory block in the heap
- *
- *Return:
- * size of the block
- *
- *******************************************************************************/
-
- _CRTIMP size_t __cdecl _msize (
- void * pUserData
- )
- {
- return _msize_dbg(pUserData, _NORMAL_BLOCK);
- }
-
-
- /***
- *size_t _msize_dbg() - calculate the size of specified block in the heap
- *
- *Purpose:
- * Calculates the size of memory block (in the heap) pointed to by
- * pUserData.
- *
- *Entry:
- * void * pUserData - pointer to a (user portion) of memory block in the
- * debug heap
- * int nBlockUse - block type
- *
- * For any type of supported block.
- *
- *Return:
- * size of the block
- *
- *******************************************************************************/
-
- _CRTIMP size_t __cdecl _msize_dbg (
- void * pUserData,
- int nBlockUse
- )
- {
- size_t nSize;
- _CrtMemBlockHeader * pHead;
-
- /* verify heap before getting size */
- if (_crtDbgFlag & _CRTDBG_CHECK_ALWAYS_DF)
- _ASSERTE(_CrtCheckMemory());
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- /*
- * If this ASSERT fails, a bad pointer has been passed in. It may be
- * totally bogus, or it may have been allocated from another heap.
- * The pointer MUST come from the 'local' heap.
- */
- _ASSERTE(_CrtIsValidHeapPointer(pUserData));
-
- /* get a pointer to memory block header */
- pHead = pHdr(pUserData);
-
- /* verify block type */
- _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
-
- /* CRT blocks can be treated as NORMAL blocks */
- if (pHead->nBlockUse == _CRT_BLOCK && nBlockUse == _NORMAL_BLOCK)
- nBlockUse = _CRT_BLOCK;
-
- if (pHead->nBlockUse != _IGNORE_BLOCK)
- _ASSERTE(pHead->nBlockUse == nBlockUse);
-
- nSize = pHead->nDataSize;
-
- _munlock(_HEAP_LOCK); /* release other threads */
-
- return nSize;
- }
-
- /***
- *long _CrtSetBreakAlloc() - set allocation on which to break
- *
- *Purpose:
- * set allocation on which to break
- *
- *Entry:
- * long lBreakAlloc
- *
- *Exit:
- * return previous break number
- *
- *Exceptions:
- *
- *******************************************************************************/
- _CRTIMP long __cdecl _CrtSetBreakAlloc(
- long lNewBreakAlloc
- )
- {
- long lOldBreakAlloc = _crtBreakAlloc;
- _crtBreakAlloc = lNewBreakAlloc;
- return lOldBreakAlloc;
- }
-
- /***
- *void _CrtSetDbgBlockType() - change memory block type
- *
- *Purpose:
- * change memory block type
- *
- *Entry:
- * void * pUserData - pointer to a (user portion) of memory block in the
- * debug heap
- * int nBlockUse - block type
- *
- *Exit:
- *
- *Exceptions:
- *
- *******************************************************************************/
- _CRTIMP void __cdecl _CrtSetDbgBlockType(
- void * pUserData,
- int nBlockUse
- )
- {
- _CrtMemBlockHeader * pHead;
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- /* If from local heap, then change block type. */
- if (_CrtIsValidHeapPointer(pUserData))
- {
- /* get a pointer to memory block header */
- pHead = pHdr(pUserData);
-
- /* verify block type */
- _ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
-
- pHead->nBlockUse = nBlockUse;
- }
-
- _munlock(_HEAP_LOCK); /* release other threads */
-
- return;
- }
-
- /*---------------------------------------------------------------------------
- *
- * Client-defined allocation hook
- *
- --------------------------------------------------------------------------*/
-
- /***
- *_CRT_ALLOC_HOOK _CrtSetAllocHook() - set client allocation hook
- *
- *Purpose:
- * set client allocation hook
- *
- *Entry:
- * _CRT_ALLOC_HOOK pfnNewHook - new allocation hook
- *
- *Exit:
- * return previous hook
- *
- *Exceptions:
- *
- *******************************************************************************/
- _CRTIMP _CRT_ALLOC_HOOK __cdecl _CrtSetAllocHook(
- _CRT_ALLOC_HOOK pfnNewHook
- )
- {
- _CRT_ALLOC_HOOK pfnOldHook = _pfnAllocHook;
- _pfnAllocHook = pfnNewHook;
- return pfnOldHook;
- }
-
-
- /*---------------------------------------------------------------------------
- *
- * Memory management
- *
- --------------------------------------------------------------------------*/
-
- /***
- *static int CheckBytes() - verify byte range set to proper value
- *
- *Purpose:
- * verify byte range set to proper value
- *
- *Entry:
- * unsigned char *pb - pointer to start of byte range
- * unsigned char bCheck - value byte range should be set to
- * size_t nSize - size of byte range to be checked
- *
- *Return:
- * TRUE - if all bytes in range equal bcheck
- * FALSE otherwise
- *
- *******************************************************************************/
- static int __cdecl CheckBytes(
- unsigned char * pb,
- unsigned char bCheck,
- size_t nSize
- )
- {
- int bOkay = TRUE;
- while (nSize--)
- {
- if (*pb++ != bCheck)
- {
- _RPT3(_CRT_WARN, "memory check error at 0x%08X = 0x%02X, should be 0x%02X.\n",
- (BYTE *)(pb-1),*(pb-1), bCheck);
- bOkay = FALSE;
- }
- }
- return bOkay;
- }
-
-
- /***
- *int _CrtCheckMemory() - check heap integrity
- *
- *Purpose:
- * Confirm integrity of debug heap. Call _heapchk to validate underlying
- * heap.
- *
- *Entry:
- * void
- *
- *Return:
- * TRUE - if debug and underlying heap appear valid
- * FALSE otherwise
- *
- *******************************************************************************/
- _CRTIMP int __cdecl _CrtCheckMemory(
- void
- )
- {
- int allOkay = TRUE;
- int nHeapCheck;
- _CrtMemBlockHeader * pHead;
-
- if (!(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF))
- return TRUE; /* can't do any checking */
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- /* check underlying heap */
-
- nHeapCheck = _heapchk();
- if (nHeapCheck != _HEAPEMPTY && nHeapCheck != _HEAPOK)
- {
- switch (nHeapCheck)
- {
- case _HEAPBADBEGIN:
- _RPT0(_CRT_WARN, "_heapchk fails with _HEAPBADBEGIN.\n");
- break;
- case _HEAPBADNODE:
- _RPT0(_CRT_WARN, "_heapchk fails with _HEAPBADNODE.\n");
- break;
- case _HEAPEND:
- _RPT0(_CRT_WARN, "_heapchk fails with _HEAPBADEND.\n");
- break;
- case _HEAPBADPTR:
- _RPT0(_CRT_WARN, "_heapchk fails with _HEAPBADPTR.\n");
- break;
- default:
- _RPT0(_CRT_WARN, "_heapchk fails with unknown return value!\n");
- break;
- }
- _munlock(_HEAP_LOCK); /* release other threads */
- return FALSE;
- }
-
- /* check all allocated blocks */
-
- for (pHead = _pFirstBlock; pHead != NULL; pHead = pHead->pBlockHeaderNext)
- {
- int okay = TRUE; /* this block okay ? */
- unsigned char * blockUse;
-
- if (_BLOCK_TYPE_IS_VALID(pHead->nBlockUse))
- blockUse = szBlockUseName[_BLOCK_TYPE(pHead->nBlockUse)];
- else
- blockUse = "DAMAGED";
-
-
- /* check no-mans-land gaps */
- if (!CheckBytes(pHead->gap, _bNoMansLandFill, nNoMansLandSize))
- {
- _RPT3(_CRT_WARN, "DAMAGE: before %hs block (#%d) at 0x%08X.\n",
- blockUse, pHead->lRequest, (BYTE *) pbData(pHead));
- okay = FALSE;
- }
-
- if (!CheckBytes(pbData(pHead) + pHead->nDataSize, _bNoMansLandFill,
- nNoMansLandSize))
- {
- _RPT3(_CRT_WARN, "DAMAGE: after %hs block (#%d) at 0x%08X.\n",
- blockUse, pHead->lRequest, (BYTE *) pbData(pHead));
- okay = FALSE;
- }
-
- /* free blocks should remain undisturbed */
- if (pHead->nBlockUse == _FREE_BLOCK &&
- !CheckBytes(pbData(pHead), _bDeadLandFill, pHead->nDataSize))
- {
- _RPT1(_CRT_WARN, "DAMAGE: on top of Free block at 0x%08X.\n",
- (BYTE *) pbData(pHead));
- okay = FALSE;
- }
-
- if (!okay)
- {
- /* report some more statistics about the broken object */
-
- if (pHead->szFileName != NULL)
- _RPT3(_CRT_WARN, "%hs allocated at file %hs(%d).\n",
- blockUse, pHead->szFileName, pHead->nLine);
-
- _RPT3(_CRT_WARN, "%hs located at 0x%08X is %u bytes long.\n",
- blockUse, (BYTE *)pbData(pHead), pHead->nDataSize);
-
- allOkay = FALSE;
- }
- }
- _munlock(_HEAP_LOCK); /* release other threads */
-
- return allOkay;
- }
-
-
- /***
- *int _CrtSetDbgFlag() - get/set the _crtDbgFlag
- *
- *Purpose:
- * get or set the _crtDbgFlag
- *
- *Entry:
- * int bNewBits - new Flag or _CRTDBG_REPORT_FLAG
- *
- *Return:
- * previous flag state
- *
- *******************************************************************************/
- _CRTIMP int __cdecl _CrtSetDbgFlag(
- int fNewBits
- )
- {
- int fOldBits = _crtDbgFlag;
-
- if (fNewBits != _CRTDBG_REPORT_FLAG)
- _crtDbgFlag = fNewBits;
-
- return fOldBits;
- }
-
-
- /***
- *int _CrtDoForAllClientObjects() - call a client-supplied function for all
- * client objects in the heap
- *
- *Purpose:
- * call a client-supplied function for all client objects in the heap
- *
- *Entry:
- * void (*pfn)(void *, void *) - pointer to client function to call
- * void * pContext - pointer to user supplied context to pass to function
- *
- *Return:
- * void
- *
- *******************************************************************************/
- _CRTIMP void __cdecl _CrtDoForAllClientObjects(
- void (*pfn)(void *, void *),
- void * pContext
- )
- {
- _CrtMemBlockHeader * pHead;
-
- if (!(_crtDbgFlag & _CRTDBG_ALLOC_MEM_DF))
- return; /* sorry not enabled */
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- for (pHead = _pFirstBlock; pHead != NULL; pHead = pHead->pBlockHeaderNext)
- {
- if (_BLOCK_TYPE(pHead->nBlockUse) == _CLIENT_BLOCK)
- (*pfn)((void *) pbData(pHead), pContext);
- }
-
- _munlock(_HEAP_LOCK); /* release other threads */
- }
-
-
- /***
- *int _CrtIsValidPointer() - verify memory range is valid for reading/writing
- *
- *Purpose:
- * verify memory range range is valid for reading/writing
- *
- *Entry:
- * const void * pv - start of memory range to test
- * unsigned int nBytes - size of memory range
- * int bReadWrite - TRUE if read/write, FALSE if read-only
- *
- *Return:
- * TRUE - if valid address
- * FALSE otherwise
- *
- *******************************************************************************/
- _CRTIMP int __cdecl _CrtIsValidPointer(
- const void * pv,
- unsigned int nBytes,
- int bReadWrite
- )
- {
- return (
- pv != NULL
- #ifdef _WIN32
- && !IsBadReadPtr(pv, nBytes) &&
- (!bReadWrite || !IsBadWritePtr((LPVOID)pv, nBytes))
- #endif /* _WIN32 */
- );
- }
-
- /***
- *int _CrtIsValidHeapPointer() - verify pointer is from 'local' heap
- *
- *Purpose:
- * Verify pointer is not only a valid pointer but also that it is from
- * the 'local' heap. Pointers from another copy of the C runtime (even in the
- * same process) will be caught.
- *
- *Entry:
- * const void * pUserData - pointer of interest
- *
- *Return:
- * TRUE - if valid and from local heap
- * FALSE otherwise
- *
- *******************************************************************************/
- _CRTIMP int __cdecl _CrtIsValidHeapPointer(
- const void * pUserData
- )
- {
- #ifdef WINHEAP
- PHEADER pHeader;
- #else /* WINHEAP */
- int i;
- void * base;
- #endif /* WINHEAP */
-
- if (!pUserData)
- return FALSE;
-
- if (!_CrtIsValidPointer(pHdr(pUserData), sizeof(_CrtMemBlockHeader), TRUE))
- return FALSE;
-
- #ifdef WINHEAP
-
- if (pHeader = __sbh_find_block(pHdr(pUserData)))
- {
- return __sbh_verify_block(pHeader, pHdr(pUserData));
- }
- else if ( (_osver & 0x8000) != 0 )
- return TRUE;
- else
- return HeapValidate( _crtheap, 0, pHdr(pUserData) );
-
- #else /* WINHEAP */
-
- /*
- * Go through the heap regions and see if the pointer lies within one
- * of the regions of the local heap.
- *
- * Pointers from non-local heaps cannot be handled. For example, a
- * non-local pointer may come from a DLL that has the CRT linked-in.
- *
- */
-
- #ifdef _WIN32
- for (i = 0; (base = _heap_regions[i]._regbase) != NULL &&
- i < _HEAP_REGIONMAX; i++)
- {
- if (pUserData >= base && pUserData <
- (void *)(((char *)base)+_heap_regions[i]._currsize))
- return TRUE;
- }
- #else /* _WIN32 */
- {
- struct _heap_region_ *pHeapRegions
- = (struct _heap_region_ *)(*hHeapRegions);
-
- for (i = 0; (base = (pHeapRegions+i)->_regbase) != NULL &&
- i < _HEAP_REGIONMAX; i++)
- {
- if (pUserData >= base && pUserData <
- (void *)(((char *)base)+(pHeapRegions+i)->_currsize))
- return TRUE;
- }
- }
- #endif /* _WIN32 */
-
- return FALSE;
-
- #endif /* WINHEAP */
- }
-
-
- /***
- *int _CrtIsMemoryBlock() - verify memory block is debug heap block
- *
- *Purpose:
- * verify memory block is debug heap block
- *
- *Entry:
- * const void * pUserData - start of memory block
- * unsigned int nBytes - size of memory block
- * long * plRequestNumber - if !NULL, set to request number
- * char ** pszFileName - if !NULL, set to file name
- * int * pnLine - if !NULL, set to line number
- *
- *Return:
- * TRUE - if debug memory heap address
- * FALSE otherwise
- *
- *******************************************************************************/
- _CRTIMP int __cdecl _CrtIsMemoryBlock(
- const void * pUserData,
- unsigned int nBytes,
- long * plRequestNumber,
- char ** pszFileName,
- int * pnLine
- )
- {
- _CrtMemBlockHeader * pHead;
-
- if (!_CrtIsValidHeapPointer(pUserData))
- return FALSE;
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- pHead = pHdr(pUserData);
-
- if (_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) &&
- _CrtIsValidPointer(pUserData, nBytes, TRUE) &&
- pHead->nDataSize == nBytes &&
- pHead->lRequest <= _lRequestCurr
- )
- {
- if (plRequestNumber != NULL)
- *plRequestNumber = pHead->lRequest;
- if (pszFileName != NULL)
- *pszFileName = pHead->szFileName;
- if (pnLine != NULL)
- *pnLine = pHead->nLine;
-
- _munlock(_HEAP_LOCK); /* release other threads */
- return TRUE;
- }
-
- _munlock(_HEAP_LOCK); /* release other threads */
-
- return FALSE;
- }
-
-
- /*---------------------------------------------------------------------------
- *
- * Memory state
- *
- --------------------------------------------------------------------------*/
-
-
- /***
- *_CRT_DUMP_CLIENT _CrtSetDumpClient() - set client dump routine
- *
- *Purpose:
- * set client dump routine
- *
- *Entry:
- * _CRT_DUMP_CLIENT pfnNewDumpClient - new dump routine
- *
- *Exit:
- * return previous dump routine
- *
- *Exceptions:
- *
- *******************************************************************************/
- _CRTIMP _CRT_DUMP_CLIENT __cdecl _CrtSetDumpClient(
- _CRT_DUMP_CLIENT pfnNewDump
- )
- {
- _CRT_DUMP_CLIENT pfnOldDump = _pfnDumpClient;
- _pfnDumpClient = pfnNewDump;
- return pfnOldDump;
- }
-
-
- /***
- *_CrtMemState * _CrtMemStateCheckpoint() - checkpoint current memory state
- *
- *Purpose:
- * checkpoint current memory state
- *
- *Entry:
- * _CrtMemState * state - state structure to fill in, will be
- * allocated if NULL
- *
- *Return:
- * current memory state
- *
- *******************************************************************************/
- _CRTIMP void __cdecl _CrtMemCheckpoint(
- _CrtMemState * state
- )
- {
- int use;
- _CrtMemBlockHeader * pHead;
-
- if (state == NULL)
- {
- _RPT0(_CRT_WARN, "_CrtMemCheckPoint: NULL state pointer.\n");
- return;
- }
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- state->pBlockHeader = _pFirstBlock;
- for (use = 0; use < _MAX_BLOCKS; use++)
- state->lCounts[use] = state->lSizes[use] = 0;
-
- for (pHead = _pFirstBlock; pHead != NULL; pHead = pHead->pBlockHeaderNext)
- {
- if (_BLOCK_TYPE(pHead->nBlockUse) >= 0 && _BLOCK_TYPE(pHead->nBlockUse) < _MAX_BLOCKS)
- {
- state->lCounts[_BLOCK_TYPE(pHead->nBlockUse)]++;
- state->lSizes[_BLOCK_TYPE(pHead->nBlockUse)] += pHead->nDataSize;
- }
- else
- {
- _RPT1(_CRT_WARN, "Bad memory block found at 0x%08X.\n", (BYTE *)pHead);
- }
- }
-
- state->lHighWaterCount = _lMaxAlloc;
- state->lTotalCount = _lTotalAlloc;
-
- _munlock(_HEAP_LOCK); /* release other threads */
- }
-
-
- /***
- *int _CrtMemDifference() - compare two memory states
- *
- *Purpose:
- * compare two memory states
- *
- *Entry:
- * _CrtMemState * state - return memory state difference
- * _CrtMemState * oldState - earlier memory state
- * _CrtMemState * newState - later memory state
- *
- *Return:
- * TRUE if difference
- * FALSE otherwise
- *
- *******************************************************************************/
- _CRTIMP int __cdecl _CrtMemDifference(
- _CrtMemState * state,
- const _CrtMemState * oldState,
- const _CrtMemState * newState
- )
- {
- int use;
- int bSignificantDifference = FALSE;
-
- if (state == NULL || oldState == NULL || newState == NULL)
- {
- _RPT0(_CRT_WARN, "_CrtMemDifference: NULL state pointer.\n");
- return bSignificantDifference;
- }
-
- for (use = 0; use < _MAX_BLOCKS; use++)
- {
- state->lSizes[use] = newState->lSizes[use] - oldState->lSizes[use];
- state->lCounts[use] = newState->lCounts[use] - oldState->lCounts[use];
-
- if ( (state->lSizes[use] != 0 || state->lCounts[use] != 0) &&
- use != _FREE_BLOCK &&
- (use != _CRT_BLOCK ||
- (use == _CRT_BLOCK && (_crtDbgFlag & _CRTDBG_CHECK_CRT_DF)))
- )
- bSignificantDifference = TRUE;
- }
- state->lHighWaterCount = newState->lHighWaterCount - oldState->lHighWaterCount;
- state->lTotalCount = newState->lTotalCount - oldState->lTotalCount;
- state->pBlockHeader = NULL;
-
- return bSignificantDifference;
- }
-
- #define MAXPRINT 16
-
- static void __cdecl _printMemBlockData(
- _CrtMemBlockHeader * pHead
- )
- {
- int i;
- unsigned char ch;
- unsigned char printbuff[MAXPRINT+1];
- unsigned char valbuff[MAXPRINT*3+1];
-
- for (i = 0; i < min((int)pHead->nDataSize, MAXPRINT); i++)
- {
- ch = pbData(pHead)[i];
- printbuff[i] = isprint(ch) ? ch : ' ';
- sprintf(&valbuff[i*3], "%.2X ", ch);
- }
- printbuff[i] = '\0';
-
- _RPT2(_CRT_WARN, " Data: <%s> %s\n", printbuff, valbuff);
- }
-
-
- /***
- *void _CrtMemDumpAllObjectsSince() - dump all objects since memory state
- *
- *Purpose:
- * dump all objects since memory state
- *
- *Entry:
- * _CrtMemState * state - dump since this state
- *
- *Return:
- * void
- *
- *******************************************************************************/
- _CRTIMP void __cdecl _CrtMemDumpAllObjectsSince(
- const _CrtMemState * state
- )
- {
- _CrtMemBlockHeader * pHead;
- _CrtMemBlockHeader * pStopBlock = NULL;
-
- _mlock(_HEAP_LOCK); /* block other threads */
-
- _RPT0(_CRT_WARN, "Dumping objects ->\n");
-
- if (state)
- pStopBlock = state->pBlockHeader;
-
- for (pHead = _pFirstBlock; pHead != NULL && pHead != pStopBlock;
- pHead = pHead->pBlockHeaderNext)
- {
- if (_BLOCK_TYPE(pHead->nBlockUse) == _IGNORE_BLOCK ||
- _BLOCK_TYPE(pHead->nBlockUse) == _FREE_BLOCK ||
- (_BLOCK_TYPE(pHead->nBlockUse) == _CRT_BLOCK &&
- !(_crtDbgFlag & _CRTDBG_CHECK_CRT_DF))
- )
- {
- /* ignore it for dumping */
- }
- else {
- if (pHead->szFileName != NULL)
- {
- if (!_CrtIsValidPointer(pHead->szFileName, 1, FALSE))
- _RPT1(_CRT_WARN, "#File Error#(%d) : ", pHead->nLine);
- else
- _RPT2(_CRT_WARN, "%hs(%d) : ", pHead->szFileName, pHead->nLine);
- }
-
- _RPT1(_CRT_WARN, "{%ld} ", pHead->lRequest);
-
- if (_BLOCK_TYPE(pHead->nBlockUse) == _CLIENT_BLOCK)
- {
- _RPT3(_CRT_WARN, "client block at 0x%08X, subtype %x, %u bytes long.\n",
- (BYTE *)pbData(pHead), _BLOCK_SUBTYPE(pHead->nBlockUse), pHead->nDataSize);
-
- if (_pfnDumpClient)
- (*_pfnDumpClient)( (void *) pbData(pHead), pHead->nDataSize);
- else
- _printMemBlockData(pHead);
- }
- else if (pHead->nBlockUse == _NORMAL_BLOCK)
- {
- _RPT2(_CRT_WARN, "normal block at 0x%08X, %u bytes long.\n",
- (BYTE *)pbData(pHead), pHead->nDataSize);
-
- _printMemBlockData(pHead);
- }
- else if (_BLOCK_TYPE(pHead->nBlockUse) == _CRT_BLOCK)
- {
- _RPT3(_CRT_WARN, "crt block at 0x%08X, subtype %x, %u bytes long.\n",
- (BYTE *)pbData(pHead), _BLOCK_SUBTYPE(pHead->nBlockUse), pHead->nDataSize);
-
- _printMemBlockData(pHead);
- }
- }
- }
- _munlock(_HEAP_LOCK); /* release other threads */
-
- _RPT0(_CRT_WARN, "Object dump complete.\n");
- }
-
-
- /***
- *void _CrtMemDumpMemoryLeaks() - dump all objects still in heap
- *
- *Purpose:
- * dump all objects still in heap. used to detect memory leaks over the
- * life of a program
- *
- *Entry:
- * void
- *
- *Return:
- * TRUE if memory leaks
- * FALSE otherwise
- *
- *******************************************************************************/
- _CRTIMP int __cdecl _CrtDumpMemoryLeaks(
- void
- )
- {
- /* only dump leaks when there are in fact leaks */
- _CrtMemState msNow;
-
- _CrtMemCheckpoint(&msNow);
-
- if (msNow.lCounts[_CLIENT_BLOCK] != 0 ||
- msNow.lCounts[_NORMAL_BLOCK] != 0 ||
- (_crtDbgFlag & _CRTDBG_CHECK_CRT_DF &&
- msNow.lCounts[_CRT_BLOCK] != 0)
- )
- {
- /* difference detected: dump objects since start. */
- _RPT0(_CRT_WARN, "Detected memory leaks!\n");
-
- _CrtMemDumpAllObjectsSince(NULL);
- return TRUE;
- }
-
- return FALSE; /* no leaked objects */
- }
-
-
- /***
- *_CrtMemState * _CrtMemDumpStatistics() - dump memory state
- *
- *Purpose:
- * dump memory state
- *
- *Entry:
- * _CrtMemState * state - dump this state
- *
- *Return:
- * void
- *
- *******************************************************************************/
- _CRTIMP void __cdecl _CrtMemDumpStatistics(
- const _CrtMemState * state
- )
- {
- int use;
-
- if (state == NULL)
- return;
-
- for (use = 0; use < _MAX_BLOCKS; use++)
- {
- _RPT3(_CRT_WARN, "%ld bytes in %ld %hs Blocks.\n",
- state->lSizes[use], state->lCounts[use], szBlockUseName[use]);
- }
-
- _RPT1(_CRT_WARN, "Largest number used: %ld bytes.\n", state->lHighWaterCount);
- _RPT1(_CRT_WARN, "Total allocations: %ld bytes.\n", state->lTotalCount);
- }
-
-
- #endif /* _DEBUG */
-