Is "eval" supposed to be nasty?

I have used the eval Ruby function many times. But I heard people say that eval nasty. When asked why and how, I can never get a compelling reason not to use it. Are they really nasty? If so, how? What are the possible "safe" options for eval?

+21
ruby eval
Mar 12 '09 at 4:55
source share
7 answers

If you eval enter a string that the user submits or modifies the user, this is equivalent to allowing arbitrary code execution. Imagine that the line contained an OS call on rm -rf / or similar. However, in situations where you know that strings are appropriately constrained, or your Ruby interpreter is appropriately isolated, or, ideally, both eval parameters can be extremely powerful.

The problem is similar to SQL injection if you are familiar. The solution here is similar to the solution to the injection problem (parameterized queries). That is, if the statements that you would like to eval , as you know, have a very specific form, and not all instructions should be submitted by the user, only a few variables, a mathematical expression or the like, you can take these small pieces from the user, process if necessary them, then evaluate the instruction of the secure template with the connected user in the appropriate places.

+29
Mar 12 '09 at 5:02
source share

There are several tricks in Ruby that may be more appropriate than eval() :

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

I think I can’t explain them properly in detail, so I just gave you tips if you are interested that you will google.

+10
Mar 12 '09 at 17:07
source share

eval not only unsafe (as indicated elsewhere), but also slow. Each time it executes, the eval ed AST code needs to be parsed (and, for example, JRuby, bytecode accessed) again, which is a tough operation and also probably bad for localizing the cache (assuming the program is running doesn’t have eval much, and the corresponding parts of the interpreter are thus cache cold, in addition to the big one).

Why does eval exist in Ruby at all, you ask? "Because we can" basically - in fact, when eval was invented (for the LISP programming language), it was mainly for display ! Moreover, using eval is the right thing when you want to “add a translator to your interpreter,” for metaprogramming tasks such as writing a preprocessor, debugger, or template engine. The general idea for such applications is to massage some Ruby code and call eval on it, and he is confident that he will invent and implement a domain-specific toy language, a trap, also known as Greenspun Tenth Rule . Disclaimer: beware of costs, for example, for the template engine, all your eval ing do not start during startup; and eval not unreliable code if you do not know how to "tame" it, i.e. to choose and provide a safe subset of the language in accordance with the theory of discipline of possibilities . Unfortunately, this is a very difficult job (see, for example, how it was done for Java , unfortunately I do not know about such efforts for Ruby).

+8
Aug 27 '12 at 10:10
source share

This makes debugging difficult. This makes optimization difficult. But above all, this is usually a sign that there is a better way to do what you are trying to do.

If you tell us what you are trying to do with eval , you might get more relevant answers related to your specific scenario.

+7
Mar 12 '09 at 5:07
source share

Eval is an incredibly powerful feature that should be used with caution. Besides the security issues noted by Matt J, you will also find that the debugging runtime code is very complex. The problem in the tested runtime code block will be difficult for the interpreter, so finding this will be difficult.

If you agree with this problem and are not concerned about the security problem, you should not avoid using one of the functions that makes the ruby ​​attractive as it is.

+5
Mar 12 '09 at 5:09
source share

In certain situations, a well-located eval smart and reduces the amount of code required. In addition to the security issues that Matt J. mentioned, you also need to ask yourself one very simple question:

When everything is said and done, can anyone else read your code and understand what you have done?

If the answer is no, then what you got with eval is left for maintainability. This problem is not only applicable if you work in a team, but it also applies to you - you want to be able to look back at your code months, if not after a few years, and know what you have done.

+5
Mar 12 '09 at 5:15
source share

If you pass everything that you get from "outside" to eval , you are doing something wrong, and this is very unpleasant. It is very difficult to avoid code sufficient to be safe, so I find it rather unsafe. However, if you use eval to avoid duplication or other similar things, for example, in the following code example, it is normal to use.

 class Foo def self.define_getters(*symbols) symbols.each do |symbol| eval "def #{symbol}; @#{symbol}; end" end end define_getters :foo, :bar, :baz end 

However, at least in Ruby 1.9.1, Ruby has really powerful metaprogramming methods, and you can do the following:

 class Foo def self.define_getters(*symbols) symbols.each do |symbol| define_method(symbol) { instance_variable_get(symbol) } end end define_getters :foo, :bar, :baz end 

For most purposes, you want to use these methods, and no escaping is required.

Another disadvantage of eval is the fact that (at least in Ruby) it is rather slow since the interpreter must parse the string and then execute the code inside the current binding. Other methods directly call the C function, and so you should get pretty high speed.

-one
Dec 14 '09 at 17:44
source share



All Articles