Proper way to manage Lua light userdata - c++

I have a void * to a C++ created object that I pass to Lua using lua_pushlightuserdata(). Lua can perform some actions on that light userdata by passing it to Lua CFunctions and retrieving it with lua_touserdata(). At some point in the future the C++ object is destructed by its owner (C++), memory freed, and set to null. However, Lua still has a reference to this pointer, it doesn't know that it has been destroyed.
Now my Lua functions that take in this userdata make sure the pointer is valid. But what is the best approach for informing Lua that their reference to the light userdata is no longer valid? Do I expose an IsValid(lightuserdata) function to Lua so it can query the status? Or is there a better approach that I am missing.

In my experience I found that it's easier to make Lua own the objects, and you need full userdata to hold the pointer or complete object within userdata memory area. Full userdata can have metatable with __gc metamethod, so objects would be destroyed only after the last reference is garbage-collected on Lua side.
At least don't expose raw pointers to native objects to Lua through lightuserdata, it doesn't really work for native objects lifetime management. Make it some object that is owned by Lua. In simplest case it could be a Lua object (full userdata) holding smart pointer to real native object.

Related

What is the best practice of passing reference counted C++ objects to Lua?

I want to have my reference counted C++ object also managed in Lua callbacks: when it is held by a Lua variable, increase its refcount; and when the Lua variable is destroyed, release one refcount. It seems the releasing side can be automatically performed by __gc meta-method, but how to implement the increasing side?
Is it proper&enough to just increase refcount every time before adding the object to Lua stack?
Or maybe I should new a smart pointer object, use it everywhere in Lua C function, then delete it in __gc meta-method? This seems ugly as if something wrong with the Lua execution and the __gc is not called, the newed smart pointer object will be leaked, and the refcounted object it is referring would have leak one count.
In Perl that I'm more familiar with, this can be achieved by increase refcount at OUTPUT section of XS Map, and decrease refcount at destroyer.
I assume you have implemented two Lua functions in C: inc_ref_count(obj) and dec_ref_count(obj)
local MT = {__gc = dec_ref_count}
local setmetatable = setmetatable
local T = setmetatable({}, {__mode="k"})
function register_object(obj)
if not T[obj] then
T[obj] = setmetatable({}, MT)
inc_ref_count(obj)
end
end
Invoke register_object(object) on C side every time you send a ref-counted C object to Lua
You may leak memory if Lua VM crashed or was closed.
After more study on Lua manual, I found that light user data does not support metatable (see document). It should be implemented via heavy user data (lua_newuserdatauv) that allocates a chunk of memory by Lua machine. I can placement new a smart pointer object using this memory chunk, and bind a __gc on it.

Lua userdata lifetime management

Im pushing a c++ object pointer to userdata from few different places in my c++ code. I would like lua to manage the lifetime of the c++ object (userdata). My problem is that now I have multiple instances of userdata pointing to the same c++ object in the lua environment. So GC will be called when each instance.
I was thinking that one solution would be to create some weak cache table in the lua registry (LUA_REGISTRYINDEX) to map object pointer to the actual userdata. Then when I push userdata to the environment I check this cache to see if the userdata has already been created and push that instance (otherwise create userdata and add to the cache). That way only one instance of the userdata exists in the environment.
Is this the best solution or am I missing something?
The correct answer is to stop doing this:
I have multiple instances of userdata pointing to the same c++ object in the lua environment
When you give an object to Lua, then Lua owns that object. If a pointer to that object finds its way back into C++, then those C++ APIs should not be able to grant ownership of that object to anywhere else. Including back to Lua again. So there shouldn't be a bunch of functions that can return points to the same object to Lua.
And if you do have a bunch of such functions, you need to re-evaluate whether Lua should have ownership of these objects, or whether it should just be able to use them. You'd be surprised how rarely you genuinely need to give ownership of objects to Lua.
If you absolutely cannot avoid transferring ownership, then this means that your ownership semantics are not strict. That is, there isn't a single system which owns an object. You share ownership of an object with several places.
In C++, that's spelled shared_ptr. Therefore, your userdata should store a shared_ptr<T> to the object being managed. The GC should destroy the shared_ptr, which will only destroy the managed T if all other instances of shared_ptrs which share ownership with it have been destroyed.

