Files
fs2open.github.com/code/scripting/lua/LuaUtil.cpp
T
asarium b8da1106eb Fix unbalanced stack when retrieving Lua main thread
After getting the main state from the Lua registry, this function had
two Lua thread values on its Lua stack but we only removed one which
lead to a value being left on the stack.

Why did this not blow up before? Because undefined behavior.

The only place where this was called was when creating a Lua reference
value where luaL_ref is called in the same expression (see
UniqueLuaReference::create). The evaluation order of the parameters for
the make_shared call is not defined by the standard and for some reason
all major compilers (except clang) choose to execute the luaL_ref call
before the getMainThread call.

For those compilers, everything is fine. We have some extra values on
the Lua stack but that gets cleaned up after the API function finishes.

However, clang first evaluates the getMainThread which leaves an extra
Lua thread on the Lua stack. The luaL_ref call then references this
thread value instead of the intended value. In the concrete case, this
meant that LuaFunction saw that the reference points to a thread and
rightfully threw an exception.

This fixes #5904.
2023-12-31 17:44:58 +01:00

67 lines
1.3 KiB
C++

#include "LuaUtil.h"
namespace {
const char* mainStateRefName = "_lua_mainthread";
}
namespace luacpp {
namespace util {
const char* getValueName(ValueType type)
{
switch (type) {
case ValueType::NONE:
return "none";
case ValueType::NIL:
return "nil";
case ValueType::BOOLEAN:
return "boolean";
case ValueType::LIGHTUSERDATA:
return "light userdata";
case ValueType::STRING:
return "string";
case ValueType::NUMBER:
return "number";
case ValueType::TABLE:
return "table";
case ValueType::FUNCTION:
return "function";
case ValueType::USERDATA:
return "userdata";
case ValueType::THREAD:
return "thread";
default:
return "unknown";
}
}
void initializeLuaSupportLib(lua_State* L)
{
auto mainThread = lua_pushthread(L);
Assertion(mainThread, "Must be called with the main thread as the parameter!");
lua_setfield(L, LUA_REGISTRYINDEX, mainStateRefName);
}
lua_State* getMainThread(lua_State* L)
{
if (lua_pushthread(L)) {
// State is the main thread, just return that
lua_pop(L, 1);
return L;
}
lua_pushstring(L, mainStateRefName);
lua_rawget(L, LUA_REGISTRYINDEX);
auto state = lua_tothread(L, -1);
// Need to pop both the thread from L and the main thread to return the stack back to neutral
lua_pop(L, 2);
return state;
}
} // namespace util
} // namespace luacpp