Comments (14)
When registering the constructor, i was passing the callable to a function "unpacker" (what we use for normal functions), which by default is pushing the result if the call to the stack (in this case the result of the constructor is a T*), but the constructor was already pushing the newly created pointer on the stack via an owning userdata, that was then lost. The fix was to use a special unpacker that is just calling the constructor and not push again a raw pointer on the stack.
from luabridge3.
Another issue I'm seeing is that when my Lua code calls the constructor with
local foo = foobar.foo()
Inside the proxy constructor this happens:
int numArgs = lua_gettop(L);
I get numArgs == 2. Based on the docs, I was expecting numArgs == 1 (since it says the arguments start at stack location 2 if they are there). What is the correct method to get the number of arguments passed to a proxy constructor?
EDIT:
Lemme guess: the 1st argument is the void ptr, the last argument is the Lua state, and the arguments to my function are in the middle.
from luabridge3.
I'm closing this issue, because whatever is going on is more complicated than I thought. Will reopen a new issue if appropriate to do so.
from luabridge3.
Hi! I have a same problem, hove you solve it?
from luabridge3.
No, I'm trying to come up with a test case that doesn't require a lot of dependencies in my code. So far no luck. But I have a situation that is very consistent:
- if it has a traditional constructor the code works
- if it has a proxy constructor the object gets garbage collected in mid-coroutine and the program crashes.
from luabridge3.
If you compile this test case so that the traditional constructor is selected (perhaps by upping the LUABRIDGE_MAJOR_VERSION
comparison value to 4
) then the script runs without errors in both main line and coroutine. If you change the comparison value to 3
so that the proxy constructor is used, the do_foo
function usually fails to get past printing 30000 before the system crashes.
The problem appears to be that something about the proxy constructor makes Lua think foo
can be garbage-collected, so the foo
variable is getting destroyed out from under the loop.
Here is a simplified class layout for my test case. (DoublyLinkedList
drafted by ChatGPT.):
class Node {
public:
int data;
Node* next;
Node* prev;
Node(int value) {
data = value;
next = nullptr;
prev = nullptr;
}
int val() { return data; }
Node* next_node() { return next; }
};
class DoublyLinkedList {
public:
DoublyLinkedList(int numToAdd = 0) {
head = nullptr;
tail = nullptr;
for (int value = 1; value<=numToAdd; value++) {
addBack(value);
}
}
~DoublyLinkedList()
{
while(head) removeBack();
}
void addBack(int value) {
Node* newNode = new Node(value);
if (tail == nullptr) {
head = newNode;
tail = newNode;
}
else {
newNode->prev = tail;
tail->next = newNode;
tail = newNode;
}
}
void removeBack() {
if (tail == nullptr) {
std::cout << "List is empty\n";
return;
}
Node* temp = tail;
tail = tail->prev;
if (tail != nullptr) {
tail->next = nullptr;
}
else {
head = nullptr;
}
delete temp;
}
Node* first() { return head; }
private:
Node* head;
Node* tail;
};
class foo
{
DoublyLinkedList list;
public:
foo(int size = 5000) : list(size) {}
Node* first() { return list.first(); }
Node* next(Node* curr) { return curr->next_node(); }
};
class bar
{
foo* foo_;
public:
bar(foo* f) : foo_(f) {}
Node* first() { return foo_->first(); }
Node* next(Node* curr) { return foo_->next(curr); }
};
Here is the LB3 registration:
luabridge::getGlobalNamespace(L)
.beginNamespace("foobar")
.beginClass<Node>("Node")
.addFunction("val", &Node::val)
.endClass()
.beginClass<foo>("foo")
#if LUABRIDGE_MAJOR_VERSION >= 3
.addConstructor([](void*p, lua_State* L)
{
const int numArgs = lua_gettop(L);
const int size = (numArgs > 2) ? luabridge::Stack<int>::get(L, 2).value() : 5000;
return new(p) foo(size);
})
#else
.addConstructor<void(*)(size_t)>()
#endif
.addFunction("first", &foo::first)
.addFunction("next", &foo::next)
.endClass()
.beginClass<bar>("bar")
.addConstructor<void(*)(foo *)>()
.addFunction("first", &bar::first)
.addFunction("next", &bar::next)
.endClass()
.endNamespace();
Here is the lua code to run it:
local function do_foo(header)
print ("********** "..header.." **********")
local foo = foobar.foo(500000)
local bar = foobar.bar(foo)
local next = bar:first()
while next do
local v = next:val()
if v % 10000 == 0 then
print("v: "..tostring(v))
if header == "coroutine" then
--coroutine.yield()
end
--collectgarbage("collect")
end
next = bar:next(next)
end
print ("finished "..header)
end
do_foo("main function")
local my_coroutine = coroutine.create(function()
do_foo("coroutine")
end)
while true do
local success, errmsg = coroutine.resume(my_coroutine)
if not success then
error(errmsg)
end
if coroutine.status(my_coroutine) == "dead" then
break
end
end
from luabridge3.
Thanks for the repro case, will give it a spin.
from luabridge3.
After checking, it seems it has nothing to do with coroutines.
from luabridge3.
Thanks.
I'm guessing it might have something to do with ownership,
because when i create a class via
.addStaticFunction("new", [](int i){ return new Bar(i); })
the problem does not occur.
from luabridge3.
It's strange, because when i invoke the 2 constructors, they do exactly the same, but one is passing the void* to an internal lambda, the other exposes the pointer to the registered lambda. It's weird that this is messing with the lifetime (the object has the same semantic in luabridge, regardless of the constructors).
from luabridge3.
I have only tried this with Lua 5.4. Have you tried it with earlier versions? I know there was a rewrite of gc in 5.4. May this is a Lua bug.
from luabridge3.
I can save you the trouble of trying a different Lua version. It still fails in Lua 5.2.
from luabridge3.
For context, two possibly important features of the test case are:
- The class that is being gc'd (
foo
) is only referenced once at the top of the function. It is then passed to a C class and goes out of the knowledge of Lua. The C classes dish up its contents from there on out. - The function churns a ton of Lua local variables, prompting gc in mid-stream.
It wasn't until I built both of these features into the test case that I could get it to consistently fail.
I also had to jack up the number of reps. It didn't fail at 5000 at all, and it only failed sporadically at 50000. But 500000 did the trick.
from luabridge3.
I'm thrilled you found a fix. I would be interested in a summary of what the problem was, if you've got the time.
from luabridge3.
Related Issues (20)
- Compiler error use of deleted function luabridge::TypeResult<T>::TypeResult(...) HOT 6
- Enhancement Request: Custom error function for `lua_pcall`. HOT 11
- Error C3861 (using with Luau) HOT 3
- Can I cast types inside Lua? HOT 4
- Duplicate symbols on Win32 with default __stdcall HOT 9
- Debug names of C functions for Luau HOT 8
- Extensible class bug with inheritance
- Add support for addStaticIndexMetamethod and addStaticNewIndexMetamethod
- Using LuaBridge3 in a precompiled header on MSVC leads to an internal compiler error HOT 2
- Use of std::shared_ptr on classes without `std::enable_shared_from_this` HOT 1
- Stateful lambdas registered as functions loose state HOT 2
- Compile error with Cfunc property getter/setter HOT 2
- std::vector to 0-based Lua table HOT 5
- MSC Warning C4146 HOT 2
- How to expose C++ data (a vector, in this case) to Lua without making a copy? HOT 2
- Does LuaBridge3 Support Android for SDL2-based Games? HOT 2
- Passing a Lua Table (LuaRef) as an argument to C++ function HOT 1
- How to get the name of a Lua variable? HOT 2
- Comparison Issue Between `uint64_t` in C++ and Numeric Constant in Lua HOT 8
- NAI run lua code in string from cpp
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from luabridge3.