2012-03-28 7 views
7

Wenn ein Verfahren durch ein Gewinde mit $ SAFE = 4, das Verfahren ausgeführt wird mit dem gleichen $ sicheren Niveau genannt:

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 

Wenn jedoch ein Block genannt wird, ist es den $ sicher zu verwenden scheint aus der ursprüngliche Kontext stattdessen:

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 

Kann jemand erklären, warum es so funktioniert? Es scheint ein Sicherheitsproblem zu sein.

(der Grund, warum ich raise statt puts bin ist, dass puts nicht bei $ SAFE funktioniert = 4)

Dies kann eine verdorbene Zeichenfolge eval in einem scheinbar sicheren Kontext verwendet werden:

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

Würde eine Schließung den Wert zum Zeitpunkt der Definition nicht erfassen? –

+1

Können Sie Aktionen innerhalb des Blocks ausführen, die ein '$ SAFE' Level von 0 erlauben würde? –

+1

Andrew: Ja. Ersetzen Sie den Inhalt des Lambda durch etwas wie 'puts \' hostname \ '' verursacht es genau das aus dem $ SAFE = 4 Thread. Ich verstehe dieses Verhalten aus einer Perspektive (irgendwie) - Ich frage mich nur, ob $ SAFE in dieser Hinsicht völlig gebrochen ist. – rcrogers

Antwort

5

es ist, weil ein Lambda mit dem Bereich arbeitet sie an (einschließlich aller lokalen Variablen!)

daher definiert wurde, können Sie das Lambda auf einem ungefährlichen Niveau definiert 0, und es deshalb auf dieser Ebene ausgeführt wird, wenn es hieß, denn das war der Zustand der Variable.