• 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里,这样抛上来的错误就一定到此截止了。

  • 相关阅读:
    20180604_Myeclipse下配置SVN报错问题 svn
    20180603_升级Win10后,远程连接桌面连接,出现身份验证错误!
    20180603_navicat 连接sqlserver提示要安装 sql server native client
    VB.net程序实现分页
    多线程Demo
    多线程Demo VB.net
    SQLServer数据库子结构
    SQLServer数据库常用命令
    传播路径图调查2013年初
    拾遗
  • 原文地址:https://www.cnblogs.com/wellbye/p/3019006.html
Copyright © 2020-2023  润新知