LuaBridge icon indicating copy to clipboard operation
LuaBridge copied to clipboard

Chaining and garbage collection

Open bolshakov-a opened this issue 2 years ago • 3 comments

Lua GC erroneously (?) deletes an object when Lua still holds a reference on it obtained through a chain of method calls. E. g.:

#include <lua.hpp>
#include <LuaBridge/LuaBridge.h>

#include <iostream>

struct A {
  ~A() { i = -1; }
  int i = 0;
  A& fn() { i = 5; return *this; }
  int getI() const { return i; }
};

A getA() { return A{}; }

void test() {
  auto pState = luaL_newstate();
  luaL_openlibs(pState);

  luabridge::getGlobalNamespace(pState)
    .addFunction("getA", getA)
    .beginClass<A>("A")
      .addFunction("fn", &A::fn)
      .addFunction("getI", &A::getI)
    .endClass();

  static const char prog[] = R"(
local a1 = getA():fn()
collectgarbage("collect")
print(a1:getI())
)";

  luaL_loadbuffer(pState, prog, sizeof(prog) - 1, 0);
  lua_call(pState, 0, 0, 0);
  lua_close(pState);
}

The program outputs -1 (or some garbage if additional allocations were performed later), which means destructor of A was called before a1:getI() call. If the line local a1 = getA():fn() is replaced by

local a1 = getA()
a1:fn()

the output becomes 5, as expected initially.

Is it a bug of LuaBridge, or Lua itself, or such a chaining is not allowed for some reasons?

bolshakov-a avatar Aug 05 '23 09:08 bolshakov-a

Refer to the lifetime section of the manual.

http://vinniefalco.github.io/LuaBridge/Manual.html#s3

You cannot take a reference of a Lua managed object without making sure you keep it alive in lua land. Lua will have a reference count of 0 for the A created by getA because you are not keeping the refcount alive and it's free to garbage collect it.

kunitoki avatar Aug 05 '23 12:08 kunitoki

Thanks! But it seems like LuaBridge might determine that a pointer or a reference returned from C++ points to an object with Lua lifetime and increment its refcounter. On the other hand, there is a working approach with RefCountedObjectPtr.

bolshakov-a avatar Aug 05 '23 21:08 bolshakov-a

It can't, it would need to register each instance of binded classes created from lua into the registry and compare everytime a reference or pointer is to be handled.

kunitoki avatar Aug 05 '23 23:08 kunitoki