山本です。

Hash#hash の結果が、中身が等しいにもかかわらず
違う値になることがあります。

/////////////////////////////
// コード

a = {1=>nil, 2=>nil, []=>nil, {}=>nil, 5=>nil}
b = a.clone

p a
p b
p a.hash
p b.hash
p a.eql?(b)

/////////////////////////////
// 結果

{5=>nil, []=>nil, 1=>nil, {}=>nil, 2=>nil}
{[]=>nil, 5=>nil, 1=>nil, {}=>nil, 2=>nil}
3640
10552
true

これは、Hash の格納順が不定だからです。Hash#hash を求めるたびに
配列を確保するのもどうかと思ったのですが、下のパッチで一応動きます。

Index: hash.c
===================================================================
RCS file: /src/ruby/hash.c,v
retrieving revision 1.149
diff -u -w -b -p -r1.149 hash.c
--- hash.c	5 May 2005 23:08:47 -0000	1.149
+++ hash.c	8 May 2005 10:52:10 -0000
@@ -1497,21 +1497,11 @@ rb_hash_eql(hash1, hash2)
 }
 
 static int
-rb_hash_hash_i(key, value, hp)
-    VALUE key, value;
-    long *hp;
+rb_hash_hash_i(key, value, a)
+    VALUE key, value, a;
 {
-    long h = *hp;
-    VALUE n;
-
-    h = (h << 1) | (h<0 ? 1 : 0);
-    n = rb_hash(key);
-    h ^= NUM2LONG(n);
-    h = (h << 1) | (h<0 ? 1 : 0);
-    n = rb_hash(value);
-    h ^= NUM2LONG(n);
-    
-    *hp = h;
+    rb_ary_push(a, rb_hash(key));
+    rb_ary_push(a, rb_hash(value));
     return ST_CONTINUE;
 }
 
@@ -1520,14 +1510,21 @@ recursive_hash(hash, dummy, recur)
     VALUE hash, dummy;
     int recur;
 {
-    long h;
-    VALUE n;
+    long h, i;
+    VALUE n, a;
 
     if (recur) {
 	return LONG2FIX(0);
     }
     h = RHASH(hash)->tbl->num_entries;
-    rb_hash_foreach(hash, rb_hash_hash_i, (VALUE)&h);
+    a = rb_ary_new2(h*2);
+    rb_hash_foreach(hash, rb_hash_hash_i, a);
+    rb_ary_sort_bang(a);
+    for (i = 0; i < RARRAY(a)->len; i++) {
+	h = (h << 1) | (h<0 ? 1 : 0);
+	n = RARRAY(a)->ptr[i];
+	h ^= NUM2LONG(n);
+    }
     h = (h << 1) | (h<0 ? 1 : 0);
     n = rb_hash(RHASH(hash)->ifnone);
     h ^= NUM2LONG(n);

//////////////////////////////////////////////
// パッチ後

{5=>nil, []=>nil, 1=>nil, {}=>nil, 2=>nil}
{[]=>nil, 5=>nil, 1=>nil, {}=>nil, 2=>nil}
10726
10726
true