Search code examples
lualuajit

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


I'm attempting to sandbox some functions using setfenv, and I recieve the following output:

123
nil

Why is testValue when calling sandboxTest() nil, but it's 123 when it's accessed in callSandboxedTest()?

Using 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()

Solution

  • Environments aren't part of the call stack. Every function has its own environment. So sandboxTest has an environment, as does callSandboxTest. Changing the environment of one function has no effect on the environment of another.

    sandboxTest will continue to use the default environment, so it will access the regular global table to find testValue. And since testValue is never set in the global table, sandboxTest will get nil.

    That's why, when maintaining a sandbox, it is very important to carefully choose what functionality to expose to the sandbox. If a function needs to be part of the sandbox, then that function needs to have its environment set.

    That's why it's best to sandbox based on compiled Lua chunks rather than individual functions. When creating functions, the functions created will inherit the current environment.