7

少なくとも2つのluaスクリプトファイルがあるとしましょう。

test1.lua test2.lua

どちらも、init関数と同様の名前の他の関数を定義します。

同じ関数名が衝突しないように、c ++ / cを使用して各スクリプトファイルを別の環境にロードするにはどうすればよいですか?5.1のサンプルコードが見つかりましたが、これは機能しません(setenvがなくなり、lua_setuservalueが機能しないため)動作するようです)

ここでのサンプル.luaのハンドルを使用してlua関数を呼び出しますか?

基本的に、setenvをsetuservalueに置き換えると、アクセス違反が発生します。

4

2 に答える 2

8

非公式のLuaFAQには、Luaでのサンドボックス化に関するエントリがあります。私の推測では、そのロジックをC /C++コードに簡単に置き換えることができます。

lua-userswikiのLuaFiveToも参照してください。

修正

見た目ほど簡単ではありません。しかし、結局のところ、要点は単純です。チャンクをロードし、_ENVテーブルをプッシュし、を使用しますlua_setupvalue(L,-2,1)。重要なのは、テーブルがスタックの一番上にある必要があるということです。

小さな例として、メタテーブルを介してデータを読み取るためにデフォルトで_Gに設定されている2つの環境を使用します。

#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;
}

そして、2つのLuaファイルの場合:

-- 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()
于 2012-06-13T12:31:23.500 に答える
0

どちらも、init関数と同様の名前の他の関数を定義します。

まず第一に、なぜそれらの関数はグローバルなのですか?それらはスクリプトに対してローカルである必要があります。require他のファイルでそれらにアクセスする場合は、公開したい関数を含むテーブルを作成して返す必要があります。

これらのファイルを要求するときの現代のイディオムは、次のようなことを行うことです。

local Library = require 'library'

Library.Func1(...)

したがって、グローバルLua名前空間を汚染することはありません。ローカル変数を使用します。

ただし、このようなグローバルの使用を主張する場合は、ドキュメントに記載されているとおりに実行できます。コンパイルされたチャンクの最初のアップバリューを変更します。

基本的に、setenvをsetuservalueに置き換えると、アクセス違反が発生します。

もちろんそうです。それは何をするかlua_setuservalue ではありません。userdataに関連付けられた値を設定するためのものです。あなたが欲しいものは適切に呼ばれlua_setupvalueます。

引用したサンプルコードを使用すると、正解は次のようになります。

lua_setupvalue(L, -2, 1);
于 2012-06-13T14:31:58.380 に答える