我们可以通过这个技术分析内存泄漏的调用函数和位置。
#include <Windows.h>
#include <ImageHlp.h>
#include <iostream>
#include <string>
#include <atlutil.h>
#include <memory>
#pragma comment(lib, "ImageHlp.lib")
LONG DumpExceptStack(LPEXCEPTION_POINTERS pException_);
void TriggerDump();
void* __CRTDECL operator new(size_t const size)
{
TriggerDump();
for (;;)
{
if (void* const block = malloc(size))
{
return block;
}
if (_callnewh(size) == 0)
{
if (size == SIZE_MAX)
{
throw std::exception("bad alloc, SIZE_MAX");
}
else
{
throw std::exception("bad alloc");
}
}
}
}
int main()
{
std::cout << "new operator track back" << std::endl;;
char* sz = new char;
delete[] sz;
sz = new char[24];
delete[] sz;
}
#ifndef STATUS_POSSIBLE_DEADLOCK
#define STATUS_POSSIBLE_DEADLOCK ((DWORD)0xC0000194L)
#endif
struct SExceptDescTabe
{
DWORD dwCode;
const char* szDesc;
}g_ExceptDescTable[] =
{
{ EXCEPTION_ACCESS_VIOLATION, ("EXCEPTION_ACCESS_VIOLATION")},
{ EXCEPTION_DATATYPE_MISALIGNMENT, ("EXCEPTION_DATATYPE_MISALIGNMENT")},
{ EXCEPTION_BREAKPOINT, ("EXCEPTION_BREAKPOINT")},
{ EXCEPTION_SINGLE_STEP, ("EXCEPTION_SINGLE_STEP")},
{ EXCEPTION_ARRAY_BOUNDS_EXCEEDED, ("EXCEPTION_ARRAY_BOUNDS_EXCEEDED")},
{ EXCEPTION_FLT_DENORMAL_OPERAND, ("EXCEPTION_FLT_DENORMAL_OPERAND")},
{ EXCEPTION_FLT_DIVIDE_BY_ZERO, ("EXCEPTION_FLT_DIVIDE_BY_ZERO")},
{ EXCEPTION_FLT_INEXACT_RESULT, ("EXCEPTION_FLT_INEXACT_RESULT")},
{ EXCEPTION_FLT_INVALID_OPERATION, ("EXCEPTION_FLT_INVALID_OPERATION")},
{ EXCEPTION_FLT_OVERFLOW, ("EXCEPTION_FLT_OVERFLOW")},
{ EXCEPTION_FLT_STACK_CHECK, ("EXCEPTION_FLT_STACK_CHECK")},
{ EXCEPTION_FLT_UNDERFLOW, ("EXCEPTION_FLT_UNDERFLOW")},
{ EXCEPTION_INT_DIVIDE_BY_ZERO, ("EXCEPTION_INT_DIVIDE_BY_ZERO")},
{ EXCEPTION_INT_OVERFLOW, ("EXCEPTION_INT_OVERFLOW")},
{ EXCEPTION_PRIV_INSTRUCTION, ("EXCEPTION_PRIV_INSTRUCTION")},
{ EXCEPTION_IN_PAGE_ERROR, ("EXCEPTION_IN_PAGE_ERROR")},
{ EXCEPTION_ILLEGAL_INSTRUCTION, ("EXCEPTION_ILLEGAL_INSTRUCTION")},
{ EXCEPTION_NONCONTINUABLE_EXCEPTION, ("EXCEPTION_NONCONTINUABLE_EXCEPz`TION")},
{ EXCEPTION_STACK_OVERFLOW, ("EXCEPTION_STACK_OVERFLOW")},
{ EXCEPTION_INVALID_DISPOSITION, ("EXCEPTION_INVALID_DISPOSITION")},
{ EXCEPTION_GUARD_PAGE, ("EXCEPTION_GUARD_PAGE")},
{ EXCEPTION_INVALID_HANDLE, ("EXCEPTION_INVALID_HANDLE")},
{ EXCEPTION_POSSIBLE_DEADLOCK, ("EXCEPTION_POSSIBLE_DEADLOCK")},
};
struct FunctionCall
{
char FunctionName[128];
char FileName[512];
int LineNumber;
};
void TriggerDump()
{
std::cout << "\n\n----------call stack---------\n" << std::endl;
__try
{
RaiseException(0xC0000194L + 12, 0, 0, NULL);
}
__except (DumpExceptStack(GetExceptionInformation()), 1)
{
}
}
LONG DumpExceptStack(LPEXCEPTION_POINTERS pException_)
{
char _strStack[8192];
_strStack[0] = '\0';
CONTEXT* _pContext;
CONTEXT _ctxt;
memset(&_ctxt, 0, sizeof(_ctxt));
if (!pException_)
{
return 0;
#if 0
#if defined(_WIN64)
__asm mov _ctxt.Rsp, RSP;
__asm mov _ctxt.Rbp, RBP;
#elif defined(WIN32)
__asm mov _ctxt.Esp, Esp;
__asm mov _ctxt.Ebp, Ebp;
#endif
#endif
_pContext = &_ctxt;
}
else
_pContext = pException_->ContextRecord;
// Initialize stack frame
STACKFRAME64 sf;
memset(&sf, 0, sizeof(STACKFRAME));
#if defined(_WIN64)
sf.AddrPC.Offset = _pContext->Rip;
sf.AddrStack.Offset = _pContext->Rsp;
sf.AddrFrame.Offset = _pContext->Rbp;
#elif defined(WIN32)
sf.AddrPC.Offset = _pContext->Eip;
sf.AddrStack.Offset = _pContext->Esp;
sf.AddrFrame.Offset = _pContext->Ebp;
#endif
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Mode = AddrModeFlat;
DWORD _dwMachineType = 0;
char* chArchVar;
size_t requiredSize;
getenv_s(&requiredSize, NULL, 0, "PROCESSOR_ARCHITECTURE");
chArchVar = (char*)malloc(requiredSize * sizeof(char));
getenv_s(&requiredSize, chArchVar, requiredSize, "PROCESSOR_ARCHITECTURE");
if (chArchVar)
{
if ((!strcmp("EM64T", chArchVar)) || !strcmp("AMD64", chArchVar))
_dwMachineType = IMAGE_FILE_MACHINE_AMD64;
else if (!strcmp("x86", chArchVar))
_dwMachineType = IMAGE_FILE_MACHINE_I386;
}
free(chArchVar);
if (0 == _dwMachineType)
return EXCEPTION_EXECUTE_HANDLER;
DWORD _dwCode = pException_ ? pException_->ExceptionRecord->ExceptionCode : 0;
int _nTableCount = sizeof(g_ExceptDescTable) / sizeof(g_ExceptDescTable[0]);
bool _bFind = false;
for (int _i = 0; _i < _nTableCount; ++_i)
{
if (_dwCode == g_ExceptDescTable[_i].dwCode)
{
strcat(_strStack, g_ExceptDescTable[_i].szDesc);
strcat(_strStack, "\r\n");
_bFind = true;
break;
}
}
char _sz[256];
if (!_bFind)
{
sprintf_s(_sz, "except code: 0x%x\r\n", _dwCode);
strcat(_strStack, _sz);
}
// Walk through the stack frames.
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
if (!SymInitialize(GetCurrentProcess(), NULL, TRUE))
{
SymCleanup(hProcess);
return EXCEPTION_EXECUTE_HANDLER;
}
while (StackWalk64(_dwMachineType, hProcess, hThread, &sf, _pContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0))
{
if (sf.AddrFrame.Offset == 0)
break;
// 1. Get function name at the address
const int nBuffSize = (sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64);
ULONG64 symbolBuffer[nBuffSize];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
FunctionCall curCall;
curCall.FunctionName[0] = '\0';
curCall.FileName[0] = '\0';
curCall.LineNumber = 0;
DWORD64 dwSymDisplacement = 0;
if (SymFromAddr(hProcess, sf.AddrPC.Offset, &dwSymDisplacement, pSymbol))
{
strcpy(curCall.FunctionName, pSymbol->Name);
}
//2. get line and file name at the address
IMAGEHLP_LINE64 lineInfo = { sizeof(IMAGEHLP_LINE64) };
DWORD dwLineDisplacement = 0;
if (SymGetLineFromAddr64(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo))
{
strcpy(curCall.FileName, (lineInfo.FileName));
curCall.LineNumber = lineInfo.LineNumber;
}
CStackDumper::_ATL_SYMBOL_INFO info;
sprintf_s(_sz, "%llX: ", sf.AddrPC.Offset);
strcat(_strStack, _sz);
if (CStackDumper::ResolveSymbol(hProcess, UINT_PTR(sf.AddrPC.Offset), info))
{
strcat(_strStack, info.szModule);
strcat(_strStack, " ");
strcat(_strStack, info.szSymbol);
strcat(_strStack, "\r\n");
}
else
strcat(_strStack, "symbol not found");
strcat(_strStack, "File: ");
strcat(_strStack, curCall.FileName);
strcat(_strStack, "\r\n");
strcat(_strStack, "Func: ");
strcat(_strStack, curCall.FunctionName);
strcat(_strStack, "\r\n");
sprintf_s(_sz, "Line: %d", curCall.LineNumber);
strcat(_strStack, _sz);
strcat(_strStack, "\r\n\r\n");
}
SymCleanup(hProcess);
std::cout << _strStack << std::endl;
return EXCEPTION_EXECUTE_HANDLER;
}