VEH
优先级最高
进程级别,跨线程有效
1
2
3
4
5// 在主线程注册VEH
AddVectoredExceptionHandler(0, GlobalHandler);
// 在工作线程中发生的异常也会被处理
Create(NULL, 0, WorkerThread, NULL, 0, NULL);可以注册多个,形成处理链
1
2
3PVOID handler1 = AddVectoredExceptionHandler(0, Handler1);
PVOID handler2 = AddVectoredExceptionHandler(0, Handler2);
// 执行顺序: Handler1 -> Handler2 (如果 Handler1 返回 CONTINUE_SEARCH)储存在堆内存中
- 不依赖栈帧,即使栈损坏也能工作
- 适合处理栈溢出等严重异常
SEH
基于栈帧,线程布局
1
2
3
4
5
6
7
8__try
{
*((int*)0) = 42;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
printf("Access violation caught\n");
}嵌套结构,就近原则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22void OuterFunction()
{
__try
{
InnerFunction();
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("Outer handler\n"); // executes second
}
}
void InnerFunction()
{
__try
{
*((int*)0) = 42;
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
printf("Inner handler\n"); // executes first
}
}编译器集成,语法简洁
UEF (Unhandled Exception Filter)
全局唯一,最后防线
1
2LPTOP_LEVEL_EXCEPTION_FILTER oldFilter = SetUnhandledExceptionFilter(MyUEF);
// 新的 UEF 会覆盖旧的UEF返回值直接决定程序生死
1
2
3
4
5
6
7
8
9
10
11
12
13LONG NTAPI UEFHandler (struct _EXCEPTION_POINTERS* ExceptionInfo)
{
if (CanRecover (ExceptionInfo))
{
FixTheException (ExceptionInfo);
return EXCEPTION_CONTINUE_EXECUTION; // 程序继续运行
}
else
{
GenerateCrashDump (ExceptionInfo);
return EXCEPTION_EXECUTE_HANDLER; // 程序终止
}
}不受调试器影响
- 即使在调试器下运行,UEF 仍然会被调用
- 适合实现产品级的崩溃报告系统
VCH (Vectored Continue Handler)
它的名字比较有迷惑性。VCH 的执行在所有其它异常处理程序之后,不管前面的异常处理结果如何都不影响它的执行,即使程序崩溃,它也会发出最后的波纹。
无条件调用
1
2
3
4
5
6// 无论异常是否被处理,VCH 都会被调用
LONG NTAPI AlwaysCalledHandler (struct _EXCEPTION_POINTERS* ExceptionInfo)
{
printf("This ALWAYS executes\n");
return EXCEPTION_CONTINUE_SEARCH;
}主要用于监控和清理
1
2
3
4
5
6
7
8
9LONG NTAPI MonitoringContinueHandler (struct _EXCEPTION_POINTERS* ExceptionInfo)
{
// 记录所有异常,包括已被处理的
LogExceptionToFile (ExceptionInfo);
// 更新性能计数器
IncrementExceptionCounter();
// 不影响程序执行
return EXCEPTION_CONTINUE_SEARCH;
}可以注册多个,形成处理链
VCH 不是为了“挽救”失败的异常处理而设计的,而是为了:
- 监控和日志记录
- 记录所有异常,包括致命的、已被处理的
- 统计异常发生频率和类型
- 资源清理和数据保存
- 在程序崩溃前保存重要数据
- 清理可能导致资源泄露的对象
- 调试和诊断
- 在异常处理完成后执行额外的调试逻辑
- 收集诊断信息
SEH Function Definition:
1 | EXCEPTION_DISPOSITION __cdecl _except_handler( |
UEF, VEH, VCH 函数的参数只有一个,即指向结构体 _EXCEPTION_POINTERS 的指针。
1 | typedef struct _EXCEPTION_POINTERS { |
线程上下文,没有细看
1 | /* 浮点寄存器 */ |
一些使用方法/API
SEH
1 | __asm |
或者 __try/__except
Others
SetUnhandledExceptionFilter
1 | AddVectoredEcceptionHandler(ULONG first, // 1 表示添加到链表头部,0 表示添加到链表i尾部 |
RemoveVectoredExceptionHandler
AddVectoredContinueHandler
RemoveVectoredContinueHandler
1 | LONG PvectoredExceptionHandler( |
异常处理程序的参数
1 | typedef struct _EXCEPTION_POINTERS |
返回值
EXCEPTION_CONTINUE_EXECUTION 表示继续执行;
EXCEPTION_CONTINUE_SEARCH 表示继续查找
SEH 的返回值 (VEH, VCH 只有前两种)
1 | typedef enum _EXCEPTION_DISPOSITION { |
__except & SEH
__except 是对 _except_handler 函数的封装
EH 调用顺序
调试器 > VEH > SEH > UEF > VCH > 调试器 > 调用异常端口通知 csrss.exe (弹出一个对话框, 但在Win11没有见到, 可能和系统版本有关)
1 |
|