From 2eb3fbc73a0343d112ae3cc15acb75b4c2ff2bcc Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Wed, 31 Jul 2019 17:03:11 -0700 Subject: [PATCH] Make attr* methods define public methods if self in caller is not same as receiver Previously, attr* methods could be private even if not in the private section of a class/module block. This uses the same approach that ruby started using for define_method in 1fc33199736f316dd71d0c551edbf514528ddde6. Fixes [Bug #4537] --- test/ruby/test_module.rb | 28 ++++++++++++++++++++++++++++ vm.c | 2 +- vm_method.c | 4 +++- 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index 37045ad0d9..cdc084c8bc 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -705,6 +705,34 @@ def initialize assert_equal(false, o.respond_to?(:bar=)) end + def test_attr_public_at_toplevel + eval(<<-END, TOPLEVEL_BINDING) + String.send(:attr_accessor, :x) + String.send(:attr, :y) + String.send(:attr_reader, :z) + String.send(:attr_writer, :w) + END + s = "" + assert_nil s.x + s.x = 1 + assert_equal 1, s.x + + assert_nil s.y + s.instance_variable_set(:@y, 2) + assert_equal 2, s.y + + assert_nil s.z + s.instance_variable_set(:@z, 3) + assert_equal 3, s.z + + s.w = 4 + assert_equal 4, s.instance_variable_get(:@w) + ensure + [:x, :x=, :y, :z, :w=].each do |meth| + String.undef_method(meth) rescue nil + end + end + def test_const_get_evaled c1 = Class.new c2 = Class.new(c1) diff --git a/vm.c b/vm.c index ca5df22315..38f4050b20 100644 --- a/vm.c +++ b/vm.c @@ -1383,7 +1383,7 @@ rb_vm_cref_in_context(VALUE self, VALUE cbase) const rb_execution_context_t *ec = GET_EC(); const rb_control_frame_t *cfp = rb_vm_get_ruby_level_next_cfp(ec, ec->cfp); const rb_cref_t *cref; - if (cfp->self != self) return NULL; + if (!cfp || cfp->self != self) return NULL; if (!vm_env_cref_by_cref(cfp->ep)) return NULL; cref = vm_get_cref(cfp->ep); if (CREF_CLASS(cref) != cbase) return NULL; diff --git a/vm_method.c b/vm_method.c index 35634d275c..da891229f8 100644 --- a/vm_method.c +++ b/vm_method.c @@ -1135,14 +1135,16 @@ rb_scope_module_func_set(void) vm_cref_set_visibility(METHOD_VISI_PRIVATE, TRUE); } +const rb_cref_t *rb_vm_cref_in_context(VALUE self, VALUE cbase); void rb_attr(VALUE klass, ID id, int read, int write, int ex) { ID attriv; rb_method_visibility_t visi; const rb_execution_context_t *ec = GET_EC(); + const rb_cref_t *cref = rb_vm_cref_in_context(klass, klass); - if (!ex) { + if (!ex || !cref) { visi = METHOD_VISI_PUBLIC; } else { -- 2.21.0