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

ruby-changes:64104

From: Koichi <ko1@a...>
Date: Sat, 12 Dec 2020 06:19:35 +0900 (JST)
Subject: [ruby-changes:64104] d741c77b5f (master): fix ivar with shareable objects issue

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

From d741c77b5fd976300815c1ea987e76e92b71122f Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
Date: Fri, 11 Dec 2020 16:37:20 +0900
Subject: fix ivar with shareable objects issue

Instance variables of sharable objects are accessible only from
main ractor, so we need to check it correctly.

diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 2bbf823..81bea95 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -809,6 +809,53 @@ assert_equal 'can not access instance variables of shareable objects from non-ma https://github.com/ruby/ruby/blob/trunk/bootstraptest/test_ractor.rb#L809
   end
 }
 
+# ivar in shareable-objects are not allowed to access from non-main Ractor, by @iv (get)
+assert_equal 'can not access instance variables of shareable objects from non-main Ractors', %q{
+  class Ractor
+    def setup
+      @foo = ''
+    end
+
+    def foo
+      @foo
+    end
+  end
+
+  shared = Ractor.new{}
+  shared.setup
+
+  r = Ractor.new shared do |shared|
+    p shared.foo
+  end
+
+  begin
+    r.take
+  rescue Ractor::RemoteError => e
+    e.cause.message
+  end
+}
+
+# ivar in shareable-objects are not allowed to access from non-main Ractor, by @iv (set)
+assert_equal 'can not access instance variables of shareable objects from non-main Ractors', %q{
+  class Ractor
+    def setup
+      @foo = ''
+    end
+  end
+
+  shared = Ractor.new{}
+
+  r = Ractor.new shared do |shared|
+    p shared.setup
+  end
+
+  begin
+    r.take
+  rescue Ractor::RemoteError => e
+    e.cause.message
+  end
+}
+
 # But a shareable object is frozen, it is allowed to access ivars from non-main Ractor
 assert_equal '11', %q{
   [Object.new, [], ].map{|obj|
diff --git a/variable.c b/variable.c
index 81c0a7d..45385fb 100644
--- a/variable.c
+++ b/variable.c
@@ -926,6 +926,8 @@ generic_ivtbl(VALUE obj, ID id, bool force_check_ractor) https://github.com/ruby/ruby/blob/trunk/variable.c#L926
         !RB_OBJ_FROZEN_RAW(obj) &&
         UNLIKELY(!rb_ractor_main_p()) &&
         UNLIKELY(rb_ractor_shareable_p(obj))) {
+
+        // TODO: RuntimeError?
         rb_raise(rb_eRuntimeError, "can not access instance variables of shareable objects from non-main Ractors");
     }
     return generic_iv_tbl_;
@@ -961,6 +963,21 @@ rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **ivtbl) https://github.com/ruby/ruby/blob/trunk/variable.c#L963
     return gen_ivtbl_get(obj, 0, ivtbl);
 }
 
+MJIT_FUNC_EXPORTED VALUE
+rb_ivar_generic_lookup_with_index(VALUE obj, ID id, uint32_t index)
+{
+    struct gen_ivtbl *ivtbl;
+
+    if (gen_ivtbl_get(obj, id, &ivtbl)) {
+        if (LIKELY(index < ivtbl->numiv)) {
+            VALUE val = ivtbl->ivptr[index];
+            return val;
+        }
+    }
+
+    return Qundef;
+}
+
 static VALUE
 generic_ivar_delete(VALUE obj, ID id, VALUE undef)
 {
diff --git a/variable.h b/variable.h
index 4d71f87..bfe1be2 100644
--- a/variable.h
+++ b/variable.h
@@ -17,5 +17,6 @@ struct gen_ivtbl { https://github.com/ruby/ruby/blob/trunk/variable.h#L17
 };
 
 int rb_ivar_generic_ivtbl_lookup(VALUE obj, struct gen_ivtbl **);
+VALUE rb_ivar_generic_lookup_with_index(VALUE obj, ID id, uint32_t index);
 
 #endif /* RUBY_TOPLEVEL_VARIABLE_H */
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 9205273..9a94b10 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1095,6 +1095,21 @@ iv_index_tbl_lookup(struct st_table *iv_index_tbl, ID id, struct rb_iv_index_tbl https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1095
     return found ? true : false;
 }
 
+ALWAYS_INLINE(static void fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, struct rb_iv_index_tbl_entry *ent));
+
+static inline void
+fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, struct rb_iv_index_tbl_entry *ent)
+{
+    // fill cache
+    if (!is_attr) {
+        ic->entry = ent;
+        RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value);
+    }
+    else {
+        vm_cc_attr_index_set(cc, (int)ent->index + 1);
+    }
+}
+
 ALWAYS_INLINE(static VALUE vm_getivar(VALUE, ID, const rb_iseq_t *, IVC, const struct rb_callcache *, int));
 static inline VALUE
 vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)
