File tree Expand file tree Collapse file tree
core/src/main/java/org/jruby Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -1129,7 +1129,7 @@ public RubyHash rehash(ThreadContext context) {
11291129 RubyHashEntry tmpNext = entry .nextAdded ;
11301130 RubyHashEntry tmpPrev = entry .prevAdded ;
11311131 tmpPrev .nextAdded = tmpNext ;
1132- tmpPrev .prevAdded = tmpPrev ;
1132+ tmpNext .prevAdded = tmpPrev ;
11331133 size --;
11341134 } else {
11351135 // replace entry if hash changed
@@ -1159,7 +1159,7 @@ public RubyHash rehash(ThreadContext context) {
11591159 RubyHashEntry tmpNext = entry .nextAdded ;
11601160 RubyHashEntry tmpPrev = entry .prevAdded ;
11611161 tmpPrev .nextAdded = tmpNext ;
1162- tmpPrev .prevAdded = tmpPrev ;
1162+ tmpNext .prevAdded = tmpPrev ;
11631163 size --;
11641164 }
11651165 nextEntry = nextEntry .next ;
Original file line number Diff line number Diff line change @@ -108,4 +108,31 @@ def test_compare_by_identity
108108 assert_equal 2 , hash [ arr2 ]
109109 end
110110
111+ # GH-9340: Hash#rehash corrupts insertion-order linked list when
112+ # deduplicating keys. After rehash removes a duplicate, new
113+ # insertions would disconnect existing entries from iteration.
114+ def test_rehash_dedup_preserves_insertion_order
115+ a = [ 1 ] ; b = [ 2 ]
116+ h = { a => "a" , b => "b" }
117+ a [ 0 ] = 2 # a now equals b
118+ h . rehash # deduplicates, should keep b's value
119+ h [ [ 3 ] ] = "c"
120+
121+ assert_equal 2 , h . size
122+ assert_equal [ [ 2 ] , [ 3 ] ] , h . keys
123+ assert_equal [ "b" , "c" ] , h . values
124+ end
125+
126+ def test_rehash_dedup_reverse_each
127+ a = [ 1 ] ; b = [ 2 ] ; c = [ 3 ]
128+ h = { a => "a" , b => "b" , c => "c" }
129+ a [ 0 ] = 2
130+ h . rehash
131+ h [ [ 10 ] ] = "d"
132+
133+ result = [ ]
134+ h . reverse_each { |k , v | result << k }
135+ assert_equal [ [ 10 ] , [ 3 ] , [ 2 ] ] , result
136+ end
137+
111138end
You can’t perform that action at this time.
0 commit comments