在Lua 5.2中重新创建setfenv() [英] Recreating setfenv() in Lua 5.2

查看:225
本文介绍了在Lua 5.2中重新创建setfenv()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何在Lua 5.2中重新创建setfenv的功能?我在准确了解您应该如何使用新的_ENV环境变量时遇到了一些麻烦.

在Lua 5.1中,您可以使用setfenv轻松地沙盒化任何功能.

--# Lua 5.1

print('_G', _G)             -- address of _G

local foo = function()  
    print('env', _G)        -- address of sandbox _G
    bar = 1
end

-- create a simple sandbox
local env = { print = print }
env._G = env

-- set the environment and call the function
setfenv(foo, env)
foo()

-- we should have global in our environment table but not in _G
print(bar, env.bar)

运行此示例显示输出:

_G    table: 0x62d6b0
env   table: 0x635d00
nil   1



我想在Lua 5.2中重新创建这个简单的示例.下面是我的尝试,但它与上面的示例不同.

--# Lua 5.2

local function setfenv(f, env)
    local _ENV = env or {}       -- create the _ENV upvalue
    return function(...)
        print('upvalue', _ENV)   -- address of _ENV upvalue
        return f(...)
    end
end

local foo = function()
    print('_ENV', _ENV)          -- address of function _ENV
    bar = 1
end

-- create a simple sandbox
local env = { print = print }
env._G = env

-- set the environment and call the function
foo_env = setfenv(foo, env)
foo_env()

-- we should have global in our envoirnment table but not in _G
print(bar, env.bar)

运行此示例显示输出:

upvalue    table: 0x637e90
_ENV       table: 0x6305f0
1          nil



我知道关于此主题的其他几个问题,但是它们似乎主要是在处理动态代码(文件或字符串)的加载,这些代码使用Lua 5.2中提供的新load函数可以很好地工作.在这里,我特别要求提供一种在沙箱中运行任意功能的解决方案.我想在不使用debug库的情况下执行此操作.根据Lua 文档,我们不必依赖它. /p>

解决方案

如果不使用Lua 5.2中来自Lua的调试库,则无法更改函数的环境.创建功能后,即为其具有的环境.修改此环境的唯一方法是修改其第一个升值,这需要调试库.

Lua 5.2中有关环境的一般想法是,应将环境视为在欺骗之外是不可变的(即:调试库).您在环境中创建函数;一旦在那里创建,那就是它所具有的环境.永远.

这是Lua 5.1中经常使用环境的方式,但是通过随便的函数调用来修改任何东西的环境是容易的并且被批准.而且,如果您的Lua解释器删除了setfenv(以防止用户破坏沙箱),则用户代码无法在内部为自己的函数设置环境.因此,外部世界有一个沙箱,但内部世界在沙箱中 内没有沙箱.

Lua 5.2机制使得在函数创建后修改环境变得更加困难,但是它确实允许您在创建过程中设置环境.这样一来,您就可以在沙箱中使用沙箱了.<​​/p>

因此,您真正想要的只是重新排列代码,如下所示:

local foo;

do
  local _ENV = { print = print }

  function foo()
    print('env', _ENV)
    bar = 1
  end
end

foo现在已沙箱化.而现在,某人打破沙箱变得更加困难.

您可以想象,这在Lua开发人员中引起了一些争执.

How can I recreate the functionality of setfenv in Lua 5.2? I'm having some trouble understanding exactly how you are supposed to use the new _ENV environment variable.

In Lua 5.1 you can use setfenv to sandbox any function quite easily.

--# Lua 5.1

print('_G', _G)             -- address of _G

local foo = function()  
    print('env', _G)        -- address of sandbox _G
    bar = 1
end

-- create a simple sandbox
local env = { print = print }
env._G = env

-- set the environment and call the function
setfenv(foo, env)
foo()

-- we should have global in our environment table but not in _G
print(bar, env.bar)

Running this example shows an output:

_G    table: 0x62d6b0
env   table: 0x635d00
nil   1



I would like to recreate this simple example in Lua 5.2. Below is my attempt, but it does not work like the above example.

--# Lua 5.2

local function setfenv(f, env)
    local _ENV = env or {}       -- create the _ENV upvalue
    return function(...)
        print('upvalue', _ENV)   -- address of _ENV upvalue
        return f(...)
    end
end

local foo = function()
    print('_ENV', _ENV)          -- address of function _ENV
    bar = 1
end

-- create a simple sandbox
local env = { print = print }
env._G = env

-- set the environment and call the function
foo_env = setfenv(foo, env)
foo_env()

-- we should have global in our envoirnment table but not in _G
print(bar, env.bar)

Running this example shows the output:

upvalue    table: 0x637e90
_ENV       table: 0x6305f0
1          nil



I am aware of several other questions on this subject, but they mostly seem to be dealing with loading dynamic code (files or string) which work quite well using the new load function provided in Lua 5.2. Here I am specifically asking for a solution to run arbitrary functions in a sandbox. I would like to do this without using the debug library. According to the Lua documentation we should not have to rely on it.

解决方案

You cannot change the environment of a function without using the debug library from Lua in Lua 5.2. Once a function has been created, that is the environment it has. The only way to modify this environment is by modifying its first upvalue, which requires the debug library.

The general idea with environments in Lua 5.2 is that the environment should be considered immutable outside of trickery (ie: the debug library). You create a function in an environment; once created there, that's the environment it has. Forever.

This is how environments were often used in Lua 5.1, but it was easy and sanctioned to modify the environment of anything with a casual function call. And if your Lua interpreter removed setfenv (to prevent users from breaking the sandbox), then the user code can't set the environment for their own functions internally. So the outside world gets a sandbox, but the inside world can't have a sandbox within the sandbox.

The Lua 5.2 mechanism makes it harder to modify the environment post function-creation, but it does allow you to set the environment during creation. Which lets you sandbox inside the sandbox.

So what you really want is to just rearrange your code like this:

local foo;

do
  local _ENV = { print = print }

  function foo()
    print('env', _ENV)
    bar = 1
  end
end

foo is now sandboxed. And now, it's much harder for someone to break the sandbox.

As you can imagine, this has caused some contention among Lua developers.

这篇关于在Lua 5.2中重新创建setfenv()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