2012-03-02 6 views
8

Jak mogę załadować plik tabel i zmiennych Lua bez zanieczyszczania środowiska globalnego? Od robienia pliku load i uruchamiania go ładuję wszystko w przestrzeni globalnej i mogę nadpisać coś innego, czego nie chcę.Plik ładowania bez zanieczyszczania środowiska globalnego

+0

Czy używasz lua 5.2 lub 5.1? – kikito

+1

Znaleziono go: 'x = loadFile ("myfile.lua")' 'setfenv (x ENV)' ' x() - wszystkie globalne dostępy pójdzie ENV a następnie _G' – Milind

+0

Dokładnie. Wyglądasz na 5.1. Powinieneś odpowiedzieć sobie i zaznaczyć swoją odpowiedź jako poprawną, więc nie wydaje się "bez odpowiedzi", ale nie masz za to przedstawiciela. :/ – kikito

Odpowiedz

10

w Lua 5.1 i bez większego błędu obsługi można to zrobić:

-- 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 

Pierwsza linia tworzy pustą tablicę środowiska, które można zobaczyć wszystkie istniejące globalnych, ale których nie można trywialnie zmienić je, ponieważ są one widoczne tylko przez proxy za pośrednictwem metametodu __index. Wszystkie globale utworzone przez skrypt zostaną zapisane w postaci env, która zostanie zwrócona. To zadziała dobrze w przypadku prostych skryptów, które po prostu ustawiają kilka parametrów konfiguracyjnych, i które mogą wymagać wywoływania prostych bezpiecznych funkcji, aby ustawić je na podstawie warunków w czasie wykonywania.

Należy pamiętać, że tworzenie globali widocznych w skrypcie jest wygodą. Mimo że globalnych nie można w sposób oczywisty zmodyfikować ze skryptu, _G jest zmienną globalną zawierającą odniesienie do środowiska globalnego (zawierającą _G._G, _G._G._G, itp.) I _G można zmodyfikować ze skryptu, który może prowadzić do dalsze problemy.

Dlatego zamiast używać indeksu, należy znacznie lepiej skonstruować tabelę zawierającą tylko funkcje znane jako bezpieczne i znane autorowi skryptu.

Kompletnym rozwiązaniem byłoby uruchomienie skryptu w piaskownicy i ewentualnie dalsze zabezpieczenie przed przypadkową (lub celową) odmową usługi lub gorzej. Sandboxes są omówione bardziej szczegółowo na Wiki użytkownika Lua. Temat jest głębszy, niż się wydaje na pierwszy rzut oka, ale dopóki twoi użytkownicy są zaufani, aby nie byli złośliwi, praktyczne rozwiązania są proste.

Lua 5.2 zmienia trochę rzeczy, eliminując setfenv() na korzyść nowego parametru do load(). Szczegóły znajdują się również na stronie wiki.

+2

Jednym ze sposobów obejścia modyfikacji '_G' jest ustawienie' _G' na coś innego w środowisku: 'local env = setmetatable ({_ G = false}, {__index = _G})' –

+0

W rzeczywistości zdałem sobie sprawę, że bardzo łatwo jest przerwać skrypt: '_G = nil; _G.print = nil'.Potrzebne by było coś takiego: 'local env = setmetatable ({}, {__index = funkcja (t, k), jeśli k == '_ G', a następnie zwraca zero, to zwraca _G [k] koniec})' –

+0

Jedna kluczowa idea wyrażone na stronie wiki, której nie poruszałem w mojej odpowiedzi, to użycie białej listy funkcji, które są starannie wybrane jako bezpieczne i potrzebne * raczej * niż dopuszczenie _G lub innej globalnie znanej tabeli modułów do wycieku do środowiska skryptu. O wiele bezpieczniej jest umieścić 'string.find' w środowisku niż na przykład' string'. To powiedziawszy, odpowiedź, którą podałem, jest całkiem praktyczna w przypadku plików konfiguracyjnych małych niezabezpieczonych narzędzi. – RBerteig

2

Oto dofile() wersja RBerteig za odpowiedź gdzie dostarczyć środowiska oraz wynik, jeśli w ogóle, jest zwracana (próbowałem zrobić to jako komentarz, ale nie mogliśmy zorientować się, do formatu it):

local function DofileIntoEnv(filename, env) 
    setmetatable (env, { __index = _G }) 
    local status, result = assert(pcall(setfenv(assert(loadfile(filename)), env))) 
    setmetatable(env, nil) 
    return result 
end 

Chciałem móc załadować wiele plików do tego samego środowiska, a niektóre z tych plików miały "coś w sobie". Dzięki RBerteig, twoja odpowiedź była pomocna i pouczająca!

Powiązane problemy