24.1 SetUnhandledExceptionFilter未处理异常--《Windows核心编程》

对于未处理异常,例如异常过滤返回EXCEPTION_CONTINUE_SEARCH,向上搜索,但无法搜索到处理部分,产生未处理异常。Windows提供了 SetUnhandledExceptionFilter 函数,给我们处理异常的最后机会,否则 Windows 会正式认为这个异常没有得到处理。

默认情况下,如果没有设置 SetUnhandledExceptionFilter 函数,对于未处理异常,会调用操作系统的默认异常处理代码 UnhandledExceptionHandler

通常应该在进程初始化阶段调用这个函数,一旦调用,进程中所有线程的未抛出异常都会导致 SetUnhandledExceptionFilter 参数所指定的的异常过滤函数的执行。

// 负责处理未处理异常
// 进程初始化时,设置处理未处理异常过滤函数
PTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(
PTOP_LEVEL_EXCEPTION_FILTER pTopLevelExceptionFilter
);

参数是一个异常过虑函数,原型必须与下面类似

// 返回值和结果
// EXCEPTION_EXECUTE_HANDLER 进程终止
// EXCEPTION_CONTINUE_EXECUTION 从抛出异常处再执行
// EXCEPTION_CONTINUE_SEARCH 不处理
LONG WINAPI TopLevelUnhandledExceptionFilter(
PEXCEPTION_POINTERS pExceptionInfo
);

C/C++运行函数安装的默认的全局异常过滤程序: __CxxUnhandledExceptionFilter,用 NULL 调用 SetUnhandledExceptionFilter 将全局未处理异常过滤程序设回 UnhandledExceptionFilter

#include <windows.h>   
#include <stdio.h>

long   __stdcall   callback(_EXCEPTION_POINTERS*   excp)
{
	MessageBox(0, "Error", "error", MB_OK);

	printf("Error   address   %x\n", excp->ExceptionRecord->ExceptionAddress);
	printf("CPU   register:\n");
	printf("eax   %x   ebx   %x   ecx   %x   edx   %x\n", excp->ContextRecord->Eax,
		excp->ContextRecord->Ebx, excp->ContextRecord->Ecx,
		excp->ContextRecord->Edx);

	return   EXCEPTION_EXECUTE_HANDLER;	// 进程终止
}

int   main(int   argc, char*   argv[])
{
	PTOP_LEVEL_EXCEPTION_FILTER pException = SetUnhandledExceptionFilter(callback);
	_asm   int   3   // 只是为了让程序崩溃
	return   0;
}

 



我们都知道,每个线程的执行都是从 NTDLL.dll 中的函数 BaseThreadStart 开始的:

VOID BaseThreadStart(
	PTHREAD_START_ROUTINE pfnStartAddr,
	PVOID pvParam
)
{
	__try
	{
		ExitThread((pfnStartAddr)(pvParam));
	}
	__except (UnhandledExceptionFilter(GetExceptionInformation()))
	{
		ExitProcess(GetExceptionCode());
	}
}

// 上述UnhandledExceptionFilter的返回值和结果
// EXCEPTION_EXECUTE_HANDLER 执行ExitProcess,进程退出
// EXCEPTION_CONTINUE_EXECUTION 从抛出异常处再次执行
// EXCEPTION_CONTINUE_SEARCH 未处理异常

// 上述UnhandledExceptionFilter的返回值和结果
// EXCEPTION_EXECUTE_HANDLER 执行ExitProcess,进程退出
// EXCEPTION_CONTINUE_EXECUTION 从抛出异常处再次执行
// EXCEPTION_CONTINUE_SEARCH 未处理异常

如果我们的线程抛出一个异常,并且所有安装的异常过滤程序都返回 EXCEPTION_CONTINUE_SEARCH,系统提供的一个特殊函数 UnhandledExceptionFilter 将会被调用。


本书讨论的是用户态的开发。对内核态线程抛出未处理异常,在蓝屏前,系统让相关设备驱动调用 CrashDmp.sys在页文件中建立 Crash Dump,再停止所有操作。重启后,会查看页文件是否包含了一个 Crash Dump,如果有表示数据得到了存储 ,系统让WerFault运行,产生错误报告,并发送给Microsoft服务器。

 

posted @ 2022-11-25 16:33  人类观察者  阅读(1042)  评论(0编辑  收藏  举报