@@ -1116,38 +1131,38 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1131
         if (LIKELY(BUILTIN_TYPE(obj) == T_OBJECT) &&
             LIKELY(index < ROBJECT_NUMIV(obj))) {
             val = ROBJECT_IVPTR(obj)[index];
+
+            VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true);
         }
         else if (FL_TEST_RAW(obj, FL_EXIVAR)) {
-            struct gen_ivtbl *ivtbl;
-
-            if (LIKELY(rb_ivar_generic_ivtbl_lookup(obj, &ivtbl)) &&
-                LIKELY(index < ivtbl->numiv)) {
-                val = ivtbl->ivptr[index];
-            }
+            val = rb_ivar_generic_lookup_with_index(obj, id, index);
         }
+
         goto ret;
     }
     else {
-        struct st_table *iv_index_tbl;
-        st_index_t numiv;
-        VALUE *ivptr;
+        struct rb_iv_index_tbl_entry *ent;
 
         if (BUILTIN_TYPE(obj) == T_OBJECT) {
-            iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
-            numiv = ROBJECT_NUMIV(obj);
-            ivptr = ROBJECT_IVPTR(obj);
-            goto fill;
-	}
-        else if (FL_TEST_RAW(obj, FL_EXIVAR)) {
-            struct gen_ivtbl *ivtbl;
-            if (LIKELY(rb_ivar_generic_ivtbl_lookup(obj, &ivtbl))) {
-                numiv = ivtbl->numiv;
-                ivptr = ivtbl->ivptr;
-                iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
-                goto fill;
+            struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj);
+
+            if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
+                fill_ivar_cache(iseq, ic, cc, is_attr, ent);
+
+                // get value
+                if (ent->index < ROBJECT_NUMIV(obj)) {
+                    val = ROBJECT_IVPTR(obj)[ent->index];
+
+                    VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true);
+                }
             }
-            else {
-                goto ret;
+        }
+        else if (FL_TEST_RAW(obj, FL_EXIVAR)) {
+            struct st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
+
+            if (iv_index_tbl && iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
+                fill_ivar_cache(iseq, ic, cc, is_attr, ent);
+                val = rb_ivar_generic_lookup_with_index(obj, id, ent->index);
             }
         }
         else {
@@ -1155,25 +1170,6 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1170
             goto general_path;
         }
 
-      fill:
-        if (iv_index_tbl) {
-            struct rb_iv_index_tbl_entry *ent;
-
-            if (iv_index_tbl_lookup(iv_index_tbl, id, &ent)) {
-                if (!is_attr) {
-                    ic->entry = ent;
-                    RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value);
-                }
-                else { /* call_info */
-                    vm_cc_attr_index_set(cc, (int)ent->index + 1);
-                }
-
-                if (ent->index < numiv) {
-                    val = ivptr[ent->index];
-                }
-            }
-        }
-
       ret:
         if (LIKELY(val != Qundef)) {
             return val;
@@ -1204,6 +1200,8 @@ vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const str https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1200
 	VALUE klass = RBASIC(obj)->klass;
 	uint32_t index;
 
+        VM_ASSERT(!rb_ractor_shareable_p(obj));
+
 	if (LIKELY(
 	    (!is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_serial, ic->entry && ic->entry->class_serial  == RCLASS_SERIAL(klass))) ||
             ( is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_unset, vm_cc_attr_index(cc) > 0)))) {
-- 
cgit v0.10.2


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

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