当前位置:网站首页>VC开发非MFC程序内存泄漏跟踪代码
VC开发非MFC程序内存泄漏跟踪代码
2022-07-05 13:56:00 【joshua0137】
在可执行模块源码中重写new和delete函数,在里面插入跟踪代码,程序最后t退出前保存统计信息。下面的代码基本能解决问题,但程序运行时较慢,作为测试时使用可以满足要求。
namespace foundation
{
std::string MemleakNewDump()
{
DWORD id = ::GetCurrentThreadId();
HANDLE h = OpenThread(
THREAD_GET_CONTEXT,
TRUE,
id
); //获得真实句柄
std::string strStack;
std::thread th([&] {
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_ALL;
::SuspendThread(h);
::GetThreadContext(h, &ctx);
MINIDUMP_EXCEPTION_INFORMATION eInfo;
EXCEPTION_POINTERS excpInfo;
excpInfo.ExceptionRecord = NULL;
excpInfo.ContextRecord = &ctx;
eInfo.ThreadId = GetCurrentThreadId();
eInfo.ExceptionPointers = &excpInfo;
eInfo.ClientPointers = FALSE;
strStack.clear();
// Initialize stack frame
STACKFRAME64 sf;
memset(&sf, 0, sizeof(STACKFRAME));
#if defined(_WIN64)
sf.AddrPC.Offset = ctx.Rip;
sf.AddrStack.Offset = ctx.Rsp;
sf.AddrFrame.Offset = ctx.Rbp;
#elif defined(WIN32)
sf.AddrPC.Offset = ctx.Eip;
sf.AddrStack.Offset = ctx.Esp;
sf.AddrFrame.Offset = ctx.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;
DWORD _dwCode = 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)
{
strStack += g_ExceptDescTable[_i].szDesc;
strStack += "\r\n";
_bFind = true;
break;
}
}
char _sz[256];
if (!_bFind)
{
sprintf_s(_sz, "cxx except code: 0x%x\r\n", _dwCode);
strStack += _sz;
}
// Walk through the stack frames.
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
if (!SymInitialize(hProcess, NULL, TRUE))
{
SymCleanup(hProcess);
return;
}
while (StackWalk64(_dwMachineType, hProcess, hThread, &sf, &ctx, 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 = "";
curCall.FileName = "";
curCall.LineNumber = 0;
DWORD64 dwSymDisplacement = 0;
if (SymFromAddr(hProcess, sf.AddrPC.Offset, &dwSymDisplacement, pSymbol))
{
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))
{
curCall.FileName = (lineInfo.FileName);
curCall.LineNumber = lineInfo.LineNumber;
}
CStackDumper::_ATL_SYMBOL_INFO info;
sprintf_s(_sz, "%016I64X: ", sf.AddrPC.Offset);
strStack += _sz;
if (CStackDumper::ResolveSymbol(hProcess, UINT_PTR(sf.AddrPC.Offset), info))
{
strStack += info.szModule;
strStack += " ";
strStack += info.szSymbol;
strStack += "\r\n";
}
else
strStack += "symbol not found";
strStack += "File: ";
strStack += curCall.FileName;
strStack += "\r\n";
strStack += "Func: ";
strStack += curCall.FunctionName;
strStack += "\r\n";
sprintf_s(_sz, "Line: %d", curCall.LineNumber);
strStack += _sz;
strStack += "\r\n\r\n";
}
SymCleanup(hProcess);
::ResumeThread(h);
::CloseHandle(h);
});
th.join();
return strStack;
}
struct myMap
{
const void* pData;
char* sz = NULL;
bool deleted = false;
};
static std::atomic<int> mmk = 0;
myMap* mmmap = NULL;;
std::mutex mtx;
HANDLE hProcess = NULL;
struct TWk
{
const void* block;
HANDLE h;
};
DWORD lastThreadID = 0;
char strStack[8192 * 2] = { 0 };
bool inAlloc = true;
bool userCreateThreadEnvNotReady = true;
void allocStackString(HANDLE h, const void* block)
{
EnterCriticalSection(&csMemLeakDump);
strStack[0] = 0;
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_ALL;
strStack[0] = 0;
::SuspendThread(h);
::GetThreadContext(h, &ctx);
MINIDUMP_EXCEPTION_INFORMATION eInfo;
EXCEPTION_POINTERS excpInfo;
excpInfo.ExceptionRecord = NULL;
excpInfo.ContextRecord = &ctx;
eInfo.ThreadId = GetCurrentThreadId();
eInfo.ExceptionPointers = &excpInfo;
eInfo.ClientPointers = FALSE;
// Initialize stack frame
STACKFRAME64 sf;
memset(&sf, 0, sizeof(STACKFRAME));
#if defined(_WIN64)
sf.AddrPC.Offset = ctx.Rip;
sf.AddrStack.Offset = ctx.Rsp;
sf.AddrFrame.Offset = ctx.Rbp;
#elif defined(WIN32)
sf.AddrPC.Offset = ctx.Eip;
sf.AddrStack.Offset = ctx.Esp;
sf.AddrFrame.Offset = ctx.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)
{
inAlloc = false;
LeaveCriticalSection(&csMemLeakDump);
if (-1 != ::ResumeThread(h))
::CloseHandle(h);
return;
}
char _sz[256];
bool xmemory = false;
if (!SymInitialize(hProcess, NULL, TRUE))
{
printf("%s", strStack);
SymCleanup(hProcess);
inAlloc = false;
if (-1 != ::ResumeThread(h))
::CloseHandle(h);
LeaveCriticalSection(&csMemLeakDump);
return;
}
while (StackWalk64(_dwMachineType, hProcess, h, &sf, &ctx, 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_2 curCall;
strcpy(curCall.FunctionName, "");
strcpy(curCall.FileName, "");
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, "%016I64X: ", 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);
int n = strlen(curCall.FileName);
if (n >= 7)
{
char* p = curCall.FileName + n - 7;
if (!strcmp(p, "xmemory")) //std::string need this
xmemory = true;
}
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");
}
if (mmk < 102400 * 4 - 2 && strStack[0] && !xmemory)
{
(mmmap + mmk)->pData = block;
(mmmap + mmk)->deleted = false;
(mmmap + mmk)->sz = (char*)malloc(strlen(strStack) + 4);
strcpy((mmmap + mmk)->sz, strStack);
mmk++;
}
SymCleanup(hProcess);
if (-1 != ::ResumeThread(h))
::CloseHandle(h);
LeaveCriticalSection(&csMemLeakDump);
inAlloc = false;
}
void MemleakNewDump(const void* block)
{
if (hProcess == NULL)
{
InitializeCriticalSection(&csMemLeakDump);
InitializeCriticalSection(&csMemLeakFree);
}
hProcess = GetCurrentProcess();
if (mmmap == NULL)
{
mmmap = (myMap*)malloc(102400 * 4 * sizeof(myMap));
memset(mmmap, 0, 102400 * 4 * sizeof(myMap));
}
DWORD id = ::GetCurrentThreadId();
if (lastThreadID == id)
return;
lastThreadID = id;
HANDLE h = OpenThread(
THREAD_GET_CONTEXT,
TRUE,
id
); //获得真实句柄
if (h == INVALID_HANDLE_VALUE)
return;
std::thread th([&] {
allocStackString(h, block);
});
inAlloc = true;
if (userCreateThreadEnvNotReady)
{
th.detach();
int n = 20;
while (inAlloc && n--)
Sleep(60);
if (n > 0)
userCreateThreadEnvNotReady = false;
else
allocStackString(h, block);
}
else
th.join();
lastThreadID = 0;
}
void dumpMemLeak()
{
if (!mmmap)
return;
SYSTEMTIME st;
GetLocalTime(&st);
char sz[MAX_PATH + 4];
sprintf(sz, "memLeak-%d-%02d-%02d=%02d-%02d-%02d.txt", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
FILE* f = NULL;
int cnt = 0;
for (int i = 0; i < 102400 * 4 - 2; i++)
{
if (!(mmmap + i)->sz || (mmmap + i)->deleted)
continue;
printf("\n\n=============== %d =====================\n", ++cnt);
printf("%s", (mmmap + i)->sz);
if (f == NULL)
f = fopen(sz, "w");
fprintf(f, "\n\n=============== %d =====================\n", cnt);
fprintf(f, "%s", (mmmap + i)->sz);
}
if (f != NULL)
fclose(f);
}
void memLeakFree(void* db)
{
EnterCriticalSection(&csMemLeakFree);
for (int i = 0; i < 102400 * 4 - 2; i++)
{
if (db == (mmmap + i)->pData)
{
(mmmap + i)->deleted = true;
break;
}
}
LeaveCriticalSection(&csMemLeakFree);
}
};
//#define FOUNDATION_MEMLEAK_DETECT
void* __cdecl operator new(size_t const size)
{
for (;;)
{
if (void* const block = malloc(size))
{
#ifdef FOUNDATION_MEMLEAK_DETECT
foundation::TriggerDump(block);
#endif
return block;
}
if (_callnewh(size) == 0)
{
if (size == SIZE_MAX)
{
throw std::exception("bad alloc, SIZE_MAX");
}
else
{
throw std::exception("bad alloc");
}
}
}
}
void __cdecl operator delete(void* p)
{
#if !defined(_ATL_NO_DEBUG_CRT) && defined(_DEBUG)
_free_dbg(p, _NORMAL_BLOCK);
#else
free(p);
#endif
#ifdef FOUNDATION_MEMLEAK_DETECT
foundation::memLeakFree(p);
#endif
}
边栏推荐
- 金融壹賬通香港上市:市值63億港元 葉望春稱守正篤實,久久為功
- Laravel - model (new model and use model)
- Convolutional Neural Networks简述
- [machine learning notes] how to solve over fitting and under fitting
- Aspx simple user login
- Require, require in PHP_ once、include、include_ Detailed explanation of the efficiency of repeated introduction of once class library
- PHP5下WSDL,SOAP调用实现过程
- web3.eth. Filter related
- 基于微信小程序的订餐系统
- [server data recovery] a case of RAID5 data recovery stored in a brand of server
猜你喜欢

