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

ruby-changes:58774

From: Dylan <ko1@a...>
Date: Wed, 13 Nov 2019 15:37:24 +0900 (JST)
Subject: [ruby-changes:58774] ac112f2b5d (master): Avoid top-level search for nested constant reference from nil in defined?

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

From ac112f2b5dc7e16ccde8f048be80946187a033b0 Mon Sep 17 00:00:00 2001
From: Dylan Thacker-Smith <Dylan.Smith@s...>
Date: Wed, 6 Nov 2019 01:47:32 -0500
Subject: Avoid top-level search for nested constant reference from nil in
 defined?

Fixes [Bug #16332]

Constant access was changed to no longer allow top-level constant access
through `nil`, but `defined?` wasn't changed at the same time to stay
consistent.

Use a separate defined type to distinguish between a constant
referenced from the current lexical scope and one referenced from
another namespace.

diff --git a/compile.c b/compile.c
index b45aaef..f439abb 100644
--- a/compile.c
+++ b/compile.c
@@ -4728,13 +4728,13 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, https://github.com/ruby/ruby/blob/trunk/compile.c#L4728
 
         ADD_INSN3(ret, line, defined,
 		  (rb_is_const_id(node->nd_mid) ?
-		   INT2FIX(DEFINED_CONST) : INT2FIX(DEFINED_METHOD)),
+		   INT2FIX(DEFINED_CONST_FROM) : INT2FIX(DEFINED_METHOD)),
 		  ID2SYM(node->nd_mid), needstr);
         return;
       case NODE_COLON3:
         ADD_INSN1(ret, line, putobject, rb_cObject);
         ADD_INSN3(ret, line, defined,
-		  INT2FIX(DEFINED_CONST), ID2SYM(node->nd_mid), needstr);
+		  INT2FIX(DEFINED_CONST_FROM), ID2SYM(node->nd_mid), needstr);
         return;
 
 	/* method dispatch */
@@ -7493,7 +7493,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in https://github.com/ruby/ruby/blob/trunk/compile.c#L7493
 	if (node->nd_aid == idOROP) {
 	    lassign = NEW_LABEL(line);
 	    ADD_INSN(ret, line, dup); /* cref cref */
-	    ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST),
+	    ADD_INSN3(ret, line, defined, INT2FIX(DEFINED_CONST_FROM),
 		      ID2SYM(mid), Qfalse); /* cref bool */
 	    ADD_INSNL(ret, line, branchunless, lassign); /* cref */
 	}
diff --git a/iseq.c b/iseq.c
index 48a4d4b..6c2d225 100644
--- a/iseq.c
+++ b/iseq.c
@@ -1830,13 +1830,20 @@ rb_insn_operand_intern(const rb_iseq_t *iseq, https://github.com/ruby/ruby/blob/trunk/iseq.c#L1830
       case TS_NUM:		/* ULONG */
 	if (insn == BIN(defined) && op_no == 0) {
 	    enum defined_type deftype = (enum defined_type)op;
-	    if (deftype == DEFINED_FUNC) {
-		ret = rb_fstring_lit("func"); break;
-	    }
-	    if (deftype == DEFINED_REF) {
-		ret = rb_fstring_lit("ref"); break;
+	    switch (deftype) {
+	      case DEFINED_FUNC:
+		ret = rb_fstring_lit("func");
+		break;
+	      case DEFINED_REF:
+		ret = rb_fstring_lit("ref");
+		break;
+	      case DEFINED_CONST_FROM:
+		ret = rb_fstring_lit("constant-from");
+		break;
+	      default:
+		ret = rb_iseq_defined_string(deftype);
+		break;
 	    }
-	    ret = rb_iseq_defined_string(deftype);
 	    if (ret) break;
 	}
 	else if (insn == BIN(checktype) && op_no == 0) {
diff --git a/iseq.h b/iseq.h
index c9cc125..1fcf7cb 100644
--- a/iseq.h
+++ b/iseq.h
@@ -300,7 +300,8 @@ enum defined_type { https://github.com/ruby/ruby/blob/trunk/iseq.h#L300
     DEFINED_EXPR,
     DEFINED_IVAR2,
     DEFINED_REF,
-    DEFINED_FUNC
+    DEFINED_FUNC,
+    DEFINED_CONST_FROM
 };
 
 VALUE rb_iseq_defined_string(enum defined_type type);
diff --git a/test/ruby/test_const.rb b/test/ruby/test_const.rb
index 6284434..1c73b66 100644
--- a/test/ruby/test_const.rb
+++ b/test/ruby/test_const.rb
@@ -50,8 +50,13 @@ class TestConst < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_const.rb#L50
 
   def test_const_access_from_nil
     assert_raise(TypeError) { eval("nil::Object") }
+    assert_nil eval("defined?(nil::Object)")
+
     assert_raise(TypeError) { eval("c = nil; c::Object") }
+    assert_nil eval("c = nil; defined?(c::Object)")
+
     assert_raise(TypeError) { eval("sc = Class.new; sc::C = nil; sc::C::Object") }
+    assert_nil eval("sc = Class.new; sc::C = nil; defined?(sc::C::Object)")
   end
 
   def test_redefinition
diff --git a/tool/ruby_vm/views/_leaf_helpers.erb b/tool/ruby_vm/views/_leaf_helpers.erb
index 12defa5..ac60f2d 100644
--- a/tool/ruby_vm/views/_leaf_helpers.erb
+++ b/tool/ruby_vm/views/_leaf_helpers.erb
@@ -81,6 +81,7 @@ leafness_of_defined(rb_num_t op_type) https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/views/_leaf_helpers.erb#L81
       case DEFINED_ZSUPER:
         return false;
       case DEFINED_CONST:
+      case DEFINED_CONST_FROM:
         /* has rb_autoload_load(); */
         return false;
       case DEFINED_FUNC:
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index 5c83c34..205b4d9 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -3477,11 +3477,14 @@ vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_ https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L3477
 	break;
       }
       case DEFINED_CONST:
+      case DEFINED_CONST_FROM: {
+	bool allow_nil = type == DEFINED_CONST;
 	klass = v;
-        if (vm_get_ev_const(ec, klass, SYM2ID(obj), 1, 1)) {
+        if (vm_get_ev_const(ec, klass, SYM2ID(obj), allow_nil, true)) {
 	    expr_type = DEFINED_CONST;
 	}
 	break;
+      }
       case DEFINED_FUNC:
 	klass = CLASS_OF(v);
 	if (rb_method_boundp(klass, SYM2ID(obj), 0)) {
-- 
cgit v0.10.2


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

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