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?
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 notrequire
it, but doloadfile
, 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 inModules
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.