Bug #1885: Proper comparison of recursive Struct & Range
http://redmine.ruby-lang.org/issues/show/1885

Author: Marc-Andre Lafortune
Status: Open, Priority: Normal
Category: core
ruby -v: ruby 1.9.2dev (2009-08-05 trunk 24397) [i386-darwin9.7.0]

The following code freezes the latest ruby 1.9:

  MyClass = Struct.new(:foo)
  x = MyClass.new; x[:foo] = x
  y = MyClass.new; y[:foo] = y
  x == y  # Loops forever (can not be interrupted)

Solution: rb_struct_equal & rb_struct_eql should handle recursion in a similar fashion as Array and Hash (i.e. by calling rb_exec_recursive_paired and returning Qtrue if recursion is detected). I could make a patch if needed.

Searching the source code for rb_exec_recursive revealed that Range is potentially recursive too (see range_inspect). The ==, eql? and === methods do not call rb_exec_recursive_paired and are thus also potentially troublesome. To build a recursive Range is not trivial though; either some intermediate container class is needed or else some crazy thing like:

  class CrazyRange < Range
    def initialize
      super(self..self)
    end
  
    def <=>(x)
      0   # Needed so CrazyRange can be the begin and end values of a range...
    end
  end

  CrazyRange.new == CrazyRange.new  # Loops forever (can not be interrupted)

I'm not sure that it is worth modifying ==, eql? and === to use rb_exec_recursive_paired and make them bulletproof.

Note that both Struct#hash and Range#hash face the same issue than Array#hash & Hash#hash (see issue #1852)


----------------------------------------
http://redmine.ruby-lang.org