Песочница в Lua 5.2

Я учусь на «Программировании в Lua» Роберто Ирусалимши, и я обнаружил, что в книге в примере песочницы используется функция setfenv() для изменения окружения данной функции, но в lua 5.2 эта функция больше недоступна.

Я попытался загрузить некоторые значения из файла (файла конфигурации) в поле таблицы, но в lua 5.2 я не могу использовать setfenv (поэтому я могу загружать значения в данной среде). Прочитав несколько статей о lua 5.2, я обнаружил, что каждая функция может иметь (или не иметь) повышающее значение, называемое _ENV, которое служит средой, поэтому я попробовал следующий код:

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

Замена _ENV в функции «песочницы» работает хорошо (не может получить доступ к обычным полям), но, когда «код» выполняется, кажется, что он игнорирует замену _ENV, он по-прежнему может получить доступ к обычным полям (print, loadfile, dofile и т. д.).

Прочитав немного больше, я обнаружил, что lua 5.2 предоставляет функцию для этой цели, это функция loadin(env, chunk), которая запускает данный фрагмент в данной среде, но, когда я пытаюсь добавить эту функцию в свой код, функция не работает. существует (отсутствует в глобальном поле _G).

Некоторая помощь будет оценена по достоинству.


person Daniel Rivas    schedule 01.07.2012    source источник


Ответы (1)


Когда вы назначаете _ENV из sandbox, вы не перезаписываете глобальную среду - вы заменяете _ENV upvalue текущего выполняемого кода. Добавление вызовов к print(_ENV) может помочь вам лучше понять идентификаторы задействованных таблиц.

Например:

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

Функция loadin присутствовала в некоторых предварительных версиях Lua 5.2, но была удалена перед окончательной версией. Вместо этого load и loadfile в Lua 5.2 принимают аргумент env . Вы также можете изменить _ENV другой функции, используя debug.setupvalue. .

person Miles    schedule 01.07.2012
comment
Спасибо! Решение было простым. Я думаю, что этот подход к изменению среды в load и loadfile лучше, потому что setfenv использовался в основном в загруженном коде, поэтому ... Спасибо! Я запустил песочницу, как и ожидал. - person Daniel Rivas; 01.07.2012
comment
@Miles Когда функция print_env () определена, разве она не получает глобальное значение _ENV в качестве повышающего значения? Так как же это изменить, когда print_env () вызывается внутри sandbox ()? - person Tiago Costa; 25.07.2013
comment
@TiagoCosta upvalues ​​- это внешние локальные переменные. _ENV в этом случае является локальным для чанка; присвоение _ENV влияет на эту локальную переменную чанка, которая является общим повышающим значением для обоих замыканий. - person Miles; 26.07.2013