mirror of
https://github.com/OpenMW/openmw.git
synced 2025-04-01 22:36:39 +00:00
Use normalized path in LuaState
This commit is contained in:
parent
090c65c017
commit
32ec92e71c
4 changed files with 52 additions and 41 deletions
|
@ -81,13 +81,14 @@ return {
|
||||||
|
|
||||||
TEST_F(LuaStateTest, Sandbox)
|
TEST_F(LuaStateTest, Sandbox)
|
||||||
{
|
{
|
||||||
sol::table script1 = mLua.runInNewSandbox("aaa/counter.lua");
|
const VFS::Path::Normalized path("aaa/counter.lua");
|
||||||
|
sol::table script1 = mLua.runInNewSandbox(path);
|
||||||
|
|
||||||
EXPECT_EQ(LuaUtil::call(script1["get"]).get<int>(), 42);
|
EXPECT_EQ(LuaUtil::call(script1["get"]).get<int>(), 42);
|
||||||
LuaUtil::call(script1["inc"], 3);
|
LuaUtil::call(script1["inc"], 3);
|
||||||
EXPECT_EQ(LuaUtil::call(script1["get"]).get<int>(), 45);
|
EXPECT_EQ(LuaUtil::call(script1["get"]).get<int>(), 45);
|
||||||
|
|
||||||
sol::table script2 = mLua.runInNewSandbox("aaa/counter.lua");
|
sol::table script2 = mLua.runInNewSandbox(path);
|
||||||
EXPECT_EQ(LuaUtil::call(script2["get"]).get<int>(), 42);
|
EXPECT_EQ(LuaUtil::call(script2["get"]).get<int>(), 42);
|
||||||
LuaUtil::call(script2["inc"], 1);
|
LuaUtil::call(script2["inc"], 1);
|
||||||
EXPECT_EQ(LuaUtil::call(script2["get"]).get<int>(), 43);
|
EXPECT_EQ(LuaUtil::call(script2["get"]).get<int>(), 43);
|
||||||
|
@ -122,12 +123,14 @@ return {
|
||||||
|
|
||||||
TEST_F(LuaStateTest, ErrorHandling)
|
TEST_F(LuaStateTest, ErrorHandling)
|
||||||
{
|
{
|
||||||
EXPECT_ERROR(mLua.runInNewSandbox("invalid.lua"), "[string \"invalid.lua\"]:1:");
|
const VFS::Path::Normalized path("invalid.lua");
|
||||||
|
EXPECT_ERROR(mLua.runInNewSandbox(path), "[string \"invalid.lua\"]:1:");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LuaStateTest, CustomRequire)
|
TEST_F(LuaStateTest, CustomRequire)
|
||||||
{
|
{
|
||||||
sol::table script = mLua.runInNewSandbox("bbb/tests.lua");
|
const VFS::Path::Normalized path("bbb/tests.lua");
|
||||||
|
sol::table script = mLua.runInNewSandbox(path);
|
||||||
|
|
||||||
EXPECT_FLOAT_EQ(
|
EXPECT_FLOAT_EQ(
|
||||||
LuaUtil::call(script["sin"], 1).get<float>(), -LuaUtil::call(script["requireMathSin"], -1).get<float>());
|
LuaUtil::call(script["sin"], 1).get<float>(), -LuaUtil::call(script["requireMathSin"], -1).get<float>());
|
||||||
|
@ -135,7 +138,7 @@ return {
|
||||||
EXPECT_EQ(LuaUtil::call(script["useCounter"]).get<int>(), 43);
|
EXPECT_EQ(LuaUtil::call(script["useCounter"]).get<int>(), 43);
|
||||||
EXPECT_EQ(LuaUtil::call(script["useCounter"]).get<int>(), 44);
|
EXPECT_EQ(LuaUtil::call(script["useCounter"]).get<int>(), 44);
|
||||||
{
|
{
|
||||||
sol::table script2 = mLua.runInNewSandbox("bbb/tests.lua");
|
sol::table script2 = mLua.runInNewSandbox(path);
|
||||||
EXPECT_EQ(LuaUtil::call(script2["useCounter"]).get<int>(), 43);
|
EXPECT_EQ(LuaUtil::call(script2["useCounter"]).get<int>(), 43);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(LuaUtil::call(script["useCounter"]).get<int>(), 45);
|
EXPECT_EQ(LuaUtil::call(script["useCounter"]).get<int>(), 45);
|
||||||
|
@ -145,7 +148,8 @@ return {
|
||||||
|
|
||||||
TEST_F(LuaStateTest, ReadOnly)
|
TEST_F(LuaStateTest, ReadOnly)
|
||||||
{
|
{
|
||||||
sol::table script = mLua.runInNewSandbox("bbb/tests.lua");
|
const VFS::Path::Normalized path("bbb/tests.lua");
|
||||||
|
sol::table script = mLua.runInNewSandbox(path);
|
||||||
|
|
||||||
// rawset itself is allowed
|
// rawset itself is allowed
|
||||||
EXPECT_EQ(LuaUtil::call(script["callRawset"]).get<int>(), 3);
|
EXPECT_EQ(LuaUtil::call(script["callRawset"]).get<int>(), 3);
|
||||||
|
@ -161,25 +165,27 @@ return {
|
||||||
|
|
||||||
TEST_F(LuaStateTest, Print)
|
TEST_F(LuaStateTest, Print)
|
||||||
{
|
{
|
||||||
|
const VFS::Path::Normalized path("bbb/tests.lua");
|
||||||
{
|
{
|
||||||
sol::table script = mLua.runInNewSandbox("bbb/tests.lua");
|
sol::table script = mLua.runInNewSandbox(path);
|
||||||
testing::internal::CaptureStdout();
|
testing::internal::CaptureStdout();
|
||||||
LuaUtil::call(script["print"], 1, 2, 3);
|
LuaUtil::call(script["print"], 1, 2, 3);
|
||||||
std::string output = testing::internal::GetCapturedStdout();
|
std::string output = testing::internal::GetCapturedStdout();
|
||||||
EXPECT_EQ(output, "[bbb/tests.lua]:\t1\t2\t3\n");
|
EXPECT_EQ(output, "unnamed:\t1\t2\t3\n");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
sol::table script = mLua.runInNewSandbox("bbb/tests.lua", "prefix");
|
sol::table script = mLua.runInNewSandbox(path, "prefix");
|
||||||
testing::internal::CaptureStdout();
|
testing::internal::CaptureStdout();
|
||||||
LuaUtil::call(script["print"]); // print with no arguments
|
LuaUtil::call(script["print"]); // print with no arguments
|
||||||
std::string output = testing::internal::GetCapturedStdout();
|
std::string output = testing::internal::GetCapturedStdout();
|
||||||
EXPECT_EQ(output, "prefix[bbb/tests.lua]:\n");
|
EXPECT_EQ(output, "prefix:\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(LuaStateTest, UnsafeFunction)
|
TEST_F(LuaStateTest, UnsafeFunction)
|
||||||
{
|
{
|
||||||
sol::table script = mLua.runInNewSandbox("bbb/tests.lua");
|
const VFS::Path::Normalized path("bbb/tests.lua");
|
||||||
|
sol::table script = mLua.runInNewSandbox(path);
|
||||||
EXPECT_ERROR(LuaUtil::call(script["callLoadstring"]), "a nil value");
|
EXPECT_ERROR(LuaUtil::call(script["callLoadstring"]), "a nil value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,11 +196,13 @@ return {
|
||||||
sol::table api1 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api1"));
|
sol::table api1 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api1"));
|
||||||
sol::table api2 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api2"));
|
sol::table api2 = LuaUtil::makeReadOnly(view.sol().create_table_with("name", "api2"));
|
||||||
|
|
||||||
sol::table script1 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api1 } });
|
const VFS::Path::Normalized path("bbb/tests.lua");
|
||||||
|
|
||||||
|
sol::table script1 = lua.runInNewSandbox(path, "", { { "test.api", api1 } });
|
||||||
|
|
||||||
lua.addCommonPackage("sqrlib", view.sol().create_table_with("sqr", [](int x) { return x * x; }));
|
lua.addCommonPackage("sqrlib", view.sol().create_table_with("sqr", [](int x) { return x * x; }));
|
||||||
|
|
||||||
sol::table script2 = lua.runInNewSandbox("bbb/tests.lua", "", { { "test.api", api2 } });
|
sol::table script2 = lua.runInNewSandbox(path, "", { { "test.api", api2 } });
|
||||||
|
|
||||||
EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib");
|
EXPECT_ERROR(LuaUtil::call(script1["sqr"], 3), "module not found: sqrlib");
|
||||||
EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get<int>(), 9);
|
EXPECT_EQ(LuaUtil::call(script2["sqr"], 3).get<int>(), 9);
|
||||||
|
@ -217,12 +225,13 @@ return {
|
||||||
return mLua.getTotalMemoryUsage();
|
return mLua.getTotalMemoryUsage();
|
||||||
};
|
};
|
||||||
int64_t memWithScript;
|
int64_t memWithScript;
|
||||||
|
const VFS::Path::Normalized path("requireBig.lua");
|
||||||
{
|
{
|
||||||
sol::object s = mLua.runInNewSandbox("requireBig.lua");
|
sol::object s = mLua.runInNewSandbox(path);
|
||||||
memWithScript = getMem();
|
memWithScript = getMem();
|
||||||
}
|
}
|
||||||
for (int i = 0; i < 100; ++i) // run many times to make small memory leaks visible
|
for (int i = 0; i < 100; ++i) // run many times to make small memory leaks visible
|
||||||
mLua.runInNewSandbox("requireBig.lua");
|
mLua.runInNewSandbox(path);
|
||||||
int64_t memWithoutScript = getMem();
|
int64_t memWithoutScript = getMem();
|
||||||
// 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);
|
||||||
|
@ -230,7 +239,8 @@ return {
|
||||||
|
|
||||||
TEST_F(LuaStateTest, SafeIndexMetamethod)
|
TEST_F(LuaStateTest, SafeIndexMetamethod)
|
||||||
{
|
{
|
||||||
sol::table t = mLua.runInNewSandbox("metaIndexError.lua");
|
const VFS::Path::Normalized path("metaIndexError.lua");
|
||||||
|
sol::table t = mLua.runInNewSandbox(path);
|
||||||
// without safe get we crash here
|
// without safe get we crash here
|
||||||
EXPECT_ERROR(LuaUtil::safeGet(t, "any key"), "meta index error");
|
EXPECT_ERROR(LuaUtil::safeGet(t, "any key"), "meta index error");
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,16 @@
|
||||||
|
|
||||||
namespace LuaUtil
|
namespace LuaUtil
|
||||||
{
|
{
|
||||||
|
static VFS::Path::Normalized packageNameToVfsPath(std::string_view packageName, const VFS::Manager& vfs)
|
||||||
static std::string packageNameToVfsPath(std::string_view packageName, const VFS::Manager* vfs)
|
|
||||||
{
|
{
|
||||||
std::string path(packageName);
|
std::string pathValue(packageName);
|
||||||
std::replace(path.begin(), path.end(), '.', '/');
|
std::replace(pathValue.begin(), pathValue.end(), '.', '/');
|
||||||
std::string pathWithInit = path + "/init.lua";
|
VFS::Path::Normalized pathWithInit(pathValue + "/init.lua");
|
||||||
path.append(".lua");
|
pathValue.append(".lua");
|
||||||
if (vfs->exists(path))
|
VFS::Path::Normalized path(pathValue);
|
||||||
|
if (vfs.exists(path))
|
||||||
return path;
|
return path;
|
||||||
else if (vfs->exists(pathWithInit))
|
else if (vfs.exists(pathWithInit))
|
||||||
return pathWithInit;
|
return pathWithInit;
|
||||||
else
|
else
|
||||||
throw std::runtime_error("module not found: " + std::string(packageName));
|
throw std::runtime_error("module not found: " + std::string(packageName));
|
||||||
|
@ -202,7 +202,7 @@ namespace LuaUtil
|
||||||
sol["setEnvironment"]
|
sol["setEnvironment"]
|
||||||
= [](const sol::environment& env, const sol::function& fn) { sol::set_environment(env, fn); };
|
= [](const sol::environment& env, const sol::function& fn) { sol::set_environment(env, fn); };
|
||||||
sol["loadFromVFS"] = [this](std::string_view packageName) {
|
sol["loadFromVFS"] = [this](std::string_view packageName) {
|
||||||
return loadScriptAndCache(packageNameToVfsPath(packageName, mVFS));
|
return loadScriptAndCache(packageNameToVfsPath(packageName, *mVFS));
|
||||||
};
|
};
|
||||||
sol["loadInternalLib"] = [this](std::string_view packageName) { return loadInternalLib(packageName); };
|
sol["loadInternalLib"] = [this](std::string_view packageName) { return loadInternalLib(packageName); };
|
||||||
|
|
||||||
|
@ -341,15 +341,14 @@ namespace LuaUtil
|
||||||
mCommonPackages.insert_or_assign(std::move(packageName), std::move(package));
|
mCommonPackages.insert_or_assign(std::move(packageName), std::move(package));
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::protected_function_result LuaState::runInNewSandbox(const std::string& path, const std::string& namePrefix,
|
sol::protected_function_result LuaState::runInNewSandbox(const VFS::Path::Normalized& path,
|
||||||
const std::map<std::string, sol::object>& packages, const sol::object& hiddenData)
|
const std::string& envName, const std::map<std::string, sol::object>& packages, const sol::object& hiddenData)
|
||||||
{
|
{
|
||||||
// TODO
|
// TODO
|
||||||
sol::protected_function script = loadScriptAndCache(path);
|
sol::protected_function script = loadScriptAndCache(path);
|
||||||
|
|
||||||
sol::environment env(mSol, sol::create, mSandboxEnv);
|
sol::environment env(mSol, sol::create, mSandboxEnv);
|
||||||
std::string envName = namePrefix + "[" + path + "]:";
|
env["print"] = mSol["printGen"](envName + ":");
|
||||||
env["print"] = mSol["printGen"](envName);
|
|
||||||
env["_G"] = env;
|
env["_G"] = env;
|
||||||
env[sol::metatable_key]["__metatable"] = false;
|
env[sol::metatable_key]["__metatable"] = false;
|
||||||
|
|
||||||
|
@ -395,12 +394,12 @@ namespace LuaUtil
|
||||||
return std::move(res);
|
return std::move(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::function LuaState::loadScriptAndCache(const std::string& path)
|
sol::function LuaState::loadScriptAndCache(const VFS::Path::Normalized& path)
|
||||||
{
|
{
|
||||||
auto iter = mCompiledScripts.find(path);
|
auto iter = mCompiledScripts.find(path);
|
||||||
if (iter != mCompiledScripts.end())
|
if (iter != mCompiledScripts.end())
|
||||||
{
|
{
|
||||||
sol::load_result res = mSol.load(iter->second.as_string_view(), path, sol::load_mode::binary);
|
sol::load_result res = mSol.load(iter->second.as_string_view(), path.value(), sol::load_mode::binary);
|
||||||
// Unless we have memory corruption issues, the bytecode is valid at this point, but loading might still
|
// Unless we have memory corruption issues, the bytecode is valid at this point, but loading might still
|
||||||
// fail because we've hit our Lua memory cap
|
// fail because we've hit our Lua memory cap
|
||||||
if (!res.valid())
|
if (!res.valid())
|
||||||
|
@ -412,10 +411,10 @@ namespace LuaUtil
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
sol::function LuaState::loadFromVFS(const std::string& path)
|
sol::function LuaState::loadFromVFS(const VFS::Path::Normalized& path)
|
||||||
{
|
{
|
||||||
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.value(), sol::load_mode::text);
|
||||||
if (!res.valid())
|
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());
|
||||||
return res;
|
return res;
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
|
|
||||||
#include <sol/sol.hpp>
|
#include <sol/sol.hpp>
|
||||||
|
|
||||||
|
#include <components/vfs/pathutil.hpp>
|
||||||
|
|
||||||
#include "configuration.hpp"
|
#include "configuration.hpp"
|
||||||
|
|
||||||
namespace VFS
|
namespace VFS
|
||||||
|
@ -141,13 +143,13 @@ namespace LuaUtil
|
||||||
// (the result is expected to be an interface of the script).
|
// (the result is expected to be an interface of the script).
|
||||||
// Args:
|
// Args:
|
||||||
// path: path to the script in the virtual filesystem;
|
// path: path to the script in the virtual filesystem;
|
||||||
// namePrefix: sandbox name will be "<namePrefix>[<filePath>]". Sandbox name
|
// envName: sandbox name.
|
||||||
// will be added to every `print` output.
|
|
||||||
// packages: additional packages that should be available from the sandbox via `require`. Each package
|
// packages: additional packages that should be available from the sandbox via `require`. Each package
|
||||||
// should be either a sol::table or a sol::function. If it is a function, it will be evaluated
|
// should be either a sol::table or a sol::function. If it is a function, it will be evaluated
|
||||||
// (once per sandbox) with the argument 'hiddenData' the first time when requested.
|
// (once per sandbox) with the argument 'hiddenData' the first time when requested.
|
||||||
sol::protected_function_result runInNewSandbox(const std::string& path, const std::string& namePrefix = "",
|
sol::protected_function_result runInNewSandbox(const VFS::Path::Normalized& path,
|
||||||
const std::map<std::string, sol::object>& packages = {}, const sol::object& hiddenData = sol::nil);
|
const std::string& envName = "unnamed", const std::map<std::string, sol::object>& packages = {},
|
||||||
|
const sol::object& hiddenData = sol::nil);
|
||||||
|
|
||||||
void dropScriptCache() { mCompiledScripts.clear(); }
|
void dropScriptCache() { mCompiledScripts.clear(); }
|
||||||
|
|
||||||
|
@ -157,7 +159,7 @@ namespace LuaUtil
|
||||||
// directly.
|
// directly.
|
||||||
void addInternalLibSearchPath(const std::filesystem::path& path) { mLibSearchPaths.push_back(path); }
|
void addInternalLibSearchPath(const std::filesystem::path& path) { mLibSearchPaths.push_back(path); }
|
||||||
sol::function loadInternalLib(std::string_view libName);
|
sol::function loadInternalLib(std::string_view libName);
|
||||||
sol::function loadFromVFS(const std::string& path);
|
sol::function loadFromVFS(const VFS::Path::Normalized& path);
|
||||||
sol::environment newInternalLibEnvironment();
|
sol::environment newInternalLibEnvironment();
|
||||||
|
|
||||||
uint64_t getTotalMemoryUsage() const { return mSol.memory_used(); }
|
uint64_t getTotalMemoryUsage() const { return mSol.memory_used(); }
|
||||||
|
@ -182,7 +184,7 @@ namespace LuaUtil
|
||||||
friend sol::protected_function_result call(
|
friend sol::protected_function_result call(
|
||||||
ScriptId scriptId, const sol::protected_function& fn, Args&&... args);
|
ScriptId scriptId, const sol::protected_function& fn, Args&&... args);
|
||||||
|
|
||||||
sol::function loadScriptAndCache(const std::string& path);
|
sol::function loadScriptAndCache(const VFS::Path::Normalized& path);
|
||||||
static void countHook(lua_State* L, lua_Debug* ar);
|
static void countHook(lua_State* L, lua_Debug* ar);
|
||||||
static void* trackingAllocator(void* ud, void* ptr, size_t osize, size_t nsize);
|
static void* trackingAllocator(void* ud, void* ptr, size_t osize, size_t nsize);
|
||||||
|
|
||||||
|
@ -227,7 +229,7 @@ namespace LuaUtil
|
||||||
sol::state_view mSol;
|
sol::state_view mSol;
|
||||||
const ScriptsConfiguration* mConf;
|
const ScriptsConfiguration* mConf;
|
||||||
sol::table mSandboxEnv;
|
sol::table mSandboxEnv;
|
||||||
std::map<std::string, sol::bytecode> mCompiledScripts;
|
std::map<VFS::Path::Normalized, sol::bytecode> mCompiledScripts;
|
||||||
std::map<std::string, sol::object> mCommonPackages;
|
std::map<std::string, sol::object> mCommonPackages;
|
||||||
const VFS::Manager* mVFS;
|
const VFS::Manager* mVFS;
|
||||||
std::vector<std::filesystem::path> mLibSearchPaths;
|
std::vector<std::filesystem::path> mLibSearchPaths;
|
||||||
|
|
|
@ -97,7 +97,7 @@ namespace LuaUtil
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
sol::object scriptOutput = mLua.runInNewSandbox(path, mNamePrefix, mAPI, script.mHiddenData);
|
sol::object scriptOutput = mLua.runInNewSandbox(path, debugName, mAPI, script.mHiddenData);
|
||||||
if (scriptOutput == sol::nil)
|
if (scriptOutput == sol::nil)
|
||||||
return true;
|
return true;
|
||||||
sol::object engineHandlers = sol::nil, eventHandlers = sol::nil;
|
sol::object engineHandlers = sol::nil, eventHandlers = sol::nil;
|
||||||
|
|
Loading…
Reference in a new issue