luabind在尝试使用lua错误调用object方法时中止(luabind abort when trying to call object method with lua errors)

编程入门 行业动态 更新时间:2024-10-25 08:28:22
luabind在尝试使用lua错误调用object方法时中止(luabind abort when trying to call object method with lua errors)

我使用http://www.rasterbar.com/products/luabind/docs.html#deriving-in-lua中的示例来定义c ++中的一个类,我可以在lua中派生它:

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) ];

然后我在lua中创建了一个派生类:

class 'base_derived' (base) function base_derived:__init(str) base.__init(self,str) end function base_derived:f() this_function_doesnt_exist() end

任何对'f'的调用都应该抛出一个lua错误,如果我在lua中执行它会正常工作:

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

我想做相同的,但在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); }

但是'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); }

该行中的异常实际上并未抛出,但它是导致中止的原因。

但是,只有在lua函数导致lua错误时才会发生中止。 如果我评论'this_function_doesnt_exist()' - 调用,那么lua和c ++版本都运行得很好。

为什么'throw luabind :: error(L);' 导致中止,即使有潜在的lua错误,我还能做些什么来安全地从c ++调用该函数?

//编辑:这是中止时的调用堆栈(当'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++

这是中止的消息:

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:

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:

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:

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++:

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:

// 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. If I comment the 'this_function_doesnt_exist()'-call, both the lua- and c++-versions run just fine.

Why is the 'throw luabind::error(L);' causing an abort and what can I do to safely call the function from c++ even with potential lua errors?

// Edit: This is the call stack at the time of the abort (When 'luabind::call_member(o,"f",5);' is called):

> 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:

最满意答案

见第254行:

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

在这里, pcall要求lua执行你的x:f(5)等效调用。 显然这段代码会返回错误,因为pcall()会返回不同于零的内容。 这是预期的,因为你确实通过调用this_function_doesnt_exist()在lua中创建了一个错误。 这也解释了为什么在评论this_function_doesnt_exist()调用时不会发生中止。

然后,到C ++代码:

throw luabind::error(L);

这个错误是从析构函数抛出的: ~proxy_member_void_caller() ,结果是从析构函数中抛出异常是不好的做法 。 这个问题以luabind( 参见这个问题 )而闻名,以便在没有投掷的情况下触发中止调用。

解决方法是在~proxy_member_void_caller()的签名中添加noexcept(false) ~proxy_member_void_caller() ,如下所示:

~proxy_member_void_caller() noexcept(false)

See line 254:

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

Here, pcall is asking lua to execute your x:f(5) equivalent call. Apparently this code returns an error because pcall() returns something different than zero. This is expected because you are indeed creating an error in lua by calling this_function_doesnt_exist(). This also explains why the abort does not happen when you comment the this_function_doesnt_exist() call.

Then, to the C++ code:

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. This problem is known for luabind (see this question) to trigger the call of abort without even throwing.

The solution is to add noexcept(false)to the signature of ~proxy_member_void_caller(), like this:

~proxy_member_void_caller() noexcept(false)

更多推荐

本文发布于:2023-08-06 17:42:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1454034.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:错误   方法   object   luabind   lua

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!