While researching Ruby's new-in-1.9 Object methods untrusted?, untrust, and trust, I discovered something I did not know about the $SAFE variable: in addition to being Thread-local, it is also Proc-local. Proc objects (both procs and lambdas) have their own copy of $SAFE, and they run at whatever $SAFE level was in effect when the Proc was created not the safe level that is in effect when they are invoked. This was discussed three years ago over at _why's old blog.
There is a corollary, however that was demonstrated but not discussed in a recent ruby-core post by Shugo Maeda: if you set $SAFE inside a proc or a lambda, that setting is local, and does not change the global safe level. Googling for "safe_eval" implementations shows that everyone uses Thread.new to create a sandbox with a locally elevated safe level. It turns out, however, that an ordinary lambda will also work. (One can argue, however, that a thread gives extra safety because it can be monitored and killed to guard against runaway code that doesn't terminate.)
In any case, here is the method I defined to try this out. Pass it a safe level (it defaults to 4) and a block of code, and it will execute the block at that level without altering the global safe level and without creating a new thread:
# Execute a block at the specified safe level. Tested with Ruby 1.9 and 1.8.7
def safely(level = 4)
sandbox = lambda do # Set up a sandbox
$SAFE = level # Go to the specified safe level for this lambda only
yield # Invoke the block at that level
end
sandbox.call # Invoke the sandbox without changing $SAFE globally
end
# Use this method like this.
x = safely { eval('"untrusted code"') }
[x, x.tainted?, x.untrusted?] # => ["untrusted code", true, true]
I'm not convinced that this method is actually useful in practice, but I thought it was interesting, and it reminds me again how cool it is to be able to define methods that accept blocks and act like control statements.




Hi David,
really interested in seeing the code for this old post if possible please : http://www.davidflanagan.com/2005/08/canvas-tag-in-java-and-xbl.html
I'm investigating renderering canvas tags on the serverside to images.
cheers
Colin