开发者

Assertion failure in Luabind

I am currently having problems using Luabind to interface a Lua scripted AI with a C++ game.

I call an update function inside a loop (once per frame) and this function retrieves informations from C++ functions registered in Luabind.

My problem is as follows : After a variable, non predictible time, there is an assertion failure in Luabind wich causes an abort. The error always occurs into /usr/include/luabind/wrapper_base.hpp:124 while descending inside the Lua.

Do you have any idea on what can do that ? For my tests, the called functions in C++ and in LUA are always the same.

More details about the problem :

The content arround the assertion that failed in wrapper_base.hpp

typedef typename boost::mpl::if_<boost::is_void<R>, luabind::detail::proxy_member_void_caller<boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> >
, luabind::detail::proxy_member_caller<R, boost::tuples::tuple<BOOST_PP_ENUM(BOOST_PP_ITERATION(), LUABIND_TUPLE_PARAMS, _)> > >::type proxy_type;

// Comments removed

lua_State* L = m_self.state();
m_self.get(L);
assert(!lua_isnil(L, -1));
detail::do_call_member_selection(L, name);

if (lua_isnil(L, -1))
  {
    lua_pop(L, 1);
    throw std::runtime_error("Attempt to call nonexistent function");
  }

// push the self reference as the first parameter
m_self.get(L);

// now the function and self objects
// are on the stack. These will both
// be popped by pcall
return proxy_type(L, args);

The exact error

bomberman: /usr/include/luabind/wrapper_base.hpp:124: typename boost::mpl::if_<boost::is_void<T>, luabind::detail::proxy_member_void_caller<boost::tuples::tuple<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> >, luabind::detail::pro开发者_StackOverflow中文版xy_member_caller<R, boost::tuples::tuple<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> > >::type luabind::wrap_base::call(const char*, luabind::detail::type_<Derived>*) const [with R = void]:
Assertion `!(lua_type(L, (-1)) == 0)' failed.
Aborted (core dumped)


I had this problem a few days ago. In my particular case, the implicitly created Lua table that held all the methods that had been overridden in Lua for each object was being garbage collected, while the underlying C++ object was not. Because of this, if you tried to call a Lua member function from a C++ object, it would fail.

The solution in my case was to keep a reference to the lua table alive as long as the C++ instance was alive. That was as simple as adding a luabind::object field to the C++ class and then setting it when you instantiate the class and it will be destroyed when the C++ class's destructor is called, so in most cases you won't have to worry about memory leaks. My code looks something like this now:

class LuaC : public BaseC, public luabind::wrap_base {
    private:
        luabind::object _self; //retain a reference to the Lua part of this object so it doesn't get gc'd
    public:
        void setSelf(luabind::object nSelf) { _self=nSelf; }
};
//expose LuaC including the method setSelf
// ...

(BaseC is the C++ class you're wrapping)

Then from Lua, whenever you instantiate an instance of LuaC, call setSelf and pass self as an additional argument

c = LuaC()
c:setSelf(self)

I would be surprised if there isn't a way to simplify this and put it all inside the LuaC constructor so that it's less error-prone (ie so you don't have to worry about calling setSelf every time). But the documentation for LuaBind is rather shallow, so I couldn't find any way to do this.

Also, I believe the only way for this problem to occur is if you're telling Luabind to only use references like shared_ptrs, because then the Lua part get's garbage collected, along with the shared_ptr, but not necessarily the C++ instance referenced by the pointer. If Lua is managing the entire instance, then I don't see how the Lua table could get deleted while the C++ instance lives on.


It seems you are suffering from split ownership of the object. This usually happens when the wrapper for a C++ class does not properly wrap around virtual methods.

I encountered this issue before but it went away after I carefully implemented the wrapper. In my library, I don't need the workaround mentioned here.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