2012-07-01 12 views
5

Estoy aprendiendo de "Programming in Lua" de Roberto Ierusalimschy, y encontré que en el libro, el ejemplo de Sandboxing usa la función setfenv() para cambiar el entorno de una función dada, pero en lua 5.2 esto la función ya no está disponible.Sandboxing en Lua 5.2

Intenté cargar algunos valores de un archivo (un archivo de configuración) en un campo de una tabla, pero en lua 5.2 no puedo usar setfenv (para poder cargar los valores en el entorno dado). Después de leer algunos artículos sobre Lua 5.2 me encontré con que cada función puede tener (o no) upvalue llamada _ENV que sirve como el medio ambiente, por lo que, probé el siguiente código:

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 

Sustitución _ENV en la 'caja de arena' la función funciona bien (no puede acceder a los campos regulares), pero cuando se ejecuta el 'código' parece que ignora que reemplacé _ENV, todavía puede acceder a los campos normales (imprimir, cargar archivo, dofile, etc.).

Leyendo un poco más, encontré que lua 5.2 proporciona una función para este propósito, esta función es loadin(env, chunk), que ejecuta el fragmento dado en el entorno dado, pero cuando intento agregar esta función a mi código, la función no existe (no está presente en el campo global _G).

Alguna ayuda será apreciada.

Respuesta

7

Cuando se asigna a _ENV desde dentro sandbox, usted no es sobrescribir el medio ambiente mundial - usted está reemplazando el _ENV upvalue del código se está ejecutando actualmente. Agregar llamadas al print(_ENV) puede ayudarlo a comprender mejor las identidades de las tablas involucradas.

Por ejemplo:

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 

La función loadin estaba presente en algunas versiones preliminares de Lua 5,2 pero se retiró antes de la liberación final. En cambio, el Lua 5.2 load and loadfile functions toma un argumento env. También puede modificar el _ENV de otra función usando debug.setupvalue.

+1

Gracias! La solución fue fácil. Creo que este enfoque para cambiar el entorno en 'load' y' loadfile' es mejor, porque 'setfenv' se usó principalmente en código cargado así que ... ¡Gracias! Me sandboxed como se esperaba. –

+0

@Miles Cuando se define print_env(), ¿no recibe el _ENV global como un valor ascendente? Entonces, ¿cómo se cambia cuando print_env() se llama dentro de sandbox()? –

+1

@TiagoCosta upvalues ​​son variables locales externas. '_ENV' en este caso es local al fragmento; la asignación a '_ENV' afecta a esa variable local de fragmento, que es un valor de actualización compartido para ambos cierres. – Miles