2012-07-01 16 views
5

Uczę się z "Programowania w Lua" przez Roberto Ierusalimschy, i odkryłem, że w książce przykład Sandboxing wykorzystuje funkcję setfenv() do zmiany środowiska danej funkcji, ale w lua 5.2 to funkcja nie jest już dostępna.Piaskownica w Lua 5.2

Próbowałem załadować niektóre wartości z pliku (pliku konfiguracyjnego) do pola w tabeli, ale w lua 5.2 nie mogę użyć setfenv (aby móc wczytać wartości w danym środowisku). Po przeczytaniu kilku artykułów na temat Lua 5,2 Okazało się, że każda funkcja może mieć (lub nie) jest upvalue nazwie _ENV który służy jako środowisko, tak, próbowałem następujący kod:

function sandbox(sb_func, sb_env) 
    if not sb_func then return nil, "sandbox function not valid" end 
    sb_orig_env = _ENV 
    _ENV = sb_env -- yes, replaces the global _ENV 
    pcall_res, message = pcall(sb_func) 
    local modified_env = _ENV -- gets the environment that was used in the pcall(sb_func) 
    _ENV = sb_orig_env 
    return true, modified_env 
end 

function readFile(filename) 
    code = loadfile(filename) 
    res, table = sandbox(code, {}) 
    if res then 
     --[[ Use table (modified_env) ]]-- 
    else 
     print("Code not valid") 
end 

Wymiana _ENV w „piaskownicy” funkcja działa dobrze (nie może uzyskać dostępu do zwykłych pól), ale gdy "kod" zostanie wykonany wydaje się, że ignoruje to, że zastąpiłem _ENV, nadal może uzyskać dostęp do zwykłych pól (print, loadfile, dofile itp.).

Czytając nieco więcej, stwierdziłem, że lua 5.2 udostępnia funkcję do tego celu, ta funkcja to loadin(env, chunk), która uruchamia dany fragment w danym środowisku, ale gdy próbuję dodać tę funkcję do mojego kodu, funkcja nie istnieje (nie występuje w globalnym polu _G).

Pewna pomoc zostanie doceniona.

Odpowiedz

7

Po przypisaniu do _ENV od wewnątrz sandbox, nie jesteś nadpisywania globalnym środowisku - you're zastępując _ENV upvalue kodu aktualnie uruchomione. Dodanie połączeń pod numer print(_ENV) może pomóc w lepszym zrozumieniu tożsamości powiązanych tabel.

Na przykład

function print_env() 
    print(_ENV) 
end 

function sandbox() 
    print(_ENV) -- prints: "table: 0x100100610" 
    -- need to keep access to a few globals: 
    _ENV = { print = print, print_env = print_env, debug = debug, load = load } 
    print(_ENV) -- prints: "table: 0x100105140" 
    print_env() -- prints: "table: 0x100105140" 
    local code1 = load('print(_ENV)') 
    code1()  -- prints: "table: 0x100100610" 
    debug.setupvalue(code1, 1, _ENV) -- set our modified env 
    code1()  -- prints: "table: 0x100105140" 
    local code2 = load('print(_ENV)', nil, nil, _ENV) -- pass 'env' arg 
    code2()  -- prints: "table: 0x100105140" 
end 

Funkcja loadin był obecny w niektórych wersjach PRZEDPREMIEROWYCH lua 5.2, usuwa się przed ostatnim wydaniu. Zamiast tego Lua 5.2 load and loadfile functions przyjmuje argument env. Można również zmodyfikować _ENV innej funkcji za pomocą debug.setupvalue.

+1

Dzięki! Rozwiązanie było łatwe. Myślę, że to podejście do zmiany środowiska w 'load' i' loadfile' jest lepsze, ponieważ 'setfenv' był używany głównie w załadowanym kodzie, więc ... Dziękuję! Piaskowałem zgodnie z oczekiwaniami. –

+0

@Miles Kiedy zdefiniowano print_env(), czy nie otrzymuje globalnego _ENV jako upvue? Jak to się zmienia, gdy wywoływana jest funkcja print_env() wewnątrz piaskownicy()? –

+1

@TiagoCosta upvalues ​​są zewnętrznymi zmiennymi lokalnymi. "_ENV" w tym przypadku jest lokalne dla porcji; przypisanie do '_ENV' wpływa na tę zmienną lokalną porcji, która jest wspólną uprawą dla obu zamknięć. – Miles