zoukankan      html  css  js  c++  java
  • luaL_error与c++ stack unwind的冲突

      一般在用c写的lua函数里,检测到某些参数或前置条件错误时,会用luaL_error来报错,这时脚本层如果是xpcall,其错误处理函数就会被调用,在其中可用debug.traceback()来打印记录错误栈,这是脚本错误调试的常用做法。

      但是在c++环境中使用lua时,却有一个细微而致命的bug:lua通常是按c语言方式编译,因此luaL_error最终会调用longjump来实现跨函数远程跳转,而这种跳转不会遵循c++关于stack unwinding的规范,其最直接的影响就是局部变量的析构函数不会被调用。

      如果使用的是官方版lua,那么可以用c++方式编译lua来解决。但是如果用的luajit,它本身是不支持c++编译的(很多语法错误),那只有自求多福了,在luajit的网站上对此也有说明:

    C++ Exception Interoperability

    LuaJIT has built-in support for interoperating with C++ exceptions. The available range of features depends on the target platform and the toolchain used to compile LuaJIT:

    Platform Compiler Interoperability
    POSIX/x64, DWARF2 unwinding GCC 4.3+ Full
    Other platforms, DWARF2 unwinding GCC Limited
    Windows/x64 MSVC or WinSDK Full
    Windows/x86 Any No
    Other platforms Other compilers No

    Full interoperability means:

    • C++ exceptions can be caught on the Lua side with pcall()lua_pcall() etc.
    • C++ exceptions will be converted to the generic Lua error "C++ exception", unless you use the C call wrapper feature.
    • It's safe to throw C++ exceptions across non-protected Lua frames on the C stack. The contents of the C++ exception object pass through unmodified.
    • Lua errors can be caught on the C++ side with catch(...). The corresponding Lua error message can be retrieved from the Lua stack.
    • Throwing Lua errors across C++ frames is safe. C++ destructors will be called.

    Limited interoperability means:

    • C++ exceptions can be caught on the Lua side with pcall()lua_pcall() etc.
    • C++ exceptions will be converted to the generic Lua error "C++ exception", unless you use the C call wrapper feature.
    • C++ exceptions will be caught by non-protected Lua frames and are rethrown as a generic Lua error. The C++ exception object will be destroyed.
    • Lua errors cannot be caught on the C++ side.
    • Throwing Lua errors across C++ frames will not call C++ destructors.

    No interoperability means:

    • It's not safe to throw C++ exceptions across Lua frames.
    • C++ exceptions cannot be caught on the Lua side.
    • Lua errors cannot be caught on the C++ side.
    • Throwing Lua errors across C++ frames will not call C++ destructors.
    • Additionally, on Windows/x86 with SEH-based C++ exceptions: it's not safe to throw a Lua error across any frames containing a C++ function with any try/catch construct or using variables with (implicit) destructors. This also applies to any functions which may be inlined in such a function. It doesn't matter whether lua_error() is called inside or outside of a try/catch or whether any object actually needs to be destroyed: the SEH chain is corrupted and this will eventually lead to the termination of the process.

      在x86平台上是完全不支持的。那么解决办法只有一条:自己保证luaL_error的调用不会冲掉局部对象的析构函数。在同一个函数里,一般可以用无条件的块来人为分隔作用域,如:

    {
      std::string s="abc";
      ...
    }
    luaL_error(L,...);

      但是如果上层函数中还有局部对象,那只有自己根据具体的业务需求做调整了。通常来说,通过lua_register注册的c函数,其上层调用就是lua函数了,因此只要管好从它到抛出错误的点之间的调用路径上,没有被冲击的局部对象即可。但如果调用该c函数的lua函数,本身又是从另一个c函数里调过来的,该怎样考虑呢?很简单,从c里调lua时,必须包在pcall里,这样抛上来的错误就一定到此截止了。

  • 相关阅读:
    AcWing 157. 树形地铁系统 (hash判断树同构)打卡
    AcWing 156. 矩阵 (哈希二维转一维查询)打卡
    AcWing 144. 最长异或值路径 01字典树打卡
    AcWing 143. 最大异或对 01字典树打卡
    AcWing 142. 前缀统计 字典树打卡
    AcWing 139. 回文子串的最大长度 hash打卡
    AcWing 138. 兔子与兔子 hash打卡
    常用C库函数功能及用法
    编程实现C库函数
    C语言面试题5
  • 原文地址:https://www.cnblogs.com/wellbye/p/3019006.html
Copyright © 2011-2022 走看看