summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--set.c17
-rw-r--r--test/ruby/test_set.rb19
2 files changed, 35 insertions, 1 deletions
diff --git a/set.c b/set.c
index 4d2bc997fa..1a5d0e26fa 100644
--- a/set.c
+++ b/set.c
@@ -124,6 +124,14 @@ struct set_object {
};
static int
+mark_and_pin_key(st_data_t key, st_data_t data)
+{
+ rb_gc_mark((VALUE)key);
+
+ return ST_CONTINUE;
+}
+
+static int
mark_key(st_data_t key, st_data_t data)
{
rb_gc_mark_movable((VALUE)key);
@@ -135,7 +143,14 @@ static void
set_mark(void *ptr)
{
struct set_object *sobj = ptr;
- if (sobj->table.entries) set_table_foreach(&sobj->table, mark_key, 0);
+ if (sobj->table.entries) {
+ if (sobj->table.type == &identhash) {
+ set_table_foreach(&sobj->table, mark_and_pin_key, 0);
+ }
+ else {
+ set_table_foreach(&sobj->table, mark_key, 0);
+ }
+ }
}
static void
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]