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>
This commit is contained in:
parent
3c11cdbcfe
commit
96c5a4be7b
5
method.h
5
method.h
@ -101,8 +101,9 @@ static inline void
|
|||||||
METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src)
|
METHOD_ENTRY_FLAGS_COPY(rb_method_entry_t *dst, const rb_method_entry_t *src)
|
||||||
{
|
{
|
||||||
dst->flags =
|
dst->flags =
|
||||||
(dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2)) |
|
(dst->flags & ~(IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2
|
||||||
(src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2));
|
|IMEMO_FL_USER3)) |
|
||||||
|
(src->flags & (IMEMO_FL_USER0|IMEMO_FL_USER1|IMEMO_FL_USER2|IMEMO_FL_USER3));
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -3292,6 +3292,35 @@ class TestModule < Test::Unit::TestCase
|
|||||||
CODE
|
CODE
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def assert_top_method_is_private(method)
|
def assert_top_method_is_private(method)
|
||||||
|
@ -693,11 +693,13 @@ rb_method_entry_create(ID called_id, VALUE klass, rb_method_visibility_t visi, c
|
|||||||
const rb_method_entry_t *
|
const rb_method_entry_t *
|
||||||
rb_method_entry_clone(const rb_method_entry_t *src_me)
|
rb_method_entry_clone(const rb_method_entry_t *src_me)
|
||||||
{
|
{
|
||||||
rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class,
|
rb_method_entry_t *me = rb_method_entry_alloc(src_me->called_id, src_me->owner, src_me->defined_class, src_me->def);
|
||||||
method_definition_addref(src_me->def));
|
|
||||||
if (METHOD_ENTRY_COMPLEMENTED(src_me)) {
|
if (METHOD_ENTRY_COMPLEMENTED(src_me)) {
|
||||||
method_definition_addref_complement(src_me->def);
|
method_definition_addref_complement(src_me->def);
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
method_definition_addref(src_me->def);
|
||||||
|
}
|
||||||
|
|
||||||
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
||||||
return me;
|
return me;
|
||||||
@ -724,7 +726,7 @@ rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID cal
|
|||||||
def = NULL;
|
def = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
def = method_definition_addref_complement(def);
|
method_definition_addref_complement(def);
|
||||||
}
|
}
|
||||||
me = rb_method_entry_alloc(called_id, src_me->owner, defined_class, def);
|
me = rb_method_entry_alloc(called_id, src_me->owner, defined_class, def);
|
||||||
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
METHOD_ENTRY_FLAGS_COPY(me, src_me);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user