Eval statement

Christopher Dicely <cmdicely@gmail.com> writes:

···

On 2/6/09, Pascal J. Bourguignon <pjb@informatimago.com> wrote:

badboy <badboy@heartofgold.co.cc> writes:

Jonathan Wills schrieb:
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.

Ok. In CL we say EVAL is evil because it cannot do some things, and in
Ruby you say it's evil because it can. How interesting...

Of couse, when you execute dynamic code, you must trust the source of
that code. This doesn't "evilize" the mechanism to execute it.

--
__Pascal Bourguignon__

Christopher Dicely wrote:

can run ruby code. Basically I want the user to be able to supply an
unspecified number of ruby files, all of which will get run, and not
have to worry about namespace collisions. Additionally I want access to
the scopes that those files were executed in after they are done. I
know I can create a binding from my current scope, but if I put anything
in it, it can get modified when I do my_binding.eval.

You can get a binding from any object that has a method to tell you
its binding. Something like this (off the top of my head) might work:
---
class ExecutionContext
  private_class_method :new

  @@contexts = {}

  def self.(key)
    @@contexts[key]
  end

  def self.new_binding(key)
    new(key).binding
  end

  def initialize(key)
    raise KeyError if @@contexts[key]
    @@contexts[key] = self
  end

  def get_binding
    binding
  end
end
---

So, when you want a new binding to use, you call
ExecutionContext.new_binding(key), and to get back the a binding used
previously, you call ExecutionContext[key].get_binding, where "key" is
the key given when you called new_binding to generate the binding.

But while these are mostly "fresh" bindings, they are nothing at all
like safe sandboxes. You may need something like this:
http://github.com/why/sandbox/tree/master

Interesting. Someone else has shown me a similar way of getting a fresh
context. Do you know what exactly about it is unlike a sandbox?

The code being eval'd can, as I understand, do anything that a method
on the object providing the binding could do, including, e.g., using
ObjectSpace to mess with any object in the current interpreter
instance, even if it is out of scope of the binding.

Are there any plans for ruby to support a sandboxed eval like I can get
in python?

I think the use of the trusted/untrusted distinction with $SAFE levels
in Ruby 1.9 may be able to do some, perhaps all, of what you want, but
I haven't done any work with it (just read the description in the Beta
of the new edition of Programming Ruby), so I can't really say. It's
not an eval-specific sandbox, though.

···

On Fri, Feb 6, 2009 at 1:46 PM, Jonathan Wills <runningwild@gmail.com> wrote:

On Fri, Feb 6, 2009 at 11:55 AM, Jonathan Wills <runningwild@gmail.com> >> wrote:

Hi --

Mike Gold wrote:
If all assignments were the same, this would print '3':

  eval("a = 3", binding)
  puts a

Or even better,

eval("a = 3", binding)
p local_variables #=> ["a"]
p a #=> undefined local variable or method `a'

We see that the local exists, but because the parser has not seen the "a
= ..." syntax, we can't access it.

In 1.9 you get:


-:3:in `<main>': undefined local variable or method `a' for
main:Object (NameError)

so I guess that's been changed. The point about rb_method_missing (as
the source of that error message) is interesting, though since it's be
handled by a handler for non-existent methods, and within that handler
it determines that it also isn't a local variable, I think it's
reasonable to say that it can't tell -- or, perhaps more accurately,
it *can* tell that it is neither a (viable) method call nor a
variable, but it can't tell which you meant (hence the wording of the
error message).

There's also this interesting difference. In 1.8, given this code:

eval("a=3")
p a rescue p "undef"
eval("p a")

you get this output:

"undef"
3

whereas in 1.9 the output for the same code is:

"undef"
-:3:in `eval': undefined local variable or method `a'

So the business of having eval always return to the same scope seems
to have been done away with. (I always thought of it as similar to the
phenomenon of having to be drunk again to remember what you did when
drunk :slight_smile:

David

···

On Sat, 7 Feb 2009, Mike Gold wrote:

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2\)

http://www.wishsight.com => Independent, social wishlist management!

David A. Black wrote:

Hi --

Mike Gold wrote:
If all assignments were the same, this would print '3':

  eval("a = 3", binding)
  puts a

Or even better,

eval("a = 3", binding)
p local_variables #=> ["a"]
p a #=> undefined local variable or method `a'

We see that the local exists, but because the parser has not seen the "a
= ..." syntax, we can't access it.

In 1.9 you get:


-:3:in `<main>': undefined local variable or method `a' for
main:Object (NameError)

so I guess that's been changed. The point about rb_method_missing (as
the source of that error message) is interesting, though since it's be
handled by a handler for non-existent methods, and within that handler
it determines that it also isn't a local variable, I think it's
reasonable to say that it can't tell -- or, perhaps more accurately,
it *can* tell that it is neither a (viable) method call nor a
variable, but it can't tell which you meant (hence the wording of the
error message).

There's also this interesting difference. In 1.8, given this code:

eval("a=3")
p a rescue p "undef"
eval("p a")

you get this output:

"undef"
3

whereas in 1.9 the output for the same code is:

"undef"
-:3:in `eval': undefined local variable or method `a'

So the business of having eval always return to the same scope seems
to have been done away with. (I always thought of it as similar to the
phenomenon of having to be drunk again to remember what you did when
drunk :slight_smile:

That's known as "state dependent learning" (but maybe you already know that!) - an interesting phenomenon, for sure. ~t.

···

On Sat, 7 Feb 2009, Mike Gold wrote:

David

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website) << sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

David A. Black:

