В Lua 5.1 и без особой обработки ошибок вы можете сделать это:
-- load and run a script in the provided environment
-- returns the modified environment table
function run(scriptfile)
local env = setmetatable({}, {__index=_G})
assert(pcall(setfenv(assert(loadfile(scriptfile)), env)))
setmetatable(env, nil)
return env
end
В первой строке создается пустая таблица окружения, которая может видеть все существующие глобальные переменные, но не может их тривиально изменить, так как они виднытолько через прокси через метаметод __index
.Любые глобальные переменные, которые создает скрипт, будут храниться в env
, который возвращается.Это будет хорошо работать для простых сценариев, которые просто устанавливают кучу параметров конфигурации, и которым может потребоваться вызвать простые безопасные функции, чтобы установить их на основе условий во время выполнения.
Обратите внимание, что глобальные переменные видны сценариюэто удобство.Хотя глобальные переменные не могут быть изменены из сценария очевидным образом, _G
- это глобальная переменная, которая содержит ссылку на глобальную среду (содержащую _G._G
, _G._G._G
и т. Д.), И _G
может бытьизменен из скрипта, что может привести к дальнейшим проблемам.
Поэтому вместо использования _G
для индекса было бы намного лучше создать таблицу, содержащую только функции, которые, как известно, безопасны и известны как необходимые.автором вашего скрипта.
Полное решение - запустить скрипт в песочнице и, возможно, дополнительно защитить для предотвращения случайного (или умышленного) отказа в обслуживании или, что еще хуже. Песочницы более подробно описаны в вики Lua User.Эта тема глубже, чем кажется на первый взгляд, но если ваши пользователи уверены, что они не являются злонамеренными, практические решения просты.
Lua 5.2 немного меняет положение, исключая setfenv()
в пользунового параметра в load()
.Подробности также на вики-странице.