1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 21:09:41 +00:00

Move LuaState::makeReadOnly(sol::table) out of the class because it doesn't need to access LuaState internals.

This commit is contained in:
Petr Mikheev 2021-09-19 14:38:27 +02:00
parent 8d86d90782
commit 2f25257a3e
10 changed files with 44 additions and 41 deletions

View file

@ -7,7 +7,7 @@ namespace MWLua
{ {
sol::table api(context.mLua->sol(), sol::create); sol::table api(context.mLua->sol(), sol::create);
// TODO // TODO
return context.mLua->makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
} }

View file

@ -48,7 +48,7 @@ namespace MWLua
api["getControlSwitch"] = [input](const std::string& key) { return input->getControlSwitch(key); }; api["getControlSwitch"] = [input](const std::string& key) { return input->getControlSwitch(key); };
api["setControlSwitch"] = [input](const std::string& key, bool v) { input->toggleControlSwitch(key, v); }; api["setControlSwitch"] = [input](const std::string& key, bool v) { input->toggleControlSwitch(key, v); };
api["ACTION"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( api["ACTION"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
"GameMenu", MWInput::A_GameMenu, "GameMenu", MWInput::A_GameMenu,
"Screenshot", MWInput::A_Screenshot, "Screenshot", MWInput::A_Screenshot,
"Inventory", MWInput::A_Inventory, "Inventory", MWInput::A_Inventory,
@ -102,7 +102,7 @@ namespace MWLua
"ZoomOut", MWInput::A_ZoomOut "ZoomOut", MWInput::A_ZoomOut
)); ));
api["CONTROL_SWITCH"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( api["CONTROL_SWITCH"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
"Controls", "playercontrols", "Controls", "playercontrols",
"Fighting", "playerfighting", "Fighting", "playerfighting",
"Jumping", "playerjumping", "Jumping", "playerjumping",
@ -112,7 +112,7 @@ namespace MWLua
"VanityMode", "vanitymode" "VanityMode", "vanitymode"
)); ));
api["CONTROLLER_BUTTON"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( api["CONTROLLER_BUTTON"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
"A", SDL_CONTROLLER_BUTTON_A, "A", SDL_CONTROLLER_BUTTON_A,
"B", SDL_CONTROLLER_BUTTON_B, "B", SDL_CONTROLLER_BUTTON_B,
"X", SDL_CONTROLLER_BUTTON_X, "X", SDL_CONTROLLER_BUTTON_X,
@ -130,7 +130,7 @@ namespace MWLua
"DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT "DPadRight", SDL_CONTROLLER_BUTTON_DPAD_RIGHT
)); ));
api["CONTROLLER_AXIS"] = context.mLua->makeReadOnly(context.mLua->sol().create_table_with( api["CONTROLLER_AXIS"] = LuaUtil::makeReadOnly(context.mLua->sol().create_table_with(
"LeftX", SDL_CONTROLLER_AXIS_LEFTX, "LeftX", SDL_CONTROLLER_AXIS_LEFTX,
"LeftY", SDL_CONTROLLER_AXIS_LEFTY, "LeftY", SDL_CONTROLLER_AXIS_LEFTY,
"RightX", SDL_CONTROLLER_AXIS_RIGHTX, "RightX", SDL_CONTROLLER_AXIS_RIGHTX,
@ -144,7 +144,7 @@ namespace MWLua
"MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + MWInput::A_MoveLeftRight "MoveLeftRight", SDL_CONTROLLER_AXIS_MAX + MWInput::A_MoveLeftRight
)); ));
return context.mLua->makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
} }

View file

