eval going boom

Discussion in 'Ruby' started by Giles Bowkett, Jun 21, 2007.

  1. Object X is going to be an exact clone of Object Y, but it's a member
    of a different class.

    This does not work:

    x.attributes.each {|attr, value| eval("y.#{attr}= #{value}")}

    irb says:

    (eval):1: warning: parenthesize argument(s) for future version
    SyntaxError: (eval):1:in `irb_binding': compile error
    (eval):1: parse error, unexpected tINTEGER, expecting $
    wv.updated_at= Mon May 07 11:13:27 -0700 2007

    The second two lines make perfect sense to me; the first two seem pretty weird.

    I suppose I should just create an AbstractZ class, from which both Y
    and X inherit.

    --
    Giles Bowkett

    Blog: http://gilesbowkett.blogspot.com
    Portfolio: http://www.gilesgoatboy.org
     
    Giles Bowkett, Jun 21, 2007
    #1
    1. Advertising

  2. The problem, basically, is that the attributes come back from
    #inspect. So a Date becomes a String (in the example of the error
    reported in my previous mail).

    This works perfectly:

    x.attributes.each {|attr, value| eval("y.#{attr}= x.#{attr}")}

    w00t w00t
    00ntz 00ntz 00ntz

    --
    Giles Bowkett

    Blog: http://gilesbowkett.blogspot.com
    Portfolio: http://www.gilesgoatboy.org
     
    Giles Bowkett, Jun 21, 2007
    #2
    1. Advertising

  3. Hi,

    Am Donnerstag, 21. Jun 2007, 09:19:47 +0900 schrieb Giles Bowkett:
    > This does not work:
    >
    > x.attributes.each {|attr, value| eval("y.#{attr}= #{value}")}


    Maybe #{value.inspect} is better or even

    y.send "{#attr}=", value

    Untested.

    Bertram


    --
    Bertram Scharpf
    Stuttgart, Deutschland/Germany
    http://www.bertram-scharpf.de
     
    Bertram Scharpf, Jun 21, 2007
    #3
  4. Giles Bowkett

    Ryan Davis Guest

    On Jun 20, 2007, at 17:19 , Giles Bowkett wrote:

    > Object X is going to be an exact clone of Object Y, but it's a member
    > of a different class.
    >
    > This does not work:
    >
    > x.attributes.each {|attr, value| eval("y.#{attr}= #{value}")}


    >> p x.class

    => CommandsIShouldNeverEval
    >> p x.attributes

    => { :z => "`rm -rf /`" }
    >> x.attributes.each {|attr, value| eval("y.#{attr}= #{value}")}

    ...

    Don't use eval. There is no need in this example.

    CHALLENGE: rewrite the above code to not use eval at all. For that
    matter, don't even use #send.
     
    Ryan Davis, Jun 22, 2007
    #4
  5. > Don't use eval. There is no need in this example.

    Why's everyone so scared of eval? Yes it can destroy your system
    completely and forever, but life's short. Might as well enjoy it.
    Drive without your seat belt. Go to wild parties. Use eval().

    Nobody on their deathbed will ever say "I wish I'd never used eval()."

    > CHALLENGE: rewrite the above code to not use eval at all. For that
    > matter, don't even use #send.


    Aargh! Must rise to challenge!

    I tried with write_attribute and failed. I can do it with
    instance_eval but that's just a loophole.

    On my blog Marcel Molina Jr. pointed out you can use

    x.attributes = y.attributes

    That's almost an answer to the challenge, but Pat Maddox pointed out
    it won't cover protected attributes.

    (e.g., attr_protected :some_attribute)

    Pat also wrote up the send version. Haven't tested it but it looks solid.

    (http://gilesbowkett.blogspot.com/2007/06/clone-activerecord-models.html)

    Anyway, so far, this challenge has kicked my butt. But I'm not giving up yet!

    --
    Giles Bowkett

    Blog: http://gilesbowkett.blogspot.com
    Portfolio: http://www.gilesgoatboy.org
     
    Giles Bowkett, Jun 22, 2007
    #5
  6. Giles Bowkett, Jun 22, 2007
    #6
  7. > > CHALLENGE: rewrite the above code to not use eval at all. For that
    > > matter, don't even use #send.

    >
    > original_obj.attributes.each{|attr, value|
    > new_obj.update_attribute(attr.to_sym, value)}


    prettier:

    original_obj.attributes.each do |attr, value|
    new_obj.update_attribute(attr.to_sym, value)
    end

    --
    Giles Bowkett

    Blog: http://gilesbowkett.blogspot.com
    Portfolio: http://www.gilesgoatboy.org
     
    Giles Bowkett, Jun 22, 2007
    #7
  8. Giles Bowkett

    Xavier Noria Guest

    On Jun 22, 2007, at 10:30 PM, Giles Bowkett wrote:

    >> > CHALLENGE: rewrite the above code to not use eval at all. For that
    >> > matter, don't even use #send.

    >>
    >> original_obj.attributes.each{|attr, value|
    >> new_obj.update_attribute(attr.to_sym, value)}

    >
    > prettier:
    >
    > original_obj.attributes.each do |attr, value|
    > new_obj.update_attribute(attr.to_sym, value)
    > end


    You don't even need #to_sym :). Note that rewrite has the side-
    effect of actually saving those attributes of new_object in the
    database, whereas the original assignments didn't. Perhaps that's OK
    though.

    -- fxn
     
    Xavier Noria, Jun 22, 2007
    #8
  9. > > original_obj.attributes.each do |attr, value|
    > > new_obj.update_attribute(attr.to_sym, value)
    > > end

    >
    > You don't even need #to_sym :). Note that rewrite has the side-
    > effect of actually saving those attributes of new_object in the
    > database, whereas the original assignments didn't. Perhaps that's OK
    > though.


    Well, if you've got validation callbacks (e.g.
    validates_uniqueness_of) this version could blow up on that. That's
    assuming you're copying objects of the same class as one another - I
    originally came up with this to copy things of different classes
    (near-identical subclasses of an as-yet-unconstructed abstract
    superclass).

    Also - I didn't realize these methods came from ActiveSupport. Doh.
    The original ran in pure Ruby without Rails - it'd probably be ideal
    to implement the solution in pure Ruby.

    --
    Giles Bowkett

    Blog: http://gilesbowkett.blogspot.com
    Portfolio: http://www.gilesgoatboy.org
     
    Giles Bowkett, Jun 22, 2007
    #9
  10. Giles Bowkett

    Xavier Noria Guest

    On Jun 23, 2007, at 12:06 AM, Giles Bowkett wrote:

    >> > original_obj.attributes.each do |attr, value|
    >> > new_obj.update_attribute(attr.to_sym, value)
    >> > end

    >>
    >> You don't even need #to_sym :). Note that rewrite has the side-
    >> effect of actually saving those attributes of new_object in the
    >> database, whereas the original assignments didn't. Perhaps that's OK
    >> though.

    >
    > Well, if you've got validation callbacks (e.g.
    > validates_uniqueness_of) this version could blow up on that.


    Not really, update_attribute() bypasses validations by default, it's
    written like this:

    send(name.to_s + '=', value)
    save(false)

    > Also - I didn't realize these methods came from ActiveSupport. Doh.
    > The original ran in pure Ruby without Rails - it'd probably be ideal
    > to implement the solution in pure Ruby.


    Yeah, except for the call to attributes(), which is a Railism. In
    fact I thought this thread belonged to the Rails mailing list because
    of that.

    -- fxn
     
    Xavier Noria, Jun 23, 2007
    #10
  11. Giles Bowkett wrote:
    >> Don't use eval. There is no need in this example.

    >
    > Why's everyone so scared of eval? Yes it can destroy your system
    > completely and forever, but life's short. Might as well enjoy it.
    > Drive without your seat belt. Go to wild parties. Use eval().


    Do you tell that your customers too?

    Besides security issues:
    -eval is factors slower
    -eval is less concise (remember, you read code far more often than you
    write it)
    -eval is more annoying to debug

    I'm sure there are more reasons. You see, only "security issue" (which
    is *huge*, mind you), none of them is based on "fear".

    Regards
    Stefan

    --
    Posted via http://www.ruby-forum.com/.
     
    Stefan Rusterholz, Jun 23, 2007
    #11
  12. Giles Bowkett, Jun 23, 2007
    #12
  13. On 6/23/07, Stefan Rusterholz <> wrote:
    > Giles Bowkett wrote:
    > >> Don't use eval. There is no need in this example.

    > >
    > > Why's everyone so scared of eval? Yes it can destroy your system
    > > completely and forever, but life's short. Might as well enjoy it.
    > > Drive without your seat belt. Go to wild parties. Use eval().

    >
    > Do you tell that your customers too?


    Of course not. That's a rude, ridiculous question.

    > Besides security issues:
    > -eval is factors slower
    > -eval is less concise (remember, you read code far more often than you
    > write it)
    > -eval is more annoying to debug
    >
    > I'm sure there are more reasons. You see, only "security issue" (which
    > is *huge*, mind you), none of them is based on "fear".


    I wouldn't recommend eval() in production code, without bulletproof
    ways of keeping it clear of user input, but I find it a lot *more*
    concise and a lot *easier* to debug. Certainly the code examples in
    this thread which use eval are slimmer than the non-eval versions. (To
    my eyes, they're also clearer.) To each his own, I guess.

    --
    Giles Bowkett

    Blog: http://gilesbowkett.blogspot.com
    Portfolio: http://www.gilesgoatboy.org
     
    Giles Bowkett, Jun 23, 2007
    #13
  14. Giles Bowkett wrote:
    > On 6/23/07, Stefan Rusterholz <> wrote:
    >> Giles Bowkett wrote:
    >> >> Don't use eval. There is no need in this example.
    >> >
    >> > Why's everyone so scared of eval? Yes it can destroy your system
    >> > completely and forever, but life's short. Might as well enjoy it.
    >> > Drive without your seat belt. Go to wild parties. Use eval().

    >>
    >> Do you tell that your customers too?

    >
    > Of course not. That's a rude, ridiculous question.


    I don't think it was rude. Assuming your application is in some way
    responsible for sensitive data then creating a security hole with eval
    is incompetence at best and willful endangerment at worst. Explaining
    the reason of the loss of sensitive data to an affected customer without
    lying could be a bit difficult.
    Also, IANAL, but I think in my country you could (theoretically -
    practically it's probably a bit too difficult to prove) even be held
    responsible for sensitive data lost, compromised or stolen through such
    a security hole. So I'm quite serious about that.
    But my apologies if it offended you.

    > I wouldn't recommend eval() in production code, without bulletproof
    > ways of keeping it clear of user input, but I find it a lot *more*
    > concise and a lot *easier* to debug. Certainly the code examples in
    > this thread which use eval are slimmer than the non-eval versions. (To
    > my eyes, they're also clearer.) To each his own, I guess.


    Ok. Different opinions obviously, no issue with that :)

    Regards
    Stefan

    --
    Posted via http://www.ruby-forum.com/.
     
    Stefan Rusterholz, Jun 23, 2007
    #14
  15. On 6/23/07, Stefan Rusterholz <> wrote:
    > Giles Bowkett wrote:
    > > On 6/23/07, Stefan Rusterholz <> wrote:
    > >> Giles Bowkett wrote:
    > >> >> Don't use eval. There is no need in this example.
    > >> >
    > >> > Why's everyone so scared of eval? Yes it can destroy your system
    > >> > completely and forever, but life's short. Might as well enjoy it.
    > >> > Drive without your seat belt. Go to wild parties. Use eval().
    > >>
    > >> Do you tell that your customers too?

    > >
    > > Of course not. That's a rude, ridiculous question.

    >
    > I don't think it was rude. Assuming your application is in some way
    > responsible for sensitive data then creating a security hole with eval
    > is incompetence at best and willful endangerment at worst. Explaining
    > the reason of the loss of sensitive data to an affected customer without
    > lying could be a bit difficult.


    I thought Giles was joking...
     
    Gregory Brown, Jun 23, 2007
    #15
  16. > >> > Why's everyone so scared of eval? Yes it can destroy your system
    > >> > completely and forever, but life's short. Might as well enjoy it.
    > >> > Drive without your seat belt. Go to wild parties. Use eval().
    > >>
    > >> Do you tell that your customers too?

    > >
    > > Of course not. That's a rude, ridiculous question.

    >
    > I don't think it was rude. Assuming your application is in some way
    > responsible for sensitive data then creating a security hole with eval
    > is incompetence at best and willful endangerment at worst. Explaining
    > the reason of the loss of sensitive data to an affected customer without
    > lying could be a bit difficult.
    > Also, IANAL, but I think in my country you could (theoretically -
    > practically it's probably a bit too difficult to prove) even be held
    > responsible for sensitive data lost, compromised or stolen through such
    > a security hole. So I'm quite serious about that.
    > But my apologies if it offended you.


    My bad, I totally took it wrong. I thought you meant the part about
    going to wild parties and living on the edge. Telling customers to
    play fast and loose for the hell of it, no, I generally don't tell
    them to do that. I actually totally do appreciate the security
    concerns. The code the thread started with is really just for playing
    around and for using in irb.

    (I did look into packaging up that code for distribution, but mostly
    just for the exercise of it - I didn't actually anticipate anyone
    finding it remarkably useful.)

    > I thought Giles was joking...


    No, I was dead serious. I went home and cried. Then I retained a
    lawyer. We're suing for mental anguish.

    --
    Giles Bowkett

    Blog: http://gilesbowkett.blogspot.com
    Portfolio: http://www.gilesgoatboy.org
     
    Giles Bowkett, Jun 24, 2007
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Eric Newton
    Replies:
    3
    Views:
    9,430
    Brock Allen
    Apr 4, 2005
  2. DataBinder.Eval and Eval.

    , Jun 16, 2006, in forum: ASP .Net
    Replies:
    1
    Views:
    552
    Karl Seguin [MVP]
    Jun 16, 2006
  3. manstey
    Replies:
    16
    Views:
    560
    Dennis Lee Bieber
    Jul 10, 2006
  4. Greg Ewing

    ANN: 555-BOOM! version 0.6

    Greg Ewing, Sep 25, 2007, in forum: Python
    Replies:
    0
    Views:
    279
    Greg Ewing
    Sep 25, 2007
  5. Alex van der Spek

    eval('07') works, eval('08') fails, why?

    Alex van der Spek, Jan 8, 2009, in forum: Python
    Replies:
    6
    Views:
    1,470
    Bruno Desthuilliers
    Jan 8, 2009
Loading...

Share This Page