From a384bcce350acf5e8be5d45f0258e6ef5bdeb033 Mon Sep 17 00:00:00 2001 From: Francois Chagnon Date: Thu, 17 Nov 2016 14:52:52 -0500 Subject: Fix instances where return value of mrb_method_search_vm is unchecked Reported by @charliesome --- test/t/nomethoderror.rb | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'test/t/nomethoderror.rb') diff --git a/test/t/nomethoderror.rb b/test/t/nomethoderror.rb index 5fed79689..ce3514782 100644 --- a/test/t/nomethoderror.rb +++ b/test/t/nomethoderror.rb @@ -20,3 +20,34 @@ assert('NoMethodError#args', '15.2.32.2.1') do end end end + +assert('Can still raise when BasicObject#method_missing is removed') do + assert_raise(TypeError) do + begin + BasicObject.alias_method(:old_method_missing, :method_missing) + BasicObject.remove_method(:method_missing) + 1.__send__(:foo) + ensure + BasicObject.alias_method(:method_missing, :old_method_missing) + BasicObject.remove_method(:old_method_missing) + end + end +end + +assert('Can still call super when BasicObject#method_missing is removed') do + assert_raise(TypeError) do + class A + def foo + super + end + end + begin + BasicObject.alias_method(:old_method_missing, :method_missing) + BasicObject.remove_method(:method_missing) + A.new.foo + ensure + BasicObject.alias_method(:method_missing, :old_method_missing) + BasicObject.remove_method(:old_method_missing) + end + end +end -- cgit v1.2.3 From 144006a20e7d97733d682ff1502f24b032b3db59 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 3 Dec 2016 18:23:04 +0900 Subject: update NoMethodError tests; ref #3291 --- test/t/nomethoderror.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test/t/nomethoderror.rb') diff --git a/test/t/nomethoderror.rb b/test/t/nomethoderror.rb index ce3514782..1c09bc20e 100644 --- a/test/t/nomethoderror.rb +++ b/test/t/nomethoderror.rb @@ -22,7 +22,7 @@ assert('NoMethodError#args', '15.2.32.2.1') do end assert('Can still raise when BasicObject#method_missing is removed') do - assert_raise(TypeError) do + assert_raise(NoMethodError) do begin BasicObject.alias_method(:old_method_missing, :method_missing) BasicObject.remove_method(:method_missing) @@ -35,7 +35,7 @@ assert('Can still raise when BasicObject#method_missing is removed') do end assert('Can still call super when BasicObject#method_missing is removed') do - assert_raise(TypeError) do + assert_raise(NoMethodError) do class A def foo super -- cgit v1.2.3 From 6be5160eb634e7b045cba83a38675cf14fa16593 Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Tue, 6 Dec 2016 14:25:56 -0500 Subject: Fix 36fc1f14 not checking in the right location --- src/error.c | 5 +++-- test/t/nomethoderror.rb | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'test/t/nomethoderror.rb') diff --git a/src/error.c b/src/error.c index fda2cd15c..d7facd0b9 100644 --- a/src/error.c +++ b/src/error.c @@ -280,8 +280,6 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) mrb->exc = 0; } else { - if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) - mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); mrb->exc = mrb_obj_ptr(exc); } } @@ -289,6 +287,9 @@ mrb_exc_set(mrb_state *mrb, mrb_value exc) MRB_API mrb_noreturn void mrb_exc_raise(mrb_state *mrb, mrb_value exc) { + if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) { + mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + } mrb_exc_set(mrb, exc); if (!mrb->gc.out_of_memory) { exc_debug_info(mrb, mrb->exc); diff --git a/test/t/nomethoderror.rb b/test/t/nomethoderror.rb index 1c09bc20e..41a3ba14f 100644 --- a/test/t/nomethoderror.rb +++ b/test/t/nomethoderror.rb @@ -51,3 +51,21 @@ assert('Can still call super when BasicObject#method_missing is removed') do end end end + +assert("NoMethodError#new does not return an exception") do + begin + class << NoMethodError + def new(*) + nil + end + end + + assert_raise(TypeError) do + Object.q + end + ensure + class << NoMethodError + remove_method :new + end + end +end -- cgit v1.2.3 From 3f9450e7b07bea475dc0ceccda55c216a4a8a2c2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 12:56:27 +0900 Subject: Move BasicObject#method_missing to Kernel#method_missing; ref #3417 More compatibility to CRuby. Updated tests that assume old mruby behavior. --- src/class.c | 72 ------------------------------------------------- src/kernel.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ test/t/nomethoderror.rb | 20 +++++++------- 3 files changed, 82 insertions(+), 82 deletions(-) (limited to 'test/t/nomethoderror.rb') diff --git a/src/class.c b/src/class.c index 84cc08a10..0b7521e61 100644 --- a/src/class.c +++ b/src/class.c @@ -1486,77 +1486,6 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv) return mrb_bool_value(!mrb_test(cv)); } -void -mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) -{ - mrb_sym inspect; - mrb_value repr; - - inspect = mrb_intern_lit(mrb, "inspect"); - if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { - /* method missing in inspect; avoid recursion */ - repr = mrb_any_to_s(mrb, self); - } - else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) { - repr = mrb_funcall_argv(mrb, self, inspect, 0, 0); - if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { - repr = mrb_any_to_s(mrb, self); - } - } - else { - repr = mrb_any_to_s(mrb, self); - } - - mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S", - mrb_sym2str(mrb, name), repr); -} - -/* 15.3.1.3.30 */ -/* - * call-seq: - * obj.method_missing(symbol [, *args] ) -> result - * - * Invoked by Ruby when obj is sent a message it cannot handle. - * symbol is the symbol for the method called, and args - * are any arguments that were passed to it. By default, the interpreter - * raises an error when this method is called. However, it is possible - * to override the method to provide more dynamic behavior. - * If it is decided that a particular method should not be handled, then - * super should be called, so that ancestors can pick up the - * missing method. - * The example below creates - * a class Roman, which responds to methods with names - * consisting of roman numerals, returning the corresponding integer - * values. - * - * class Roman - * def romanToInt(str) - * # ... - * end - * def method_missing(methId) - * str = methId.id2name - * romanToInt(str) - * end - * end - * - * r = Roman.new - * r.iv #=> 4 - * r.xxiii #=> 23 - * r.mm #=> 2000 - */ -static mrb_value -mrb_bob_missing(mrb_state *mrb, mrb_value mod) -{ - mrb_sym name; - mrb_value *a; - mrb_int alen; - - mrb_get_args(mrb, "n*", &name, &a, &alen); - mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); - /* not reached */ - return mrb_nil_value(); -} - MRB_API mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid) { @@ -2306,7 +2235,6 @@ mrb_init_class(mrb_state *mrb) MRB_SET_INSTANCE_TT(cls, MRB_TT_CLASS); mrb_define_method(mrb, bob, "initialize", mrb_bob_init, MRB_ARGS_NONE()); mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); - mrb_define_method(mrb, bob, "method_missing", mrb_bob_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ mrb_define_class_method(mrb, cls, "new", mrb_class_new_class, MRB_ARGS_OPT(1)); mrb_define_method(mrb, cls, "superclass", mrb_class_superclass, MRB_ARGS_NONE()); /* 15.2.3.3.4 */ diff --git a/src/kernel.c b/src/kernel.c index 02bb3c99b..fd00d0484 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -963,6 +963,77 @@ mrb_obj_remove_instance_variable(mrb_state *mrb, mrb_value self) return val; } +void +mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args) +{ + mrb_sym inspect; + mrb_value repr; + + inspect = mrb_intern_lit(mrb, "inspect"); + if (mrb->c->ci > mrb->c->cibase && mrb->c->ci[-1].mid == inspect) { + /* method missing in inspect; avoid recursion */ + repr = mrb_any_to_s(mrb, self); + } + else if (mrb_respond_to(mrb, self, inspect) && mrb->c->ci - mrb->c->cibase < 64) { + repr = mrb_funcall_argv(mrb, self, inspect, 0, 0); + if (mrb_string_p(repr) && RSTRING_LEN(repr) > 64) { + repr = mrb_any_to_s(mrb, self); + } + } + else { + repr = mrb_any_to_s(mrb, self); + } + + mrb_no_method_error(mrb, name, args, "undefined method '%S' for %S", + mrb_sym2str(mrb, name), repr); +} + +/* 15.3.1.3.30 */ +/* + * call-seq: + * obj.method_missing(symbol [, *args] ) -> result + * + * Invoked by Ruby when obj is sent a message it cannot handle. + * symbol is the symbol for the method called, and args + * are any arguments that were passed to it. By default, the interpreter + * raises an error when this method is called. However, it is possible + * to override the method to provide more dynamic behavior. + * If it is decided that a particular method should not be handled, then + * super should be called, so that ancestors can pick up the + * missing method. + * The example below creates + * a class Roman, which responds to methods with names + * consisting of roman numerals, returning the corresponding integer + * values. + * + * class Roman + * def romanToInt(str) + * # ... + * end + * def method_missing(methId) + * str = methId.id2name + * romanToInt(str) + * end + * end + * + * r = Roman.new + * r.iv #=> 4 + * r.xxiii #=> 23 + * r.mm #=> 2000 + */ +static mrb_value +mrb_obj_missing(mrb_state *mrb, mrb_value mod) +{ + mrb_sym name; + mrb_value *a; + mrb_int alen; + + mrb_get_args(mrb, "n*", &name, &a, &alen); + mrb_method_missing(mrb, name, mod, mrb_ary_new_from_values(mrb, alen, a)); + /* not reached */ + return mrb_nil_value(); +} + static inline mrb_bool basic_obj_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym id, int pub) { @@ -1199,6 +1270,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "iterator?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.25 */ mrb_define_method(mrb, krn, "kind_of?", mrb_obj_is_kind_of_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.26 */ mrb_define_method(mrb, krn, "local_variables", mrb_local_variables, MRB_ARGS_NONE()); /* 15.3.1.3.28 */ + mrb_define_method(mrb, krn, "method_missing", mrb_obj_missing, MRB_ARGS_ANY()); /* 15.3.1.3.30 */ mrb_define_method(mrb, krn, "methods", mrb_obj_methods_m, MRB_ARGS_OPT(1)); /* 15.3.1.3.31 */ mrb_define_method(mrb, krn, "nil?", mrb_false, MRB_ARGS_NONE()); /* 15.3.1.3.32 */ mrb_define_method(mrb, krn, "object_id", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.33 */ diff --git a/test/t/nomethoderror.rb b/test/t/nomethoderror.rb index 41a3ba14f..35cbdaee9 100644 --- a/test/t/nomethoderror.rb +++ b/test/t/nomethoderror.rb @@ -21,20 +21,20 @@ assert('NoMethodError#args', '15.2.32.2.1') do end end -assert('Can still raise when BasicObject#method_missing is removed') do +assert('Can still raise when Kernel#method_missing is removed') do assert_raise(NoMethodError) do begin - BasicObject.alias_method(:old_method_missing, :method_missing) - BasicObject.remove_method(:method_missing) + Kernel.alias_method(:old_method_missing, :method_missing) + Kernel.remove_method(:method_missing) 1.__send__(:foo) ensure - BasicObject.alias_method(:method_missing, :old_method_missing) - BasicObject.remove_method(:old_method_missing) + Kernel.alias_method(:method_missing, :old_method_missing) + Kernel.remove_method(:old_method_missing) end end end -assert('Can still call super when BasicObject#method_missing is removed') do +assert('Can still call super when Kernel#method_missing is removed') do assert_raise(NoMethodError) do class A def foo @@ -42,12 +42,12 @@ assert('Can still call super when BasicObject#method_missing is removed') do end end begin - BasicObject.alias_method(:old_method_missing, :method_missing) - BasicObject.remove_method(:method_missing) + Kernel.alias_method(:old_method_missing, :method_missing) + Kernel.remove_method(:method_missing) A.new.foo ensure - BasicObject.alias_method(:method_missing, :old_method_missing) - BasicObject.remove_method(:old_method_missing) + Kernel.alias_method(:method_missing, :old_method_missing) + Kernel.remove_method(:old_method_missing) end end end -- cgit v1.2.3