-
-
Notifications
You must be signed in to change notification settings - Fork 939
Open
Milestone
Description
Hash#rehash corrupts the internal insertion-order doubly-linked list when it deduplicates keys (i.e., when mutated keys now compare as equal). After the corrupted rehash, inserting new entries disconnects existing entries from iteration, and calling h.keys can trigger a NullPointerException.
Root Cause
In RubyHash#rehash, when a duplicate key is found and its entry is unlinked from the insertion-order list:
RubyHashEntry tmpNext = entry.nextAdded;
RubyHashEntry tmpPrev = entry.prevAdded;
tmpPrev.nextAdded = tmpNext; // correct: prev.next skips over entry
tmpPrev.prevAdded = tmpPrev; // BUG: should be tmpNext.prevAdded = tmpPrevReproducer
a = [1]; b = [2]
h = { a => "a", b => "b" }
a[0] = 2
h.rehash
h[[3]] = "c"
expected = [[2], [3]]
actual = []
h.each { |k, v| actual << k }
if actual == expected
puts "PASS: each yields #{actual.inspect}"
else
puts "FAIL: each yields #{actual.inspect}, expected #{expected.inspect}"
end
# h.keys.inspect triggers NullPointerException on JRuby
# puts h.keys.inspectCRuby 3.4.8: PASS: each yields [[2], [3]]
JRuby (master): FAIL: each yields [[3]], expected [[2], [3]]
Uncommenting h.keys.inspect produces:
Unhandled Java exception: java.lang.NullPointerException: Cannot read field "metaClass" because "arg" is null
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels