10

我使用 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

4

6 回答 6

9

Sandboxing Lua

Setting hooks is not sufficient at all to prevent unintended waste of resources, let alone abuse- here's a simple example (the time is spent during string pattern matching- no debug hooks get called):

s=('a'):rep(20000):match('.-b')

The only reliable way to force time/memory constraints on a piece of Lua code is to run the Lua interpreter in a process of its own and to make your OS monitor that process.

The nice thing with Lua is that you won't need any complicated, OS-dependent permission setup for sandboxing: you just limit time and memory (reasonable; on windows there are Job Objects, Unix has ulimits- relevant: Linux resource limitation) and then keep things like os.execute, half the io-library and modules like luasocket away from the scripter (pretty easy).

Recovering from errors in sandboxed code

You can handle almost everything (except violation of time/memory limits) without trashing your Lua interpreter: Just wrap the execution of user-supplied code inside a pcall; if you call any Lua-API functions that might fail yourself, you need to wrap them inside a function that you can pcall, too (or set a Lua panic function and handle it from there).


[I didn't want people glancing at this thread to assume that debug.sethook is adequate for sandboxing, and stackoverflow would not let me comment (yet)]

于 2012-09-24T23:38:30.260 回答
1

将 Lua 循环放入协程中,并在每个循环结束时,仅用于Yield return null等待一帧(允许执行工作线程)。

于 2020-02-07T06:44:58.687 回答
0

我建议像处理任何其他 Lua 错误一样处理它。换句话说,就像用户刚刚写的一样威胁上面的代码

error("Script execution has been cancelled after stalling for too long")

(我假设您通过假设没有脚本应该花费超过固定时间来运行来检测无限循环。如果不是这种情况,请适当地更改消息)

您必须处理的方式将取决于您如何处理 Lua 错误 - 但无论如何您都必须这样做,所以很可能大部分代码已经存在。

编辑:马丁詹姆斯的建议似乎是你最好的选择。您可以使用 debug.setHook() 每 100 条 Lua 指令左右运行一些 lua 代码,如果在相同的客户端代码上花费了太多时间,则抛出错误。可以在这个邮件列表和lua-project repo上的代码示例中找到有关这方面的详细信息。

于 2012-04-27T22:00:19.043 回答
0

我使用了两种技术来解决这个问题。第一种是在单独的任务中调用 DoFile 或 DoString 方法。这样你就可以中止线程。我不知道退出解释器的任何技术(比如从钩子中)。

另一种方法是设置一个单独的Appdomain。使用它,您还可以设置单独的约束(证据和权限集),请参阅CreateDomain了解详细信息。

于 2014-09-17T19:05:57.710 回答
0

在运行 lua 代码之前设置 line hook 怎么样?我不知道在 C# 中是否可能,但在原始 C lua 中是可能的。

你的循环检测器是否已经在不同的 C# 任务中运行?

  • 如果是,请使用带有 C# 钩子的 C# 变量。在这种情况下,您的循环检测器设置和 hool 检查 C# 变量之类的terminateLua并抛出 lua 错误(应该是可能的)。
  • 如果不是,并且您在 lua 端检测到循环(也使用钩子?),设置 lua 变量(使其成为上值以防止用户欺骗)并抛出错误。

重要的部分是在您真正确定要完成任务之前不要重置此(C# 或 lua)变量,因为用户可以通过捕获您的错误pcall并尝试处理它。

于 2018-08-25T09:24:29.043 回答
0

如果您想检测循环是否仍在运行,您可以这样做。

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
于 2021-10-06T11:31:27.887 回答