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/