简体   繁体   English

尝试使用lua错误调用对象方法时luabind中止

[英]luabind abort when trying to call object method with lua errors

I've used the example from http://www.rasterbar.com/products/luabind/docs.html#deriving-in-lua to define a class in c++ that I can derive from in lua: 我使用了http://www.rasterbar.com/products/luabind/docs.html#deriving-in-lua中的示例来定义我可以从lua派生的c ++类:

class base
{
public:
    base(const char* s)
    { std::cout << s << "\n"; }

    virtual void f(int a)
    { std::cout << "f(" << a << ")\n"; }
};

struct base_wrapper : base, luabind::wrap_base
{
    base_wrapper(const char* s)
        : base(s)
    {}

    virtual void f(int a)
    {
        call<void>("f", a);
    }

    static void default_f(base* ptr, int a)
    {
        return ptr->base::f(a);
    }
};

...

module(L)
[
    class_<base, base_wrapper>("base")
        .def(constructor<const char*>())
        .def("f", &base::f, &base_wrapper::default_f)
];

I've then created a derived class in lua: 然后,我在lua中创建了一个派生类:

class 'base_derived' (base)

function base_derived:__init(str)
    base.__init(self,str)
end

function base_derived:f()
    this_function_doesnt_exist()
end

Any call to 'f' is supposed to throw a lua error, which works fine if I do it in lua: 任何对'f'的调用都应该引发lua错误,如果我在lua中这样做,它会很好地工作:

local x = base_derived("Test")
x:f() -- Throws "attempt to call a nil value..." error

I'd like to do the equivalent of that, but in c++: 我想做相当于的事情,但是在c ++中:

auto g = luabind::globals(l);
auto r = g["base_derived"];
if(r)
{
    luabind::object o = r("Test");
    auto gm = luabind::object_cast<base_wrapper*>(o);
    if(gm != nullptr)
    {
        try
        {
            luabind::call_member<void>(o,"f",5);
        }
        catch(luabind::error &e)
        {
            std::cout<<"[LUA] Error: "<<e.what()<<std::endl;
        }
    }
    o.push(l);
}

However the 'luabind::call_member'-call causes an abort in 'luabind/detail/call_member.hpp', line 258: 但是,“ luabind :: call_member”调用会导致“ luabind / detail / call_member.hpp”第258行中止:

// Code snippet of luabind/detail/call_member.hpp
~proxy_member_void_caller()
{
    if (m_called) return;

    m_called = true;

    // don't count the function and self-reference
    // since those will be popped by pcall
    int top = lua_gettop(L) - 2;

    // pcall will pop the function and self reference
    // and all the parameters

    push_args_from_tuple<1>::apply(L, m_args);
    if (pcall(L, boost::tuples::length<Tuple>::value + 1, 0))
    {
        assert(lua_gettop(L) == top + 1);
#ifndef LUABIND_NO_EXCEPTIONS
////////////////////////////////////////////
        throw luabind::error(L); // LINE 258
////////////////////////////////////////////
#else
        error_callback_fun e = get_error_callback();
        if (e) e(L);

        assert(0 && "the lua function threw an error and exceptions are disabled."
            "If you want to handle this error use luabind::set_error_callback()");
        std::terminate();
#endif
    }
    // pops the return values from the function
    stack_pop pop(L, lua_gettop(L) - top);
}

The exception in that line isn't actually thrown, but it is what causes the abort. 该行中的异常实际上并未抛出,但这是导致异常终止的原因。

However, the abort only happens if the lua-functions causes a lua error. 但是,仅当lua函数导致lua错误时才会中止。 If I comment the 'this_function_doesnt_exist()'-call, both the lua- and c++-versions run just fine. 如果我评论“ this_function_doesnt_exist()”调用,那么lua版本和c ++版本都可以正常运行。

Why is the 'throw luabind::error(L);' 为什么是“ throw luabind :: error(L);” causing an abort and what can I do to safely call the function from c++ even with potential lua errors? 导致异常终止,即使存在潜在的lua错误,我该怎么做才能安全地从c ++调用该函数?

// Edit: This is the call stack at the time of the abort (When 'luabind::call_member(o,"f",5);' is called): //编辑:这是中止时的调用堆栈(当调用'luabind :: call_member(o,“ f”,5);'时):

>   vcruntime140d.dll!__CxxFrameHandler(EHExceptionRecord * pExcept, unsigned __int64 RN, _CONTEXT * pContext, _xDISPATCHER_CONTEXT * pDC) Line 213 C++
    ntdll.dll!RtlpExecuteHandlerForException()  Unknown
    ntdll.dll!RtlDispatchException()    Unknown
    ntdll.dll!KiUserExceptionDispatch() Unknown
    KernelBase.dll!RaiseException() Unknown
    vcruntime140d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 136    C++
    server.dll!luabind::detail::proxy_member_void_caller<boost::tuples::tuple<int const * __ptr64,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> >::~proxy_member_void_caller<boost::tuples::tuple<int const * __ptr64,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> >() Line 258    C++

And this is the abort message: 这是中止消息: 在此处输入图片说明

See line 254: 参见第254行:

if (pcall(L, boost::tuples::length<Tuple>::value + 1, 0))

Here, pcall is asking lua to execute your x:f(5) equivalent call. 在这里, pcall要求lua执行您的x:f(5)等效调用。 Apparently this code returns an error because pcall() returns something different than zero. 显然,此代码返回错误,因为pcall()返回的内容不同于零。 This is expected because you are indeed creating an error in lua by calling this_function_doesnt_exist() . 这是预料之中的,因为您确实通过调用this_function_doesnt_exist()在lua中创建了错误。 This also explains why the abort does not happen when you comment the this_function_doesnt_exist() call. 这也解释了为什么在注释this_function_doesnt_exist()调用时不会发生中止。

Then, to the C++ code: 然后,转到C ++代码:

     throw luabind::error(L);

This error is thrown from a destructor: ~proxy_member_void_caller() , and it turns out that throwing an exception from a destructor is bad practice . 从析构函数~proxy_member_void_caller()引发此错误,事实证明, 从析构函数引发异常是不好的做法 This problem is known for luabind ( see this question ) to trigger the call of abort without even throwing. 这个问题以luabind( 请参阅此问题 )而闻名,它可以触发甚至不抛出的异常终止调用。

The solution is to add noexcept(false) to the signature of ~proxy_member_void_caller() , like this: 该解决方案是增加noexcept(false)以签名~proxy_member_void_caller()就像这样:

~proxy_member_void_caller() noexcept(false)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM