Sandboxing Embedded Lua in 5.2 / Set Envirenment f

2020-07-09 09:42发布

Lets say i have at least two lua script files.

test1.lua test2.lua

both define an init function and other functions with similar names.

How can i load each script file using c++/c into a separate environment using Lua 5.2 so that the same function names will not clash - i found a sample code for 5.1 which does not work for me (because setenv is gone and lua_setuservalue does not seem to work)

Sample here Calling lua functions from .lua's using handles?

Basically if i replace setenv with setuservalue - i get an access violation.

标签: lua
2条回答
家丑人穷心不美
2楼-- · 2020-07-09 10:11

both define an init function and other functions with similar names.

First of all, why are those functions global? They should be local to the script. If you're going to require them in other files, they should create and return a table containing the functions that they wish to expose.

The modern idiom when requiring these files is to do something like this:

local Library = require 'library'

Library.Func1(...)

Thus, you do not pollute the global Lua namespace. You use local variables.

However, if you insist on using globals like this, you can do exactly what the documentation said: change the first upvalue of the compiled chunk.

Basically if i replace setenv with setuservalue - i get an access violation.

Of course you do. That's not what lua_setuservalue does. It's for setting values associated with userdata. What you want is appropriately called lua_setupvalue.

Using the sample code you cite, the correct answer would be:

lua_setupvalue(L, -2, 1);
查看更多
叛逆
3楼-- · 2020-07-09 10:15

The unofficial Lua FAQ has an entry about sandboxing in Lua. My guess is that you can transpose that logic easily enough to your C/C++ code.

See also LuaFiveTo on the lua-users wiki.

Correction

It's indeed not as trivial as it seemed. But in the end the point is simple: load your chunk, push the _ENV table, use lua_setupvalue(L,-2,1). The important is that the table should be at the top of the stack.

As a small example, using 2 environments defaulting to _G for reading stuff via metatables:

#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>

int main(void){
        lua_State *L = luaL_newstate();
        char *file1 = "file1.lua";
        char *file2 = "file2.lua";

        luaL_openlibs(L);

        luaL_loadfile(L,file2); // S: 1
        luaL_loadfile(L,file1); // S: 2
        lua_newtable(L); // ENV for file 1: S: 321
        lua_newtable(L); // ENV for file 2: S: 4321

        //lets have each function have its metatable, where missed lookups are
        //instead looked up in the global table _G

        lua_newtable(L); // metatable S: 54321
        lua_getglobal(L,"_G"); // pushes _G, which will be the __index metatable entry S: 654321

        lua_setfield(L,-2,"__index"); // metatable on top S: 54321
        lua_pushvalue(L,-1); // copy the metatable S: 554321
        lua_setmetatable(L,-3); // set the last copy for env2 S: 54321
        lua_setmetatable(L,-3); // set the original for env1  S: 4321
        // here we end up having 2 tables on the stack for 2 environments
        lua_setupvalue(L,1,1); // first upvalue == _ENV so set it. S: 321
        lua_setupvalue(L,2,1); // set _ENV for file S: 21
        // Remaining on the stack: 2 chunks with env set.
        lua_pcall(L,0,LUA_MULTRET,0);
        lua_pcall(L,0,LUA_MULTRET,0);
        lua_close(L);
        return 0;
}

And for the 2 Lua files:

-- file1.lua
function init()
        A="foo"
        print("Hello from file1")
        print(A)
end
init()

-- file2.lua
-- this shows that stuff defined in file1 will not polute the environment for file2
print("init function is",tostring(init))
function init()
        A="bar"
        print("Hello from file2")
        print(A)
end
init()
查看更多
登录 后发表回答