@ -18,7 +18,7 @@ namespace MWLua
sol::table res(lua.sol(), sol::create); sol::table res(lua.sol(), sol::create);
for (const std::string& v : values) for (const std::string& v : values)
res[v] = v; res[v] = v;
return lua.makeReadOnly(res); return LuaUtil::makeReadOnly(res);
} }
sol::table initCorePackage(const Context& context) sol::table initCorePackage(const Context& context)
@ -43,7 +43,7 @@ namespace MWLua
"Activator", "Armor", "Book", "Clothing", "Creature", "Door", "Ingredient", "Activator", "Armor", "Book", "Clothing", "Creature", "Door", "Ingredient",
"Light", "Miscellaneous", "NPC", "Player", "Potion", "Static", "Weapon" "Light", "Miscellaneous", "NPC", "Player", "Potion", "Static", "Weapon"
}); });
api["EQUIPMENT_SLOT"] = lua->makeReadOnly(lua->sol().create_table_with( api["EQUIPMENT_SLOT"] = LuaUtil::makeReadOnly(lua->sol().create_table_with(
"Helmet", MWWorld::InventoryStore::Slot_Helmet, "Helmet", MWWorld::InventoryStore::Slot_Helmet,
"Cuirass", MWWorld::InventoryStore::Slot_Cuirass, "Cuirass", MWWorld::InventoryStore::Slot_Cuirass,
"Greaves", MWWorld::InventoryStore::Slot_Greaves, "Greaves", MWWorld::InventoryStore::Slot_Greaves,
@ -64,7 +64,7 @@ namespace MWLua
"CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft, "CarriedLeft", MWWorld::InventoryStore::Slot_CarriedLeft,
"Ammunition", MWWorld::InventoryStore::Slot_Ammunition "Ammunition", MWWorld::InventoryStore::Slot_Ammunition
)); ));
return lua->makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
sol::table initWorldPackage(const Context& context) sol::table initWorldPackage(const Context& context)
@ -107,7 +107,7 @@ namespace MWLua
// return GObjectList{worldView->selectObjects(query, false)}; // return GObjectList{worldView->selectObjects(query, false)};
}; };
// TODO: add world.placeNewObject(recordId, cell, pos, [rot]) // TODO: add world.placeNewObject(recordId, cell, pos, [rot])
return context.mLua->makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
sol::table initNearbyPackage(const Context& context) sol::table initNearbyPackage(const Context& context)
@ -137,7 +137,7 @@ namespace MWLua
// TODO: Maybe use sqlite // TODO: Maybe use sqlite
// return LObjectList{worldView->selectObjects(query, true)}; // return LObjectList{worldView->selectObjects(query, true)};
}; };
return context.mLua->makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
sol::table initQueryPackage(const Context& context) sol::table initQueryPackage(const Context& context)
@ -148,7 +148,7 @@ namespace MWLua
query[t] = Queries::Query(std::string(t)); query[t] = Queries::Query(std::string(t));
for (const QueryFieldGroup& group : getBasicQueryFieldGroups()) for (const QueryFieldGroup& group : getBasicQueryFieldGroups())
query[group.mName] = initFieldGroup(context, group); query[group.mName] = initFieldGroup(context, group);
return query; // makeReadonly is applied by LuaState::addCommonPackage return query; // makeReadOnly is applied by LuaState::addCommonPackage
} }
sol::table initFieldGroup(const Context& context, const QueryFieldGroup& group) sol::table initFieldGroup(const Context& context, const QueryFieldGroup& group)
@ -163,12 +163,12 @@ namespace MWLua
{ {
const std::string& name = field->path()[i]; const std::string& name = field->path()[i];
if (subgroup[name] == sol::nil) if (subgroup[name] == sol::nil)
subgroup[name] = context.mLua->makeReadOnly(context.mLua->newTable()); subgroup[name] = LuaUtil::makeReadOnly(context.mLua->newTable());
subgroup = context.mLua->getMutableFromReadOnly(subgroup[name]); subgroup = LuaUtil::getMutableFromReadOnly(subgroup[name]);
} }
subgroup[field->path().back()] = field; subgroup[field->path().back()] = field;
} }
return context.mLua->makeReadOnly(res); return LuaUtil::makeReadOnly(res);
} }
} }

View file

@ -62,7 +62,7 @@ namespace MWLua
else else
return sol::make_object<float>(lua->sol(), value.getFloat()); return sol::make_object<float>(lua->sol(), value.getFloat());
}; };
return lua->makeReadOnly(config); return LuaUtil::makeReadOnly(config);
} }
sol::table initGlobalSettingsPackage(const Context& context) { return initSettingsPackage(context, true, false); } sol::table initGlobalSettingsPackage(const Context& context) { return initSettingsPackage(context, true, false); }

