Safely passing a intptr_t to Lua [duplicate] - c++

I would like to know is there a way to pass a struct pointer to a lua script,
and reach it's members from lua without copy (for read and write purposes).
So, for example is it possible to overwrite a member of a c struct directly through of its pointer?
(I am using luajit)

In addition to Tim's answer, you can also go for light userdata. You don't end up with a copy of your data in the Lua stack, all you push to Lua is a pointer.
Lua has no understanding of what is in this pointer, whether it still points to valid memory, or how to access any objects in this pointer, so you'll have to handle all of this yourself in C. I am usually sending a pointer to an item on a list, so if there's any risk that entry has been deleted from the list, I first iterate over the list to validate the pointer (not a big deal if your lists are short). To access items within the pointer in Lua, you need to write get/set functions in C that you can call from Lua.
To get started, here are the entries on pushing and retrieving the lightuserdata:
lua_pushlightuserdata - push an entry on the stack
lua_touserdata - retrieve the pointer value
lua_islightuserdata - validate entry is light userdata
Programming in Lua entry on light userdata

Seeing as you have tagged this for luajit, you can combine the light userdata (as mentioned by others) with FFI for direct struct member access, see the tutorial here: http://luajit.org/ext_ffi_tutorial.html

The way to do this is with a lua userdata. Here are a couple examples: link, another link.

Related

"Cast" the address of a Lua table to a Lua table

Say I have the address of a table - how would I "cast" a table variable to it? I'm not concerned about "bad practice" or crashes because this is just an individual problem.
I want to do something like
lua_table tab = *(lua_table*)0xaddr
...but within the Lua global environment.
I understand how bad this is but I really need to know if this is possible. It may not be the best way to do what I'm trying to do, but I'm quite certain it's the easiest and that it will work if this is possible. I am using Lua 5.1.4.
Lua exposes no API for doing this.
It would be easier and much more robust to fix your design rather than trying to force this to work.
In order to do what you're attempting, you must:
Get a pointer to the Lua table's data structure. I'm sure you believe that you already have such a pointer. But there's nothing in Lua that guarantees that the pointer you have obtained (through some means) is actually a pointer to the table data structure. It could be a pointer to something else. So you need to hunt through Lua's internals to make sure that wherever you're getting this pointer from is giving you a pointer to the actual object.
Find the correct type, declared within Lua's internals. There is some C type (Lua's written in C, not C++) that Lua uses to represent the main table data structure. You will have to track down this struct definition and use that.
A cursory examination of the Lua library suggests that the main table data structure is defined in lobject.h, under the name Table.
Find the internal APIs that Lua uses to manipulate this table correctly. It's obviously some kind of hash table, but you're going to need to use Lua's functions to actually do anything with it.
A cursory examination of Lua's internals suggests that this code would be found in ltable.h. However, there are probably more APIs than that. Also, do note that many of those APIs take a lua_State, so they may be doing some stack fiddling.
You will also need to look through Lua's API so that you can learn how to use them without breaking the table. Lua may have certain expectations about when certain functions are called or the order between them or whatever. Break these at your own peril.
Even then, this:
Table tab = *(Table*)0xaddr
Will never work. Or at least, not the way you mean for it to. Lua is written in C. Which means that Table is not going to work like a C++ value type. Copying it will only do a bitwise copy. So modifying tab will only modify your local copy of those values. If those are pointers to other data structures, that may be OK, since your pointers and the original pointers point to the same data structures. But if you perform some operation that changes the Table::flags field on the table, for example, the table stored in Lua will not be affected, only your local tab copy will be.
You have to manipulate the object as a pointer, not a copy of the original.
Table *tab = reinterpret_cast<Table*>(0xaddr);

luabind : Accessing an invalidated c++ object from lua results in access violation

