我使用lua接口在我的C#程序中获得lua支持,如果用户提交这样的代码,工作线程将冻结
while true do end
我有办法检测无限循环是否正在运行,但我需要一种从Worker线程退出DoString方法的好方法。有什么想法吗?
编辑:@kikito,是的,我正在发现它。我遇到的问题是我找不到一种杀死DoString方法的简洁方法,看起来Lua接口主类(Lua)有一些静态依赖,因为如果我在我的实例上做lua.Close();
它会中止DoString方法,但是下次我实例化一个lua类new Lua();
它会崩溃说一些保护性内存
编辑:显示我的.Close代码的功能分支 https://github.com/AndersMalmgren/FreePIE/tree/detect-and-recover-infite-lua-loop
答案 0 :(得分:8)
在所有中设置挂钩是不够的以防止意外浪费资源,更不用说滥用了 - 这是一个简单的例子(在字符串模式匹配期间花费的时间 - 没有调用挂钩调用):< / p>
对Lua代码强制时间/内存限制的唯一可靠方法是在自己的进程中运行Lua解释器,并使您的OS监视器处理。 Lua的优点是你不需要任何复杂的,依赖于操作系统的沙盒权限设置:你只是限制时间和内存(合理;在Windows上有Job Objects,Unix有ulimits-相关:Linux resource limitation)然后保存像os.execute,一半的io-library和像luasocket这样的模块远离脚本编写器(非常简单)。 您可以处理几乎所有内容(除了违反时间/内存限制)而不会破坏您的Lua解释器:只需将用户提供的代码的执行包装在pcall内;如果你调用任何可能自己失败的Lua-API函数,你需要将它们包装在一个你可以实现的函数中(或者设置一个Lua恐慌函数并从那里处理它)。 [我不希望看到这个线程的人认为debug.sethook足以用于沙盒,而stackoverflow不会让我评论(还)] s=('a'):rep(20000):match('.-b')
从沙盒代码中的错误中恢复
答案 1 :(得分:0)
我建议像处理任何其他Lua错误一样处理它。换句话说,威胁上面的代码就好像用户刚写的那样
error("Script execution has been cancelled after stalling for too long")
(我假设您通过假设没有脚本运行的时间超过固定时间来检测无限循环。如果不是这样,则适当地更改消息)
你必须处理这个问题的方式将取决于你如何处理Lua错误 - 但无论如何你都必须这样做,所以很可能已经存在大部分代码。
编辑:马丁詹姆斯的建议似乎是你最好的选择。您可以使用debug.setHook()每100 Lua指令运行一些lua代码,如果在同一客户端代码上传递了太多时间,则抛出错误。有关详细信息,请参阅this mailing list,以及lua-project repo上的代码示例。答案 2 :(得分:0)
我使用了两种技术来解决这个问题。第一种是在单独的Task中调用DoFile或DoString方法。这样你就可以中止线程了。我不知道退出解释器的任何技术(比如在钩子内)。
另一种方法是设置单独的Appdomain。使用此功能,您还可以设置单独的约束(证据和权限集),详细信息请参见CreateDomain。
答案 3 :(得分:0)
在运行lua代码之前在 之前设置行钩子怎么样?我不知道在C#中是可能的,但是在原始C lua中是可能的。
您的循环检测器是否已在其他C#任务中运行?
terminateLua
并抛出lua错误(应该可以)。重要的一点是在您真的确定要完成任务之前,请勿重置此变量(C#或lua),因为用户可以通过pcall
捕获错误并尝试进行处理。
答案 4 :(得分:0)
将Lua循环放在协程中,并在每个循环结束时,只需使用Yield return null
等待一帧(允许执行工作线程)。