首页
社区
课程
招聘
[原创]关于异常处理
发表于: 2010-10-20 15:27 8774

[原创]关于异常处理

2010-10-20 15:27
8774

关于异常处理, Exception Handling,写了点总结。

VC6 begin ------------

如果VC6不带编译选项 /GX, 代码中便不支持 try catch 否则会报错:
        warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX

在VC6中,编译选项 /GX 可以通过
        Project Settings | C/C++ | C++ Language | Enable exception handling
来控制是否使用。

编译选项 /EHsc 与 /GX 等价。

VC6新建工程默认是带 /GX 的。但新建 ATL COM AppWizard 工程默认是不带 /GX 的。

检查带 try catch 的 C++ 代码生成的汇编,发现它是用以下框架实现的:
                push    -1
                push    offset __ehhandler$?test@@YAXXZ
                mov     eax, large fs:0
                push    eax
                mov     large fs:0, esp
                ....
__ehhandler$?test@@YAXXZ:
                mov     eax, offset stru_426490        ; stru_426490 is struct _msExcept
                jmp     ___CxxFrameHandler

_msExcept       struc ; (sizeof=0x20, variable size)
Magic           dd ?                    ; base 16
Count           dd ?                    ; base 10
InfoPtr         dd ?                    ; offset
CountDtr        dd ?                    ; base 10
DtrPtr          dd ?                    ; offset
_unk            dd 3 dup(?)
Info            _msExcInfo 0 dup(?)
_msExcept       ends

VC6 也可以用 __try __except 它是这样实现的:
                push    -1
                push    offset __sehtable$?test@@YAXXZ
                push    offset __except_handler3
                mov     eax, dword ptr fs:0
                push    eax
                mov     dword ptr fs:0, esp
                ...

__sehtable$?test@@YAXXZ _msEH <0FFFFFFFFh, offset $L600, offset $L601>

_msEH           struc ; (sizeof=0xC)
_unk            dd ?                    ; base 16
FilterProc      dd ?                    ; offset
ExitProc        dd ?                    ; offset
_msEH           ends

这种__try __except不需要 /GX 可以直接支持

总之,无论是 try catch 还是 __try __except 都是通过 X86 CPU 提供的 FS:0 来实现的,可以认识,它实现上是一回事。就是说,在汇编一级,它们是同理的。不过是 FS:0 对应的实现函数有不同的写法。如果发现 __except_handler3 那是 __try __except.如果发现
___CxxFrameHandler, 那是 try catch.
VC6 end ------------

VS 2008 begin -----------
换 Visual Studio 2008 测试,
        Visual Studio 2008 Professional Edition
        Version 9.0.21022.8 RTM
新建一个 Win32 Console 工程,测试可以直接使用 try catch 在编译选项中已经包含了 /EHsc

打开工程属性,
        C/C++ | Code Generation | Enable C++ Exceptions
对应的选择
        No
        Yes /EHsc
        Yes with SEH Exceptions /EHa

网上搜一下,有说法:/EHa 的意思是 asynchronous model, /EHsc 的意思是 synchronous

如果选 No 代码中便不支持 try catch 否则会报错:
        warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc

测试try catch 用 release 编译 /EHsc 或 /EHa 选项,结果类似 VC6 ,用到了
        jmp __CxxFrameHandler3        ; export from MSVCR90.dll

VS 2008 end -----------

最后总结

使用 try catch 技术,叫做 C++ exception handling
使用 __try __except 技术,叫做 structured exception handling(简称SEH)
另外还有 MFC exceptions 我想应该是 MFC 所做的扩展。

try throw catch 是C++标准关键字。而 __try __exception __finally 是 Microsoft 扩展。

无论是 C++ exception handling 还是 structured exception handling ,都是通过 X86 CPU 提供的 FS:0 来实现的,可以认为,它们实现上是一回事。可以用 _set_se_handler 来实现自己的处理程序。

网上找到一句话:
As stated by MSDN, for "C++ programs, C++ exception handling should be used instead of structured exception handling"

就是说,Microsoft 推荐我们用 try catch 尽量不要用 __try __except.

Microsoft 很 BT 地推荐我们用 C 而不是 C++ 写驱动,所以我们在驱动代码中大量看到 __try __except 而看不到 try catch. 实现上,用 C++ 写驱动是可以的,在驱动中用 try catch 也是可以的。

C 也支持 try catch ,这时应该叫 C exception handling 了。

C++ exception handling 使用简单说明

C++ exception handling 可以包含 try throw catch,可以有多个 catch,每个 catch 处理不同的数据类型,用 catch(...) 处理所有类型。

在函数定义后面可以加 throw 来表示这个函数可能会抛出异常。
        void funcname(double) throw(string, double, bool);

如果 #include <exception> 可以使用 class std::exception.

structured exception handling(简称SEH) 使用简单说明
SEH 可以包含
        __try
        __except
        __finally
        __leave
提供了
        EXCEPTION_CONTINUE_EXECUTION (–1)
        EXCEPTION_CONTINUE_SEARCH (0)
        EXCEPTION_EXECUTE_HANDLER (1)
甚至可以从出问题的地方继续执行。

提供了
        GetExceptionCode()
        GetExceptionInformation()
函数。

__try __leave __finally 实际上是 Microsft 利用 fs:0 技术所做的一个C++扩展,它与异常无关,方便编程。


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 7
支持
分享
最新回复 (2)
雪    币: 338
活跃值: (103)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
2
学习了
2010-10-20 17:02
0
雪    币: 168
活跃值: (152)
能力值: ( LV11,RANK:180 )
在线值:
发帖
回帖
粉丝
3
学习~~~~
2010-10-22 10:23
0
游客
登录 | 注册 方可回帖
返回
//