- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在我的项目中,我正在执行 XML 文件中包含的一些 lua 函数。我从 C++ 读取 XML,解析代码字符串,执行它们并获得结果。我发现的所有相关问题要么使用专用的 .lua
文件,要么直接在 Lua 中完成,但我找不到适合我的案例的解决方案。
我无法修改文件中的函数,它们都具有以下签名:
function() --or function ()
--do stuff
return foo
end
从 C++ 我像这样加载它们:
lua_State *L = luaL_newstate();
luaL_openlibs(L);
std::string code = get_code_from_XML();
std::string wrapped_code = "return " + code;
luaL_loadstring(L, wrapped_code.c_str());
if (lua_pcall(L, 0, 1, 0)){
return 1;
}
argNum = load_arg_number();
if (lua_pcall(L, argNum, 1, 0)){
return 1;
}
return 0;
一切正常,但从 XML 字符串运行任意 Lua 代码似乎不太安全,所以我想设置一个代码可以使用的函数白名单。
正在关注 this lua-users discussion 我创建了我的允许功能列表,例如:
// Of course my list is bigger
std::string whitelist = "sandbox_env = {ipairs = ipairs} _ENV = sandbox_env"
问题是我不明白如何加载它以便在我调用的函数中可用。
我试着像在 lua-users 网站上那样做:
std::string Lua_sandboxed_script_to_run( Lua_sandboxing_script + Lua_script_to_run )
if (luaL_dostring(sandboxed_L, Lua_sandboxed_script_to_run))
{
// error checking
}
但是这样会导致函数加载不正确,出现Lua错误
Trying to execute a string value
我也试过:
luaL_loadstring(L, whitelist.c_str());
lua_getglobal(L, "_ENV");
lua_setupvalue(L, -2, 1);
在执行加载的 XML 函数之前,这不会使程序崩溃,但也不会为被调用的函数设置 _ENV
。
我发现拥有我想要的东西的唯一方法是用 C++ 搜索 ()
解析函数字符串,在它之后插入 whitelist
然后 luaL_loadstring
和 lua_pcall
执行它两次。
像这样:
.
.
size_t n = code.find("()") + 2;
code.insert(n, whitelist);
std::string wrapped_code = "return " + code;
.
.
这有效并为该函数设置了我的自定义 _ENV,但在我看来这是一种非常 hacky 的方式。
如何以更好的方式为从 C 加载的字符串函数设置 _ENV 变量?
如果有一种方法可以为整个 lua_State
保存一次而不是每次我调用一个函数时,就加分。
最佳答案
在深入研究示例之前,让我们解释一下我们如何(以及在什么级别)在 Lua 中或多或少地编写沙箱代码:
全局 - 删除或从不将不需要的模块/函数添加到全局环境中。
Chunk(ly) - 修改 block 的 _ENV
上值。
本地 - 通过 Lua 脚本中的本地或上值修改 _ENV
。它可以通过 upvalue 传播给 child 。
查看问题中提供的示例,您尝试执行 2 或 3。
我不确定您的需求是什么,但我会尝试为您提供上面列出的每种方法的示例。请注意,这些示例不是最终示例,也不是唯一可能的方法,并且不要采用您的 return function () ... end
包装器。选择任何适合您的。
这个非常简单。如果您不打算使用所提供的所有库...
lua_State * L = luaL_newstate();
luaL_openlibs(L); // <-- Remove this
...然后就不要加载它们了:
lua_State * L = luaL_newstate();
// Instead of luaL_openlibs:
luaL_requiref(L, "_G", luaopen_base, 1);
luaL_requiref(L, LUA_MATHLIBNAME, luaopen_math, 1);
luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
// luaL_requiref pushes to stack - clean it up:
lua_pop(L, 3);
// Load and execute desired scripts here.
引用6 Standard Libraries和 linit.c可用库的列表。另请参阅:luaL_requiref
.
除了选择性的库加载之外,您还可以通过将它们设置为 nil
来删除选定的全局变量:
lua_pushnil(L);
lua_setglobal(L, "print");
你为 lua_State 设置一次。
让我们将自己限制在一个非常基本的操作上,即更改加载的主 block 的第一个上值。此类 block 的第一个上值预计为 _ENV
(引用下文)。
请注意,我说的是主要 block 。通常,您很少会加载期望除 _ENV
以外的东西作为其第一个上值的 block ,但记住这种情况总是好的。
无论如何,请考虑以下示例:
lua_State * L = luaL_newstate();
luaL_openlibs(L);
luaL_loadstring(L, "print2 \"Hello there\"");
// (A) Create a table with desired environment and place it at the top of the stack.
// Replace this comment with any of the options described below
lua_setupvalue(L, -2, 1);
lua_call(L, 0, 0);
您可以通过多种方式实现 (A)。您可以使用 Lua C API:
lua_newtable(L);
lua_pushliteral(L, "print2");
lua_getglobal(L, "print");
lua_settable(L, -3);
或者你可以通过 dostring
来完成:
lua_dostring(L, "return { print2 = print }");
或者您可以尝试另一种方法,类似于问题中的方法:
lua_dostring(L, "sandbox_env = { print2 = print }"); // Without _ENV = sandbox_env
lua_getglobal(L, "sandbox_env");
关于环境的一般引用:2.2 Environments and the Global Environment .
参见 lua_setupvalue
有关使用详情的文档。
请参阅 load_aux
中的另一个示例.请注意,这是 Lua 中可用的 load
函数源代码的一部分。此函数允许通过其参数之一设置加载 block 的环境(参见 load
)。
您可以修改上值 _ENV
或直接在 Lua 脚本中用本地覆盖它。让我们做后者:
local _ENV = { print2 = print }
(function ()
print2("Hello there")
end)()
这意味着您可以包装加载的脚本并像这样运行它:
std::string loaded_script /* = ... */;
std::string wrapped_script = "local _ENV = { print2 = print }; (" + loaded_script + ")()";
luaL_loadstring(L, wrapped_script.c_str());
lua_call(L, 0, 0);
这也适用于 return function () ... end
换行(而不是 (...)()
)。这是因为 local _ENV
将作为上值传递给返回的匿名函数。
引用Environments Tutorial有关 Lua 内部环境操作的更详细解释。
关于c++ - 从 C++ 为字符串函数设置 _ENV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58604393/
如何使用 SPListCollection.Add(String, String, String, String, Int32, String, SPListTemplate.QuickLaunchO
我刚刚开始使用 C++ 并且对 C# 有一些经验,所以我有一些一般的编程经验。然而,似乎我马上就被击落了。我试过在谷歌上寻找,以免浪费任何人的时间,但没有结果。 int main(int argc,
这个问题已经有答案了: In Java 8 how do I transform a Map to another Map using a lambda? (8 个回答) Convert a Map>
我正在使用 node + typescript 和集成的 swagger 进行 API 调用。我 Swagger 提出以下要求 http://localhost:3033/employees/sear
我是 C++ 容器模板的新手。我收集了一些记录。每条记录都有一个唯一的名称,以及一个字段/值对列表。将按名称访问记录。字段/值对的顺序很重要。因此我设计如下: typedef string
我需要这两种方法,但j2me没有,我找到了一个replaceall();但这是 replaceall(string,string,string); 第二个方法是SringBuffer但在j2me中它没
If string is an alias of String in the .net framework为什么会发生这种情况,我应该如何解释它: type JustAString = string
我有两个列表(或字符串):一个大,另一个小。 我想检查较大的(A)是否包含小的(B)。 我的期望如下: 案例 1. B 是 A 的子集 A = [1,2,3] B = [1,2] contains(A
我有一个似乎无法解决的小问题。 这里...我有一个像这样创建的输入... var input = $(''); 如果我这样做......一切都很好 $(this).append(input); 如果我
我有以下代码片段 string[] lines = objects.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.No
这可能真的很简单,但我已经坚持了一段时间了。 我正在尝试输出一个字符串,然后输出一个带有两位小数的 double ,后跟另一个字符串,这是我的代码。 System.out.printf("成本:%.2
以下是 Cloud Firestore 列表查询中的示例之一 citiesRef.where("state", ">=", "CA").where("state", "= 字符串,我们在Stack O
我正在尝试检查一个字符串是否包含在另一个字符串中。后面的代码非常简单。我怎样才能在 jquery 中做到这一点? function deleteRow(locName, locID) { if
这个问题在这里已经有了答案: How to implement big int in C++ (14 个答案) 关闭 9 年前。 我有 2 个字符串,都只包含数字。这些数字大于 uint64_t 的
我有一个带有自定义转换器的 Dozer 映射: com.xyz.Customer com.xyz.CustomerDAO customerName
这个问题在这里已经有了答案: How do I compare strings in Java? (23 个回答) 关闭 6 年前。 我想了解字符串池的工作原理以及一个字符串等于另一个字符串的规则是
我已阅读 this问题和其他一些问题。但它们与我的问题有些无关 对于 UILabel 如果你不指定 ? 或 ! 你会得到这样的错误: @IBOutlet property has non-option
这两种方法中哪一种在理论上更快,为什么? (指向字符串的指针必须是常量。) destination[count] 和 *destination++ 之间的确切区别是什么? destination[co
This question already has answers here: Closed 11 years ago. Possible Duplicates: Is String.Format a
我有一个Stream一个文件的,现在我想将相同的单词组合成 Map这很重要,这个词在 Stream 中出现的频率. 我知道我必须使用 collect(Collectors.groupingBy(..)
我是一名优秀的程序员,十分优秀!