/***
*dbgheap.c - Debug CRT Heap Functions
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Defines debug versions of heap functions.
*
*******************************************************************************/
#ifdef _DEBUG
#include <windows.h>
#include <winheap.h>
#include <ctype.h>
#include <dbgint.h>
#include <crtdbg.h>
#include <rtcsup.h>
#include <internal.h>
#include <limits.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <locale.h>
#include <mtdll.h>
#include <setlocal.h>
#pragma warning(disable:4390)
extern "C" void * __cdecl _heap_alloc_base (size_t size);
extern "C" static void * __cdecl _heap_alloc_dbg_impl(size_t nSize, int nBlockUse, const char * szFileName, int nLine, int * errno_tmp);
/*---------------------------------------------------------------------------
*
* Heap management
*
--------------------------------------------------------------------------*/
#define IGNORE_REQ 0L /* Request number for ignore block */
#define IGNORE_LINE 0xFEDCBABC /* Line number for ignore block */
#define _ALLOCATION_FILE_LINENUM "\nMemory allocated at %hs(%d).\n"
/*
* Bitfield flag that controls CRT heap behavior --
* default is to record all allocations (_CRTDBG_ALLOC_MEM_DF)
* AND check heap consistency on every alloc/dealloc (_CRTDBG_CHECK_ALWAYS_DF)
*/
extern "C" int _crtDbgFlag = _CRTDBG_ALLOC_MEM_DF | _CRTDBG_CHECK_DEFAULT_DF;
/*
* Size threshold for filling behavior. See _CrtSetDebugFillThreshold.
*/
extern "C" size_t __crtDebugFillThreshold = SIZE_MAX;
extern "C" int __crtDebugCheckCount = FALSE;
/*
* struct used by _aligned routines as block header.
*/
#define nAlignGapSize sizeof(void *)
typedef struct _AlignMemBlockHdr
{
void *pHead;
unsigned char Gap[nAlignGapSize];
} _AlignMemBlockHdr;
#define IS_2_POW_N(x) (((x)&(x-1)) == 0)
/*
* Statics governing how often _CrtCheckMemory is called.
*/
static unsigned check_frequency = _CRTDBG_CHECK_DEFAULT_DF >> 16;
static unsigned check_counter;
static long _lRequestCurr = 1; /* Current request number */
extern "C" _CRTIMP long _crtBreakAlloc = -1L; /* Break on allocation by request number */
static size_t _lTotalAlloc; /* Grand total - sum of all allocations */
static size_t _lCurAlloc; /* Total amount currently allocated */
static size_t _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.
* 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.
*
* _bAlignLandFill has been changed from 0xBD to 0xED, to ensure that
* 4 bytes of that (0xEDEDEDED) would give an inaccessible address under 3gb.
*/
static unsigned char _bNoMansLandFill = 0xFD; /* fill no-man's land with this */
static unsigned char _bAlignLandFill = 0xED; /* fill no-man's land for aligned routines */
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 const char * const szBlockUseName[_MAX_BLOCKS] = {
"Free",
"Normal",
"CRT",
"Ignore",
"Client",
};
extern "C" int __cdecl CheckBytes(unsigned char *, unsigned char, size_t);
/***
*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:
*
*******************************************************************************/
extern "C" _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);
RTCCALLBACK(_RTC_Allocate_hook, (res, nSize, 0));
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:
*
*******************************************************************************/
extern "C" void * __cdecl _nh_malloc (
size_t nSize,
int nhFlag
)
{
return _nh_malloc_dbg(nSize, nhFlag, _NORMAL_BLOCK, NULL, 0);
}
/***
*void * _nh_malloc_dbg_impl() - 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
* int * errno_tmp - pointer of the temporary errno
*
*Exit:
* Success: Pointer to (user portion of) memory block
* Failure: NULL
*
*Exceptions:
*
*******************************************************************************/
extern "C" static void * __cdecl _nh_malloc_dbg_impl (
size_t nSize,
int nhFlag,
int nBlockUse,
const char * szFileName,
int nLine,
int * errno_tmp
)
{
void * pvBlk;
for (;;)
{
/* do the allocation
*/
pvBlk = _heap_alloc_dbg_impl(nSize, nBlockUse, szFileName, nLine, errno_tmp);
if (pvBlk)
{
return pvBlk;
}
if (nhFlag == 0)
{
if (errno_tmp)
{
*errno_tmp = ENOMEM;
}
return