LuaJIT setfenv 似乎没有设置对给定环境的进一步函数调用

LuaJIT setfenv not appearing to set further function calls to the given environment

我正在尝试使用 setfenv 对一些函数进行沙箱化,我收到以下输出:

123
nil

为什么调用sandboxTest()时是testValuenil,而在callSandboxedTest()中访问时是123?

使用 LuaJIT 2.1.0-beta2 (Lua 5.1)

function sandboxTest()
    print(testValue)
end

local aNumber = 123

function callSandboxedTest()
    setfenv(1, {
        print = print,
        testValue = aNumber,
        sandboxTest = sandboxTest
    })
    print(testValue)
    sandboxTest()
end

callSandboxedTest()

环境不是调用堆栈的一部分。每个函数都有其 自己的 环境。所以 sandboxTestcallSandboxTest 一样有一个环境。更改一个函数的环境不会影响另一个函数的环境。

sandboxTest 将继续使用默认环境,因此它将访问常规全局 table 以查找 testValue。由于 testValue 从未在全局 table 中设置,sandboxTest 将得到 nil.

这就是为什么在维护沙箱时,仔细选择向沙箱公开哪些功能非常重要。如果某个函数需要成为沙箱的一部分,则该函数需要设置其环境。

这就是为什么最好基于编译的 Lua 块而不是单个函数进行沙箱化。创建函数时,创建的函数会继承当前环境

您还没有修改sandboxTest正在使用的环境;您只修改了当前函数的环境。您可以使用 setfenv 通过传递函数名称来设置特定函数的环境(传递数字会修改调用堆栈中函数的环境):

setfenv(sandboxTest, {
        print = print,
        testValue = aNumber,
        sandboxTest = sandboxTest
    })

这将打印 123 123.