📄 dbgheap.c
字号:
/***
*dbgheap.c - Debug CRT Heap Functions
*
* Copyright (c) 1988-1998, 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
)
{
void *res = _nh_malloc_dbg(nSize, _newmode, _NORMAL_BLOCK, NULL, 0);
return res;
}
/***
*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
)
{
void *res = _nh_malloc_dbg(nSize, _newmode, nBlockUse, szFileName, nLine);
return res;
}
/***
*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 (;;)
{
#ifdef _MT
/* lock the heap
*/
_mlock(_HEAP_LOCK);
__try {
#endif /* _MT */
/* do the allocation
*/
pvBlk = _heap_alloc_dbg(nSize, nBlockUse, szFileName, nLine);
#ifdef _MT
}
__finally {
/* unlock the heap
*/
_munlock(_HEAP_LOCK);
}
#endif /* _MT */
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
)
{
void *res = _calloc_dbg(nNum, nSize, _NORMAL_BLOCK, NULL, 0);
return res;
}
/***
*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);
}
/***
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -