c++ - 使用 MiniDumpWriteDump 的 _set_se_translator 何时无法写入转储?
问题描述
我们在 Windows 上的 32 位 C++ 可执行文件中发生了罕见的崩溃,它不会产生内存转储。我们没有重现案例,当崩溃发生时,游戏会在几秒钟后消失,因此我们需要内存转储来查找原因。其他崩溃确实会产生内存转储,因此我们知道我们的内存转储功能有时会起作用,只是不适用于这次特定的崩溃。
在什么情况下组合_set_se_translator
和MiniDumpWriteDump
失败会产生内存转储?我们是否在内存转储处理中做错了什么导致它有时不产生转储?
这是我们目前所做的:
在我们调用的主线程中主函数的开始处SetUnhandledExceptionFilter(CrashDumpManager::unhandledExceptionHandler);
在我们调用的每个线程中_set_se_translator(CrashDumpManager::MiniDumpFunction);
这就是 CrashDumpManager.h 的样子:
#include <Windows.h>
#include <Dbghelp.h>
class CrashDumpManager
{
public:
static void MiniDumpFunction(unsigned int nExceptionCode, EXCEPTION_POINTERS *pException);
static LONG CALLBACK unhandledExceptionHandler(EXCEPTION_POINTERS* e);
//If the game crashes because of a memory leak then there won't be enough memory free to generate a memory dump
//Therefore 10MB is allocated here and deleted before the crashdump is written.
static unsigned char* crashdumpMemory;
};
这就是 CrashDumpManager.cpp 的样子:
#include "CrashDumpManager.h"
void CrashDumpManager::MiniDumpFunction(unsigned int nExceptionCode, EXCEPTION_POINTERS *pException)
{
delete crashdumpMemory;
crashdumpMemory = nullptr;
// prevent stack overflow when crashing in this function
static bool calledFunctionOnce = false;
if (!calledFunctionOnce)
{
calledFunctionOnce = true;
HMODULE dbgHelpModule = LoadLibraryA("dbghelp");
if (dbgHelpModule == nullptr)
return;
auto writeMiniDumpFunction = (decltype(&MiniDumpWriteDump))GetProcAddress(dbgHelpModule, "MiniDumpWriteDump");
if (writeMiniDumpFunction == nullptr)
return;
char name[MAX_PATH];
{
char* nameEnd = name + GetModuleFileNameA(GetModuleHandleA(0), name, MAX_PATH);
SYSTEMTIME t;
GetSystemTime(&t);
wsprintfA(nameEnd - strlen(".exe"), "_%4d%02d%02d_%02d%02d%02d.mdmp",
t.wYear, t.wMonth, t.wDay, t.wHour, t.wMinute, t.wSecond);
}
HANDLE dumpFileHandle = CreateFileA(name, GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
if (dumpFileHandle == INVALID_HANDLE_VALUE)
return;
MINIDUMP_EXCEPTION_INFORMATION exceptionInfo;
exceptionInfo.ThreadId = GetCurrentThreadId();
exceptionInfo.ExceptionPointers = pException;
exceptionInfo.ClientPointers = FALSE;
auto dumped = writeMiniDumpFunction(GetCurrentProcess(), GetCurrentProcessId(), dumpFileHandle,
MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory),
pException ? &exceptionInfo : nullptr, nullptr, nullptr);
CloseHandle(dumpFileHandle);
}
}
LONG CALLBACK CrashDumpManager::unhandledExceptionHandler(EXCEPTION_POINTERS* e)
{
CrashDumpManager::MiniDumpFunction(0, e);
return EXCEPTION_CONTINUE_SEARCH;
}
unsigned char* CrashDumpManager::crashdumpMemory = new unsigned char[10*1024*1024];
解决方案
推荐阅读
- php - 分批处理
- python - 如何使用 matplotlib 绘制条形范围图?
- clio-api - 为 CLIO API“联系人”端点使用 custom_file_ids[] 查询参数时正确的多 ID 语法
- javascript - Javascript:随机播放表行
- python - 查询模型字段?在models.py中可以吗?
- excel - 条形图需要我点击更新 - 有办法吗?
- python - 按另一列降序分组对 DataFrame 元素进行排序
- angular - 如何以角度将电话簿添加到列表中?
- c# - c# 错误消息 - 类型或命名空间定义或预期文件结尾
- android - RecyclerView 作为 NestedScrollView 的子级 - 不回收视图