Bug #1535
closedHash#merge! Inside Iterator Can Cause RuntimeError
Description
=begin
While iterating over a hash I can cause a RuntimeError to be raised when calling Hash#merge! on the same hash under very specific circumstances. Specifically, before the merge! the size of the two hashes combined needs to be about 67 or 68. Much more or less and the code runs correctly. For example:
hash = {1 => 2, 3 => 4, 5 => 6}
big_hash = {}
64.times { |k| big_hash[k.to_s] = k }
hash.each { hash.merge!(big_hash) }
This raises a RuntimeError: "hash modified during iteration" on 1.8.6.368 and 1.8.7.72. It runs correctly on 1.9.1.129. I've tested on a 32-bit Linux box, but it has been confirmed on a Mac, too.
I believe this to be a bug for three principle reasons:
1 - This behaviour is not documented for #each or #merge!. Something similar is documented for #rehash, but as the user does not explicitly call #rehash, they cannot be held responsible for its side effects.
2 - It seemingly operates under very specific conditions such that it may only be visible given such data structures, so the user would likely be unaware of this fatal consequence prior to experiencing it.
3 - It does not occur under 1.9.1, implying that this isn't the desired behaviour.
The ideal resolution is that this code works correctly, regardless of the dimensions of the data structures. If that is not possible, calling Hash#merge inside such an iterator block should be prohibited, so as to notify users of the incompatibility at design time.
=end