Question

I've been trying to work with setfenv() in order to load a chunk into an environment outside of the global environment but I'm having a little trouble. The following is the code I'm running:

-- main.lua
function SandboxScript(scriptTable, scriptName)
    setmetatable(scriptTable, { __index = _G })
    local sandbox = loadfile(scriptName)
    setfenv(sandbox, scriptTable)
    sandbox()
    return scriptTable
end

local function main()
    print(Singleton)
    local test = {}
    local single1 = SandboxScript(test, "C:\\pathto\\TestTable.lua")
    print(Singleton)
    test.Update()

    local test2 = {}
    local single2 = SandboxScript(test2, "C:\\pathto\\TestTable.lua")
    test2.Update()
end
main()

-- TestTable.lua
require("Singleton")
local test = {}

function Update()
    test = Singleton:new()
    print(test.var)
    test.var = "Changed"
    print(test.var)
end

-- Singleton.lua
Singleton = {}
Instance = {}

function Singleton:new()
    if(next(Instance)) then
        return Instance
    end

    Instance.var = "Init"
    return Instance
end

I'm expecting the output of this to be:

nil      --(First check in global table before running sandbox code)
nil      --(Second check in global table after running sandbox code)
Init     --(Initial value of the Singleton's var)
Changed  --(Singleton's var after we change it)
Init     --(Initial value of the Singleton's var in a different sandbox)
Changed  --(Singleton's var after we change it in the different sandbox)


Instead I'm getting:

nil
table: 05143108
Init
Changed
Changed
Changed

Indicating that the "sandbox()" is loading the table into the global space even though the I set the sandbox's environment to "scriptTable" using "setfenv(sandbox, scriptTable)" prior to execution of "sandbox()".

I've gone through the Sand Boxes Example mentioned in other posts but I'm still getting the same results. Any idea what I can do to load a script in it's own environment without polluting the global environment?

Was it helpful?

Solution

You are not really polluting the global environment, what you see here is a nature of package system, that modules are cached and shared for every call to require, not depending on environment of calling function. That allows Singleton module to work, because if you will not require it, but do loadfile, it will load twice (and be very less singleton than expected).

So, if the real task is to load module only once per sandbox, then you may swap package.loaded, package.preload and other loader state variables before entering into a sandbox. More info in Modules section of Lua 5.1 Reference Manual.

The solution with loadfile may be just fine, but if you plan to cross-require modules in complex module system inside your sandbox, this will lead to a big problem indeed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top