Is it possible that luabind checks, if a member function call to an exported class (object) is for a valid object?
lets assume that i have a Class called Actor exposed using luabind to lua. Im calling a lua function from C++ with an actor object as parameter. Now before the function finishes, a script write would put the actor object in a global lua reference to be accessed later.
Later on, the actor object is deleted from the C++ site, another function is called which tries to access the invalidated actor object (any method from it) - and obviously since it has been deleted, it results in a crash (access violation)
sample:
local myObjRef = nil
function doSomethingWithActor(actor)
-- save, still valid object
actor:Say("hello")
myObjRef = actor
end
function calledAfterActorWasDeleted()
--- will crash if the c++ object has been deleted meanwhile, works fine if it still exists
myObjRef:Say("Crash...")
end
A NIL check doesnt help here, is this something that can be checked on luabinds site? The functions are executed using lua_pcall(....) and the stacktrace shows the error at luabinds call.hpp results = maybe_yield(L, lua_gettop(L) - arguments, (Policies*)0);
If not, is there another solution how to make sure somebody who writes a script cannot create these issues?
Now before the function finishes, a script write would put the actor object in a global lua reference to be accessed later.
That right there is where your problem is coming from. If you want Lua code to own the object (that is, preserve the existence of this object), then you need to use Luabind mechanics to tell Luabind that you want to do that. Otherwise, if you pass a pointer to some Lua function, Luabind will assume that the function will not be trying to gain ownership of it.
If you want ownership to be shared between Lua and Luabind, then you should wrap your objects in a boost::shared_ptr, and use Luabind's smart pointer mechanisms to do this.
You could also simply segregate your scripts better. If you have some script that operates on a particular actor, then that script and any functions it contains should be destroyed (ie: lose all references to it) along with the object. This requires proper coding discipline on the C++ side. It will also require that you use Lua environments to properly encapsulate each instance of a script, so that they can't sneak things out via globals. Lastly, you will need to have C++ maintain total control over when scripts are called and when they aren't.
Otherwise, ownership is something your scripters are simply going to have to know about and be careful of. They can't treat C++ parameters like any old Lua value.
If exercising disciplined programming practice is not possible or practical for you, then you will simply have to not pass Lua the actual C++ object. Instead, you need to pass Lua some proxy object, which is a reference to the original. boost::weak_ptr is a good example of such an object (though you wouldn't pass it exactly to Lua). The proxy would forward calls to the actual object. If the object has been deleted, the proxy would detect this and fail or do nothing or whatever.
I solved my issue the following way:
When im about to delete an object, i iterate through all lua functions from C++ (i have them in a list, they are bound to specific actor objects each). Then i inspect each upvalue (global/local vars accessable to a function) - then i compare the userdata pointer with my object im about to delete - if they match (and their classes) and NIL the upvalue. Optionally, i could just remove that offending function because it would not work well anymore anyway.
So the next the time the function is called, im just getting a soft lua error "trying to access xxx a nil value..." - no more access violations.
I know people would say "dont use lua_getupvalue/lua_setupvalue - they are only for debugging!" - but there is actually no documented or spoken side effect - and in my case its perfectly safe and works well - also there isnt the issue with left over proxy objects i could not delete.

Delete all of my Lua userdata in C++

I'm wondering if it's possible to access all of the userdata "tables" (is it called userdata tables?) and then delete them from Lua because this is my problem:
a = Object(5, 5)
a:Delete()
a:SetPosition(3,3)
As you can see first I create an object and save an pointer to a c++ class called Object which is allocated using "new" in my map class. Then I delete the object which means I delete the allocated memory for the pointer in my map class. And last I call SetPosition, if the memory still is allocated for the c++ Object class everything will run fun. But if it is deletes (as it is in this case because we called Delete() before the SetPosition(...) call) my program will crash. So what I'm wondering is following:
Is it possible to set the varaible 'a' in lua to nil by calling Delete ? I know I could do something like 'a = a:Delete()' if Delete return nil but if I forget to do the 'a =' part it fail. Also I'm wondering if it's possible to delete the userdata and check if it doesn't exist when I call SetPositon(), if it doesn't I will just return.
Also, the base code is from: http://lua-users.org/wiki/SimpleCppBinding
First, let me answer your question:
Is it possible to set the varaible 'a' in lua to nil by calling Delete ?
No. There is no means to do what you're saying. And there's a reason for that: what you're trying to do is terrible code.
Lua is a garbage collected system. Lua should not be expected to delete objects. If Lua gets a pointer to some external object, then either your code owns it or Lua owns it.
If your code owns it, Lua should not be deleting it. Lua can use it for some period of time. But it is up to your Lua code to use it for exactly and only that period of time. Once its lifetime has expired, Lua shouldn't be talking to it anymore.
This is no different from dealing with pointers to objects in C and C++. If your function is handed a naked pointer (ie: not a smart pointer), your code needs to know how long it can reasonably expect to talk to that object. Can it store it? How long can it store a pointer to that object? When will that object die, and who's responsible for destroying it?
If you pass an object to Lua such that Lua now owns the object, Lua shouldn't be explicitly deleting it either. Lua is a garbage collected system; you should attach a __gc metamethod to your type, so that Lua's garbage collector will call your code when the userdata is collected. That way, you can call destructors, free memory, etc.
When you give Lua something that now belongs to Lua, it should look like a regular Lua object. You don't call Delete methods for tables and strings you create in Lua; you let the garbage collector do its job. It is your job, as the one writing the C++-to-Lua interface, to ensure that the objects you give to Lua behave the way that Lua wants them to.
In cases where you need to do significant resource management, where you want Lua to release resources as quickly as possible (such as for file handles, etc), then you need to store a pointer to your C++ object inside of the non-light userdata. That's the pointer you NULL out. All of your interface functions on that object will check the pointer to see if it's NULL and simply do nothing or raise an error.
Lua's file handles (returned by io.open) are a good example of this. If you try to call functions on them, Lua throws a Lua error.
In the Delete method, set the metatable of the received object to nil and you'll get an error message if you later call a method on that object.
I'd rather advice using SWIG or LuaBind instead, they've already taken care of such pitfalls for you.

when do luabind free created objects?

I'm having problems with luabind. I define a std::map to allocate objects created in lua. I publish this map as a global object in lua in this way:
luabind::globals(L)["g_SceneManager2D"] = this;
After that, this object is used into a function into lua, where many objects are created and inserted into this map. The problem comes when lua function ends and luabind returns the control to C++ side program, because automatically all contents of the map are lost.
I was looking for the error. I keep the lua context alive, so this object must exists.
Could you helpme??
Many thanks :)
I suggest use a shared_ptr<>(this) rather than raw this. boost::shared_from_this might help. Make sure your class is registered using Luabind too, and that the class_ is specified as held by a shared_ptr.
Another fun idea might be to make your Lua function just generate the "map" as a Lua table, return it, and you can iterate over it in C++ to build your std::map.
If I understand your problem correctly, it seems you are creating objects in Lua, which you then insert into the map (either through Lua or C++) and subsequently lose. Without some more code, it's hard to tell exactly what the problem is. However, I would first look to make sure that those objects are indeed being created (double check it) and then I would check to see that Lua isn't garbage collecting them. If Lua is indeed garbage collecting those objects, then you won't see them on the C++ side because they're, well, gone.
If it helps, I'm finishing up a project which does something similar. I had to create and retrieve C++ objects from Lua, but instead of creating the objects in Lua, I just called C++ functions to do it for me, sending any necessary data in the Lua call (bound by Luabind). Those (C++) functions indexed the objects by IDs into hash tables and the IDs were returned to Lua in case it needed to retrieve the object script-side for operations. This setup makes it easier (and safer) to handle memory stuff correctly and prevents Lua from garbage collecting your objects.

