SetUnhandledExceptionFilter 无法捕获异常 x64系统解决办法

背景

windows下开发,设置了SetUnhandledExceptionFilter,但是仍然无法捕获异常。百度后,知道这里设置后可能会被重置为NULL。所以此次设置好后,还需要保护一下。

方法

SetUnhandledExceptionFilter()之后,再调用DisableSetUnhandledExceptionFilter即可。

注意,DisableSetUnhandledExceptionFilter()中,网上大多是仅支持x86的。此处是x64的方法。

代码

#include "MainWidget.h"
#include <QWindow>
#include <iostream>
#include <stdint.h>
#include "JsonHelper.h"
#include <windows.h>
#include <signal.h>
#include <new.h>
#include <limits>
#include <exception>
#include <DbgHelp.h>

#include <minwinbase.h>

#pragma comment(lib,"Dbghelp.lib")

#pragma comment(lib,"User32.lib")

static int GenerateDump(EXCEPTION_POINTERS* exceptionPointers, const std::string& path)
{
	HANDLE hFile = ::CreateFileA(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (INVALID_HANDLE_VALUE != hFile)
	{
		MINIDUMP_EXCEPTION_INFORMATION minidumpExceptionInformation;
		minidumpExceptionInformation.ThreadId = GetCurrentThreadId();
		minidumpExceptionInformation.ExceptionPointers = exceptionPointers;
		minidumpExceptionInformation.ClientPointers = TRUE;
		bool isMiniDumpGenerated = MiniDumpWriteDump(
			GetCurrentProcess(),
			GetCurrentProcessId(),
			hFile,
			MINIDUMP_TYPE::MiniDumpNormal,
			&minidumpExceptionInformation,
			nullptr,
			nullptr);
		CloseHandle(hFile);
		if (!isMiniDumpGenerated)
		{
			printf("MiniDumpWriteDump failed\n");
		}
	}
	else
	{
		printf("Failed to create dump file\n");
	}
	return EXCEPTION_EXECUTE_HANDLER;
}

void Snapshot(const std::string& path)
{
	__try
	{
		//通过触发异常获取堆栈
		RaiseException(0xE0000001, 0, 0, 0);
	}
	__except (GenerateDump(GetExceptionInformation(), path)) {}
}

LONG UnhandledStructuredException(struct _EXCEPTION_POINTERS *excp)
{
	GenerateDump(excp, ".\\test.dmp");

	std::stringstream ss;
	ss << "IN UnhandledStructuredException.";
	ss << " ExceptionCode: 0x" << std::hex << excp->ExceptionRecord->ExceptionCode;
	ss << " ExceptionFlags:" << excp->ExceptionRecord->ExceptionFlags;

	system(("cmd /K echo " + ss.str()).c_str());
	exit(EXIT_FAILURE);
}

void PureCallHandler(void)
{
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}


int NewHandler(size_t id) {
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
	return 0;
}

void InvalidParameterHandler(const wchar_t* expression,
	const wchar_t* function,
	const wchar_t* file,
	unsigned int line,
	uintptr_t pReserved)
{
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}

void SigabrtHandler(int id) {
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}

void SigintHandler(int id) {
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}

void SigtermHandler(int id) {
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}

void SigillHandler(int id) {
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}

void TerminateHandler() {
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}

void UnexpectedHandler() {
	Snapshot(".\\test.dmp");
	exit(EXIT_FAILURE);
}

void InstallUnexceptedExceptionHandler()
{
	//SEH(Windows 结构化异常处理),属于Win32 API
	::SetUnhandledExceptionFilter(UnhandledStructuredException);
	//C 运行时库 (CRT) 异常处理,由 CRT 提供的异常处理机制。
	_set_purecall_handler(PureCallHandler);
	_set_new_handler(NewHandler);
	_set_invalid_parameter_handler(InvalidParameterHandler);
	_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
	//C 运行时信号处理,由 CRT 提供的信号处理机制。
	signal(SIGABRT, SigabrtHandler);
	signal(SIGINT, SigintHandler);
	signal(SIGTERM, SigtermHandler);
	signal(SIGILL, SigillHandler);
	//C++ 运行时异常处理,API由标准库提供
	set_terminate(TerminateHandler);
	set_unexpected(UnexpectedHandler);
}

void DisableSetUnhandlerExcptionFilter()
{
#ifndef _WIN64
	system("cmd /K echo The following code only works for x64");
	exit(EXIT_FAILURE);
#endif
	void* addr = (void*)GetProcAddress(LoadLibrary(L"kernel32.dll"), "SetUnhandledExceptionFilter");

	if (addr)
	{
		unsigned char code[16];
		int size = 0;

		code[size++] = 0x48;
		code[size++] = 0x31;
		code[size++] = 0xC0;
		code[size++] = 0xC3;

		DWORD dwOldFlag, dwTempFlag;
		VirtualProtect(addr, size, PAGE_READWRITE, &dwOldFlag);
		WriteProcessMemory(GetCurrentProcess(), addr, code, size, NULL);
		VirtualProtect(addr, size, dwOldFlag, &dwTempFlag);
	}
}

int main(int argc, char *argv[])
{
	InstallUnexceptedExceptionHandler();
	DisableSetUnhandlerExcptionFilter();

	QApplication::setFont(QFont("Arial", 10));
	QApplication app(argc, argv);

	MainWidget mainUI;
	mainUI.showMaximized();

	return app.exec();
}

}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值