Hi
There is a small bug in GetStackTrace (in traceallocations.cpp) that causes the code to write data in nomans land. These lines:
if (index <= MAXSTACK) {
ranOffsets[index][0] = 0;
ranOffsets[index][1] = 0;
}
Should be:
if (index < MAXSTACK) {
ranOffsets[index][0] = 0;
ranOffsets[index][1] = 0;
}
In the code below this bug is fixed. I have also fixed a bug in LeakDump that corrupted the output. To the output I have also information about largest total allocation, largest single allocation and largest stack level usage.
New code for traceallocations.cpp:
#include "MemLeakFindDll.h"
#if defined(_DEBUG) && defined(WIN32) && defined(DETECT_LEAKS)
#include <windows.h>
#include <tchar.h>
#include <iostream>
#include <dbghelp.h>
#include <string>
#include <assert.h>
#include <WinNT.h>
using namespace std;
typedef std::basic_string<TCHAR, char_traits<TCHAR> > tcstring;
#define BUFFERSIZE 4096
#define MAXSTACK 50
#define NO_MANS_LAND_SIZE 16
#define NML_CHECK_EVERY 1000
#define NUM_LEVELS_TO_IGNORE 2
#define LEADING_NOMANSLAND_NUMBER_BYTE 0xbe
#define TAIL_NOMANSLAND_NUMBER_BYTE 0xed
#define MAGIC_NUMBER 0x55555555
void GetStackTrace(HANDLE hThread, DWORD64 ranOffsets[][2] );
void WriteStackTrace(DWORD64 ranOffsets[][2], tcstring& roOut);
void* TraceAlloc(size_t nSize);
void TraceDealloc(void* poMem);
USHORT (WINAPI *s_pfnCaptureStackBackTrace)(ULONG, ULONG, PVOID*, PULONG) = 0;
bool bTraceAlloactions = true;
static int nMaxStackLevelUsage = 0;
static size_t nCurrentMemoryUsage = 0;
static size_t nLargestMemoryUsage = 0;
static size_t nLargestAllocationSize = 0;
void OutputDebugStringFormat( LPCTSTR lpszFormat, ... )
{
TCHAR lpszBuffer[BUFFERSIZE];
va_list fmtList;
va_start( fmtList, lpszFormat );
_vstprintf_s( lpszBuffer, BUFFERSIZE, lpszFormat, fmtList );
va_end( fmtList );
::OutputDebugString( lpszBuffer );
}
void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut, rsize_t outSize )
{
#if defined(UNICODE)||defined(_UNICODE)
ULONG index = 0;
PCSTR lpAct = lpszIn;
for( ; ; lpAct++ )
{
lpszOut[index++] = (TCHAR)(*lpAct);
if ( *lpAct == 0 )
break;
}
#else
strcpy_s( lpszOut, outSize, lpszIn );
#endif
}
BOOL __stdcall myReadProcMem(
HANDLE hProcess,
DWORD64 qwBaseAddress,
PVOID lpBuffer,
DWORD nSize,
LPDWORD lpNumberOfBytesRead
) {
SIZE_T st;
BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);
*lpNumberOfBytesRead = (DWORD) st;
return bRet;
}
void InitSymbolPath( PSTR lpszSymbolPath, rsize_t symPathSize, PCSTR lpszIniPath )
{
CHAR lpszPath[BUFFERSIZE];
strcpy_s( lpszSymbolPath, symPathSize, "." );
if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
{
strcat_s( lpszSymbolPath, symPathSize, ";" );
strcat_s( lpszSymbolPath, symPathSize, lpszPath );
}
if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", lpszPath, BUFFERSIZE ) )
{
strcat_s( lpszSymbolPath, symPathSize, ";" );
strcat_s( lpszSymbolPath, symPathSize, lpszPath );
}
if ( GetEnvironmentVariableA( "SYSTEMROOT", lpszPath, BUFFERSIZE ) )
{
strcat_s( lpszSymbolPath, symPathSize, ";" );
strcat_s( lpszSymbolPath, symPathSize, lpszPath );
strcat_s( lpszSymbolPath, symPathSize, ";" );
strcat_s( lpszSymbolPath, symPathSize, lpszPath );
strcat_s( lpszSymbolPath, symPathSize, "\\System32" );
}
if ( lpszIniPath != NULL )
if ( lpszIniPath[0] != '\0' )
{
strcat_s( lpszSymbolPath, symPathSize, ";" );
strcat_s( lpszSymbolPath, symPathSize, lpszIniPath );
}
}
BOOL UninitSymInfo()
{
return SymCleanup( GetCurrentProcess() );
}
BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
{
CHAR lpszSymbolPath[BUFFERSIZE];
DWORD symOptions = SymGetOptions();
symOptions |= SYMOPT_LOAD_LINES;
symOptions &= ~SYMOPT_UNDNAME;
SymSetOptions( symOptions );
InitSymbolPath( lpszSymbolPath, sizeof(lpszSymbolPath), lpszInitialSymbolPath );
return SymInitialize( GetCurrentProcess(), lpszSymbolPath, TRUE);
}
BOOL GetModuleNameFromAddress( DWORD64 address, LPTSTR lpszModule, rsize_t lpszModuleSize )
{
BOOL ret = FALSE;
IMAGEHLP_MODULE64 moduleInfo;
::ZeroMemory( &moduleInfo, sizeof(moduleInfo) );
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
if ( SymGetModuleInfo64( GetCurrentProcess(), (DWORD)address, &moduleInfo ) )
{
PCSTR2LPTSTR( moduleInfo.ModuleName, lpszModule, lpszModuleSize );
ret = TRUE;
}
else
_tcscpy_s( lpszModule, lpszModuleSize, _T("?") );
return ret;
}
BOOL GetFunctionInfoFromAddresses( DWORD64 fnAddress, DWORD64 stackAddress, LPTSTR lpszSymbol, rsize_t lpszSymbolSize )
{
BOOL ret = FALSE;
DWORD dwDisp = 0;
DWORD dwSymSize = 10000;
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
LPTSTR lpszParamSep = NULL;
LPCTSTR lpszParsed = lpszUnDSymbol;
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
::ZeroMemory( pSym, dwSymSize );
pSym->SizeOfStruct = dwSymSize;
pSym->MaxNameLength = dwSymSize - sizeof(IMAGEHLP_SYMBOL);
_tcscpy_s( lpszSymbol, lpszSymbolSize, _T("?") );
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
{
UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
UNDNAME_COMPLETE |
UNDNAME_NO_THISTYPE |
UNDNAME_NO_SPECIAL_SYMS |
UNDNAME_NO_MEMBER_TYPE |
UNDNAME_NO_MS_KEYWORDS |
UNDNAME_NO_ACCESS_SPECIFIERS );
PCSTR2LPTSTR( lpszNonUnicodeUnDSymbol, lpszUnDSymbol, sizeof(lpszUnDSymbol) );
if ( _tcscmp(lpszUnDSymbol, _T("_WinMain@16")) == 0 )
_tcscpy_s(lpszUnDSymbol, sizeof(lpszUnDSymbol), _T("WinMain(HINSTANCE,HINSTANCE,LPCTSTR,int)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_main")) == 0 )
_tcscpy_s(lpszUnDSymbol, sizeof(lpszUnDSymbol), _T("main(int,TCHAR * *)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_mainCRTStartup")) == 0 )
_tcscpy_s(lpszUnDSymbol, sizeof(lpszUnDSymbol), _T("mainCRTStartup()"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_wmain")) == 0 )
_tcscpy_s(lpszUnDSymbol, sizeof(lpszUnDSymbol), _T("wmain(int,TCHAR * *,TCHAR * *)"));
else
if ( _tcscmp(lpszUnDSymbol, _T("_wmainCRTStartup")) == 0 )
_tcscpy_s(lpszUnDSymbol, sizeof(lpszUnDSymbol), _T("wmainCRTStartup()"));
lpszSymbol[0] = _T('\0');
if (_tcschr( lpszParsed, _T('<') ) == NULL) {
if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
{
ULONG index = 0;
for( ; ; index++ )
{
lpszParamSep = const_cast<LPTSTR>(_tcschr( lpszParsed, _T(',') ));
if ( lpszParamSep == NULL )
break;
*lpszParamSep = _T('\0');
_tcscat_s( lpszSymbol, lpszSymbolSize, lpszParsed );
_stprintf_s( lpszSymbol + _tcslen(lpszSymbol), lpszSymbolSize-_tcslen(lpszSymbol), _T("=0x%08X,"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
}
lpszParamSep = const_cast<LPTSTR>(_tcschr( lpszParsed, _T(')') ));
if ( lpszParamSep != NULL )
{
*lpszParamSep = _T('\0');
_tcscat_s( lpszSymbol, lpszSymbolSize, lpszParsed );
_stprintf_s( lpszSymbol + _tcslen(lpszSymbol), lpszSymbolSize - _tcslen(lpszSymbol), _T("=0x%08X)"), *((ULONG*)(stackAddress) + 2 + index) );
lpszParsed = lpszParamSep + 1;
}
}
}
_tcscat_s( lpszSymbol, lpszSymbolSize, lpszParsed );
ret = TRUE;
}
GlobalFree( pSym );
return ret;
}
BOOL GetSourceInfoFromAddress( DWORD64 address, LPTSTR lpszSourceInfo, rsize_t lpszSourceInfoSize )
{
BOOL ret = FALSE;
IMAGEHLP_LINE64 lineInfo;
DWORD dwDisp;
TCHAR lpszFileName[BUFFERSIZE] = _T("");
TCHAR lpModuleInfo[BUFFERSIZE] = _T("");
_tcscpy_s( lpszSourceInfo, lpszSourceInfoSize, _T("?(?)") );
::ZeroMemory( &lineInfo, sizeof( lineInfo ) );
lineInfo.SizeOfStruct = sizeof( lineInfo );
if ( SymGetLineFromAddr64( GetCurrentProcess(), address, &dwDisp, &lineInfo ) )
{
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName, sizeof(lpszFileName) );
_stprintf_s( lpszSourceInfo, lpszSourceInfoSize, _T("%s(%d)"), lpszFileName, lineInfo.LineNumber );
ret = TRUE;
}
else
{
GetModuleNameFromAddress( address, lpModuleInfo, sizeof(lpModuleInfo) );
if ( lpModuleInfo[0] == _T('?') || lpModuleInfo[0] == _T('\0'))
_stprintf_s( lpszSourceInfo, lpszSourceInfoSize, _T("0x%08X"), lpModuleInfo, address );
else
_stprintf_s( lpszSourceInfo, lpszSourceInfoSize, _T("%s!0x%08X"), lpModuleInfo, address );
ret = FALSE;
}
return ret;
}
void GetStackTrace(HANDLE hThread, DWORD64 ranOffsets[][2])
{
#ifndef STACKWALK_PRECISE
if (s_pfnCaptureStackBackTrace) {
void* stacktrace[MAXSTACK+1];
int capcount = s_pfnCaptureStackBackTrace(NUM_LEVELS_TO_IGNORE, MAXSTACK, stacktrace, NULL);
int index;
for (index = 0; index < capcount; index++) {
ranOffsets[index][0] = (DWORD64) stacktrace[index];
ranOffsets[index][1] = (DWORD64) stacktrace[index];
}
if (index < MAXSTACK) {
ranOffsets[index][0] = 0;
ranOffsets[index][1] = 0;
}
if( capcount > nMaxStackLevelUsage )
nMaxStackLevelUsage = capcount;
}
#else
STACKFRAME64 callStack;
BOOL bResult;
CONTEXT context;
HANDLE hProcess = GetCurrentProcess();
memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_FULL;
if (hThread == GetCurrentThread())
{
RtlCaptureContext(&context);
}
else
{
if ( SuspendThread( hThread ) == -1 )
{
OutputDebugStringFormat( _T("Call stack info(thread=0x%X) SuspendThread failed.\n") );
return;
}
if (GetThreadContext(hThread, &context) == FALSE)
{
OutputDebugStringFormat( _T("Call stack info(thread=0x%X) GetThreadContext failed.\n") );
ResumeThread(hThread);
return;
}
}
::ZeroMemory( &callStack, sizeof(callStack) );
DWORD imageType;
#ifdef _M_IX86
imageType = IMAGE_FILE_MACHINE_I386;
callStack.AddrPC.Offset = context.Eip;
callStack.AddrPC.Mode = AddrModeFlat;
callStack.AddrFrame.Offset = context.Ebp;
callStack.AddrFrame.Mode = AddrModeFlat;
callStack.AddrStack.Offset = context.Esp;
callStack.AddrStack.Mode = AddrModeFlat;
#elif _M_X64
imageType = IMAGE_FILE_MACHINE_AMD64;
callStack.AddrPC.Offset = context.Rip;
callStack.AddrPC.Mode = AddrModeFlat;
callStack.AddrFrame.Offset = context.Rsp;
callStack.AddrFrame.Mode = AddrModeFlat;
callStack.AddrStack.Offset = context.Rsp;
callStack.AddrStack.Mode = AddrModeFlat;
#elif _M_IA64
imageType = IMAGE_FILE_MACHINE_IA64;
callStack.AddrPC.Offset = context.StIIP;
callStack.AddrPC.Mode = AddrModeFlat;
callStack.AddrFrame.Offset = context.IntSp;
callStack.AddrFrame.Mode = AddrModeFlat;
callStack.AddrBStore.Offset = context.RsBSP;
callStack.AddrBStore.Mode = AddrModeFlat;
callStack.AddrStack.Offset = context.IntSp;
callStack.AddrStack.Mode = AddrModeFlat;
#else
#error "Platform not supported!"
#endif
for( ULONG index = 0;; index++ )
{
bResult = StackWalk64(
imageType,
hProcess,
hThread,
&callStack,
&context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL);
if ( index < NUM_LEVELS_TO_IGNORE )
continue;
if ( index-NUM_LEVELS_TO_IGNORE == MAXSTACK)
break;
if( !bResult || callStack.AddrFrame.Offset == 0) {
ranOffsets[index-NUM_LEVELS_TO_IGNORE][0] = 0;
ranOffsets[index-NUM_LEVELS_TO_IGNORE][1] = 0;
break;
}
ranOffsets[index-NUM_LEVELS_TO_IGNORE][0] = callStack.AddrPC.Offset;
ranOffsets[index-NUM_LEVELS_TO_IGNORE][1] = callStack.AddrFrame.Offset;
}
if ( hThread != GetCurrentThread() )
ResumeThread( hThread );
#endif
}
void WriteStackTrace(DWORD64 ranOffsets[][2], tcstring& roOut)
{
TCHAR symInfo[BUFFERSIZE] = _T("?");
TCHAR srcInfo[BUFFERSIZE] = _T("?");
for (ULONG index = 0; index < MAXSTACK && ranOffsets[index][0] != 0 && ranOffsets[index][1] != 0; index++) {
GetFunctionInfoFromAddresses( ranOffsets[index][0], ranOffsets[index][1], symInfo, sizeof(symInfo) );
GetSourceInfoFromAddress( ranOffsets[index][0], srcInfo, sizeof(srcInfo) );
roOut += _T(" ");
roOut += srcInfo;
roOut += _T(" : ");
roOut += symInfo;
roOut += _T("\n");
}
}
struct sdAllocBlock {
unsigned long nMagicNumber;
sdAllocBlock* poNext;
sdAllocBlock* poPrev;
size_t nSize;
DWORD64 anStack[MAXSTACK][2];
char pzNoMansLand[NO_MANS_LAND_SIZE];
sdAllocBlock()
{
Init();
}
void Init() {
poNext = this;
poPrev = this;
nMagicNumber = MAGIC_NUMBER;
}
void Disconnect() {
if (poNext != this) {
poNext->poPrev = poPrev;
poPrev->poNext = poNext;
poNext = this;
poPrev = this;
}
}
void ConnectTo(sdAllocBlock* poPos) {
Disconnect();
poPrev = poPos;
poNext = poPos->poNext;
poPos->poNext->poPrev = this;
poPos->poNext = this;
}
};
void LeakDump(tcstring& roOut);
class CS {
private:
CRITICAL_SECTION cs;
public:
CS() { InitializeCriticalSection(&cs); }
~CS() { }
operator CRITICAL_SECTION& () { return cs; }
};
class Guard {
private:
CRITICAL_SECTION& rcs;
public:
Guard(CRITICAL_SECTION& rcs)
: rcs(rcs) { EnterCriticalSection(&rcs); }
~Guard() { LeaveCriticalSection(&rcs); }
};
class cLeakDetector
{
public:
cLeakDetector() {
if (s_pfnCaptureStackBackTrace == 0) {
const HMODULE hNtDll = ::GetModuleHandle("ntdll.dll");
reinterpret_cast<void*&>(s_pfnCaptureStackBackTrace) = ::GetProcAddress(hNtDll, "RtlCaptureStackBackTrace");
}
InitSymInfo(NULL);
}
~cLeakDetector() {
bTraceAlloactions = false;
tcstring leaks;
LeakDump(leaks);
OutputDebugString(leaks.c_str());
Sleep(1000);
UninitSymInfo();
}
};
static unsigned int nNumAllocs = 0;
static unsigned int nCurrentAllocs = 0;
static unsigned int nMaxConcurrent = 0;
CS& Gate() {
static CS cs;
return cs;
}
sdAllocBlock& Head()
{
static cLeakDetector oDetector;
static sdAllocBlock oHead;
return oHead;
}
class cInitializer {
public: cInitializer() { Head(); };
} oInitalizer;
void LeakDump(tcstring& roOut)
{
Guard at(Gate());
TCHAR buffer[65];
int leakCount = 0;
sdAllocBlock* poBlock = Head().poNext;
while (poBlock != &Head()) {
tcstring stack;
WriteStackTrace(poBlock->anStack, stack);
bool bIsKnownLeak = false;
if (stack.find(_T(": afxMap")) != tcstring::npos)
bIsKnownLeak = true;
if (!bIsKnownLeak) {
roOut += _T("\nLeak of ");
_itot_s(poBlock->nSize, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T(" bytes detected (");
_itot_s(poBlock->nSize + sizeof(sdAllocBlock) + NO_MANS_LAND_SIZE, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T(" bytes with headers and no mans land)\n");
roOut += stack;
leakCount++;
}
poBlock = poBlock->poNext;
}
roOut += _T("\nMemory statistics\n-----------------\n");
if( leakCount > 0 )
{
roOut += _T("Number of leaks: ");
_itot_s(leakCount, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T("\n");
}
roOut += _T("Total allocations: ");
_itot_s(nNumAllocs, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T("\n");
roOut += _T("Max concurrent allocations: ");
_itot_s(nMaxConcurrent, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T("\n");
roOut += _T("Largest total allocations: ");
_itot_s(nLargestMemoryUsage, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T("\n");
roOut += _T("Largest single allocation: ");
_itot_s(nLargestAllocationSize, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T("\n");
roOut += _T("Max stack level usage: ");
_itot_s(nMaxStackLevelUsage, buffer, sizeof(buffer), 10);
roOut += buffer;
roOut += _T("\n\n");
}
bool AssertMem(char* m, char c, size_t s)
{
size_t i;
for (i = 0; i < s; i++)
if (m[i] != c) break;
return i >= s;
}
void CheckNoMansLand()
{
Guard at(Gate());
sdAllocBlock* poBlock = Head().poNext;
while (poBlock != &Head()) {
if (!AssertMem(poBlock->pzNoMansLand, (char) LEADING_NOMANSLAND_NUMBER_BYTE, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD = false;
tcstring stack;
WriteStackTrace(poBlock->anStack, stack);
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD);
}
char* pzNoMansLand = ((char*)poBlock) + sizeof(sdAllocBlock) + poBlock->nSize;
if (!AssertMem(pzNoMansLand, (char) TAIL_NOMANSLAND_NUMBER_BYTE, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL = false;
tcstring stack;
WriteStackTrace(poBlock->anStack, stack);
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL);
}
poBlock = poBlock->poNext;
}
}
void* TraceAlloc(size_t nSize)
{
Guard at(Gate());
if (bTraceAlloactions) {
nNumAllocs++;
#ifdef DETECT_OVERWRITES
if (nNumAllocs % NML_CHECK_EVERY == 0) {
CheckNoMansLand();
}
#endif
sdAllocBlock* poBlock = (sdAllocBlock*) malloc(nSize + sizeof(sdAllocBlock) + NO_MANS_LAND_SIZE);
poBlock->Init();
poBlock->nSize = nSize;
char* pzNoMansLand = ((char*)poBlock) + sizeof(sdAllocBlock) + poBlock->nSize;
memset(poBlock->pzNoMansLand, LEADING_NOMANSLAND_NUMBER_BYTE, NO_MANS_LAND_SIZE);
memset(pzNoMansLand, TAIL_NOMANSLAND_NUMBER_BYTE, NO_MANS_LAND_SIZE);
GetStackTrace(GetCurrentThread(), poBlock->anStack );
poBlock->ConnectTo(&Head());
nCurrentAllocs++;
if (nCurrentAllocs > nMaxConcurrent)
nMaxConcurrent = nCurrentAllocs;
nCurrentMemoryUsage += nSize;
if( nLargestMemoryUsage < nCurrentMemoryUsage )
nLargestMemoryUsage = nCurrentMemoryUsage;
if( nLargestAllocationSize < nSize )
nLargestAllocationSize = nSize;
return (void*)(((char*) poBlock) + sizeof(sdAllocBlock));
}
else {
return malloc(nSize);
}
}
void TraceDealloc(void* poMem)
{
Guard at(Gate());
if (!poMem) return;
if (bTraceAlloactions) {
sdAllocBlock* poBlock = (sdAllocBlock*) ((char*)poMem - sizeof(sdAllocBlock));
char* pzNoMansLand = ((char*)poBlock) + sizeof(sdAllocBlock) + poBlock->nSize;
nCurrentMemoryUsage -= poBlock->nSize;
if (poBlock->nMagicNumber != MAGIC_NUMBER) {
sdAllocBlock* poLoopBlock = Head().poNext;
while (poLoopBlock != &Head() && poLoopBlock != poBlock)
poLoopBlock = poLoopBlock->poNext;
if (poLoopBlock == &Head()) {
free(poMem);
}
else {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD = false;
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD);
}
}
else if (!AssertMem(poBlock->pzNoMansLand, (char) LEADING_NOMANSLAND_NUMBER_BYTE, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD = false;
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_LEAD);
}
else if (!AssertMem(pzNoMansLand, (char) TAIL_NOMANSLAND_NUMBER_BYTE, NO_MANS_LAND_SIZE)) {
bool MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL = false;
assert(MEMORYERROR_STUFF_WRITTEN_IN_NOMANSLAND_TAIL);
}
else {
poBlock->Disconnect();
free(poBlock);
nCurrentAllocs--;
}
}
else {
free(poMem);
}
}
void* operator new(size_t s)
{
return TraceAlloc(s);
}
void* operator new[](size_t s)
{
return TraceAlloc(s);
}
void operator delete(void* pMem)
{
TraceDealloc(pMem);
}
void operator delete[] (void* pMem)
{
TraceDealloc(pMem);
}
void* __cdecl operator new(size_t s, LPCSTR lpszFileName, int nLine)
{
return TraceAlloc(s);
}
void* __cdecl operator new[](size_t s, LPCSTR lpszFileName, int nLine)
{
return TraceAlloc(s);
}
void __cdecl operator delete(void* pMem, LPCSTR , int )
{
TraceDealloc(pMem);
}
void __cdecl operator delete[](void* pMem, LPCSTR , int )
{
TraceDealloc(pMem);
}
#endif
|