[前][次][番号順一覧][スレッド一覧]

ruby-changes:64430

From: Koichi <ko1@a...>
Date: Tue, 22 Dec 2020 06:09:46 +0900 (JST)
Subject: [ruby-changes:64430] 520dcbd600 (master): reset cache before iterating

https://git.ruby-lang.org/ruby.git/commit/?id=520dcbd600

From 520dcbd6009b07458d67309ae33a602d77062975 Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Tue, 22 Dec 2020 05:27:47 +0900
Subject: reset cache before iterating

cee02d754d76563635c1db90d2ab6c01f8492470 resets pCMC and `me`
will be a invalidated and continuing the invalidated `me`,
it will break the data structure. This patch tris to clear
all methods of specified class before manipulating the `me`s.
[Issue #17417]

diff --git a/class.c b/class.c
index 6d5cabc..47f35b1 100644
--- a/class.c
+++ b/class.c
@@ -1105,12 +1105,11 @@ include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super) https://github.com/ruby/ruby/blob/trunk/class.c#L1105
 static enum rb_id_table_iterator_result
 move_refined_method(ID key, VALUE value, void *data)
 {
-    rb_method_entry_t *me = (rb_method_entry_t *) value;
-    VALUE klass = (VALUE)data;
-    struct rb_id_table *tbl = RCLASS_M_TBL(klass);
+    rb_method_entry_t *me = (rb_method_entry_t *)value;
 
     if (me->def->type == VM_METHOD_TYPE_REFINED) {
-        rb_clear_method_cache(klass, me->called_id);
+        VALUE klass = (VALUE)data;
+        struct rb_id_table *tbl = RCLASS_M_TBL(klass);
 
         if (me->def->body.refined.orig_me) {
 	    const rb_method_entry_t *orig_me = me->def->body.refined.orig_me, *new_me;
@@ -1130,6 +1129,19 @@ move_refined_method(ID key, VALUE value, void *data) https://github.com/ruby/ruby/blob/trunk/class.c#L1129
     }
 }
 
+static enum rb_id_table_iterator_result
+cache_clear_refined_method(ID key, VALUE value, void *data)
+{
+    rb_method_entry_t *me = (rb_method_entry_t *) value;
+
+    if (me->def->type == VM_METHOD_TYPE_REFINED) {
+        VALUE klass = (VALUE)data;
+        rb_clear_method_cache(klass, me->called_id);
+    }
+
+    return ID_TABLE_CONTINUE;
+}
+
 static void
 ensure_origin(VALUE klass)
 {
@@ -1141,6 +1153,7 @@ ensure_origin(VALUE klass) https://github.com/ruby/ruby/blob/trunk/class.c#L1153
 	RCLASS_SET_ORIGIN(klass, origin);
 	RCLASS_M_TBL(origin) = RCLASS_M_TBL(klass);
 	RCLASS_M_TBL_INIT(klass);
+        rb_id_table_foreach(RCLASS_M_TBL(origin), cache_clear_refined_method, (void *)klass);
 	rb_id_table_foreach(RCLASS_M_TBL(origin), move_refined_method, (void *)klass);
     }
 }
diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb
index b27a176..c364de4 100644
--- a/test/ruby/test_refinement.rb
+++ b/test/ruby/test_refinement.rb
@@ -2441,12 +2441,6 @@ class TestRefinement < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L2441
     $VERBOSE = verbose_bak
   end
 
-  private
-
-  def eval_using(mod, s)
-    eval("using #{mod}; #{s}", Sandbox::BINDING)
-  end
-
   # [Bug #17386]
   def test_prepended_with_method_cache
     foo = Class.new do
@@ -2473,4 +2467,30 @@ class TestRefinement < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_refinement.rb#L2467
     foo.prepend code
     assert_equal :Code, obj.foo
   end
+
+  # [Bug #17417]
+  def test_prepended_with_method_cache_17417
+    assert_normal_exit %q{
+      module M
+        def hoge; end
+      end
+
+      module R
+        refine Hash do
+          def except *args; end
+        end
+      end
+
+      h = {}
+      h.method(:except) # put it on pCMC
+      Hash.prepend(M)
+      h.method(:except)
+    }
+  end
+
+  private
+
+  def eval_using(mod, s)
+    eval("using #{mod}; #{s}", Sandbox::BINDING)
+  end
 end
-- 
cgit v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]