From 173a6b6a802d80b8cf200308fd3653832b700b1c Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Wed, 9 Mar 2022 14:57:49 -0800 Subject: Make define_singleton_method always define a public method In very unlikely cases, it could previously define a non-public method starting in Ruby 2.1. Fixes [Bug #18561] --- proc.c | 108 +++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 58 insertions(+), 50 deletions(-) (limited to 'proc.c') diff --git a/proc.c b/proc.c index 93b4013c31..4f43c56006 100644 --- a/proc.c +++ b/proc.c @@ -2165,61 +2165,14 @@ rb_mod_public_instance_method(VALUE mod, VALUE vid) return mnew_unbound(mod, id, rb_cUnboundMethod, TRUE); } -/* - * call-seq: - * define_method(symbol, method) -> symbol - * define_method(symbol) { block } -> symbol - * - * Defines an instance method in the receiver. The _method_ - * parameter can be a +Proc+, a +Method+ or an +UnboundMethod+ object. - * If a block is specified, it is used as the method body. - * If a block or the _method_ parameter has parameters, - * they're used as method parameters. - * This block is evaluated using #instance_eval. - * - * class A - * def fred - * puts "In Fred" - * end - * def create_method(name, &block) - * self.class.define_method(name, &block) - * end - * define_method(:wilma) { puts "Charge it!" } - * define_method(:flint) {|name| puts "I'm #{name}!"} - * end - * class B < A - * define_method(:barney, instance_method(:fred)) - * end - * a = B.new - * a.barney - * a.wilma - * a.flint('Dino') - * a.create_method(:betty) { p self } - * a.betty - * - * produces: - * - * In Fred - * Charge it! - * I'm Dino! - * # - */ - static VALUE -rb_mod_define_method(int argc, VALUE *argv, VALUE mod) +rb_mod_define_method_with_visibility(int argc, VALUE *argv, VALUE mod, const struct rb_scope_visi_struct* scope_visi) { ID id; VALUE body; VALUE name; - const rb_cref_t *cref = rb_vm_cref_in_context(mod, mod); - const rb_scope_visibility_t default_scope_visi = {METHOD_VISI_PUBLIC, FALSE}; - const rb_scope_visibility_t *scope_visi = &default_scope_visi; int is_method = FALSE; - if (cref) { - scope_visi = CREF_SCOPE_VISI(cref); - } - rb_check_arity(argc, 1, 2); name = argv[0]; id = rb_check_id(&name); @@ -2280,12 +2233,66 @@ rb_mod_define_method(int argc, VALUE *argv, VALUE mod) return ID2SYM(id); } +/* + * call-seq: + * define_method(symbol, method) -> symbol + * define_method(symbol) { block } -> symbol + * + * Defines an instance method in the receiver. The _method_ + * parameter can be a +Proc+, a +Method+ or an +UnboundMethod+ object. + * If a block is specified, it is used as the method body. + * If a block or the _method_ parameter has parameters, + * they're used as method parameters. + * This block is evaluated using #instance_eval. + * + * class A + * def fred + * puts "In Fred" + * end + * def create_method(name, &block) + * self.class.define_method(name, &block) + * end + * define_method(:wilma) { puts "Charge it!" } + * define_method(:flint) {|name| puts "I'm #{name}!"} + * end + * class B < A + * define_method(:barney, instance_method(:fred)) + * end + * a = B.new + * a.barney + * a.wilma + * a.flint('Dino') + * a.create_method(:betty) { p self } + * a.betty + * + * produces: + * + * In Fred + * Charge it! + * I'm Dino! + * # + */ + +static VALUE +rb_mod_define_method(int argc, VALUE *argv, VALUE mod) +{ + const rb_cref_t *cref = rb_vm_cref_in_context(mod, mod); + const rb_scope_visibility_t default_scope_visi = {METHOD_VISI_PUBLIC, FALSE}; + const rb_scope_visibility_t *scope_visi = &default_scope_visi; + + if (cref) { + scope_visi = CREF_SCOPE_VISI(cref); + } + + return rb_mod_define_method_with_visibility(argc, argv, mod, scope_visi); +} + /* * call-seq: * define_singleton_method(symbol, method) -> symbol * define_singleton_method(symbol) { block } -> symbol * - * Defines a singleton method in the receiver. The _method_ + * Defines a public singleton method in the receiver. The _method_ * parameter can be a +Proc+, a +Method+ or an +UnboundMethod+ object. * If a block is specified, it is used as the method body. * If a block or a method has parameters, they're used as method parameters. @@ -2315,8 +2322,9 @@ static VALUE rb_obj_define_method(int argc, VALUE *argv, VALUE obj) { VALUE klass = rb_singleton_class(obj); + const rb_scope_visibility_t scope_visi = {METHOD_VISI_PUBLIC, FALSE}; - return rb_mod_define_method(argc, argv, klass); + return rb_mod_define_method_with_visibility(argc, argv, klass, &scope_visi); } /* -- cgit v1.2.1