防止 Lua 无限循环
我使用 Lua 接口在我的 C# 程序中支持 Lua,如果用户提交了如下代码,工作线程会冻结:
while true do end
我有一种方法来检测无限循环是否在运行,但我需要一种漂亮的方式从工作线程中退出 DoString 方法。有什么想法吗?
编辑:@kikito,是的,我正在检测类似的东西。我的问题是我找不到一种干净的方法来杀死 DoString 方法,因为 Lua 接口的主类(Lua)具有一些静态依赖项,因此如果在我的实例上执行 lua.Close();
,它将中止 DoString 方法,但是下一次我实例化 Lua 类 new Lua();
时,它将崩溃并说些什么关于内存保护的事情
编辑:一个特性分支展示了我的 .Close 代码 https://github.com/AndersMalmgren/FreePIE/tree/detect-and-recover-infite-lua-loop
原文链接 https://stackoverflow.com/questions/10352092
Lua的沙盒设置
设置钩子远远不足以防止资源的意外浪费,更不用说滥用——以下是一个简单的例子(花费时间在字符串匹配过程中——没有调试钩子被调用):
s=('a'):rep(20000):match('.-b')
强制对Lua代码进行时间/内存约束的唯一可靠方式是在其自己的进程中运行Lua解释器,并使您的操作系统监视该进程。
Lua的好处在于,您不需要进行任何复杂且依赖于操作系统的权限设置来进行沙箱设置:您只需要限制时间和内存(合理的——在Windows上有作业对象,Unix有ulimits-相关:Linux资源限制),然后将诸如os.execute、io库的一半以及像luasocket这样的模块远离脚本编写者(非常容易)。
从沙盒代码中恢复错误
您可以几乎处理所有事情(除了违反时间/内存限制)而不会损坏您的Lua解释器:只需将用户提供的代码执行包装在一个pcall中;如果您自己调用了任何可能失败的Lua API函数,您需要将它们包装在一个函数中,以便您可以调用pcall,或者设置一个Lua panic函数并从那里处理它。
[我不想让人们在瞥一眼这个线程时就认为调试.sethook足以进行沙盒设置,而stackoverflow也不让我评论(但)]
我使用了两种技术来解决这个问题。第一种是在单独的任务内调用DoFile或DoString方法。这样你就可以中止线程。我不知道有没有什么技术(比如在钩子内)可以退出解释器。
另一种方法是设置一个独立的Appdomain。使用这个方法,你也可以设置单独的限制(证据和权限集),详情请见CreateDomain。
关于在运行 lua 代码之前设置行勾子怎么样?我不知道在 C# 中是否可行,但在原始 C lua 中是可行的。
你的循环检测器已经在不同的 C# 任务中运行了吗?
- 如果是,使用带有 C# 钩子的 C# 变量。在这种情况下,您的循环检测器设置并检查 C# 变量,如
terminateLua
,并抛出 lua 错误(这应该是可能的)。 - 如果否,并且您使用钩子在 lua 侧检测到循环,则设置 lua 变量(使其成为上值以防止用户进行欺骗),然后抛出错误。
重要的是,在确保完成任务之前不要重置此(无论是 C# 还是 lua)变量,因为用户可以通过 pcall
捕获您的错误并尝试处理它。
将 Lua 循环放入协程内,在每个循环结束时,只需使用 Yield return null
等待一帧(让工作线程运行)。
如果你想要检测一个循环是否仍在运行,你可以像这样完成。
local detect = false
detect == true
goal = 5
star = 0
function loop()
while detect == true do
print("Still running")
else
print("Loop stopped running")
end
end
Spawn(loop)
while true do
if star > goal then
detect = false
end
end
输出结果将是:
Still running
Still running
Still running
Still running
Still running
Loop stopped running
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?
- addEventListener 返回 nil Lua
- Lua中获取用户配置主目录的跨平台方法
- 如何编写 Lua 模式将字符串(嵌套数组)转换为真正的数组?
我建议像处理任何其他 Lua 错误一样处理它。换句话说,将上面的代码视为用户刚刚编写的错误代码:
error("Script execution has been cancelled after stalling for too long")
(我假设你通过假定没有脚本应该花费超过固定的时间来检测无限循环。如果不是这种情况,请适当更改消息)
你处理这个问题的方式将取决于你如何处理 Lua 错误,但你无论如何都必须处理它,所以大多数代码可能已经存在了。
编辑:似乎 Martin James 的建议是你最好的选择。你可以使用 debug.setHook() 每隔大约 100 条 Lua 指令运行一些 Lua 代码,如果同一客户端的代码执行的时间太长,则抛出错误。关于此的详细信息可以在 此邮件列表 上找到,带有示例代码的库可以在 lua-project repo 上找到。