I am learning from "Programing in Lua" by Roberto Ierusalimschy, and I found that in the book, the example of Sandboxing uses the function setfenv()
to change the environment of a given function, but in lua 5.2 this function is no longer available.
I tried to load some values from a file (a configuration file) into a field in a table, but, in lua 5.2 I can't use setfenv ( so I can load the values in the given environment). After reading some articles about lua 5.2 I found that each function may have (or not) an upvalue called _ENV which serves as the environment, so, I tried the following code:
function sandbox(sb_func, sb_env)
if not sb_func then return nil, "sandbox function not valid" end
sb_orig_env = _ENV
_ENV = sb_env -- yes, replaces the global _ENV
pcall_res, message = pcall( sb_func )
local modified_env = _ENV -- gets the environment that was used in the pcall( sb_func )
_ENV = sb_orig_env
return true, modified_env
end
function readFile(filename)
code = loadfile(filename)
res, table = sandbox(code, {})
if res then
--[[ Use table (modified_env) ]]--
else
print("Code not valid")
end
Replacing _ENV
in the 'sandbox' function works well (can't access the regular fields), but, when the 'code' is executed it seems that it ignores that I replaced _ENV
, it still can access regular fields (print, loadfile, dofile, etc).
Reading a little more, I found that lua 5.2 provides a function for this purpose, this function is loadin(env, chunk)
, which runs the given chunk in the given environment, but, when I try to add this function to my code, the function doesn't exist ( Is not present in the global _G
field).
Some help will be appreciated.
When you assign to _ENV
from within sandbox
, you're not overwriting the global environment--you're replacing the _ENV
upvalue of the currently running code. Adding calls to print(_ENV)
may help you better understand the identities of the tables involved.
For example:
function print_env()
print(_ENV)
end
function sandbox()
print(_ENV) -- prints: "table: 0x100100610"
-- need to keep access to a few globals:
_ENV = { print = print, print_env = print_env, debug = debug, load = load }
print(_ENV) -- prints: "table: 0x100105140"
print_env() -- prints: "table: 0x100105140"
local code1 = load('print(_ENV)')
code1() -- prints: "table: 0x100100610"
debug.setupvalue(code1, 1, _ENV) -- set our modified env
code1() -- prints: "table: 0x100105140"
local code2 = load('print(_ENV)', nil, nil, _ENV) -- pass 'env' arg
code2() -- prints: "table: 0x100105140"
end
The loadin
function was present in some pre-release versions of Lua 5.2 but was removed before the final release. Instead, the Lua 5.2 load
and loadfile
functions take an env
argument. You can also modify the _ENV
of another function using debug.setupvalue
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With