I am using the Lua API for C/C++ to create functions in C/C++ and then register them for use in Lua scripts. Obviously these functions expect a certain number of arguments with specific types, which is no problem in C/C++ because of static typing. However, given that Lua is dynamic, I need to manually check the number of arguments passed and their types when I call this C-function from Lua. These arguments are pushed onto the Lua stack, so I can check the number of arguments with lua_gettop and then check their individual types with lua_type.
My question, though, is can I guarantee the number of elements on the stack, that is, the number of arguments passed to my function? That way, I could check this at the beginning of my C-function with an assertion: assert(lua_gettop(L) == x), with x just being a placeholder for the desired number of arguments and L being a lua_State*. This extends a little deeper, as I wonder if other functions that interact with the Lua stack clean up so that the stack is empty when I call this function; otherwise, if some things were left sitting on the stack from a previous function call, the assertion would fail. Below is a simple example.
C/C++ code:
int foo(lua_State* L) {
assert(lua_gettop(L) == 2);
// do stuff
return 1;
}
Calling the function in Lua. Assume that the function expects two strings as arguments; thus, the first call would succeed and the second would fail.
foo("hello", "world")
foo("hello", "world", 1)
If you have directly registered a function to Lua, and a Lua script calls that function with N arguments, then that function will have N values on the stack when it gets called. That's how it works, and no process can interfere with this (well, you could manually call that function from C with an improper lua_State, but that's your fault).
So long as you don't do any stack manipulation between the start of that function and whatever you use to check the current stack size, then your test will be accurate.
Every Lua function is well-documented in how (or if) it manipulates the stack. Whether it inserts values to the stack, removes them from the stack, and so forth.
That being said, assert is probably the wrong tool. If the user provides the wrong number of parameters, and you consider that erroneous behavior, you should invoke lua_error. And not just on debug builds.
Related
I'm working on a very large framework exposing many algorithms, functions and features from C/C++ to Lua. This framework also exposes some functionality that works with tables, indexers, and often is merely a proxy for default behaviour if a certain condition is not true.
My question is very basic; Is it safe to pop function arguments from a C function in i.e. a newindex implementation in C? I currently implement it by getting an object which should hold the key and value and insert it before the key and value provided to the __newindex metamethod. I then use lua_rawset to set it to the object I placed in front, popping off two of the function arguments. Is this safe?
I ran extensive tests, including checkstack tests, and monitoring the top of the Lua stack. None of these tests are conclusive enough for me though, I would like to have the opinion of other Lua developers.
I've read many parts of the Lua documentation, however there does not seem to be a clear statement about this (or I have not found it). The manual (https://www.lua.org/manual/5.3/manual.html#lua_CFunction) does state:
Any other value in the stack below the results will be properly discarded by Lua.
However this doesn't answer my question if discarding these values myself can cause problems.
// An example, is this safe to do? My guts say yes
int lm_entity__newindex(lua_State* L) {
luaL_checkany(L, 1); // udata
luaL_checkany(L, 2); // key
luaL_checkany(L, 3); // value
// does not manipulate the stack, merely casts lua_touserdata
auto entity = lm_entity(L, 1);
// get the members table
lua_rawgeti(L, LUA_REGISTRYINDEX, entity->members_ref);
// place before key and value (lua_rotate)
lua_insert(L, -3);
// store, in turn popping the two function arguments
lua_rawset(L, -3);
// pop members table
lua_pop(L, 1);
return 0;
}
I expect this to work safely, because in a function call the stack is restored afterwards based on the number of parameters passed on to the function and the number of return values pushed onto the stack. I'm not certain, though, that popping two of the arguments off the stack will cause issues in that regard, even though my testing seems to prove otherwise.
A simple example of producing.
protocol.onConnect(function() end, function () end, ...)
Now in c, i want to get the functions which are in args #1, #2.
In strings, numbers,... we can get them using (lua_getstring,..), But I at-least didn't found how to get a function.
int luaProtocolOnConnect(lua_State* L)
{
int base_func // func #1
int call_func // func #2
....
}
You cannot really "get" a Lua function. Lua functions, like Lua tables, are pure-Lua objects. As such, they have no C or C++ analog. If you want to call a Lua function, that's done through lua_call, lua_pcall or similar functions. This is done in-situ on the Lua stack.
So you can't take a Lua function and turn it into a C++ value. What you can do is take a Lua function and manipulate it in the various ways that all Lua objects can be manipulated.
For example, let's say you want to store a Lua function in a C++ object, then later call whatever Lua function was stored there. Well obviously, you can't convert the Lua function directly into a C++ value. What you can do is store that Lua function in a place which C++ can access. You use some value which does have a C++ analog to reference that stored Lua function. The value must be unique for every object you want to store like this. The value you get when storing the object will be saved in your C++ object. When the time comes to retrieve the Lua function, you simply use the stored value to retrieve it.
Because this is an exceedingly common operation, Lua has ways to facilitate this. The first is the Lua registry, a table that C++ can access but Lua code cannot (not unless you give it access).
The second is the luaL_ref series of functions. luaL_ref takes whatever is at the top of the stack and sticks it in a table you provide, returning to you an integer key that can be used to retrieve it later. lua_rawgeti can be used to retrieve the function from the table by the key, and luaL_unref takes the table and the integer key, removing the referenced function from the table when you're done with it.
So if you want to store such functions, you simply need to create such a table, stick it in a known place in the registry (so that you can fetch it whenever you need to), and then use luaL_ref to store those functions. When it comes time to call them, retrieve them with lua_rawgeti. When you're finished using them, destroy them with luaL_unref.
You can use lua_isfunction to check if it's a function, use lua_pushvalue to push its value on top of the stack and then use luaL_ref (luaL_ref(L,LUA_REGISTRYINDEX);) to turn it into a unique key you can later reference to retrieve the value (lua_rawgeti(L,LUA_REGISTRYINDEX,ref)) and call the function.
How I can say to the compiler how to optimize something or what some call to function.
I mean like create allocate method and let the compiler optimize it as it optimize it with malloc or new.
Or like if somewhere in the code the function X is called and it's return value is not used then delete this call. (Function from .lib that the compiler don't know a piece about it)
There are options for this?
For example:
auto val=X(); //Use the return value
X(); //Don't use
auto t=allocate<T>(); //Allocate on heap
t->Show(val); //Run single function and don't use it's pointer somewhere (Save it after the function is exit)
And optimize it to:
X(); //First line, just call it
T().Show(val); //Combines third and fourth lines, Allocate on stack and run the single function
If you asking 'why you need this?' I am creating programming language with my own GC and heap. (And lot of things too)
It translates to C++ then I don't want to optimize the code while translate it. (It's gonna be a pain)
Because I can call functions randomly in places. (I can't detect if their values are used or not)
Optimization is compiler-specific, so you'll need to look in your compiler's documentation to see what optimization "hints" it allows you to put in code. For example, here are some of GCC's function attributes:
The malloc attribute tells the compiler that if the function returns a non-null pointer, it's always a "new" area of memory, not another pointer to something that's already been allocated. You'd probably want to use this on a function that wraps the real malloc().
The const attribute (different from the ordinary const keyword) says that the function's return value depends solely on its arguments and has no side effects, so it's safe for the compiler to eliminate duplicate calls with the same arguments.
The noreturn attribute tells the compiler that a function never returns; you'd use this on functions that terminate the program, like C's exit().
Attributes go on the declaration of a function, typically in a header file, so you can use them even if the function's implementation is in a compiled library that'll be linked in later. But remember that function attributes are promises from you to the compiler: if you declare a function with the noreturn attribute, for example, and then implement it with code that actually can return, strange things may happen at runtime when it does.
You can also use function attributes to help with correctness checking:
The nonnull attribute tells the compiler that certain (pointer) arguments aren't supposed to be null, so it can issue warnings if it detects that they might be.
The format argument tells the compiler that the function takes a format string like C's printf(), so it can check that the types of the variadic arguments match the corresponding format codes in the format string. (For example, you shouldn't write "%s" in the format string but then pass an integer as its value.)
From http://en.wikipedia.org/wiki/Stack_pointer#Structure
I am wondering why the return address for a function is placed above the parameters for that function?
It makes more sense to have Return Address pushed onto the stack before the Parameters for Drawline because the parameters are not required any more when the Return Address is popped for returning back to the calling function.
What are the reasons for preferring the implementation shown in diagram above?
The return address is usually pushed via the call machine command, [which in the native language's instruction set] while the parameters and variables are pushed with several machine commands - which the compiler creates.
Thus, the return address is the last thing pushed by the caller, and before anything [local variables] pushed by the callee.
The parameters are all pushed before the return address, because the jump to the actual function and the insertion of the return address to the stack is done in the same machine command.
Also, another reason is - the caller is the one allocating space on stack for the parameters - It [the caller] should also be the one who cleans it up.
The reason is simple: The function arguments are pushed onto the stack by the calling function (which is the only one which can do it because only it has the necessary information; after all the whole point of doing so is to pass that information to the called function). The return address is pushed to the stack by the function call mechanism. The function is called after the calling function has set up the parameters, because after the call it's the called function which is executed, not the calling one.
OK, so now you could argue that the calling function could put the parameters beyond the currently used stack, and the called function could then just adjust the stack pointer accordingly. But that would not work out well because at any time there could be an interrupt or a signal, which would push the current state onto the stack in order to restore later (I wouldn't be surprised if a task switch did so, too). But if you set up the parameters beyond the current stack, those asynchronous events would overwrite it, and since you cannot predict when they will happen, you cannot avoid that (beyond disabling, which may have other drawbacks or even be impossible, in the case of task switch). Basically, everything beyond the current stack has to be considered volatile.
Also note that this is independent of the question of who cleans up the parameters. In principle, the called function could call call destructors of the arguments even if physically they lie in the caller's stack frame. Also, many processors (including the x86) have instructions which automatically pop extra space above the return address on return (for example, Pascal compilers usually did that because in Pascal you don't have any cleanup beyond returning memory, and at least fr the processors of the time, it was more efficient to clean up with that processor instruction (I have no idea if that is still true for modern processors). However C didn't use that mechanism due to variable-length argument lists: For those, the mechanism wasn't applicable because you'd need to know at compile time how much extra space to release, and K&R C did not require to forward-declare variadic functions (C89 does, but few if any compilers take advantage of that, due to compatibility with old code), so there was no way for the calling function to know whether to clean up the arguments unless it had to do that always.
I am using the lua C-API to read in configuration data that is stored in a lua file.
I've got a nice little table in the file and I've written a query C-function that parses out a specific field in the table. (yay it works!)
It works by calling a few of these kinds of functions over and over:
...
lua_getglobal (...);
lua_pushinteger (...);
lua_gettable (...);
lua_pushstring (...);
lua_gettable (...);
lua_lua_getfield (...);
...
you get the idea.
After I am done querying my data like this, do I have to clean up the stack?
As long as your stack doesn't grow without bound, you'll be fine. When you return integer N from the C API into Lua, two things happen:
The Lua engine takes the top N values from the stack and considers them as the results of the call.
The Lua engine deallocates (and reuses) everything else on the stack.
David Seiler mentions the possibility of your C code being called from other C code and not from the Lua engine. This is an advanced technique, and if you are asking this question, you are unlikely to have to worry about that particular issue. (But the way it happens from Lua's perspective is the same—when all the C code finishes executing, it has to return an integer, and Lua peels that many values off the stack and then deallocates the rest.)
If you use too many stack slots, your program will halt with a sane and sensible error message (as I know from experience).
It depends.
If your C function is called from Lua, the values you leave behind will be the values that your C function returns to Lua. If your C function is called by another C function that uses the Lua stack, then those values will still be on the stack, and you can do anything or nothing with them.
But if after you've called your C function you're done with Lua altogether, and from your question it sounds as though you are, then you don't have to clean up your Lua stack. Just close the Lua context, and it will clean up your stack for you.
additionally, instead of using pushstring or pushinteger followed by a gettable, use lua_getfield and lua_rawgeti respectivly (the raw will not invoke metamethods though, incase you wanted that...)