On 2/6/09, Pascal J. Bourguignon <pjb / informatimago.com> wrote:
> badboy <badboy / heartofgold.co.cc> writes:
>
>> Jonathan Wills schrieb:
>>> Trying to switch a project of mine from python to ruby.  Love ruby so
>>> far, but I'm finding that the eval statement is a bit more difficult to
>>> use than python's exec statement.  Here is one of the problems I'm
>>> having, RUBY_VERSION=1.9.1
>>>
>>> a = 1
>>> eval('a=2')
>>> puts a
>>>
>>> This will print out '2', as I want.  However if I remove the first line,
>>>
>>> eval('a=2')
>>> puts a
>>>
>>> r.rb:2:in `<main>': undefined local variable or method `a' for
>>> main:Object (NameError)
>>>
>>>
>>> Now if in the first case eval can change a variable in its scope, why
>>> can't it also create a variable in that same scope?  I may also not be
>>> totally clear on the way ruby handles scoping, which might be part of
>>> what I am having trouble understanding.
>>>
>>> Any help understanding the eval statement would be appreciated.  I will
>>> probably have more questions about it, but I'll leave at this for now.
>>>
>>> thanks,
>>> -Jonathan
>> why do you want to use eval?
>> eval is evil and in most cases not needed in Ruby
>
> Why are you saying that eval is evil?
>
> In know that in Common Lisp, EVAL has properties that make its use
> dubious in most cases.  Mostly it's because it works in the global
> environment.
>
> But this is not the case of eval in Ruby. Since there's no compiler,
> they can execute eval in the local lexical environment.  So is there
> remaining any evilness I don't know?

Without taking additional special care, restricting eval to the to a
particular binding doesn't contain it very much. eval can, unless
something is done to stop it, get access to every Object in the top
level environment.

For example try running this in irb:

hash = Hash.new
object = Object.new
def object.get_binding
  binding
end
b = object.get_binding
eval('ObjectSpace.each_object {|o| next if o.frozen?; begin def
o.inspect; "pwned";  end; rescue TypeError; end}',a)
hash #=>pwned

If you run untrusted code in eval without being extra careful, it can
reach out of the binding its in and stomp over other objects, even
outside of that binding.