How to get (up)values associated to C closures outside the given function?

Tags: c++ c pointers lua
By : Valkea

In the Lua 5.2 manual we can find the following text:

When a C function is created, it is possible to associate some values with it, thus creating a C closure (see lua_pushcclosure); these values are called upvalues and are accessible to the function whenever it is called.

Whenever a C function is called, its upvalues are located at specific pseudo-indices. These pseudo-indices are produced by the macro lua_upvalueindex. The first value associated with a function is at position lua_upvalueindex(1), and so on. Any access to lua_upvalueindex(n), where n is greater than the number of upvalues of the current function (but not greater than 256), produces an acceptable (but invalid) index.

So, I created a callback function associated with an object pointer created with "new".

Foo* ideleg = new Foo()
lua_pushlightuserdata (L, (Foo*)ideleg);
lua_pushcclosure(L, LuaCall<Tr,C,Args...>::LuaCallback,1);

And all the mechanics works very nicely... but now it's time to clean up, and I'm unable to get the pointer back so I can delete it, when I unregister the callback function or when I quit my program.

I do find the table entry using the following snippet:

while (lua_next(L, -2) != 0)
    if (lua_isstring(L, -2) && lua_tostring(L,-2) == "myCallBackFunc" ) 
        // get the pointer back and delete it!

(Can I do it using lua_getfield(L, -1, "myCallBackFunc"); ?)

But I'm unable to get the upvalue associated to the cclosure outside the LuaCall<Tr,C,Args...>::LuaCallback() function (Indeed inside this close function I can simply use lua_upvalueindex(1) but in this case I'm outside the close function...)

Is there a way to get this value so I can delete the pointer when I do not need it anymore ?

Edit: I did found the lua_getupvalue function that should do what I need, but at the moment I don't know how to get the cclosure stack index. So it still doesn't works yet.

By : Valkea

Yes, you can do this in Lua. But I strongly advise against it.

If you have access to that callback, if it's on the Lua stack, then it is entirely possible that some bit of Lua code has access to it as well. Which means that even though you think it will be destroyed, it actually won't be until Lua finishes with it. Destroying your closure puts it into a non-functioning state. Yet, because Lua may still have access to it, it is possible for the closure to be called after you destroyed its upvalue.

Badness ensues.

It would be better to put the pointer into a full userdata and attach a metatable to it with a __gc metamethod to do cleanup. That way, you can be certain that it will be be cleaned up when it truly is no longer in use.

However, if you insist on doing it your way, you can always use lua_getupvalue.

This video can help you solving your question :)
By: admin