Feature #4521
openNoMethodError#message may take very long to execute
Description
=begin
When a non-existing method is called on an object, NoMethodError is risen. If you call #message, however, your code may use up all CPU for a very long time (in my case, up to a few minutes).
I narrowed the problem down to this code in error.c (SVN snapshot) in the function name_err_mesg_to_str():
d = rb_protect(rb_inspect, obj, 0);
if (NIL_P(d) || RSTRING_LEN(d) > 65) {
d = rb_any_to_s(obj);
}
The problem is that, for a complex object, #inspect may take very long to execute, only to have its results thrown away because they will be larger than 65 characters.
Of course I can write a #to_s for all my objects, but the point is that I didn't call #to_s or #inspect, I called #message on an exception object, which then takes a few minutes just to return a short string.
Needless to say, this might be easy to spot in a simple example, but once you're writing a web application that suddenly freezes for one minute with no apparent reason, you're all but clueless as to what's going on. (The first time this happened, I didn't even know that something would eventually show up on the screen -- I thought it was an infinite loop).
Here's an example code that shows this behavior:
require 'nokogiri'
class A
def x
@xml = Nokogiri::XML(File.new('baz.xml', 'rb').read())
foo()
end
end
A.new().x()
a.x
Here, the time it takes for Ruby to print out the message that #foo doesn't exist is proportional to the size of baz.xml.
As a comparison, Python doesn't seem to do this. Take the following code:
class Test:
def str(self):
return "hello"
a = Test()
print a
print a.x()
If you execute it, this is the result:
hello
Traceback (most recent call last):
File "test.py", line 6, in
print a.x()
AttributeError: Test instance has no attribute 'x'
It uses the method str to convert the object to a string when necessary, but doesn't use it when printing out the message stating that the attribute doesn't exist.
One obvious way to fix this would be to always print out the simpler representation given by rb_any_to_s.
=end
Updated by ko1 (Koichi Sasada) over 13 years ago
- Tracker changed from Bug to Feature
- Assignee set to matz (Yukihiro Matsumoto)
It is not a bug, but a feature request.
Updated by shyouhei (Shyouhei Urabe) over 12 years ago
- Status changed from Open to Assigned
Updated by mame (Yusuke Endoh) about 12 years ago
- Description updated (diff)
- Target version set to 2.6