mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-04-16 08:42:23 +00:00
Merge branch 'lua_element_crash' into 'master'
Fix crash when throwing in index meta methods Closes #7711 See merge request OpenMW/openmw!3862
This commit is contained in:
commit
2ae137f709
@ -51,6 +51,9 @@ return {
|
|||||||
}
|
}
|
||||||
)X");
|
)X");
|
||||||
|
|
||||||
|
TestingOpenMW::VFSTestFile metaIndexErrorFile(
|
||||||
|
"return setmetatable({}, { __index = function(t, key) error('meta index error') end })");
|
||||||
|
|
||||||
std::string genBigScript()
|
std::string genBigScript()
|
||||||
{
|
{
|
||||||
std::stringstream buf;
|
std::stringstream buf;
|
||||||
@ -70,7 +73,7 @@ return {
|
|||||||
{
|
{
|
||||||
std::unique_ptr<VFS::Manager> mVFS = TestingOpenMW::createTestVFS({ { "aaa/counter.lua", &counterFile },
|
std::unique_ptr<VFS::Manager> mVFS = TestingOpenMW::createTestVFS({ { "aaa/counter.lua", &counterFile },
|
||||||
{ "bbb/tests.lua", &testsFile }, { "invalid.lua", &invalidScriptFile }, { "big.lua", &bigScriptFile },
|
{ "bbb/tests.lua", &testsFile }, { "invalid.lua", &invalidScriptFile }, { "big.lua", &bigScriptFile },
|
||||||
{ "requireBig.lua", &requireBigScriptFile } });
|
{ "requireBig.lua", &requireBigScriptFile }, { "metaIndexError.lua", &metaIndexErrorFile } });
|
||||||
|
|
||||||
LuaUtil::ScriptsConfiguration mCfg;
|
LuaUtil::ScriptsConfiguration mCfg;
|
||||||
LuaUtil::LuaState mLua{ mVFS.get(), &mCfg };
|
LuaUtil::LuaState mLua{ mVFS.get(), &mCfg };
|
||||||
@ -223,4 +226,11 @@ return {
|
|||||||
// At this moment all instances of the script should be garbage-collected.
|
// At this moment all instances of the script should be garbage-collected.
|
||||||
EXPECT_LT(memWithoutScript, memWithScript);
|
EXPECT_LT(memWithoutScript, memWithScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(LuaStateTest, SafeIndexMetamethod)
|
||||||
|
{
|
||||||
|
sol::table t = mLua.runInNewSandbox("metaIndexError.lua");
|
||||||
|
// without safe get we crash here
|
||||||
|
EXPECT_ERROR(LuaUtil::safeGet(t, "any key"), "meta index error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -376,7 +376,7 @@ namespace LuaUtil
|
|||||||
|
|
||||||
sol::protected_function_result LuaState::throwIfError(sol::protected_function_result&& res)
|
sol::protected_function_result LuaState::throwIfError(sol::protected_function_result&& res)
|
||||||
{
|
{
|
||||||
if (!res.valid() && static_cast<int>(res.get_type()) == LUA_TSTRING)
|
if (!res.valid())
|
||||||
throw std::runtime_error(std::string("Lua error: ") += res.get<sol::error>().what());
|
throw std::runtime_error(std::string("Lua error: ") += res.get<sol::error>().what());
|
||||||
else
|
else
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
@ -397,7 +397,7 @@ namespace LuaUtil
|
|||||||
std::string fileContent(std::istreambuf_iterator<char>(*mVFS->get(path)), {});
|
std::string fileContent(std::istreambuf_iterator<char>(*mVFS->get(path)), {});
|
||||||
sol::load_result res = mSol.load(fileContent, path, sol::load_mode::text);
|
sol::load_result res = mSol.load(fileContent, path, sol::load_mode::text);
|
||||||
if (!res.valid())
|
if (!res.valid())
|
||||||
throw std::runtime_error("Lua error: " + res.get<std::string>());
|
throw std::runtime_error(std::string("Lua error: ") += res.get<sol::error>().what());
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,16 +232,36 @@ namespace LuaUtil
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// work around for a (likely) sol3 bug
|
||||||
|
// when the index meta method throws, simply calling table.get crashes instead of re-throwing the error
|
||||||
|
template <class Key>
|
||||||
|
sol::object safeGet(const sol::table& table, const Key& key)
|
||||||
|
{
|
||||||
|
auto index = table.traverse_raw_get<sol::optional<sol::main_protected_function>>(
|
||||||
|
sol::metatable_key, sol::meta_function::index);
|
||||||
|
if (index)
|
||||||
|
{
|
||||||
|
sol::protected_function_result result = index.value()(table, key);
|
||||||
|
if (result.valid())
|
||||||
|
return result.get<sol::object>();
|
||||||
|
else
|
||||||
|
throw result.get<sol::error>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return table.raw_get<sol::object>(key);
|
||||||
|
}
|
||||||
|
|
||||||
// getFieldOrNil(table, "a", "b", "c") returns table["a"]["b"]["c"] or nil if some of the fields doesn't exist.
|
// getFieldOrNil(table, "a", "b", "c") returns table["a"]["b"]["c"] or nil if some of the fields doesn't exist.
|
||||||
template <class... Str>
|
template <class... Str>
|
||||||
sol::object getFieldOrNil(const sol::object& table, std::string_view first, const Str&... str)
|
sol::object getFieldOrNil(const sol::object& table, std::string_view first, const Str&... str)
|
||||||
{
|
{
|
||||||
if (!table.is<sol::table>())
|
if (!table.is<sol::table>())
|
||||||
return sol::nil;
|
return sol::nil;
|
||||||
|
sol::object value = safeGet(table.as<sol::table>(), first);
|
||||||
if constexpr (sizeof...(str) == 0)
|
if constexpr (sizeof...(str) == 0)
|
||||||
return table.as<sol::table>()[first];
|
return value;
|
||||||
else
|
else
|
||||||
return getFieldOrNil(table.as<sol::table>()[first], str...);
|
return getFieldOrNil(value, str...);
|
||||||
}
|
}
|
||||||
|
|
||||||
// String representation of a Lua object. Should be used for debugging/logging purposes only.
|
// String representation of a Lua object. Should be used for debugging/logging purposes only.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user