View file

@ -12,7 +12,7 @@ namespace MWLua
{ {
luaManager->addUIMessage(message); luaManager->addUIMessage(message);
}; };
return context.mLua->makeReadOnly(api); return LuaUtil::makeReadOnly(api);
} }
} }

View file

@ -119,7 +119,7 @@ return {
EXPECT_ERROR(LuaUtil::call(script["rawsetSystemLib"]), "bad argument #1 to 'rawset' (table expected, got userdata)"); EXPECT_ERROR(LuaUtil::call(script["rawsetSystemLib"]), "bad argument #1 to 'rawset' (table expected, got userdata)");
EXPECT_ERROR(LuaUtil::call(script["modifySystemLib"]), "a userdata value"); EXPECT_ERROR(LuaUtil::call(script["modifySystemLib"]), "a userdata value");
EXPECT_EQ(mLua.getMutableFromReadOnly(mLua.makeReadOnly(script)), script); EXPECT_EQ(LuaUtil::getMutableFromReadOnly(LuaUtil::makeReadOnly(script)), script);
} }
TEST_F(LuaStateTest, Print) TEST_F(LuaStateTest, Print)
@ -150,8 +150,8 @@ return {
{ {
LuaUtil::LuaState lua(mVFS.get()); LuaUtil::LuaState lua(mVFS.get());
sol::table api1 = lua.makeReadOnly(lua.sol().create_table_with("name", "api1")); sol::table api1 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api1"));
sol::table api2 = lua.makeReadOnly(lua.sol().create_table_with("name", "api2")); sol::table api2 = LuaUtil::makeReadOnly(lua.sol().create_table_with("name", "api2"));
sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", {{"test.api", api1}}); sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", {{"test.api", api1}});

View file

@ -67,27 +67,31 @@ namespace LuaUtil
mSandboxEnv = sol::nil; mSandboxEnv = sol::nil;
} }
sol::table LuaState::makeReadOnly(sol::table table) sol::table makeReadOnly(sol::table table)
{ {
if (table == sol::nil)
return table;
if (table.is<sol::userdata>()) if (table.is<sol::userdata>())
return table; // it is already userdata, no sense to wrap it again return table; // it is already userdata, no sense to wrap it again
lua_State* lua = table.lua_state();
table[sol::meta_function::index] = table; table[sol::meta_function::index] = table;
sol::stack::push(mLua, std::move(table)); sol::stack::push(lua, std::move(table));
lua_newuserdata(mLua, 0); lua_newuserdata(lua, 0);
lua_pushvalue(mLua, -2); lua_pushvalue(lua, -2);
lua_setmetatable(mLua, -2); lua_setmetatable(lua, -2);
return sol::stack::pop<sol::table>(mLua); return sol::stack::pop<sol::table>(lua);
} }
sol::table LuaState::getMutableFromReadOnly(const sol::userdata& ro) sol::table getMutableFromReadOnly(const sol::userdata& ro)
{ {
sol::stack::push(mLua, ro); lua_State* lua = ro.lua_state();
int ok = lua_getmetatable(mLua, -1); sol::stack::push(lua, ro);
int ok = lua_getmetatable(lua, -1);
assert(ok); assert(ok);
(void)ok; (void)ok;
sol::table res = sol::stack::pop<sol::table>(mLua); sol::table res = sol::stack::pop<sol::table>(lua);
lua_pop(mLua, 1); lua_pop(lua, 1);
return res; return res;
} }

View file