明峰医疗冲刺科创板:年营收3.5亿元 拟募资6.24亿
![Primary code audit [no dolls (modification)] assessment](/img/b8/82c32e95d1b72f75823ca91c97138e.jpg)
Primary code audit [no dolls (modification)] assessment

Assembly language - Beginner's introduction
![UE源码阅读[1]---由问题入手UE中的延迟渲染](/img/fa/f33242b01e4da973fa36c2c6f23db6.png)
UE源码阅读[1]---由问题入手UE中的延迟渲染

Deep copy is hard

RK3566添加LED

Zibll theme external chain redirection go page beautification tutorial

Set up a website with a sense of ceremony, and post it to the public 2/2 through the intranet

Convolutional Neural Networks简述

Intranet penetration tool NetApp
随机推荐
明峰医疗冲刺科创板:年营收3.5亿元 拟募资6.24亿
Pancake Bulldog robot V2 (code optimized)
金融壹賬通香港上市:市值63億港元 葉望春稱守正篤實,久久為功
Comparison of several distributed databases
Login interface code
Liste des liens (simple)
Attack and defense world crypto WP
Kafaka log collection
MySQL if else use case use
荐号 | 有趣的人都在看什么?
uplad_ Labs first three levels
Datapipeline was selected into the 2022 digital intelligence atlas and database development report of China Academy of communications and communications
JS takes key and value from an array object to form a new object
基于微信小程序的订餐系统
2022年机修钳工(高级)考试题模拟考试题库模拟考试平台操作
kafaka 日志收集
::ffff:192.168.31.101 是一个什么地址?
UE source code reading [1]--- starting with problems delayed rendering in UE
牛客网:拦截导弹
神经网络物联网未来发展趋势怎么样