> p local_variables #=> ["a"]
> p a #=> undefined local variable or method `a'
>
> We see that the local exists, but because the parser has not seen
> the "a = ..." syntax, we can't access it.

In 1.9 you get:


-:3:in `<main>': undefined local variable or method `a' for
main:Object (NameError)

so I guess that's been changed.

Yes, in 1.9 the local table is inside the parser, and a new parser is
created for each eval. In 1.8 the local table is static (as well as
the parser).

The point about rb_method_missing (as the source of that error
message) is interesting, though since it's be handled by a handler
for non-existent methods, and within that handler it determines that
it also isn't a local variable, I think it's reasonable to say that
it can't tell -- or, perhaps more accurately, it *can* tell that it
is neither a (viable) method call nor a variable, but it can't tell
which you meant (hence the wording of the error message).

No, I don't see a handler which determines that it isn't a local
variable. That was already decided by the parser which created a
method-call node because no "a = 1" syntax was found. The possibility
of a local variable was long since gone.

  p local_variables #=> [:a]
  a = nil

Is Ruby prescient? No, it's just the parser that determines locals.

Take the 1.9 example again:

  eval("a = 3")
  p local_variables #=>
  p a #=> undefined local variable or method `a'

But

  eval("a = 3")
  p local_variables #=> [:a]
  a = a
  p a #=> 3

The parser looks for local assignment syntax and builds nodes
accordingly, then the interpreter runs.

There's also this interesting difference. In 1.8, given this code:

eval("a=3")
p a rescue p "undef"
eval("p a")

you get this output:

"undef"
3

whereas in 1.9 the output for the same code is:

"undef"
-:3:in `eval': undefined local variable or method `a'

So the business of having eval always return to the same scope seems
to have been done away with. (I always thought of it as similar to the
phenomenon of having to be drunk again to remember what you did when
drunk :slight_smile:

It's not really a scope issue; it's a parser issue. When we use the
same scope it fails in the same manner,

  eval("a=3", binding)
  p a rescue p "undef" #=> "undef"
  eval("p a", binding) #=> undefined local variable or method `a'

I don't know if there is an official terminology--I would say these
two calls to 'binding' refer to the same scope while technically being
different bindings.

Curiously, we can get the 1.8 behavior in 1.9 by using the same
binding,

  bind = binding
  eval("a=3", bind)
  p a rescue p "undef" #=> "undef"
  eval("p a", bind) #=> 3

···

--
Posted via http://www.ruby-forum.com/\.

Hi --

David A. Black:

The point about rb_method_missing (as the source of that error
message) is interesting, though since it's be handled by a handler
for non-existent methods, and within that handler it determines that
it also isn't a local variable, I think it's reasonable to say that
it can't tell -- or, perhaps more accurately, it *can* tell that it
is neither a (viable) method call nor a variable, but it can't tell
which you meant (hence the wording of the error message).

No, I don't see a handler which determines that it isn't a local
variable. That was already decided by the parser which created a
method-call node because no "a = 1" syntax was found. The possibility
of a local variable was long since gone.

p local_variables #=> [:a]
a = nil

Is Ruby prescient? No, it's just the parser that determines locals.

I'll stop trying to make that particular point, which is simpler than
I'm managing to make it. All I'm really saying is that, one way or
another, Ruby deems it appropriate to tell you that something that
could, syntactically, be a local variable or a method call is in fact
neither. To some extent I think that how it arrives at that conclusion
is an implementation detail (though I'm reading the stuff you're
saying about the implementation with great interest).

Take the 1.9 example again:

eval("a = 3")
p local_variables #=>
p a #=> undefined local variable or method `a'

But

eval("a = 3")
p local_variables #=> [:a]
a = a
p a #=> 3

The parser looks for local assignment syntax and builds nodes
accordingly, then the interpreter runs.

Somewhere along the line I got the impression you were saying that it
was by parsing the argument-string, prior to executing eval, that Ruby
figured out there was an 'a' local variable. Never mind. I think I'm
back on course.

There's also this interesting difference. In 1.8, given this code:

eval("a=3")
p a rescue p "undef"
eval("p a")

you get this output:

"undef"
3

whereas in 1.9 the output for the same code is:

"undef"
-:3:in `eval': undefined local variable or method `a'

So the business of having eval always return to the same scope seems
to have been done away with. (I always thought of it as similar to the
phenomenon of having to be drunk again to remember what you did when
drunk :slight_smile:

It's not really a scope issue; it's a parser issue. When we use the
same scope it fails in the same manner,

eval("a=3", binding)
p a rescue p "undef" #=> "undef"
eval("p a", binding) #=> undefined local variable or method `a'

I don't know if there is an official terminology--I would say these
two calls to 'binding' refer to the same scope while technically being
different bindings.

It's reminiscent of what happens in a block: whatever exists already,
by way of locals, is there, but anything created there does not
survive the exit. (Reminiscent, not technically connected.) It's also
a bit like the wrapper nature of things like method or float objects,
where (for example) adding a singleton method to 1.2 doesn't do any
good the next time you write 1.2.

Curiously, we can get the 1.8 behavior in 1.9 by using the same
binding,

bind = binding
eval("a=3", bind)
p a rescue p "undef" #=> "undef"
eval("p a", bind) #=> 3

That's also similar to other wrapper behavior (like saving a
particular float in a variable). It does seem like binding should be a
proxy more than a wrapper, if that makes sense.

David

···

On Sun, 8 Feb 2009, Mike Gold wrote:

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2\)

http://www.wishsight.com => Independent, social wishlist management!