#ifdef DEVELOP_MODE
#include "MemoryLeakTest.h"
#include "MemoryLeakTest/Include/x86/detours/detours.h"
#include "MemoryLeakTest/Include/x86/detours/dbghelp.h"
#pragma comment(lib, "detours.lib")
#pragma comment(lib, "dbghelp.lib")
// 定义函数指针类型
typedef void* (*MallocType)(size_t size);
typedef void (*FreeType)(void* ptr);
MallocType MemoryLeakTest::OriginalMalloc = NULL;
FreeType MemoryLeakTest::OriginalFree = NULL;
bool MemoryLeakTest::g_IsStackInfoEnabled = false;
RayHashMap<void*, std::pair<MemoryLeakTest::STACK_TRACE_INFO, int>> MemoryLeakTest::allocatedPointers
= RayHashMap<void*, std::pair<MemoryLeakTest::STACK_TRACE_INFO, int>>(0);
QMutex MemoryLeakTest::mutex;
MemoryLeakTest::MemoryLeakTest()
{
}
MemoryLeakTest::~MemoryLeakTest()
{
}
// 获取堆栈信息的实现
void MemoryLeakTest::GetStackTrace(STACK_TRACE_INFO* stackTraceInfo)
{
// 使用 CaptureStackBackTrace 函数获取堆栈信息
stackTraceInfo->frameCount = CaptureStackBackTrace(0, MAX_STACK_FRAMES, stackTraceInfo->stackFrames, NULL);
}
// 获取堆栈信息字符串
std::string MemoryLeakTest::GetStackTraceString(void** stackTrace, WORD frames)
{
std::string stackString;
// 初始化行号信息结构体
IMAGEHLP_LINE64 lineInfo;
lineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
// 遍历堆栈帧
for (int i = 2; i < frames && i<5 ; i++)
{
DWORD64 address = (DWORD64)(stackTrace[i]);
DWORD64 displacementSym = 0;
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYM_NAME;
DWORD displacementLine = 0;
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
// 获取函数名
if (SymFromAddr(process, address, &displacementSym, pSymbol))
{
stackString += pSymbol->Name;
stackString += " ";
// 获取行号
if (SymGetLineFromAddr64(process, address, &displacementLine, &lineInfo))
{
stackString += "(";
stackString += lineInfo.FileName;
stackString += ":";
stackString += std::to_string(lineInfo.LineNumber);
stackString += ")";
}
}
else {
qInfo() << "Error Code:" << GetLastError();
}
stackString += "\n";
}
return stackString;
}
// 内存泄漏检测函数
void MemoryLeakTest::checkMemoryLeaks()
{
if (!allocatedPointers.empty())
{
qInfo() << "Memory leak detected!" ;
qInfo() << "Number of leaked allocations: " << allocatedPointers.size() ;
// 输出泄漏的指针及其对应的文件名和行号
qInfo() << "Leaked pointers: " ;
for (size_t i = 0; i < allocatedPointers.bucketsize(); i++)
{
auto entry = allocatedPointers[i];
if (entry)
{
while (entry)
{
void* ptr = entry->key;
// 获取堆栈信息
STACK_TRACE_INFO stackTraceInfo = entry->value.first;
std::string stackString = GetStackTraceString(stackTraceInfo.stackFrames, stackTraceInfo.frameCount);
if (stackString.find("operator new") != std::string::npos)
{
int size = entry->value.second;
qInfo() << "Pointer: " << ptr << ", Stack: " << stackString.c_str() << ", Size: " << size;
}
entry = entry->next;
}
}
}
}
else
{
qInfo() << "No memory leaks detected." ;
}
allocatedPointers.clear();
}
void MemoryLeakTest::removeButNoDeleateMemory(void* ptr) {
allocatedPointers.erase(ptr);
}
// Hook malloc函数
void* MemoryLeakTest::HookedMalloc(size_t size)
{
mutex.lock();
// 调用原始malloc函数
void* ptr = OriginalMalloc(size);
// 记录分配的内存信息
if (!g_IsStackInfoEnabled)
{
g_IsStackInfoEnabled = true;
// 获取堆栈信息
STACK_TRACE_INFO stackTraceInfo;
GetStackTrace(&stackTraceInfo);
std::pair<STACK_TRACE_INFO, int> pairTemp = std::make_pair(stackTraceInfo, size);
allocatedPointers.insert(ptr, pairTemp);
g_IsStackInfoEnabled = false;
}
mutex.unlock();
return ptr;
}
// Hook free函数
void MemoryLeakTest::HookedFree(void* ptr)
{
// 在未释放的内存列表中查找对应的地址
mutex.lock();
removeButNoDeleateMemory(ptr);
// 调用原始free函数
OriginalFree(ptr);
mutex.unlock();
}
void MemoryLeakTest::registerHooked()
{
allocatedPointers.clear();
allocatedPointers = RayHashMap<void*, std::pair<MemoryLeakTest::STACK_TRACE_INFO, int>>(999983);
// 获取函数地址
/*OriginalMalloc = (MallocType)DetourFindFunction("ucrtbase.dll", "malloc");
OriginalFree = (FreeType)DetourFindFunction("ucrtbase.dll", "free");*/
OriginalMalloc = (MallocType)DetourFindFunction("ucrtbased.dll", "malloc");
OriginalFree = (FreeType)DetourFindFunction("ucrtbased.dll", "free");
// 使用Detours库来Hook函数
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourAttach(&(PVOID&)OriginalMalloc, HookedMalloc);
DetourAttach(&(PVOID&)OriginalFree, HookedFree);
DetourTransactionCommit();
};
void MemoryLeakTest::removeHooked()
{
// 在程序退出时输出堆栈信息和行号
// ...
// 卸载Detours Hook
DetourTransactionBegin();
DetourUpdateThread(GetCurrentThread());
DetourDetach(&(PVOID&)OriginalMalloc, HookedMalloc);
DetourDetach(&(PVOID&)OriginalFree, HookedFree);
DetourTransactionCommit();
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
//MemoryLeakTest::registerHooked();
}
else if (ul_reason_for_call == DLL_PROCESS_DETACH)
{
//MemoryLeakTest::removeHooked();
}
return TRUE;
}
#endif // DEVELOP_MODE