summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--object.c3
-rw-r--r--test/ruby/test_shapes.rb13
2 files changed, 14 insertions, 2 deletions
diff --git a/object.c b/object.c
index 9a5a8fbe8a..a0783e9ef7 100644
--- a/object.c
+++ b/object.c
@@ -302,8 +302,7 @@ rb_obj_copy_ivar(VALUE dest, VALUE obj)
if (rb_shape_obj_too_complex(obj)) {
// obj is TOO_COMPLEX so we can copy its iv_hash
- st_table * table = rb_st_init_numtable_with_size(rb_st_table_size(ROBJECT_IV_HASH(obj)));
- st_replace(table, ROBJECT_IV_HASH(obj));
+ st_table *table = st_copy(ROBJECT_IV_HASH(obj));
rb_obj_convert_to_too_complex(dest, table);
return;
diff --git a/test/ruby/test_shapes.rb b/test/ruby/test_shapes.rb
index 885b762eb9..ee99fbad6d 100644
--- a/test/ruby/test_shapes.rb
+++ b/test/ruby/test_shapes.rb
@@ -942,6 +942,19 @@ class TestShapes < Test::Unit::TestCase
assert_shape_equal(RubyVM::Shape.of(obj), RubyVM::Shape.of(obj2))
end
+ def test_duplicating_too_complex_objects_memory_leak
+ assert_no_memory_leak([], "#{<<~'begin;'}", "#{<<~'end;'}", "[Bug #20162]", rss: true)
+ RubyVM::Shape.exhaust_shapes
+
+ o = Object.new
+ o.instance_variable_set(:@a, 0)
+ begin;
+ 1_000_000.times do
+ o.dup
+ end
+ end;
+ end
+
def test_freezing_and_duplicating_object
obj = Object.new.freeze
obj2 = obj.dup