当前位置:网站首页>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亿港元 叶望春称守正笃实,久久为功
- 昆仑太科冲刺科创板:年营收1.3亿拟募资5亿 电科太极持股40%
- NFT value and white paper acquisition
- zabbix 监控
- Zhubo Huangyu: these spot gold investment skills are not really bad
- Deep copy is hard
- Financial one account Hong Kong listed: market value of 6.3 billion HK $Ye wangchun said to be Keeping true and true, long - term work
- ZABBIX monitoring
- Detailed explanation of IP address and preparation of DOS basic commands and batch processing
- In addition to the root directory, other routes of laravel + xampp are 404 solutions
猜你喜欢
Financial one account Hong Kong listed: market value of 6.3 billion HK $Ye wangchun said to be Keeping true and true, long - term work
When using Tencent cloud for the first time, you can only use webshell connection instead of SSH connection.
What about data leakage? " Watson k'7 moves to eliminate security threats
金融壹账通香港上市:市值63亿港元 叶望春称守正笃实,久久为功
ZABBIX monitoring
那些考研后才知道的事
Kotlin协程利用CoroutineContext实现网络请求失败后重试逻辑
Data Lake (VII): Iceberg concept and review what is a data Lake
Network security - Novice introduction
Attack and defense world web WP
随机推荐
鸿蒙第四次培训
Solve the problem of invalid uni app configuration page and tabbar
These 18 websites can make your page background cool
Elfk deployment
[js] basic syntax - for loop
广发期货排名多少?网上办理广发期货开户安全可靠吗?
Jetpack Compose入门到精通
Idea remote debugging agent
Data Lake (VII): Iceberg concept and review what is a data Lake
SSH免密码登录详解
LeetCode_67(二进制求和)
昆仑太科冲刺科创板:年营收1.3亿拟募资5亿 电科太极持股40%
poi设置列的数据格式(有效)
Laravel framework operation error: no application encryption key has been specified
web3.eth. Filter related
[server data recovery] a case of RAID5 data recovery stored in a brand of server
常见问题之PHP——Fatal error: Allowed memory size of 314572800 bytes exhausted...
2022年机修钳工(高级)考试题模拟考试题库模拟考试平台操作
[machine learning notes] how to solve over fitting and under fitting
Attack and defense world web WP