Feature #4521

NoMethodError#message may take very long to execute

Added by Adiel Mittmann about 3 years ago. Updated over 1 year ago.

[ruby-core:35550]
Status:Assigned
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:-
Target version:next minor

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 nameerrmesgtostr():

d = rbprotect(rbinspect, obj, 0);
if (NILP(d) || RSTRINGLEN(d) > 65) {
d = rbanyto_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 #tos for all my objects, but the point is that I didn't call #tos 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 rbanyto_s.
=end

History

#1 Updated by Koichi Sasada almost 3 years ago

  • Tracker changed from Bug to Feature
  • Assignee set to Yukihiro Matsumoto

It is not a bug, but a feature request.

#2 Updated by Shyouhei Urabe about 2 years ago

  • Status changed from Open to Assigned

#3 Updated by Yusuke Endoh over 1 year ago

  • Description updated (diff)
  • Target version set to next minor

Also available in: Atom PDF