将Sandbox Lua视为Python中的一个功能,并在沙盒中使用调试钩子执行协程。

我有一个Python程序,用户应该能够在界面中编写自己的代码。这里的代码应该是Lua语言。到目前为止,我已经将Lua隔离并可以这样一次执行用户代码:

lua_sandbox = lua.eval('''
function()
  local function run(untrusted_code)
    local untrusted_function, message = load(untrusted_code, nil, 't', _ENV)
    if not untrusted_function then return nil, message end
    return xpcall(untrusted_function, errorHandler)
  end

-------------------- Defining Python functions and objects in Lua -------------------

  local function PythonFunctionInLua(arg)
    return python.eval('PythonFunction(' .. arg ..')')
  end

  PythonObjectInLua = python.eval('PythonObject')

-- Pass them to the local Lua sandbox
  _ENV = { print = print,
           PythonFunction = PythonFunctionInLua,
           PythonObject = PythonObjectInLua,
           coroutine = coroutine }

  assert(run [[''' + code + ''' ]])
end
''')

到目前为止,还不错。现在我想添加按步执行代码的可能性。到目前为止,我能想到的最好的主意是使用调试钩子,因此我尝试了这一点:

... (来自上文直到_ENV)
debug.sethook(scripterDebug, "l")
func = assert( run [[''' + code  + ''' ]] )
co = coroutine.create(func)
coroutine.resume(co)

这里出现了问题:我不能调用coroutine.yield来暂停例程,直到用户再次点击以处理下一行。从外部调用它,例如在scripterDebug钩子中,以及从内部调用它(将其插入code部分)都会导致attempt to yield across C-Call boundary错误(我猜是因为我在后一种情况下一直进入和退出沙盒)。

我还尝试在run [[ ]]]内创建协程,然后会有yield效果,但我不能在外部调用coroutine.resume(co),因为'co'只在沙盒内已知。我必须从外部调用它,因为当用户点击继续时调用它,并且如果我将对UI等的访问传递到沙盒中,整个过程将变得无用。

有没有一种在沙盒中好而短暂地逐步执行这个代码的方法?

点赞