http://www.perlmonks.org?node_id=549210


in reply to Small examples of string eval

I have several scripts that take numeric arguments from the command line where is is extremely useful to be able to enter expressions instead of simple values.

#! perl -slw use strict; our $LIMIT = eval $LIMIT || 'somedefault';

This way I can specify

script -LIMIT=2**33 or script -LIMIT=8*1024**3

Which beats the crap out of trying to remember

script -LIMIT=8589934592

Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.

Replies are listed 'Best First'.
Re^2: Small examples of string eval
by brian_d_foy (Abbot) on May 14, 2006 at 17:16 UTC

    You don't need eval for that, even if it makes it easier than parsing the argument and figuring out the value. The downside is that anyone can run arbitrary code using your script. With a tiny bit of programming you can do the math yourself and save yourself the security problem. :)

    --
    brian d foy <brian@stonehenge.com>
    Subscribe to The Perl Review
      anyone can run arbitrary code using your script ...

      Apart from the fact that only I run the scripts in question, those same bad people you are parnoid about could also type perl -e"the same arbitrary code"

      With a tiny bit of programming ...

      Show me the code.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        These discussion typically start with "only I run the script", and that's just a lack of imagination. You know better than that. And, it's not just a script you're running. You're telling the world it's a good idea to follow your example. You know that's not the right thing to do, and you know it's hazardous.

        The expression code is easily handled by Math::Expression (on CPAN), like everything else you want to do. This is what I use when I need this, although I had to modify the source to add ** as an operator (but that's really easy and I'm sure you'll figure it out as easily as you could have found this module, but I'll include the patch for everyone else).

        #!/usr/bin/perl use Math::Expression; my $expr = Math::Expression->new; my $tree = $expr->Parse( "8*1024**3" ); my $answer = $expr->EvalTree( $tree, 0 ); print "My answer is $answer\n";

        And, as you know, security is subverted by a combination of factors. You know that you've taken a shortcut and you know what the problem is. If someone can coerce your code to running as your userid (perhaps through changing the file mode, or even just changing a shell script that uses this script), they have their in. Again, as you know, security happens in layers and you do what you can to prevent unintended uses. You know that your eval shortcut can do a lot more than you want, and you also don't care to make the easy (and re-usable) fix. That's why some people have to be paranoid. :)

        58,59c58,59 < my $HighestOperPrec = 15; < my $PrecTerminal = 16; # Precedence of terminal (or l +ist) - ie operand --- > my $HighestOperPrec = 14; > my $PrecTerminal = 15; # Precedence of terminal (or l +ist) - ie operand 61,65c61,64 < '(' => [17, 17], < 'var' => [16, 16], < 'const' => [16, 16], < 'func' => [16, 16], < '**'=> [15, 15], --- > '(' => [16, 16], > 'var' => [15, 15], > 'const' => [15, 15], > 'func' => [15, 15], 170c169 < --- > 180c179 < elsif($expr =~ s@^(:=|>=|<=|==|<>|!=|&&|\|\||lt|gt|le| +ge|eq|ne|\ *{2}|[-./*%+,<>\?:\(\);])@@) { --- > elsif($expr =~ s@^(:=|>=|<=|==|<>|!=|&&|\|\||lt|gt|le| +ge|eq|ne|[ -./*%+,<>\?:\(\);])@@) { 480d478 < return $left ** $right if($oper eq '**');

        Maybe you don't want to use a module, though, and that's fine. That's a better reason than "that will never happen". There are all sorts of other things you can do to harden your code, but you have to want to do that. At the very least, turn on taint checking and scrub the input.

        --
        brian d foy <brian@stonehenge.com>
        Subscribe to The Perl Review