当前位置:网站首页>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
}
边栏推荐
- 最简单不用证书也可以多开功能的方式
- 蓝桥杯学习2022.7.5(上午)
- js 从一个数组对象中取key 和value组成一个新的对象
- Zhubo Huangyu: these spot gold investment skills are not really bad
- 让秒杀狂欢更从容:大促背后的数据库(下篇)
- Detailed explanation of SSH password free login
- How to deal with the Yellow Icon during the installation of wampserver
- Matlab learning 2022.7.4
- upload (1-6)
- 判断变量是否为数组
猜你喜欢

About the problem and solution of 403 error in wampserver

物联网应用技术专业是属于什么类

TiCDC 6.0原理之Sorter演进

Those things I didn't know until I took the postgraduate entrance examination

Simple process of penetration test

荐号 | 有趣的人都在看什么?

tidb-dm报警DM_sync_process_exists_with_error排查
![[South China University of technology] information sharing of postgraduate entrance examination and re examination](/img/a8/41e62a7a8d0a2e901e06c751c30291.jpg)
[South China University of technology] information sharing of postgraduate entrance examination and re examination

瑞能实业IPO被终止:年营收4.47亿 曾拟募资3.76亿

PHP basic syntax
随机推荐
深拷贝真难
Rk3566 add LED
Those things I didn't know until I took the postgraduate entrance examination
tidb-dm报警DM_sync_process_exists_with_error排查
神经网络物联网未来发展趋势怎么样
When there are too many input boxes such as input transmitted at one time in the form, the post data is intercepted
鏈錶(簡單)
Implementation process of WSDL and soap calls under PHP5
Assembly language - Beginner's introduction
Pancake Bulldog robot V2 (code optimized)
国富氢能冲刺科创板:拟募资20亿 应收账款3.6亿超营收
upload (1-6)
In addition to the root directory, other routes of laravel + xampp are 404 solutions
UE source code reading [1]--- starting with problems delayed rendering in UE
Network security - Novice introduction
蓝桥杯学习2022.7.5(上午)
判断变量是否为数组
SSH免密码登录详解
根据CronSequenceGenerator计算cron表达式的时间
搭建一个仪式感点满的网站,并内网穿透发布到公网 2/2