What happens to multiple references to the same object in JNI?

I'm using JNI to access some Java code from C++. Object references returned by the JNI must be cleaned up, but what happens if multiple methods return the same Java object? Do I need to call Delete on each of them?
E.g. java.nio.Buffer has a method clear() that clears the buffer and returns itself.
If I first create a buffer with JNI, then call clear(), do I need to clean up both jobjects, or am I good to only clean up one of them?
In JNI you have Java objects and Java object references. A jobject is an object reference that points to a Java object and that you can release with DeleteLocalRef if you don't need it anymore.
Calling clear() on a Buffer object will create a new reference for the returned object, even if it actually points to the same object. So yes, if you run out of local references, you should release all references to your Buffer but the one, you're working with.

Usage of member variable referencing own instance

I am currently investigating code of a C++ library which is not written by me.
The code seems to be a little bit ugly to me, but I have to admin that I am no C++ pro.
The Library has a class, lets call it ExampleClass, which has a member variable std::shared_ptr<ExampleClass> this_ec which is not set in the constructor, but seems to be set always when another object creates an instance of ExampleClass:
std::shared_ptr<ExampleClass> ec = std::make_shared<ExampleClass>(...);
ec->this_ec = ec;
Could it be that this is used to prevent garbage collection?
Could it be that this is used to prevent garbage collection?
Yes, if by "garbage collection", you mean "automatic deletion". The object won't be deleted as long as at least one shared pointer exists, so this will keep the object alive at least until that pointer is reset or reassigned.
This rather defeats the purpose of using smart pointers, since it's now easy to leak objects by losing all external pointers to them. Tread carefully here.
A less error-prone way to make a shared pointer to the current object available within the class is to inherit from enable_shared_from_this<ExampleClass>, and obtain the pointer with shared_from_this(). This effectively stores a weak pointer, which doesn't prevent deletion.

How do I tell if I'm leaking COM objects?

I'm writing some code that makes (relatively simple) use of COM, calling AddRef() on some objects and Release()ing them later. Other than just checking the code really thoroughly, is there a way I can check to see if I'm leaking COM objects everywhere?
(I can't use reference counted IBlahBlahPtrs because I need to pass the objects to a set of APIs who don't know what a COM is, and so don't understand the whole "reference counting pointers" thingy - they pass the pointer around like a token.)
Thanks!
It is no different from checking for leaks in any C or C++ code. Use <crtdbg.h> to detect leaks, the MSDN library article is here. You'll get a leak report for the class factory if there were not enough IUnknown::Release() calls.
Reference counting interface pointers is a hard COM requirement, you cannot just shrug it off. If the client code doesn't do it then you'll have to take care of it yourself before you pass a pointer to that code. Knowing when the pointer is no longer in use is of course the trickier issue.
If you use the CrtDebug DEBUG_NEW to allocate your objects, you'll get an automatic dump of all leaked objects at exit time (basically, all memory that is not freed), along with the file name and line where the memory was allocated.
Based on our conversation in comments, I'd say you could do the following:
Use smart pointers (i.e., IBlahBlahPtr) to create and manage COM objects in your own code.
Maintain a collection of smart pointers representing your caller's references to the pointers that you've passed upwards. Every time you hand a new COM pointer over to your caller, put its smart pointer in the collection.
If your caller relinquishes a COM pointer somehow (by, say, passing you the COM pointer token in some kind of "release" function), then look up its smart pointer in the collection and remove it. If that smart pointer (representing the caller's now-defunct reference to the object) is the only remaining holder of a reference count on the object, then destruction will occur as desired.
If your caller passes you a COM pointer in a non-relinquishing way, you can wrap a new smart pointer object around the raw pointer value for the duration of the call, just so that your use of smart pointers within your own code is consistent. It's fine for multiple smart pointers to refer to the same COM object.
Various tools will check for you. BoundsChecker does. I think, but am not 100% sure, that AppVerifier does (it has the added benefit of being free).