Tracking Lua tables in C

I have C++ objects and I have Lua objects/tables. (Also have SWIG C++ bindings.)
What I need to be able to do is associate the two objects so that if I do say
CObject* o1 = getObject();
o1->Update();
it will do the equivalent Lua:
myluatable1.Update();
So far I can imagine that CObject::Update would have the following code:
void CObject::Update(){
// Acquire table.
// ???
// Do the following operations on the table.
lua_getfield(L, -1, "Update");
lua_pcall(L, 0, 0, 0);
}
How would I store/set the Lua table to be used, and what would go in the // ??? above to make the Update call work?
I cant believe nobody noticed this!
http://www.lua.org/pil/27.3.2.html
A section of the Lua API for storing references to lua objects and tables and returning references for the purposes of being stored in C structures!!
I am curious for the reasons of this "reverse SWIG"...
The objects in Lua live within the Lua contexts, so at a minimum you would need to store "L" inside your object.
The issue of passing the "table pointer" is a bit more delicate - even though Lua allows to retrieve the pointer off the Lua stack (using lua_topointer()), there is no way of putting that back. Understandingly - because otherwise one would also need to check that the pointer does point to a valid object, etc, etc.
What you might do however, is to store the references to the tables in the global table, the index being the lightuserdata being the pointer to your object. Then by having the Lua state, and the name of the global array, you can retrieve the reference to the table and push it onto the Lua stack for that context.
This is sketchy, and I haven't even touched the question of garbage-collecting with this construct.
But in any case this is not going to be the speed racer performance-wise, and looks like a lot of boilerplate C++ code to me. I'd try to reconsider the approach and push some of what you want to do into the Lua domain.
p.s. looks like it is the third question which seems almost a dupe of the previous two ones, here and here are the previous ones. If those were not answered fully, would have been better to edit them/add the bounty to accumulate the answers.