@ -3,7 +3,6 @@
#include <map> #include <map>
#include <limits> // missing from sol/sol.hpp
#include <sol/sol.hpp> #include <sol/sol.hpp>
#include <components/vfs/manager.hpp> #include <components/vfs/manager.hpp>
@ -37,11 +36,6 @@ namespace LuaUtil
// A shortcut to create a new Lua table. // A shortcut to create a new Lua table.
sol::table newTable() { return sol::table(mLua, sol::create); } sol::table newTable() { return sol::table(mLua, sol::create); }
// Makes a table read only (when accessed from Lua) by wrapping it with an empty userdata.
// Needed to forbid any changes in common resources that can accessed from different sandboxes.
sol::table makeReadOnly(sol::table);
sol::table getMutableFromReadOnly(const sol::userdata&);
// Registers a package that will be available from every sandbox via `require(name)`. // Registers a package that will be available from every sandbox via `require(name)`.
// The package can be either a sol::table with an API or a sol::function. If it is a function, // The package can be either a sol::table with an API or a sol::function. If it is a function,
// it will be evaluated (once per sandbox) the first time when requested. If the package // it will be evaluated (once per sandbox) the first time when requested. If the package
@ -106,6 +100,11 @@ namespace LuaUtil
// 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.
std::string toString(const sol::object&); std::string toString(const sol::object&);
// Makes a table read only (when accessed from Lua) by wrapping it with an empty userdata.
// Needed to forbid any changes in common resources that can accessed from different sandboxes.
sol::table makeReadOnly(sol::table);
sol::table getMutableFromReadOnly(const sol::userdata&);
} }
#endif // COMPONENTS_LUA_LUASTATE_H #endif // COMPONENTS_LUA_LUASTATE_H

View file

@ -25,7 +25,7 @@ namespace LuaUtil
void ScriptsContainer::addPackage(const std::string& packageName, sol::object package) void ScriptsContainer::addPackage(const std::string& packageName, sol::object package)
{ {
API[packageName] = mLua.makeReadOnly(std::move(package)); API[packageName] = makeReadOnly(std::move(package));
} }
bool ScriptsContainer::addNewScript(const std::string& path) bool ScriptsContainer::addNewScript(const std::string& path)
@ -63,7 +63,7 @@ namespace LuaUtil
if (interfaceName.empty() != (publicInterface == sol::nil)) if (interfaceName.empty() != (publicInterface == sol::nil))
Log(Debug::Error) << mNamePrefix << "[" << path << "]: 'interfaceName' should always be used together with 'interface'"; Log(Debug::Error) << mNamePrefix << "[" << path << "]: 'interfaceName' should always be used together with 'interface'";
else if (!interfaceName.empty()) else if (!interfaceName.empty())
script.as<sol::table>()[INTERFACE] = mPublicInterfaces[interfaceName] = mLua.makeReadOnly(publicInterface); script.as<sol::table>()[INTERFACE] = mPublicInterfaces[interfaceName] = makeReadOnly(publicInterface);
mScriptOrder.push_back(path); mScriptOrder.push_back(path);
mScripts[path].mInterface = std::move(script); mScripts[path].mInterface = std::move(script);
return true; return true;
@ -329,7 +329,7 @@ namespace LuaUtil
mHoursTimersQueue.clear(); mHoursTimersQueue.clear();
mPublicInterfaces.clear(); mPublicInterfaces.clear();
// Assigned by mLua.makeReadOnly, but `clear` removes it, so we need to assign it again. // Assigned by LuaUtil::makeReadOnly, but `clear` removes it, so we need to assign it again.
mPublicInterfaces[sol::meta_function::index] = mPublicInterfaces; mPublicInterfaces[sol::meta_function::index] = mPublicInterfaces;
} }

View file

@ -76,7 +76,7 @@ namespace LuaUtil
virtual ~ScriptsContainer() {} virtual ~ScriptsContainer() {}
// Adds package that will be available (via `require`) for all scripts in the container. // Adds package that will be available (via `require`) for all scripts in the container.
// Automatically applies LuaState::makeReadOnly to the package. // Automatically applies LuaUtil::makeReadOnly to the package.
void addPackage(const std::string& packageName, sol::object package); void addPackage(const std::string& packageName, sol::object package);
// Finds a file with given path in the virtual file system, starts as a new script, and adds it to the container. // Finds a file with given path in the virtual file system, starts as a new script, and adds it to the container.