mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
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.
This commit is contained in:
parent
a5b6d7bca8
commit
ac112f2b5d
Notes:
git
2019-11-13 15:37:26 +09:00
6 changed files with 28 additions and 11 deletions
|
@ -4728,13 +4728,13 @@ defined_expr0(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
|
|||
|
||||
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
|
|||
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 */
|
||||
}
|
||||
|
|
19
iseq.c
19
iseq.c
|
@ -1830,13 +1830,20 @@ rb_insn_operand_intern(const rb_iseq_t *iseq,
|
|||
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;
|
||||
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;
|
||||
}
|
||||
if (deftype == DEFINED_REF) {
|
||||
ret = rb_fstring_lit("ref"); break;
|
||||
}
|
||||
ret = rb_iseq_defined_string(deftype);
|
||||
if (ret) break;
|
||||
}
|
||||
else if (insn == BIN(checktype) && op_no == 0) {
|
||||
|
|
3
iseq.h
3
iseq.h
|
@ -300,7 +300,8 @@ enum defined_type {
|
|||
DEFINED_EXPR,
|
||||
DEFINED_IVAR2,
|
||||
DEFINED_REF,
|
||||
DEFINED_FUNC
|
||||
DEFINED_FUNC,
|
||||
DEFINED_CONST_FROM
|
||||
};
|
||||
|
||||
VALUE rb_iseq_defined_string(enum defined_type type);
|
||||
|
|
|
@ -50,8 +50,13 @@ class TestConst < Test::Unit::TestCase
|
|||
|
||||
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
|
||||
|
|
|
@ -81,6 +81,7 @@ leafness_of_defined(rb_num_t op_type)
|
|||
case DEFINED_ZSUPER:
|
||||
return false;
|
||||
case DEFINED_CONST:
|
||||
case DEFINED_CONST_FROM:
|
||||
/* has rb_autoload_load(); */
|
||||
return false;
|
||||
case DEFINED_FUNC:
|
||||
|
|
|
@ -3477,11 +3477,14 @@ vm_defined(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp, rb_num_t op_
|
|||
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)) {
|
||||
|
|
Loading…
Add table
Reference in a new issue