SHE的疑问?

yuucyf 2012-10-26 03:30:23
先介绍了一下SEH在VC中的体现,就是__try/__except关键字,在__excep后面的()中是一个表达式,值可以是:
EXCEPTION_CONTINUE_EXECUTION(–1):异常被忽略,控制流将在异常出现的点之后,继续恢复运行。

EXCEPTION_CONTINUE_SEARCH(0):异常不被识别,也即当前的这个__except模块不是这个异常错误所对应的正确的异常处理模块。系统将继续到上一层的try-except域中继续查找一个恰当的__except模块。

EXCEPTION_EXECUTE_HANDLER(1):异常已经被识别,也即当前的这个异常错误,系统已经找到了并能够确认,这个__except模块就是正确的异常处理模块。控制流将进入到__except模块中。

其中例子有:

#include "stdafx.h"
#include <windows.h>

#define VAR_WATCH() printf("nDividend=%d, nDivisor=%d, nResult=%d.\n",\
nDividend, nDivisor, nResult)

int _tmain(int argc, _TCHAR* argv[])
{
int nDividend = 22, nResult = 100;
volatile int nDivisor = 0;

/*nDividend++;

_asm INT 3;

_asm
{
mov eax, eax
__asm _emit 0xcd __asm _emit 0x03
nop
nop
}

DebugBreak();*/

__try
{
printf("Before div in __try block.\n");
VAR_WATCH();

nResult = nDividend / nDivisor;

printf("After div in __try block.\n");
VAR_WATCH();
}
__except(printf("In __except block.\n"), VAR_WATCH(),
GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?
(nDivisor = 1, printf("Divide zero exception detected.\n"), VAR_WATCH(), EXCEPTION_CONTINUE_EXECUTION) :
(EXCEPTION_CONTINUE_SEARCH))
{
printf("In handler block.\n");
}

return 0;
}

这段程序想演示一个recover exception的技巧,在C/C++中,用逗号串起来的表达式还是一个表达式,这个整体表达式的值是最后一个表达式的值,所以如果GetExceptionCode()结果是EXCEPTION_INT_DIVIDE_BY_ZERO,那么结果就是EXCEPTION_CONTINUE_EXECUTION,而之前的表达式也会被evaluate,nDivisor = 1,prinf函数也会执行,这样,在这个thread回去再次执行nResult = nDividend / nDivisor的时候,nDivisor已经是1了,于是是不会再次有异常发生。真的是这样吗?
如果是VC 6.0执行结果正确,如果是VC 6.0以后那么执行会导致死循环?

我分别用VC6.0 和 VC2008 的Debug mode去追这个问题,发现生成的asm code不同,一个是
VC2008:
idiv eax,ecx //ecx即为变量nDivisor的值,后面当nDivisor的值修改后,ecx的值也会变为1
VC 6.0
idiv eax, [nDivisor Address] //这个更不用讲了,当nDivisor修改后,重新去执行idiv这条指令的话,nDivisor也为1.

这个问题真是找不到原因?

不过大家要注意一点:1) __except(EXCEPTION_CONTINUE_EXECUTION)是让thread回到发生exception的机器指令,不是回到发生exception的C/C++语句;
...全文
933 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
Coder_Y_Jao 2012-10-26
  • 打赏
  • 举报
回复
vc2008有更好的方式,当然得依赖于操作系统的支持。
重新翻了下《windows核心编程》,发现下面这对函数对于我们recover exception有帮助
AddVectoredContinueHandler
RemoveVectoredContinueHandler

程序修改如下:

#include "stdafx.h"
#include <windows.h>

#include <iostream>
using namespace std;



#define VAR_WATCH() printf("nDividend=%d, nDivisor=%d, nResult=%d.\n",\
nDividend, nDivisor, nResult)

LONG WINAPI ExceptionHandler(struct _EXCEPTION_POINTERS * pExceptionInfo)
{

pExceptionInfo->ContextRecord->Ecx = 1;
return 0;
}



int _tmain(int argc, _TCHAR* argv[])
{
int nDividend = 22, nResult = 100;
volatile int nDivisor = 0;

/*nDividend++;

_asm INT 3;

_asm
{
mov eax, eax
__asm _emit 0xcd __asm _emit 0x03
nop
nop
}

DebugBreak();*/

__try
{
printf("Before div in __try block.\n");
VAR_WATCH();

PVOID pHandle = AddVectoredContinueHandler(1,ExceptionHandler);
nResult = nDividend / nDivisor;

printf("After div in __try block.\n");
VAR_WATCH();
RemoveVectoredContinueHandler(pHandle);
}
__except(printf("In __except block.\n"), VAR_WATCH(),
GetExceptionCode() == EXCEPTION_INT_DIVIDE_BY_ZERO ?
(nDivisor = 1, printf("Divide zero exception detected.\n"), VAR_WATCH(), EXCEPTION_CONTINUE_EXECUTION) :
(EXCEPTION_CONTINUE_SEARCH))
{
printf("In handler block.\n");
}

return 0;
}


__except中那个逗号表达式也不需要了
yuucyf 2012-10-26
  • 打赏
  • 举报
回复
谢谢(Yofoo)的回复:
基本上是这样的,
不过我用
__asm{
mov eax, DWORD PTR [nDividend]
cdq
idiv DWORD PTR [ nDivisor]
mov DWORD PTR [nResult], eax
}

替换
nResult = nDividend / nDivisor;
Yofoo 2012-10-26
  • 打赏
  • 举报
回复
idiv eax,ecx //ecx即为变量nDivisor的值,后面当nDivisor的值修改后,ecx的值也会变为1

当nDivisor的值修改后, ecx的值不会变, 编译后变量与寄存器,相关信息在exe里面是已经没有保留了
要继续执行可以用下面的方法



DWORD ExpFilter(EXCEPTION_POINTERS *pInfo)
{
(*((*pInfo).ContextRecord)).Ecx = 1;
return EXCEPTION_CONTINUE_EXECUTION;
}

void xxxxx::OnBnClickedButton1()
{
int nDividend = 22, nResult = 100;
volatile int nDivisor = 0;

__try
{
printf("Before div in __try block.\n");
// VAR_WATCH();
nResult = nDividend / nDivisor;
printf("After div in __try block.\n");
// VAR_WATCH();
}

__except(nDivisor=1, ExpFilter(GetExceptionInformation()))
{


printf("In handler block.\n");
}
}




16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