2012-03-28 17 views
7

Cuando un método es llamado por un hilo con $ SAFE = 4, ese método se ejecuta con el nivel seguro mismos $:

def test_method 
    raise "value of $SAFE inside the method: #{$SAFE}" 
end 
t = Thread.new{$SAFE = 4; self.test_method}; t.join 
=> RuntimeError: value of $SAFE inside the method: 4 

Sin embargo, cuando un bloque se llama, parece que el uso de los $ SAFE de su contexto original en su lugar:

test_lambda = lambda do 
    raise "value of $SAFE inside the lambda: #{$SAFE}" 
end 
t = Thread.new{$SAFE = 4; test_lambda.call}; t.join 
=> RuntimeError: value of $SAFE inside the lambda: 0 

¿Alguien puede explicar por qué funciona de esta manera? Parece un problema de seguridad.

(la razón por la que estoy usando en lugar de raiseputs es que puts no funciona en $ SAFE = 4)

Esto puede ser usado para eval una cadena contaminada en un contexto aparentemente seguro:

test_lambda = lambda{|s| puts "Tainted: #{s.tainted?}"; eval s} 
t = Thread.new{$SAFE = 4; test_lambda.call("puts `date`")}; t.join 
=> Tainted: true 
=> Fri Mar 30 03:15:33 UTC 2012 
+0

¿No capturaría un cierre el valor en el momento de la definición? –

+1

¿Puede ejecutar acciones dentro del bloque que un nivel '$ SAFE' permitiría? –

+1

Andrew: sí. Reemplazar el contenido de la lambda con algo como 'puts \' hostname \ '' hace que haga exactamente eso dentro del hilo $ SAFE = 4. Entiendo este comportamiento desde una perspectiva de alcance (un poco) - Me pregunto si $ SAFE está completamente roto en este sentido. – rcrogers

Respuesta

5

es porque una lambda opera con el alcance que se definió en (incluyendo todas las variables locales!)

por lo tanto, se ha definido la lambda en el nivel de seguridad 0, y por lo tanto, ejecutado en ese nivel cuando fue llamado, ya que ese era el estado de la variable.

Cuestiones relacionadas