- 主题:如果才能catch住null pointer异常
有人已经写了 setjmp / longjmp
http://www.programmingunlimited.net/siteexec/content.cgi?page=mingw-seh
// Note the unmatched braces in these macros. These are to allow one to use
// the same variable name more than once (new scope).
#define __seh_try \
{ \
__SEH_EXCEPTION_REGISTRATION _lseh_er; \
__SEH_HANDLER _lseh_handler; \
\
_lseh_er.handler = \
reinterpret_cast<PEXCEPTION_HANDLER>(__SEH_HANDLER::ExceptionRouter); \
_lseh_er.exthandler = &_lseh_handler; \
asm volatile ("movl %%fs:0, %0" : "=r" (_lseh_er.prev)); \
asm volatile ("movl %0, %%fs:0" : : "r" (&_lseh_er)); \
int _lseh_setjmp_res = setjmp(_lseh_handler.context); \
while(true) { \
if(_lseh_setjmp_res != 0) { \
break; \
} \
#define __seh_except(rec, ctx) \
break; \
} \
PEXCEPTION_RECORD rec = &_lseh_handler.excRecord; \
PCONTEXT ctx = &_lseh_handler.excContext; \
\
asm volatile ("movl %0, %%fs:0" : : "r" (_lseh_er.prev)); \
if(_lseh_setjmp_res != 0)
#define __seh_end }
【 在 z16166 的大作中提到: 】
: null pointer deref不是C++异常,或者说是系统相关的异常。
: 所以只有系统支持这种时才可能捕获。比如windows上SEH/VEH。Linux上只有signal handler。
: 除了OS,还得编译器支持。如果编译器不支持,只能手动搞。
: ...................
--
FROM 38.75.136.*
不用setjmp/longjmp的思路是?讲讲学习一下。
我断断续续看过异常处理好几次,没考虑过怎么自己实现,trap a hardware exception。这个实现还是挺简单的,很有启发性:
1 安装handler,setjmp
2 根据setjmp第一次返回值,执行 try 代码,
2.1 如果异常,跳到handler,拷贝 record和context, longjmp,回到 1,转3
3 根据setjmp第二次返回值,执行 except 代码
4 出作用域,移除当前handler
这种执行一半跳到另一个函数,处理一下,再跳回来带着返回值,很像cpp coroutine 的思路。
【 在 z16166 的大作中提到: 】
: 按说不需要setjmp/longjmp
: 不过要捕捉空指针异常,这个需求本身就有问题
:
--
修改:DoorWay FROM 61.185.186.*
FROM 61.185.186.*
再多讲点,比如有个cpp函数foo,进入foo后,
先把下面的汇编写上,再把正常的逻辑guarded body 填到注释那里吗?
最后用mingw编译?
someProcedure PROC FRAME:defAsmSpecificHandler
push rbp
.pushreg rbp
mov rbp, rsp
.setframe rbp, 0
.endprolog
__TRY
; Guarded Section of code (level 0)
_TRY
; Another Guarded Section of code (level 1)
_EXCEPT
; Another Exception Handler (level 1)
_FINALLY
__EXCEPT
; Exception Handler (level 0)
__FINALLY
mov rsp, rbp
pop rbp
ret
someProcedure ENDP
【 在 z16166 的大作中提到: 】
: C++编译器生成的__try/__except的汇编代码也是这个机制,就是建立SEH chain。
: 而且C++是可以调用汇编的,用汇编写的asm文件编译成obj给c++调用就行。
: 嵌入asm也行。
: ...................
--
FROM 61.185.186.*
这些汇编语言,需要再翻译成mingw认识的汇编形式吗,如果要测试的话?
【 在 DoorWay 的大作中提到: 】
: 再多讲点,比如有个cpp函数foo,进入foo后,
: 先把下面的汇编写上,再把正常的逻辑guarded body 填到注释那里吗?
: 最后用mingw编译?
: ...................
--
FROM 61.185.186.*
对着汇编参了一会,好像看懂了,哈哈,
这是为了调用 RtlUnwindEx,只传了俩参数,
这个函数要回到抛异常的现场,里面应该有longjmp
sub rsp, 30h
mov rax, pDispatcherContext
mov rax, [rax].DISPATCHER_CONTEXT.HistoryTable
mov [rsp+28h], rax
lea rax, originalExceptContext
mov [rsp+20h], rax
call RtlUnwindEx ; Must not return. If it returns there is an error.
add rsp, 30h ; We don't expect to come here, but anyway.
函数的签名:
NTSYSAPI VOID RtlUnwindEx(
[in, optional] PVOID TargetFrame,
[in, optional] PVOID TargetIp,
[in, optional] PEXCEPTION_RECORD ExceptionRecord,
[in] PVOID ReturnValue,
[in] PCONTEXT ContextRecord,
[in, optional] PUNWIND_HISTORY_TABLE HistoryTable
);
这个方案是:
1 通过修改 Proc:Frame属性,注册handler
2 定义汇编的MACRO,try/except/final,方便使用,记录try/catch的地址,记录到自定义的数据段,dataexcp
3 发生异常后,跳到handler。handler前面的拷贝、检测block嵌套没看懂,后面就是开头的RtlUnwindEx了…… 这顺利的话函数不会返回,一路跑完了退栈过程
【 在 z16166 的大作中提到: 】
: C++编译器生成的__try/__except的汇编代码也是这个机制,就是建立SEH chain。
: 而且C++是可以调用汇编的,用汇编写的asm文件编译成obj给c++调用就行。
: 嵌入asm也行。
: ...................
--
FROM 61.185.186.*
赞,我去React OS搜源码,里面调用 *internal,转到internal,注释就是你给的链接1 。
链接2很棒。我接下来看完。
xp源码泄漏的时候,版上是不是谁编译了。作者当时参照的还是os2。哈哈。
我回头也找找下载下。
【 在 z16166 的大作中提到: 】
: 你说得对,RtlUnwindEx内部有分支是走longjmp的
: 这有个逆出来的系列文章。太长,我没细看
:
http://www.nynaeve.net/?p=113: ...................
--
FROM 117.39.199.*
读完了 Matt Pietrek 的文章,过瘾~~
MingW那篇,使用setjmp/longjmp非常有启发性,
这篇对数据结构的建立,很有启发生,尤其是让我这种汇编门外汉,对栈帧的理解上升一大截。函数一进去 push ebp,这个ebp也被包含在 _EXCEPTION_REGISTRATION, 这个细节太棒了。还有,push时,栈的地址是下降的这个细节。
【 在 z16166 的大作中提到: 】
: 你说得对,RtlUnwindEx内部有分支是走longjmp的
: 这有个逆出来的系列文章。太长,我没细看
:
http://www.nynaeve.net/?p=113: ...................
--
修改:DoorWay FROM 38.75.136.*
FROM 38.75.136.*
是的,很开心
except block里第一句修改ESP,达到不回到 *handler3的,
也让我对 栈+寄存器 的虚拟机模型有点感觉了,
相对 stack-based 虚拟机是要复杂,也方便点。
【 在 z16166 的大作中提到: 】
: 恭喜你得到了她
:
--
FROM 124.114.151.*