diff options
| author | Peter Zhu <peter@peterzhu.ca> | 2026-05-11 19:50:07 -0400 |
|---|---|---|
| committer | Peter Zhu <peter@peterzhu.ca> | 2026-05-12 19:22:07 -0400 |
| commit | baec5bbfffb38083b4180240a0319d20c9afc2a7 (patch) | |
| tree | fba745dc37dd0fa36fc66711ceaf16160752b9be /test | |
| parent | 6297af9883baa274a316eca77a9333e7c8b440d3 (diff) | |
Fix GC compaction for compare-by-identity sets
[Bug #22064]
Compare-by-identity sets use the address for hashing, so we must pin it
so the object does not move in GC compaction. Objects in a compare-by-identity
set is not currently pinned, causing the set to be broken if the object
is moved.
For example:
set = Set.new.compare_by_identity
o = Object.new
set.add(o)
puts set.include?(o)
GC.verify_compaction_references(expand_heap: true, toward: :empty)
puts set.include?(o)
It should output true twice, but it outputs true and false.
Diffstat (limited to 'test')
| -rw-r--r-- | test/ruby/test_set.rb | 19 |
1 files changed, 19 insertions, 0 deletions
diff --git a/test/ruby/test_set.rb b/test/ruby/test_set.rb index 46d649ee73..427dd4b6b0 100644 --- a/test/ruby/test_set.rb +++ b/test/ruby/test_set.rb @@ -902,6 +902,25 @@ class TC_Set < Test::Unit::TestCase assert_equal(array.uniq.sort, set.sort) end + def test_compare_by_identity_compact + omit "compaction is not supported on this platform" unless GC.respond_to?(:compact) + + # [Bug #22064] + assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + set = Set.new.compare_by_identity + + o = Object.new + set.add(o) + + assert_include(set, o) + + GC.verify_compaction_references(expand_heap: true, toward: :empty) + + assert_include(set, o) + end; + end + def test_reset [Set, Class.new(Set)].each { |klass| a = [1, 2] |
