当前位置:网站首页>VC development of non MFC program memory leak tracking code
VC development of non MFC program memory leak tracking code
2022-07-05 14:05:00 【joshua0137】
Rewrite in the executable module source code new and delete function , Insert tracking code into it , At the end of the program t Save statistics before exiting . The following code can basically solve the problem , But the program runs slowly , When used as a test, it can meet the requirements .
namespace foundation
{
std::string MemleakNewDump()
{
DWORD id = ::GetCurrentThreadId();
HANDLE h = OpenThread(
THREAD_GET_CONTEXT,
TRUE,
id
); // Get the real handle
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
); // Get the real handle
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
}
边栏推荐
- 让秒杀狂欢更从容:大促背后的数据库(下篇)
- Linked list (simple)
- [js] basic syntax - for loop
- Self built shooting range 2022
- js 从一个数组对象中取key 和value组成一个新的对象
- TiFlash 面向编译器的自动向量化加速
- Current situation, trend and view of neural network Internet of things in the future
- Matlab learning 2022.7.4
- Attack and defense world crypto WP
- UE source code reading [1]--- starting with problems delayed rendering in UE
猜你喜欢

锚点导航小demo

upload (1-6)

Self built shooting range 2022

tidb-dm报警DM_sync_process_exists_with_error排查

搭建一个仪式感点满的网站,并内网穿透发布到公网 2/2

Comparison of several distributed databases
![[machine learning notes] several methods of splitting data into training sets and test sets](/img/f6/eca239bb4b1764a1495ccd9a868ec1.jpg)
[machine learning notes] several methods of splitting data into training sets and test sets

uplad_ Labs first three levels

Simple process of penetration test

Attack and defense world web WP
随机推荐
Detailed explanation of SSH password free login
Selenium crawls Baidu pictures
matlab学习2022.7.4
鸿蒙第四次培训
Source code analysis of etcd database -- peer RT of inter cluster network layer client
LeetCode_67(二进制求和)
03_Solr之dataimport
Jetpack compose introduction to mastery
Liar report query collection network PHP source code
Embedded software architecture design - message interaction
Some ideas about Apache mesos
基于微信小程序的订餐系统
研究生可以不用学英语?只要考研英语或六级分数高!
Convolutional Neural Networks简述
瑞能实业IPO被终止:年营收4.47亿 曾拟募资3.76亿
Elfk deployment
Linux下mysql数据库安装教程
Solution to the prompt of could not close zip file during phpword use
Kotlin协程利用CoroutineContext实现网络请求失败后重试逻辑
PHP basic syntax