From 0a0cc5a217b577dfadddfb250d5a91ca69978887 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 19 Nov 2018 10:40:07 +0900 Subject: Check method existence for Enumerators; fix #3920 The issue #3920 was fixed but the fundamental flaw of lack of stack depth check along with fibers still remains, even though it's not easy to cause the issue. Use `MRB_GC_FIXED_ARENA` to avoid the issue for workaround. After this patch, `obj.to_enum` raises `ArgumentError` if the object does not respond to the enumerating method. This is incompatible to CRuby but I think this behavior is better and CRuby should be updated to behave like this. --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 3 +++ mrbgems/mruby-enumerator/test/enumerator.rb | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 7ca1d5eb6..dbc7d3004 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -614,6 +614,9 @@ module Kernel # enum.first(4) # => [1, 1, 1, 2] # def to_enum(meth=:each, *args) + unless self.respond_to?(meth) + raise ArgumentError, "undefined method #{meth}" + end Enumerator.new self, meth, *args end alias enum_for to_enum diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 428ea0307..ef4970883 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -22,8 +22,7 @@ assert 'Enumerator.new' do assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) assert_raise(ArgumentError) { Enumerator.new } - enum = @obj.to_enum - assert_raise(NoMethodError) { enum.each {} } + assert_raise(ArgumentError) { @obj.to_enum } # examples fib = Enumerator.new do |y| -- cgit v1.2.3 From afca99a40b8a3415b3a9a0e8fc41c93ddcbb11d8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 20:53:32 +0900 Subject: Remove implicit conversion using `to_int` method. The ISO standard does not include implicit type conversion using `to_int`. This implicit conversion often causes vulnerability. There will be no more attacks like #4120. In addition, we have added internal convenience method `__to_int` which does type check and conversion (from floats). --- include/mruby.h | 1 - mrbgems/mruby-enum-ext/mrblib/enum.rb | 27 +++++-------- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 8 ++-- mrbgems/mruby-enumerator/test/enumerator.rb | 6 --- mrbgems/mruby-kernel-ext/src/kernel.c | 5 +-- mrbgems/mruby-numeric-ext/src/numeric_ext.c | 17 ++++---- mrbgems/mruby-pack/src/pack.c | 6 ++- mrbgems/mruby-random/src/random.c | 12 +++--- mrbgems/mruby-random/test/random.rb | 12 ------ mrbgems/mruby-range-ext/mrblib/range.rb | 5 +-- mrbgems/mruby-string-ext/test/string.rb | 12 ------ mrblib/array.rb | 2 +- src/kernel.c | 2 + src/numeric.c | 4 -- src/object.c | 57 ++++++++------------------- 15 files changed, 51 insertions(+), 125 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/include/mruby.h b/include/mruby.h index 8eff31746..33597101a 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -716,7 +716,6 @@ MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value); * @return [mrb_value] The newly duplicated object. */ MRB_API mrb_value mrb_obj_dup(mrb_state *mrb, mrb_value obj); -MRB_API mrb_value mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method); /** * Returns true if obj responds to the given method. If the method was defined for that diff --git a/mrbgems/mruby-enum-ext/mrblib/enum.rb b/mrbgems/mruby-enum-ext/mrblib/enum.rb index ba92decee..fedf8b1ae 100644 --- a/mrbgems/mruby-enum-ext/mrblib/enum.rb +++ b/mrbgems/mruby-enum-ext/mrblib/enum.rb @@ -13,10 +13,9 @@ module Enumerable # a.drop(3) #=> [4, 5, 0] def drop(n) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "attempt to drop negative size" if n < 0 - n = n.to_int ary = [] self.each {|*val| n == 0 ? ary << val.__svalue : n -= 1 } ary @@ -57,8 +56,8 @@ module Enumerable # a.take(3) #=> [1, 2, 3] def take(n) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) - i = n.to_int + n = n.__to_int + i = n.to_i raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] return ary if i == 0 @@ -113,12 +112,12 @@ module Enumerable # [8, 9, 10] def each_cons(n, &block) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "invalid size" if n <= 0 return to_enum(:each_cons,n) unless block ary = [] - n = n.to_int + n = n.to_i self.each do |*val| ary.shift if ary.size == n ary << val.__svalue @@ -141,12 +140,12 @@ module Enumerable # [10] def each_slice(n, &block) - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) + n = n.__to_int raise ArgumentError, "invalid slice size" if n <= 0 return to_enum(:each_slice,n) unless block ary = [] - n = n.to_int + n = n.to_i self.each do |*val| ary << val.__svalue if ary.size == n @@ -223,9 +222,7 @@ module Enumerable end return nil when 1 - n = args[0] - raise TypeError, "no implicit conversion of #{n.class} into Integer" unless n.respond_to?(:to_int) - i = n.to_int + i = args[0].__to_int raise ArgumentError, "attempt to take negative size" if i < 0 ary = [] return ary if i == 0 @@ -673,13 +670,7 @@ module Enumerable if nv.nil? n = -1 else - unless nv.respond_to?(:to_int) - raise TypeError, "no implicit conversion of #{nv.class} into Integer" - end - n = nv.to_int - unless n.kind_of?(Integer) - raise TypeError, "no implicit conversion of #{nv.class} into Integer" - end + n = nv.__to_int return nil if n <= 0 end diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index dbc7d3004..6dd971f3a 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -157,12 +157,10 @@ class Enumerator def with_index(offset=0, &block) return to_enum :with_index, offset unless block - offset = if offset.nil? - 0 - elsif offset.respond_to?(:to_int) - offset.to_int + if offset.nil? + offset = 0 else - raise TypeError, "no implicit conversion of #{offset.class} into Integer" + offset = offset.__to_int end n = offset - 1 diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index ef4970883..f3bd1bdba 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -54,12 +54,6 @@ assert 'Enumerator#with_index' do assert_equal [[[1, 10], 20], [[2, 11], 21], [[3, 12], 22]], a end -assert 'Enumerator#with_index nonnum offset' do - s = Object.new - def s.to_int; 1 end - assert_equal([[1,1],[2,2],[3,3]], @obj.to_enum(:foo, 1, 2, 3).with_index(s).to_a) -end - assert 'Enumerator#with_index string offset' do assert_raise(TypeError){ @obj.to_enum(:foo, 1, 2, 3).with_index('1').to_a } end diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 32d86376a..a60e9a210 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -93,9 +93,8 @@ mrb_f_method(mrb_state *mrb, mrb_value self) * (0, 0b, and 0x) are honored. * In any case, strings should be strictly conformed to numeric * representation. This behavior is different from that of - * String#to_i. Non string values will be converted using - * to_int, and to_i. Passing nil - * raises a TypeError. + * String#to_i. Non string values will be treated as integers. + * Passing nil raises a TypeError. * * Integer(123.999) #=> 123 * Integer("0x1a") #=> 26 diff --git a/mrbgems/mruby-numeric-ext/src/numeric_ext.c b/mrbgems/mruby-numeric-ext/src/numeric_ext.c index 1d6a07769..cd8bbf187 100644 --- a/mrbgems/mruby-numeric-ext/src/numeric_ext.c +++ b/mrbgems/mruby-numeric-ext/src/numeric_ext.c @@ -2,13 +2,10 @@ #include static inline mrb_int -to_int(mrb_value x) +to_int(mrb_state *mrb, mrb_value x) { - double f; - - if (mrb_fixnum_p(x)) return mrb_fixnum(x); - f = mrb_float(x); - return (mrb_int)f; + x = mrb_to_int(mrb, x); + return mrb_fixnum(x); } /* @@ -28,7 +25,7 @@ mrb_int_chr(mrb_state *mrb, mrb_value x) mrb_int chr; char c; - chr = to_int(x); + chr = to_int(mrb, x); if (chr >= (1 << CHAR_BIT)) { mrb_raisef(mrb, E_RANGE_ERROR, "%S out of char range", x); } @@ -48,8 +45,8 @@ mrb_int_allbits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) == m); } @@ -64,8 +61,8 @@ mrb_int_anybits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) != 0); } @@ -80,8 +77,8 @@ mrb_int_nobits(mrb_state *mrb, mrb_value self) { mrb_int n, m; - n = to_int(self); mrb_get_args(mrb, "i", &m); + n = to_int(mrb, self); return mrb_bool_value((n & m) == 0); } diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 796ba4d34..5caf7b62b 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1124,14 +1124,16 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) o = mrb_ary_ref(mrb, ary, aidx); if (type == PACK_TYPE_INTEGER) { o = mrb_to_int(mrb, o); + } #ifndef MRB_WITHOUT_FLOAT - } else if (type == PACK_TYPE_FLOAT) { + else if (type == PACK_TYPE_FLOAT) { if (!mrb_float_p(o)) { mrb_float f = mrb_to_flo(mrb, o); o = mrb_float_value(mrb, f); } + } #endif - } else if (type == PACK_TYPE_STRING) { + else if (type == PACK_TYPE_STRING) { if (!mrb_string_p(o)) { mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S into String", mrb_class_path(mrb, mrb_obj_class(mrb, o))); } diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index 5b926a228..68209840a 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -79,12 +79,12 @@ get_opt(mrb_state* mrb) mrb_get_args(mrb, "|o", &arg); if (!mrb_nil_p(arg)) { - arg = mrb_check_convert_type(mrb, arg, MRB_TT_FIXNUM, "Fixnum", "to_int"); - if (mrb_nil_p(arg)) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "invalid argument type"); - } - if (mrb_fixnum(arg) < 0) { - arg = mrb_fixnum_value(0 - mrb_fixnum(arg)); + mrb_int i; + + arg = mrb_to_int(mrb, arg); + i = mrb_fixnum(arg); + if (i < 0) { + arg = mrb_fixnum_value(0 - i); } } return arg; diff --git a/mrbgems/mruby-random/test/random.rb b/mrbgems/mruby-random/test/random.rb index 1c59be3a6..1653ae4a6 100644 --- a/mrbgems/mruby-random/test/random.rb +++ b/mrbgems/mruby-random/test/random.rb @@ -74,15 +74,3 @@ assert('Array#shuffle!(random)') do ary1 != [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] and 10.times { |x| ary1.include? x } and ary1 == ary2 end - -assert('Array#sample checks input length after reading arguments') do - $ary = [1, 2, 3] - class ArrayChange - def to_i - $ary << 4 - 4 - end - end - - assert_equal [1, 2, 3, 4], $ary.sample(ArrayChange.new).sort -end diff --git a/mrbgems/mruby-range-ext/mrblib/range.rb b/mrbgems/mruby-range-ext/mrblib/range.rb index e5d1fb079..de7925ba7 100644 --- a/mrbgems/mruby-range-ext/mrblib/range.rb +++ b/mrbgems/mruby-range-ext/mrblib/range.rb @@ -15,10 +15,7 @@ class Range raise ArgumentError, "wrong number of arguments (given #{args.length}, expected 1)" unless args.length == 1 nv = args[0] - raise TypeError, "no implicit conversion from nil to integer" if nv.nil? - raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless nv.respond_to?(:to_int) - n = nv.to_int - raise TypeError, "no implicit conversion of #{nv.class} into Integer" unless n.kind_of?(Integer) + n = nv.__to_int raise ArgumentError, "negative array size (or size too big)" unless 0 <= n ary = [] each do |i| diff --git a/mrbgems/mruby-string-ext/test/string.rb b/mrbgems/mruby-string-ext/test/string.rb index f0f8be6b3..781506949 100644 --- a/mrbgems/mruby-string-ext/test/string.rb +++ b/mrbgems/mruby-string-ext/test/string.rb @@ -31,18 +31,6 @@ assert('String#setbyte') do assert_equal("Hello", str1) end -assert("String#setbyte raises IndexError if arg conversion resizes String") do - $s = "01234\n" - class Tmp - def to_i - $s.chomp! '' - 95 - end - end - tmp = Tmp.new - assert_raise(IndexError) { $s.setbyte(5, tmp) } -end - assert('String#byteslice') do str1 = "hello" assert_equal("e", str1.byteslice(1)) diff --git a/mrblib/array.rb b/mrblib/array.rb index 53d880660..a677b2a1f 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -66,7 +66,7 @@ class Array # # ISO 15.2.12.5.15 def initialize(size=0, obj=nil, &block) - raise TypeError, "expected Integer for 1st argument" unless size.kind_of? Integral + size = size.__to_int raise ArgumentError, "negative array size" if size < 0 self.clear diff --git a/src/kernel.c b/src/kernel.c index db681d510..195594d6b 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -830,6 +830,7 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) } mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); + void mrb_init_kernel(mrb_state *mrb) { @@ -871,6 +872,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "respond_to?", obj_respond_to, MRB_ARGS_ANY()); /* 15.3.1.3.43 */ mrb_define_method(mrb, krn, "to_s", mrb_any_to_s, MRB_ARGS_NONE()); /* 15.3.1.3.46 */ mrb_define_method(mrb, krn, "__case_eqq", mrb_obj_ceqq, MRB_ARGS_REQ(1)); /* internal */ + mrb_define_method(mrb, krn, "__to_int", mrb_to_int, MRB_ARGS_NONE()); /* internal */ mrb_define_method(mrb, krn, "class_defined?", mrb_krn_class_defined, MRB_ARGS_REQ(1)); diff --git a/src/numeric.c b/src/numeric.c index f7f0318e8..3624831cc 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -674,7 +674,6 @@ flo_round(mrb_state *mrb, mrb_value num) /* * call-seq: * flt.to_i -> integer - * flt.to_int -> integer * flt.truncate -> integer * * Returns flt truncated to an Integer. @@ -714,7 +713,6 @@ flo_nan_p(mrb_state *mrb, mrb_value num) /* * call-seq: * int.to_i -> integer - * int.to_int -> integer * * As int is already an Integer, all these * methods simply return the receiver. @@ -1513,7 +1511,6 @@ mrb_init_numeric(mrb_state *mrb) MRB_SET_INSTANCE_TT(integer, MRB_TT_FIXNUM); mrb_undef_class_method(mrb, integer, "new"); mrb_define_method(mrb, integer, "to_i", int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */ - mrb_define_method(mrb, integer, "to_int", int_to_i, MRB_ARGS_NONE()); #ifndef MRB_WITHOUT_FLOAT mrb_define_method(mrb, integer, "ceil", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.8 (x) */ mrb_define_method(mrb, integer, "floor", int_to_i, MRB_ARGS_REQ(1)); /* 15.2.8.3.10 (x) */ @@ -1565,7 +1562,6 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "round", flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */ mrb_define_method(mrb, fl, "to_f", flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */ mrb_define_method(mrb, fl, "to_i", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.14 */ - mrb_define_method(mrb, fl, "to_int", flo_truncate, MRB_ARGS_NONE()); mrb_define_method(mrb, fl, "truncate", flo_truncate, MRB_ARGS_NONE()); /* 15.2.9.3.15 */ mrb_define_method(mrb, fl, "divmod", flo_divmod, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "eql?", flo_eql, MRB_ARGS_REQ(1)); /* 15.2.8.3.16 */ diff --git a/src/object.c b/src/object.c index 8724c5416..ba6fa3947 100644 --- a/src/object.c +++ b/src/object.c @@ -322,19 +322,6 @@ convert_type(mrb_state *mrb, mrb_value val, const char *tname, const char *metho return mrb_funcall_argv(mrb, val, m, 0, 0); } -MRB_API mrb_value -mrb_check_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, FALSE); - if (mrb_nil_p(v) || !mrb_fixnum_p(v)) { - return mrb_nil_value(); - } - return v; -} - MRB_API mrb_value mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char *tname, const char *method) { @@ -505,25 +492,22 @@ mrb_obj_is_kind_of(mrb_state *mrb, mrb_value obj, struct RClass *c) return FALSE; } -static mrb_value -mrb_to_integer(mrb_state *mrb, mrb_value val, const char *method) -{ - mrb_value v; - - if (mrb_fixnum_p(val)) return val; - v = convert_type(mrb, val, "Integer", method, TRUE); - if (!mrb_obj_is_kind_of(mrb, v, mrb->fixnum_class)) { - mrb_value type = inspect_type(mrb, val); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer (%S#%S gives %S)", - type, type, mrb_str_new_cstr(mrb, method), inspect_type(mrb, v)); - } - return v; -} - MRB_API mrb_value mrb_to_int(mrb_state *mrb, mrb_value val) { - return mrb_to_integer(mrb, val, "to_int"); + + if (!mrb_fixnum_p(val)) { + mrb_value type; + +#ifndef MRB_WITHOUT_FLOAT + if (mrb_float_p(val)) { + return mrb_flo_to_fixnum(mrb, val); + } +#endif + type = inspect_type(mrb, val); + mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Integer", type); + } + return val; } MRB_API mrb_value @@ -533,18 +517,12 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) if (mrb_nil_p(val)) { if (base != 0) goto arg_error; - mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); + mrb_raise(mrb, E_TYPE_ERROR, "can't convert nil into Integer"); } switch (mrb_type(val)) { #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: if (base != 0) goto arg_error; - else { - mrb_float f = mrb_float(val); - if (FIXABLE_FLOAT(f)) { - break; - } - } return mrb_flo_to_fixnum(mrb, val); #endif @@ -568,11 +546,8 @@ mrb_convert_to_integer(mrb_state *mrb, mrb_value val, mrb_int base) arg_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "base specified for non string value"); } - tmp = convert_type(mrb, val, "Integer", "to_int", FALSE); - if (mrb_nil_p(tmp) || !mrb_fixnum_p(tmp)) { - tmp = mrb_to_integer(mrb, val, "to_i"); - } - return tmp; + /* to raise TypeError */ + return mrb_to_int(mrb, val); } MRB_API mrb_value -- cgit v1.2.3 From 698f5f707c2db334a15c605bf1b0d0cff42b1224 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 19 Sep 2018 22:19:55 +0900 Subject: Removed `to_ary` conversion method. --- include/mruby/array.h | 1 + mrbgems/mruby-array-ext/mrblib/array.rb | 10 ---------- mrbgems/mruby-array-ext/test/array.rb | 16 ---------------- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 4 +--- mrbgems/mruby-kernel-ext/src/kernel.c | 9 ++------- src/array.c | 27 +++++---------------------- src/class.c | 3 ++- src/object.c | 17 +++++++++++++++++ 8 files changed, 28 insertions(+), 59 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/include/mruby/array.h b/include/mruby/array.h index 6fffe4512..2457f68f2 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -199,6 +199,7 @@ MRB_API void mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val * @param other The array to replace it with. */ MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other); +MRB_API mrb_value mrb_ensure_array_type(mrb_state *mrb, mrb_value self); MRB_API mrb_value mrb_check_array_type(mrb_state *mrb, mrb_value self); /* diff --git a/mrbgems/mruby-array-ext/mrblib/array.rb b/mrbgems/mruby-array-ext/mrblib/array.rb index 54d62e3fd..bb95d70c5 100644 --- a/mrbgems/mruby-array-ext/mrblib/array.rb +++ b/mrbgems/mruby-array-ext/mrblib/array.rb @@ -772,16 +772,6 @@ class Array nil end - ## - # call-seq: - # ary.to_ary -> ary - # - # Returns +self+. - # - def to_ary - self - end - ## # call-seq: # ary.dig(idx, ...) -> object diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index b7467724c..853554bcc 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -331,27 +331,11 @@ assert('Array#to_h') do assert_raise(ArgumentError) { [[1]].to_h } end -assert('Array#to_h (Modified)') do - class A - def to_ary - $a.clear - nil - end - end - $a = [A.new] - assert_raise(TypeError) { $a.to_h } -end - assert("Array#index (block)") do assert_nil (1..10).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } assert_equal 34, (1..100).to_a.index { |i| i % 5 == 0 and i % 7 == 0 } end -assert("Array#to_ary") do - assert_equal [], [].to_ary - assert_equal [1,2,3], [1,2,3].to_ary -end - assert("Array#dig") do h = [[[1]], 0] assert_equal(1, h.dig(0, 0, 0)) diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 6dd971f3a..9d80bc552 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -624,9 +624,7 @@ module Enumerable # use Enumerator to use infinite sequence def zip(*args, &block) args = args.map do |a| - if a.respond_to?(:to_ary) - a.to_ary.to_enum(:each) - elsif a.respond_to?(:each) + if a.respond_to?(:each) a.to_enum(:each) else raise TypeError, "wrong argument type #{a.class} (must respond to :each)" diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index bc2656399..324753f6e 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -161,9 +161,7 @@ mrb_f_string(mrb_state *mrb, mrb_value self) * call-seq: * Array(arg) -> array * - * Returns +arg+ as an Array. - * - * First tries to call Array#to_ary on +arg+, then Array#to_a. + * Returns +arg+ as an Array using to_a method. * * Array(1..5) #=> [1, 2, 3, 4, 5] * @@ -174,10 +172,7 @@ mrb_f_array(mrb_state *mrb, mrb_value self) mrb_value arg, tmp; mrb_get_args(mrb, "o", &arg); - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_ary"); - if (mrb_nil_p(tmp)) { - tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a"); - } + tmp = mrb_check_convert_type(mrb, arg, MRB_TT_ARRAY, "Array", "to_a"); if (mrb_nil_p(tmp)) { return mrb_ary_new_from_values(mrb, 1, &arg); } diff --git a/src/array.c b/src/array.c index eddd9b2ac..084b48dc0 100644 --- a/src/array.c +++ b/src/array.c @@ -1058,7 +1058,7 @@ mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) MRB_API mrb_value mrb_ary_splat(mrb_state *mrb, mrb_value v) { - mrb_value a, recv_class; + mrb_value a; if (mrb_array_p(v)) { return v; @@ -1069,22 +1069,11 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v) } a = mrb_funcall(mrb, v, "to_a", 0); - if (mrb_array_p(a)) { - return a; - } - else if (mrb_nil_p(a)) { + if (mrb_nil_p(a)) { return mrb_ary_new_from_values(mrb, 1, &v); } - else { - recv_class = mrb_obj_value(mrb_obj_class(mrb, v)); - mrb_raisef(mrb, E_TYPE_ERROR, "can't convert %S to Array (%S#to_a gives %S)", - recv_class, - recv_class, - mrb_obj_value(mrb_obj_class(mrb, a)) - ); - /* not reached */ - return mrb_undef_value(); - } + mrb_ensure_array_type(mrb, a); + return a; } static mrb_value @@ -1122,12 +1111,6 @@ mrb_ary_empty_p(mrb_state *mrb, mrb_value self) return mrb_bool_value(ARY_LEN(a) == 0); } -MRB_API mrb_value -mrb_check_array_type(mrb_state *mrb, mrb_value ary) -{ - return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary"); -} - MRB_API mrb_value mrb_ary_entry(mrb_value ary, mrb_int offset) { @@ -1181,7 +1164,7 @@ join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list) val = tmp; goto str_join; } - tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + tmp = mrb_check_array_type(mrb, val); if (!mrb_nil_p(tmp)) { val = tmp; goto ary_join; diff --git a/src/class.c b/src/class.c index 90c73104e..5d6ff4b39 100644 --- a/src/class.c +++ b/src/class.c @@ -520,7 +520,8 @@ to_str(mrb_state *mrb, mrb_value val) static mrb_value to_ary(mrb_state *mrb, mrb_value val) { - return check_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); + CHECK_TYPE(mrb, val, MRB_TT_ARRAY, "Array"); + return val; } static mrb_value diff --git a/src/object.c b/src/object.c index 18ccacfb9..a105c62f0 100644 --- a/src/object.c +++ b/src/object.c @@ -606,6 +606,23 @@ mrb_check_string_type(mrb_state *mrb, mrb_value str) return str; } +MRB_API mrb_value +mrb_ensure_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S cannot be converted to Array", + inspect_type(mrb, ary)); + } + return ary; +} + +MRB_API mrb_value +mrb_check_array_type(mrb_state *mrb, mrb_value ary) +{ + if (!mrb_array_p(ary)) return mrb_nil_value(); + return ary; +} + MRB_API mrb_value mrb_inspect(mrb_state *mrb, mrb_value obj) { -- cgit v1.2.3 From bc03650c6abeb755b769355b703be7f240ae07e5 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 30 Dec 2018 09:46:48 +0900 Subject: mruby-enumerator: Refine accessors (obj/meth/args/fib). - `fib=` writer is not used. - All accessors are used as public (e.g. in `initialized_copy`). --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 9d80bc552..5697c6609 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -128,8 +128,8 @@ class Enumerator @feedvalue = nil @stop_exc = false end - attr_accessor :obj, :meth, :args, :fib - private :obj, :meth, :args, :fib + attr_accessor :obj, :meth, :args + attr_reader :fib def initialize_copy(obj) raise TypeError, "can't copy type #{obj.class}" unless obj.kind_of? Enumerator -- cgit v1.2.3 From 6218585968250ae5a1c0aa17e9cc7f2d2404b40e Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Wed, 30 Jan 2019 19:41:32 +0900 Subject: Remove unneeded `dup` in `Enumerator#initialize` --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 5697c6609..cbf53974a 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -121,7 +121,7 @@ class Enumerator @obj = obj @meth = meth - @args = args.dup + @args = args @fib = nil @dst = nil @lookahead = nil -- cgit v1.2.3 From 2650999092cac630e5bacb0a12c96bc642e939e6 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Thu, 7 Feb 2019 23:52:08 +0900 Subject: Fix `Enumerator#(initialize|inspect)` for `nil`/`false` --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 12 +++++------- mrbgems/mruby-enumerator/test/enumerator.rb | 13 ++++++++----- 2 files changed, 13 insertions(+), 12 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index cbf53974a..143f2b74f 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -109,11 +109,11 @@ class Enumerator # # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] # - def initialize(obj=nil, meth=:each, *args, &block) + def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - else - raise ArgumentError unless obj + elsif obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" end if @obj and !self.respond_to?(meth) raise NoMethodError, "undefined method #{meth}" @@ -221,13 +221,11 @@ class Enumerator end def inspect - return "#<#{self.class}: uninitialized>" unless @obj - if @args && @args.size > 0 args = @args.join(", ") - "#<#{self.class}: #{@obj}:#{@meth}(#{args})>" + "#<#{self.class}: #{@obj.inspect}:#{@meth}(#{args})>" else - "#<#{self.class}: #{@obj}:#{@meth}>" + "#<#{self.class}: #{@obj.inspect}:#{@meth}>" end end diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index f3bd1bdba..0d2a95292 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -21,6 +21,7 @@ assert 'Enumerator.new' do assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) + assert_equal [], Enumerator.new(false, :__id__).to_a assert_raise(ArgumentError) { Enumerator.new } assert_raise(ArgumentError) { @obj.to_enum } @@ -92,11 +93,13 @@ end assert 'Enumerator#inspect' do e = (0..10).each - assert_equal("#", e.inspect) - e = Enumerator.new("FooObject", :foo, 1) - assert_equal("#", e.inspect) - e = Enumerator.new("FooObject", :foo, 1, 2, 3) - assert_equal("#", e.inspect) + assert_equal('#', e.inspect) + e = Enumerator.new('FooObject', :foo, 1) + assert_equal('#', e.inspect) + e = Enumerator.new('FooObject', :foo, 1, 2, 3) + assert_equal('#', e.inspect) + e = Enumerator.new(nil, :to_s) + assert_equal('#', e.inspect) end assert 'Enumerator#each' do -- cgit v1.2.3 From 9ab7c1111bf018ce7acd6ed05eb03843d5c91683 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Feb 2019 09:31:55 +0900 Subject: Update #4265 patch. * Update doc comment to clarify `Enumerator.new` without a block is deprecated and left only for internal use. * Fixed some cases `mruby` raise `ArgumentError` too eagerly compared with `CRuby`. --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 143f2b74f..cecc424e6 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -109,14 +109,22 @@ class Enumerator # # p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] # + # In the second, deprecated, form, a generated Enumerator iterates over the + # given object using the given method with the given arguments passed. This + # form is left only for internal use. + # + # Use of this form is discouraged. Use Kernel#enum_for or Kernel#to_enum + # instead. def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - elsif obj == NONE - raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" - end - if @obj and !self.respond_to?(meth) - raise NoMethodError, "undefined method #{meth}" + else + if obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" + end + if @obj && !self.respond_to?(meth) + raise NoMethodError, "undefined method #{meth}" + end end @obj = obj @@ -610,9 +618,6 @@ module Kernel # enum.first(4) # => [1, 1, 1, 2] # def to_enum(meth=:each, *args) - unless self.respond_to?(meth) - raise ArgumentError, "undefined method #{meth}" - end Enumerator.new self, meth, *args end alias enum_for to_enum -- cgit v1.2.3 From e0bc87297e30f41d9e50299d55696759f11a1ad6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 8 Feb 2019 09:34:31 +0900 Subject: Update `mruby-enumerator` test to conform the last update. --- mrbgems/mruby-enumerator/test/enumerator.rb | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 0d2a95292..57f971fba 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -19,11 +19,8 @@ assert 'Enumerator.new' do assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a - assert_equal [1,2,3], Enumerator.new(@obj, :foo, 1,2,3).to_a assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3) - assert_equal [], Enumerator.new(false, :__id__).to_a assert_raise(ArgumentError) { Enumerator.new } - assert_raise(ArgumentError) { @obj.to_enum } # examples fib = Enumerator.new do |y| @@ -94,11 +91,11 @@ end assert 'Enumerator#inspect' do e = (0..10).each assert_equal('#', e.inspect) - e = Enumerator.new('FooObject', :foo, 1) + e = 'FooObject'.enum_for(:foo, 1) assert_equal('#', e.inspect) - e = Enumerator.new('FooObject', :foo, 1, 2, 3) + e = 'FooObject'.enum_for(:foo, 1, 2, 3) assert_equal('#', e.inspect) - e = Enumerator.new(nil, :to_s) + e = nil.enum_for(:to_s) assert_equal('#', e.inspect) end @@ -422,7 +419,6 @@ end assert 'Kernel#to_enum' do assert_equal Enumerator, [].to_enum.class - assert_raise(ArgumentError){ nil.to_enum } end assert 'modifying existing methods' do -- cgit v1.2.3 From 19740d45a1dc51627076f19578fe837c63de7c25 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Fri, 8 Feb 2019 17:40:12 +0900 Subject: Add `NoMethodError` tests to `mruby-enumerator` --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 9 ++------- mrbgems/mruby-enumerator/test/enumerator.rb | 7 +++++-- 2 files changed, 7 insertions(+), 9 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index cecc424e6..457687268 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -118,13 +118,8 @@ class Enumerator def initialize(obj=NONE, meth=:each, *args, &block) if block obj = Generator.new(&block) - else - if obj == NONE - raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" - end - if @obj && !self.respond_to?(meth) - raise NoMethodError, "undefined method #{meth}" - end + elsif obj == NONE + raise ArgumentError, "wrong number of arguments (given 0, expected 1+)" end @obj = obj diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb index 57f971fba..d609cadb5 100644 --- a/mrbgems/mruby-enumerator/test/enumerator.rb +++ b/mrbgems/mruby-enumerator/test/enumerator.rb @@ -6,11 +6,11 @@ class << @obj end end -assert 'Enumerator' do +assert 'Enumerator.class' do assert_equal Class, Enumerator.class end -assert 'Enumerator' do +assert 'Enumerator.superclass' do assert_equal Object, Enumerator.superclass end @@ -418,7 +418,10 @@ assert 'nested iteration' do end assert 'Kernel#to_enum' do + e = nil assert_equal Enumerator, [].to_enum.class + assert_nothing_raised { e = [].to_enum(:_not_implemented_) } + assert_raise(NoMethodError) { e.first } end assert 'modifying existing methods' do -- cgit v1.2.3 From cdb458ed4e07698ecb028bfe397fa273ed454e13 Mon Sep 17 00:00:00 2001 From: KOBAYASHI Shuji Date: Sun, 21 Apr 2019 20:34:39 +0900 Subject: Commented out `String#scan` because it is not implemented yet --- mrbgems/mruby-enumerator/mrblib/enumerator.rb | 7 ++++--- mrblib/string.rb | 21 +++++++++------------ test/t/string.rb | 4 +++- 3 files changed, 16 insertions(+), 16 deletions(-) (limited to 'mrbgems/mruby-enumerator') diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb index 457687268..89472ef01 100644 --- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb +++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb @@ -244,9 +244,10 @@ class Enumerator # # === Examples # - # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"] - # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"] + # Array.new(3) #=> [nil, nil, nil] + # Array.new(3) { |i| i } #=> [0, 1, 2] + # Array.to_enum(:new, 3).to_a #=> [0, 1, 2] + # Array.to_enum(:new).each(3).to_a #=> [0, 1, 2] # # obj = Object.new # diff --git a/mrblib/string.rb b/mrblib/string.rb index e9eb2be1d..c92a9e7be 100644 --- a/mrblib/string.rb +++ b/mrblib/string.rb @@ -105,18 +105,15 @@ class String self.replace(str) end - ## - # Calls the given block for each match of +pattern+ - # If no block is given return an array with all - # matches of +pattern+. - # - # ISO 15.2.10.5.32 - def scan(reg, &block) - ### *** TODO *** ### - unless Object.const_defined?(:Regexp) - raise NotImplementedError, "scan not available (yet)" - end - end +# ## +# # Calls the given block for each match of +pattern+ +# # If no block is given return an array with all +# # matches of +pattern+. +# # +# # ISO 15.2.10.5.32 +# def scan(pattern, &block) +# # TODO: String#scan is not implemented yet +# end ## # Replace only the first match of +pattern+ with diff --git a/test/t/string.rb b/test/t/string.rb index 404cf03e1..e563db55a 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -509,7 +509,9 @@ assert('String#rindex(UTF-8)', '15.2.10.5.31') do assert_equal nil, str.index("さ") end if UTF8STRING -# 'String#scan', '15.2.10.5.32' will be tested in mrbgems. +# assert('String#scan', '15.2.10.5.32') do +# # Not implemented yet +# end assert('String#size', '15.2.10.5.33') do assert_equal 3, 'abc'.size -- cgit v1.2.3