From: shugo@... Date: 2020-12-23T02:05:09+00:00 Subject: [ruby-core:101638] [Ruby master Bug#17379] Refinement with modules redefinition bug Issue #17379 has been updated by shugo (Shugo Maeda). Assignee changed from shugo (Shugo Maeda) to ko1 (Koichi Sasada) It seems that callable method entry cache caused the problem. The problem doesn't occur with the following patch: ``` diff --git a/vm_method.c b/vm_method.c index a0ccdb8a51..d3a3926780 100644 --- a/vm_method.c +++ b/vm_method.c @@ -1023,7 +1023,7 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_ mtbl = RCLASS_EXT(defined_class)->callable_m_tbl = rb_id_table_create(0); } cme = rb_method_entry_complement_defined_class(me, me->called_id, defined_class); - rb_id_table_insert(mtbl, id, (VALUE)cme); + // rb_id_table_insert(mtbl, id, (VALUE)cme); RB_OBJ_WRITTEN(defined_class, Qundef, (VALUE)cme); VM_ASSERT(callable_method_entry_p(cme)); } @@ -1122,7 +1122,8 @@ callable_method_entry(VALUE klass, ID mid, VALUE *defined_class_ptr) VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_ICLASS)); RB_VM_LOCK_ENTER(); { - cme = cached_callable_method_entry(klass, mid); + // cme = cached_callable_method_entry(klass, mid); + cme = NULL; if (cme) { if (defined_class_ptr != NULL) *defined_class_ptr = cme->defined_class; @@ -1139,7 +1140,7 @@ callable_method_entry(VALUE klass, ID mid, VALUE *defined_class_ptr) cme = negative_cme(mid); } - cache_callable_method_entry(klass, mid, cme); + // cache_callable_method_entry(klass, mid, cme); } } RB_VM_LOCK_LEAVE(); ``` (The fix of prepare_callable_method_entry() is for Kernel#method) @ko1, is there any way to fix the problem without performance regression? ---------------------------------------- Bug #17379: Refinement with modules redefinition bug https://bugs.ruby-lang.org/issues/17379#change-89429 * Author: marcandre (Marc-Andre Lafortune) * Status: Open * Priority: Normal * Assignee: ko1 (Koichi Sasada) * ruby -v: ruby 3.0.0dev (2020-12-05T10:40:00Z master 9dbb2bfd73) [x86_64-darwin18] * Backport: 2.5: UNKNOWN, 2.6: UNKNOWN, 2.7: UNKNOWN ---------------------------------------- Depending on the circumstance, a refinement can be modified even after being used: ```ruby def foo [:base] end module M def foo super << :M end end module Ext refine Object do include M end end using Ext p 'asd'.foo unless ENV['SKIP'] # => [:base, :M] (ok) module M def foo super << :new_ref end end p 'asd'.foo # => depends (not ok) ``` Running this gives: ``` $ ruby refinement.rb [:base, :M] [:base, :M] # => ok $ SKIP=t ruby refinement.rb [:base, :new_ref] # => should be [:base, :M] ``` -- https://bugs.ruby-lang.org/ Unsubscribe: