diff options
| author | U.Nakamura <usa@ruby-lang.org> | 2023-10-17 20:30:28 +0900 |
|---|---|---|
| committer | U.Nakamura <usa@ruby-lang.org> | 2023-10-17 20:30:28 +0900 |
| commit | a3e1444663005d3440b56c3a8e1b88bb28935912 (patch) | |
| tree | a23a03bc08b6fcb852b491d24f739c8f667122e8 /test/ruby | |
| parent | 84f2aabd272a54e79979795d2d405090704a1d07 (diff) | |
merge revision(s) 96c5a4be7b0d72502001734770af0f4a735c544c: [Backport #19894]
Fix memory leak in complemented method entries
[Bug #19894]
When a copy of a complemented method entry is created, there are two
issues:
1. IMEMO_FL_USER3 is not copied, so the complemented status is not
copied over.
2. In rb_method_entry_clone we increment both alias_count and
complemented_count. However, when we free the method entry in
rb_method_definition_release, we only decrement one of the two
counters, resulting in the rb_method_definition_t being leaked.
Co-authored-by: Adam Hess <adamhess1991@gmail.com>
---
method.h | 5 +++--
test/ruby/test_module.rb | 29 +++++++++++++++++++++++++++++
vm_method.c | 8 +++++---
3 files changed, 37 insertions(+), 5 deletions(-)
Diffstat (limited to 'test/ruby')
| -rw-r--r-- | test/ruby/test_module.rb | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index fa890c0e40..b5414d139e 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -3176,6 +3176,50 @@ class TestModule < Test::Unit::TestCase assert_match(/::Foo$/, mod.name, '[Bug #14895]') end + def test_iclass_memory_leak + # [Bug #19550] + assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true) + code = proc do + mod = Module.new + Class.new do + include mod + end + end + 1_000.times(&code) + PREP + 3_000_000.times(&code) + CODE + end + + def test_complemented_method_entry_memory_leak + # [Bug #19894] + assert_no_memory_leak([], <<~PREP, <<~CODE, rss: true) + code = proc do + $c = Class.new do + def foo; end + end + + $m = Module.new do + refine $c do + def foo; end + end + end + + Class.new do + using $m + + def initialize + o = $c.new + o.method(:foo).unbind + end + end.new + end + 1_000.times(&code) + PREP + 100_000.times(&code) + CODE + end + private def assert_top_method_is_private(method) |
