Is 'eval' supposed to be nasty? Is 'eval' supposed to be nasty? ruby ruby

Is 'eval' supposed to be nasty?


If you are evaling a string submitted by, or modifiable by the user, this is tantamount to allowing arbitrary code execution. Imagine if the string contained an OS call to rm -rf / or similar. That said, in situations where you know the strings are appropriately constrained, or your Ruby interpreter is sandboxed appropriately, or ideally both, eval can be extraordinarily powerful.

The problem is analogous to SQL injection, if you're familiar. The solution here is similar to the solution to the injection problem (parameterized queries). That is, if the statements you would like to eval are known to be of a very specific form, and not all of the statement need be submitted by the user, only a few variables, a math expression, or similar, you can take in these small pieces from the user, sanitize them if necessary, then evaluate the safe template statement with the user input plugged in in the appropriate places.


eval is not only insecure (as has been pointed out elsewhere), it's also slow. Every time it is executed, the AST of the evaled code needs to be parsed (and for eg JRuby, turned to bytecode) anew, which is a string-heavy operation and is also probably bad for cache locality (under the assumption that a running program doesn't eval a lot, and the corresponding parts of the interpreter are thus cache-cold, in addition to being large).

Why is there eval at all in Ruby, you ask? "Because we can" mostly - In fact, when eval was invented (for the LISP programming language), it was mostly for show! More to the point, using eval is The Right Thing when you want to "add an interpreter into your interpreter", for metaprogramming tasks such as writing a preprocessor, a debugger or a templating engine. The common idea for such applications is to massage some Ruby code and call eval on it, and it sure beats reinventing and implementing a domain-specific toy language, a pitfall also known as Greenspun's Tenth Rule. The caveats are: beware of the costs, eg for a templating engine, do all your evaling at startup time not run time; and don't eval untrusted code unless you know how to "tame" it, ie select and enforce a safe subset of the language according to the theory of capability discipline. The latter is a lot of really difficult work (see eg how that was done for Java; I'm not aware of any such effort for Ruby unfortunately).


In Ruby there are several gimmicks that might be more appropriate than eval():

  1. There is #send which allows you to call a method whose name you have as string and pass parameters to it.
  2. yield allows you to pass a block of code to a method which will be executed in the context of the receiving method.
  3. Often the simple Kernel.const_get("String") is sufficient to get the class whose name you have as string.

I think I am not able to explain them properly in detail, so I just gave you the hints, if you're interested you'll google.