[luabind] Deriving In Lua: Weak Ref Access Crashes After Garbage Collection
Brought to you by:
arvidn,
daniel_wallin
From: eduard m. <mue...@go...> - 2010-09-29 13:19:20
|
Hey all, first a big thanks to Daniel Wallin & co for the great work on luabind! I'm a former boost::python user, so switching over to luabind was a breeze and am enjoying luabind a lot. Unfortunately I'm now having some troubles with the weak refs in luabind::wrap_base, and I'm not sure if its just me being stupid or a bug in either Lua or Luabind. Maybe you guys could give me a hint. What I basically do, is inheriting from a wrap_base'd class in Lua. Then access the lua class objects from within C++ via the wrap_base (which will resolve the lua object with its weak_ref). Most of the time this works just fine as expected and documented here: http://www.rasterbar.com/products/luabind/docs.html#deriving-in-lua But sometimes (really sometimes) the garbage collector seems to destroy the weak_refs that do point to the lua class object while the lua and C++ objects are still alive. I could not find out what destroys the weak_refs, just know that they are gone at some point. So accessing the Lua objects from C++ results into a crash sooner or later. Below is a test case for the problem. Crash was verified with luabind 0.9 and Lua 5.1 (Visual CPP and GCC, debug and release builds) To test, simply run the resulting binary. It should crash sooner or later in "call_member", because object_rep can't be resolved anymore (points to nil or a number - some junk?). "local dummy2, dummy3, dummy4" in the tests make the problem just more likely. Adding a "collectgarbage()" and the end of each iteration avoids the crash. Unfortunately its more or less impossible for me to debug this in luabind, because this happens more or less randomly at "some point" after garbagecollection. So that's all I know so far. Thanks for reading and any hints! Best regards, Eduard Müller ===<<< WeakRefTest.cpp extern "C" { #include "lua.h" #include "lualib.h" } #include <luabind/luabind.hpp> // ============================================================================= class CppClass { public: virtual std::string virtual_func() { return "CppClass"; } }; class CppClassWrapper : public CppClass, public luabind::wrap_base { public: virtual std::string virtual_func() { return call<std::string>("virtual_func"); } static std::string default_virtual_func(CppClass* ptr) { return ptr->CppClass::virtual_func(); } }; static std::string call_virtual_func(CppClass* ptr) { return ptr->virtual_func(); } // ============================================================================= int main(int, char*) { lua_State* L = lua_open(); luaL_openlibs(L); luabind::open(L); luabind::module(L)[ luabind::def("call_virtual_func", call_virtual_func), luabind::class_<CppClass, CppClassWrapper>("CppClass") .def(luabind::constructor<>()) .def("virtual_func", &CppClass::virtual_func, &CppClassWrapper::default_virtual_func) ]; // segfaults sooner or later while calling "call_virtual_func": luaL_dostring(L, "class 'LuaClass'(CppClass)\n" "function LuaClass:__init()\n" " CppClass.__init(self)" "end\n" "function LuaClass:virtual_func()\n" " return 'LuaClass'" "end\n" "\n" "for i=1,10000 do\n" " local dummy = LuaClass()\n" " local dummy2 = LuaClass()\n" " local dummy3 = LuaClass()\n" " local dummy4 = LuaClass()\n" " assert(dummy:virtual_func() == 'LuaClass')\n" " assert(call_virtual_func(dummy) == 'LuaClass')\n" "end\n"); lua_close(L); return 0; } ===>>> WeakRefTest.cpp |