Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chaining and garbage collection #319

Open
bolshakov-a opened this issue Aug 5, 2023 · 3 comments
Open

Chaining and garbage collection #319

bolshakov-a opened this issue Aug 5, 2023 · 3 comments

Comments

@bolshakov-a
Copy link

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?

@kunitoki
Copy link

kunitoki commented Aug 5, 2023

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.

@bolshakov-a
Copy link
Author

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.

@kunitoki
Copy link

kunitoki commented Aug 5, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants