Deriving In Lua: Weak Ref Access Crashes After Garbage Collection

classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Deriving In Lua: Weak Ref Access Crashes After Garbage Collection

eduard mueller
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

------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user
Reply | Threaded
Open this post in threaded view
|

Re: Deriving In Lua: Weak Ref Access Crashes After Garbage Collection

eduard mueller
Hey,

just have seen that the "[luabind] weak_ref issue" topic already
describes exactly this problem/bug, and Max McGuire already submitted
a patch here: "[luabind] weak_ref issue patch". Sorry for the double
post.

I've tested the patch and this perfectly solves the
problem/testcase/crash below. Any chance that the patch gets verified
and applied soon in the github?

Best regards,
Eduard


On Wed, Sep 29, 2010 at 15:18, eduard mueller

<[hidden email]> wrote:

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

------------------------------------------------------------------------------
Start uncovering the many advantages of virtual appliances
and start using them to simplify application deployment and
accelerate your shift to cloud computing.
http://p.sf.net/sfu/novell-sfdev2dev
_______________________________________________
luabind-user mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/luabind-user