Reputation: 2144
I'm developing a program which uses Lua for scripting, and sometimes it would crash. With GDB I think I found the problem, but I don't know if it solved it, as the segfault would only occur sporadically. So, the old code was this:
void Call(std::string func){
lua_getglobal(L, func.c_str()); //This is the line GDB mentioned in a backtrace
if( lua_isfunction(L,lua_gettop(L)) ) {
int err = lua_pcall(L, 0, 0,0 );
if(err != 0){
std::cout << "Lua error: " << luaL_checkstring(L, -1) << std::endl;
}
}
}
The thing is, that this function would be called a few times per second, but the function it needs to call isn't always defined, so I thought that the stack would overflow. I added the following line:
lua_pop(L,lua_gettop(L));
And the segfault hasn't occurred anymore. Could this have been the problem?
Upvotes: 6
Views: 2712
Reputation: 429
According to www.lua.org/manual/5.2/manual.html#4.2, you are responsible for keeping the stack clean as Lua will not perform any checks. I would assume that a segfault is a reasonable result of not keeping the stack clean (new values pushed to a memory location outside the actual stack space and incidently also outside your processes virtual memory).
Since you don't call lua_pcall to remove the non-function from the stack, this would grow the stack indefinitely.
Your solution should work, unless the called function leaves something on the stack. Since you set nresults to 0, Lua does not leave any results on the stack.
My understanding of the lua_pcall reference is though, that error codes can be left on the stack even if nresults is 0. Edit: I also checked that behaviour and it's exactly as I assumed it was.
In that case calling lua_gettop at the beginning and lua_settop in the end would work in any case and keep your stack balanced.
Upvotes: 1
Reputation: 3249
Using lua_gettop(L)
as the argument for lua_pop
will clear the entire Lua API stack (it is equivalent to lua_settop(0)
), which is probably not what you want. But indeed your problem is that lua_getglobal
always pushes something; if no global with the given name exists, it pushes nil
, just like the equivalent Lua expression would do. However, lua_pcall
pops the function and all arguments (if any; in your case you specified zero), so you won't get a problem if the function exists. What you should do is adding lua_pop(L, 1)
to an else
clause of the outer if
. This way, your function will always be balanced (i.e. leave the stack as it was).
You can see these things in the Lua manual: For every function, it is spelled out in the description and also indicated in grey, in brackets beside the functions prototype. For example, lua_getglobal
has [-0, +1, e] meaning that it will pop no elements and (always) push one element (and the e meanst that it may cause errors).
Upvotes: 5