结构化异常值异常处理程序

异常过滤程序的返回值

标识
EXCETPTION_EXECUTE_HANDLER1
EXCETPTION_CONTINUE_SEARCH0
EXCETPTION_CONTINUE_EXECUTION-1

系统处理异常的过程

在这里插入图片描述

EXCEPTION_EXECUTE_HANDLER

  • except语句处理完之后,程序从except块后的第一句代码继续执行。
  • 当异常过滤程序的计算结果为EXCEPTION_EXECUTION_HANDLER时,系统必须执行全局展开。全局展开导致所有已经开始执行但尚未完成的try-finally块得以继续执行,在调用栈中,这些try-finally块位于对异常进行了处理的try-except块的下方。
  • 系统如何执行全局展开:
    在这里插入图片描述
  • 代码示例
    程序按照序号的顺序执行,其中比较费解的地方是第6步,第7步。全局展开相当于是将except(EXCEPTION_EXECUTE_HANDLER)之前的所有__finally都先执行完再执行。然后再执行完except(EXCEPTION_EXECUTE_HANDLER)的异常处理代码后再执行except之后的代码。
void FuncOStimpy1()
{
	//1. Do any processing here.
	...
	__try {
		//2. Call another function
		FuncORen1();

		//Code here never executes.
	}
	__except(/*6. Evaluate filter. */EXCEPTION_EXECUTE_HANDLER) {
		//8. After the unwind, the exception handler executes.
		MessageBox(...);
	}

	//9. Exception handled--continue exection.
	...
}

void FuncORen1() {
	DWORD dwTemp = 0;

	//3. Do any processing here.
	...
	__try {
		//4. Request permission to access protected data.
		WaitForSingleObject(g_hSem, INFINITE);

		//5. Modify the data.
		//An exception is generated here.
		g_dwProtectedData = 5 / dwTemp;
	}
	__finally {
		//7. Global unwind occurs because filter evaluated
		//to EXCEPTION_EXECUTE_HANDLER

		//Allow others to use protected data.
		ReleaseSemaphore(g_hSem, 1, NULL);
	}

	//Continue processing--never executes.
}
  • 可以理解为全局展开保证了__finally的局部展开
  • except(EXCEPTION_EXECUTE_HANDLER)是全局展开开始的标志
  • Vista开始,如果try/finally块中发生异常,而其上还没有try/except块,则不会执行全局展开,finally块也不会执行,程序会立即终止。
  • 如何停止全局展开?
    我们可以通过将return语句置于finally块中以阻止系统完成全局展开。
    如下代码,当FuncPheasant的try块调用strcpy函数时,一个访问内存违规异常被抛出。于是系统开始检查是否存在异常过滤程序可以处理这个异常。这次,系统发现FuncMonkey中的异常过滤程序可以处理它,于是系统初始化一个全局展开。
    全局展开从执行FuncPheasant中的finally代码块开始,然而这个代码块中包含一个return,它导致系统停止展开,实际上FuncPheasant也将停止执行,控制流返回到FuncFish函数。后者继续执行在屏幕上显示一个消息框,然后回到FuncMonkey。FuncMonkey中调用消息框的代码执行。
    请注意FuncMonkey的exception代码块没有机会执行对MessageBeep的调用。finally中的return语句导致系统停止之后的全局展开步骤,并让系统正常执行,就好像没有异常发生一样。
void FuncMonkey()
{
	__try {
		FuncFish();
	}
	__except (EXCEPTION_EXECUTE_HANDLER)
	{
		MessageBeep(0);
	}
	MessageBox(...);
}

void FuncFish()
{
	FuncPheasant();
	MessageBox(...);
}

void FuncPheasant()
{
	__try {
		strcpy(NULL, NULL);
	}
	__finally {
		return;
	}
}

EXCEPTION_CONTINUE_EXECUTION

  • 系统在看到过滤程序返回值为EXCEPTION_CONTINUE_EXECUTION后,将程序控制流跳转到导致异常的那条指令,并尝试重新执行这条指令。
  • 由此可以看出来,EXCETPTION_CONTINUE_EXECUTION具有纠正错误的功能。但是,我们也要慎用此返回值。因为高级语言代码所描述的行为与具体的机器指令行为可以不一样,这里收到编译优化的影响,收到CPU结构的影响等。
  • 使用EXCEPTION_CONTINUE_EXECUTION的一个场景是:内存申请相关。比如当不知道目标缓冲区多大时,可以先申请一个小的,如果使用小缓冲区操作可能会崩溃,则捕捉异常,并扩大内存申请容量再次重新执行。

EXCEPTION_CONTINUE_SEARCH

  • 异常不会得到任何处理。按照结构化异常的逻辑继续向外层查找try块,知道UnhandledExceptionFilter。
  • SetUnhandledExceptionFilter可以捕获SEARCH的返回。

GetExceptionInformation

  • 只能在异常过滤过程中使用,不能再异常处理过程中使用。原因是在处理过程中,此函数返回的结构体内容已经失效了
  • 返回一个指向EXCEPTION_POINTERS结构的指针
  • EXCEPTION_POINTERS包含一个EXCETION_RECORD,和一个CONTEXT
  • EXCEPTION_RECORD与机器无关,CONTEXT与机器有关,包含的是崩溃时各个寄存器的信息
  • ExCEPTION_RECORD结构
    1)ExceptionCode:表明异常代码,这个代码也可以使用GetExceptionCode返回
    2)ExceptionFlags:包含一些跟异常相关的标志。目前有两个值,0表示可以继续的异常,和EXCEPTION_NONCONTINUABLE表示不可以继续的异常。如果程序试图在一个不能继续的异常发生后继续执行,则会引发EXCEPTION_NONCONTINUABLE_EXCEPTION异常
    3)ExceptionRecord指向另一个未处理异常的EXCEPTION_RECORD结构。在处理一个异常时,有可能会发生另一个异常。这种被称为嵌套异常。
    4)ExceptionAddress:表明导致异常的CPU指令的地址
    5)NumberParameters:表明与异常相关参数的个数(0到15)。即ExceptionInformatica数组里的元素个数。对绝大部分的异常来说,这个值是0。
    6)ExceptionInformation:表示用来进一步描述异常的附加参数数组。
    目前只有EXCEPTION_ACCESS_VIOLATION异常,ExceptionInformation[0]包含一个标志,指出引发这个非法访问的异常类型,0表示读取不可读,1表示写入不可写,8表示当数据执行保护(DEP)时侦测到线程执行了不具备访问权限的内存页中的代码。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值