I believe I've found a bug in GetTracebackFunction(). If the debug table isn't a table, it attempts to pop two items from the stack instead of just one. This is bad behavior, because it's messing with the part of the stack that calling code owns.
This is the problem code:
I inserted lua stack-tracking comments to illustrate what's going wrong, too.
You could fix it by passing 1 instead of 2 to lua_pop(), but I decided to clean it up instead. Here's my proposed replacement:
It's actually shorter, and it would be even more compact if I didn't have the trace comments there.
This is the problem code:
void GetTracebackFunction (lua_State *L)
{
// L: ...
lua_pushliteral (L, LUA_DBLIBNAME); // "debug"
// L: ... "debug"
lua_rawget (L, LUA_GLOBALSINDEX); // get debug library
// L: ... debug_table
if (!lua_istable (L, -1))
{
lua_pop (L, 2); // pop result and debug table
lua_pushnil (L);
return;
}
// get debug.traceback
lua_pushstring(L, "traceback");
lua_rawget (L, -2); // get getinfo function
if (!lua_isfunction (L, -1))
{
lua_pop (L, 2); // pop result and debug table
lua_pushnil (L);
return;
}
lua_remove (L, -2); // remove debug table, leave traceback function
}I inserted lua stack-tracking comments to illustrate what's going wrong, too.
You could fix it by passing 1 instead of 2 to lua_pop(), but I decided to clean it up instead. Here's my proposed replacement:
void GetTracebackFunction (lua_State *L)
{
// L: ...
lua_getfield (L, LUA_GLOBALSINDEX, LUA_DBLIBNAME);
// L: ... debug
if (lua_istable (L, -1))
{
lua_getfield (L, -1, "traceback");
// L: ... debug, traceback
lua_remove (L, -2);
// L: ... traceback
if (lua_isfunction (L, -1))
return; // L: ... traceback
}
// L: ... unknown
// can't find it; leave nil on the stack
lua_pop (L, 1);
lua_pushnil (L);
return; // L: ... nil
}It's actually shorter, and it would be even more compact if I didn't have the trace comments there.