本文主要是介绍C++ SEH结构化异常捕获处理(双平台支持 Linux、Windows)。,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
测试:
try_ctor();try_call([](){printf("1111111111111111111111\r\n");int* p = NULL;*p = 100;throw 1;// try_eeh();}, [](){printf("2222222222222222222222\r\n");});
设置NULL指针P的值引发程式崩溃,可以被正确捕获(catch)处理,不支持 finally,可以自己改改,这是一个相对来说较为简洁的实现,该实现的代码可以在WIN、LINUX平台上编译通过且正常就绪运行。
##
try_call 保护代码快调用类似 lua 的 xpcall,try_ctor,注册所需的信号,try_eeh 是回到当前压入栈顶的结构化的异常处理器,vc++ 的seh 结构化处理也是这个处理,可以参考易语言seh结构化异常处理,写这个小哥是用汇编来写的,或者自己反调试看看seh展开的机器代码,思想上这个东西都差不多,但 try_catch 也有缺点,如果栈坏的很彻底就没法恢复了,比如C#.NET,单一时间内异常抛多了,catch 是捕获不了的,毕竟不是java 这类型的语言。
实现:
class __try_context__ final {
public:jmp_buf __try_jmp_buf;bool __try_jmp_flg;public:std::function<void()> __try_block;std::function<void()> __try_catch;public:inline __try_context__(): __try_jmp_flg(false) {}
};static thread_local std::list<std::shared_ptr<__try_context__>> __try_contexts__;
static thread_local std::shared_ptr<__try_context__> __try_eeh__;static std::shared_ptr<__try_context__> try_seh_pop_context() noexcept {auto tail = __try_contexts__.begin();auto endl = __try_contexts__.end();if (tail == endl) {return NULL;}std::shared_ptr<__try_context__> context = std::move(*tail);__try_contexts__.erase(tail);return context;
}static void try_seh_pop() noexcept {std::shared_ptr<__try_context__> context = try_seh_pop_context();context.reset();
}static void try_seh_eeh_clear() noexcept {__try_eeh__ = NULL;
}static void try_seh_linux(__try_context__* context) noexcept {int32_t signo = setjmp(context->__try_jmp_buf);if (signo == 0) {context->__try_jmp_flg = true;context->__try_block();try_seh_pop();}else {context = __try_eeh__.get();context->__try_catch();}try_seh_eeh_clear();
}#ifdef _MSC_VER
static void try_seh_windows(__try_context__* context) {__try {try_seh_linux(context);}__except (sehCrashFilter(GetExceptionCode(), GetExceptionInformation())) { /* GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH */context->__try_catch();try_seh_pop();try_seh_eeh_clear();}
}
#endifvoid try_call(std::function<void()>&& __try_block, std::function<void()>&& __try_catch) {if (NULL == __try_block) {throw std::runtime_error("__try_block argument not allow is NULL.");}__try_context__* context = NULL;if (NULL == __try_catch) {throw std::runtime_error("__try_catch argument not allow is NULL.");}else{std::shared_ptr<__try_context__> try_context = std::make_shared<__try_context__>();if (NULL == try_context) {throw std::runtime_error("unable to make try context.");}else {context = try_context.get();}try_context->__try_block = std::move(__try_block);try_context->__try_catch = std::move(__try_catch);__try_contexts__.emplace_back(try_context);}#ifdef _MSC_VERtry_seh_windows(context);
#elsetry_seh_linux(context);
#endif
}bool try_eeh() {jmp_buf __try_jmp_buf;for (;;) {{std::shared_ptr<__try_context__> context = try_seh_pop_context();if (NULL == context) {break;}if (!context->__try_jmp_flg) {continue;}else {__try_eeh__ = context;}memcpy(__try_jmp_buf, context->__try_jmp_buf, sizeof(__try_jmp_buf));}longjmp(__try_jmp_buf, 1);return true;}return false;
}void try_ctor() {auto __try_eeh__ = [](int signo) noexcept -> void {bool ok = try_eeh();if (!ok) {signal(signo, SIG_DFL);raise(signo);}};#ifdef __GNUC__signal(SIGTRAP, __try_eeh__); // 调试陷阱signal(SIGBUS, __try_eeh__); // 总线错误(常见于结构对齐问题)signal(SIGQUIT, __try_eeh__); // CTRL+\退出终端signal(SIGSTKFLT, __try_eeh__); // 进程堆栈崩坏
#endifsignal(SIGSEGV, __try_eeh__); // 段错误(试图访问无效地址)signal(SIGFPE, __try_eeh__); // 致命的算术运算问题(常见于试图除以零或者FPU/IEEE-754浮点数问题)signal(SIGABRT, __try_eeh__); // 程式被中止执行(常见于三方库或固有程式遭遇一般性错误执行abort()强行关闭主板程式)signal(SIGILL, __try_eeh__); // 非法硬件指令(CPU/RING 0 ABORT)
}
这篇关于C++ SEH结构化异常捕获处理(双平台支持 Linux、Windows)。的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!