From efe4f30b3982e8ff85a9142933955d6fa0bdebc7 Mon Sep 17 00:00:00 2001 From: ksss Date: Wed, 12 Oct 2016 22:05:14 +0900 Subject: Module#define_method supports proc argument --- src/class.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 47a6c846b..00fc9c12e 100644 --- a/src/class.c +++ b/src/class.c @@ -1773,9 +1773,21 @@ mod_define_method(mrb_state *mrb, mrb_value self) struct RClass *c = mrb_class_ptr(self); struct RProc *p; mrb_sym mid; + mrb_value proc = mrb_undef_value(); mrb_value blk; - mrb_get_args(mrb, "n&", &mid, &blk); + mrb_get_args(mrb, "n|o&", &mid, &proc, &blk); + switch (mrb_type(proc)) { + case MRB_TT_PROC: + blk = proc; + break; + case MRB_TT_UNDEF: + /* ignored */ + break; + default: + mrb_raisef(mrb, E_TYPE_ERROR, "wrong argument type %S (expected Proc)", mrb_obj_value(mrb_obj_class(mrb, proc))); + break; + } if (mrb_nil_p(blk)) { mrb_raise(mrb, E_ARGUMENT_ERROR, "no block given"); } -- cgit v1.2.3 From e3c8092ccdd3a9991ccd31634e28e9a5a0e29d91 Mon Sep 17 00:00:00 2001 From: Felix Jones Date: Thu, 10 Nov 2016 19:51:56 +0000 Subject: Renamed class_under_defined to class_defined_under --- include/mruby.h | 8 ++++---- src/class.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 886b15e50..1b227d41a 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -578,10 +578,10 @@ MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name); * example_outer = mrb_define_module(mrb, "ExampleOuter"); * * example_inner = mrb_define_class_under(mrb, example_outer, "ExampleInner", mrb->object_class); - * cd = mrb_class_under_defined(mrb, example_outer, "ExampleInner"); + * cd = mrb_class_defined_under(mrb, example_outer, "ExampleInner"); * - * // If mrb_class_under_defined returns 1 then puts "True" - * // If mrb_class_under_defined returns 0 then puts "False" + * // If mrb_class_defined_under returns 1 then puts "True" + * // If mrb_class_defined_under returns 0 then puts "False" * if (cd == 1){ * puts("True"); * } @@ -595,7 +595,7 @@ MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name); * @param [const char *] name A string representing the name of the inner class. * @return [mrb_bool] A boolean value. */ -MRB_API mrb_bool mrb_class_under_defined(mrb_state *mrb, struct RClass *outer, const char *name); +MRB_API mrb_bool mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name); /** * Gets a child class. diff --git a/src/class.c b/src/class.c index ed2e5d5ba..b81859ab8 100644 --- a/src/class.c +++ b/src/class.c @@ -272,7 +272,7 @@ mrb_class_defined(mrb_state *mrb, const char *name) } MRB_API mrb_bool -mrb_class_under_defined(mrb_state *mrb, struct RClass *outer, const char *name) +mrb_class_defined_under(mrb_state *mrb, struct RClass *outer, const char *name) { mrb_value sym = mrb_check_intern_cstr(mrb, name); if (mrb_nil_p(sym)) { -- cgit v1.2.3 From 88604e39ac9c25ffdad2e3f03be26516fe866038 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 12 Nov 2016 05:23:05 +0900 Subject: Hash#[] to call Hash#default --- src/hash.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 2ad6a9642..015b2d614 100644 --- a/src/hash.c +++ b/src/hash.c @@ -173,10 +173,8 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) /* not found */ if (MRB_RHASH_DEFAULT_P(hash)) { - if (MRB_RHASH_PROCDEFAULT_P(hash)) { - return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); - } - return RHASH_IFNONE(hash); + /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ + return mrb_funcall(mrb, hash, "default", 1, key); } return mrb_nil_value(); } @@ -385,13 +383,16 @@ mrb_hash_default(mrb_state *mrb, mrb_value hash) mrb_bool given; mrb_get_args(mrb, "|o?", &key, &given); - if (MRB_RHASH_PROCDEFAULT_P(hash)) { - if (!given) return mrb_nil_value(); - return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); - } - else { - return RHASH_IFNONE(hash); + if (MRB_RHASH_DEFAULT_P(hash)) { + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + if (!given) return mrb_nil_value(); + return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); + } + else { + return RHASH_IFNONE(hash); + } } + return mrb_nil_value(); } /* 15.2.13.4.6 */ -- cgit v1.2.3 From 1422e5763005e50ce5f7874910e1a130a12091c9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 13 Nov 2016 16:12:13 +0900 Subject: move mrb_str_dup() to mrb_class_path; ref #2470 Class#to_s used to return same string repeatedly, that mean you can modify "class name" by modifying the return value from Class#to_s. --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 7097a593a..d044cb68a 100644 --- a/src/class.c +++ b/src/class.c @@ -1539,7 +1539,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) } mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path); } - return path; + return mrb_str_dup(mrb, path); } MRB_API struct RClass * -- cgit v1.2.3 From 4f6cce059b317f7e6c1da801fe0edd487985df6e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 15 Nov 2016 04:15:24 +0900 Subject: class/module statement should re-open; fix #3225 --- src/class.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'src') diff --git a/src/class.c b/src/class.c index d044cb68a..e5d60a693 100644 --- a/src/class.c +++ b/src/class.c @@ -174,6 +174,14 @@ MRB_API struct RClass* mrb_vm_define_module(mrb_state *mrb, mrb_value outer, mrb_sym id) { check_if_class_or_module(mrb, outer); + if (mrb_const_defined_at(mrb, outer, id)) { + mrb_value old = mrb_const_get(mrb, outer, id); + + if (mrb_type(old) != MRB_TT_MODULE) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a module", mrb_inspect(mrb, old)); + } + return mrb_class_ptr(old); + } return define_module(mrb, id, mrb_class_ptr(outer)); } @@ -255,6 +263,21 @@ mrb_vm_define_class(mrb_state *mrb, mrb_value outer, mrb_value super, mrb_sym id s = 0; } check_if_class_or_module(mrb, outer); + if (mrb_const_defined_at(mrb, outer, id)) { + mrb_value old = mrb_const_get(mrb, outer, id); + + if (mrb_type(old) != MRB_TT_CLASS) { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a class", mrb_inspect(mrb, old)); + } + c = mrb_class_ptr(old); + if (s) { + /* check super class */ + if (mrb_class_real(c->super) != s) { + mrb_raisef(mrb, E_TYPE_ERROR, "superclass mismatch for class %S", old); + } + } + return c; + } c = define_class(mrb, id, s, mrb_class_ptr(outer)); mrb_class_inherited(mrb, mrb_class_real(c->super), c); -- cgit v1.2.3 From 739dad6e87e91c74cda794ae3f33cd94a7c33eb1 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 16 Nov 2016 01:29:04 +0900 Subject: Fixed a memory problem in Array#to_h Reported from Alex Snaps via Mathieu Leduc-Hamel, both from shopify.com. Thank you! --- include/mruby/array.h | 9 +++++++++ mrbgems/mruby-array-ext/src/array.c | 2 +- mrbgems/mruby-array-ext/test/array.rb | 11 +++++++++++ src/array.c | 9 --------- 4 files changed, 21 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/mruby/array.h b/include/mruby/array.h index bd78db066..8f9d5d502 100644 --- a/include/mruby/array.h +++ b/include/mruby/array.h @@ -134,6 +134,15 @@ mrb_ary_len(mrb_state *mrb, mrb_value ary) return RARRAY_LEN(ary); } +static inline mrb_value +ary_elt(mrb_value ary, mrb_int offset) +{ + if (offset < 0 || RARRAY_LEN(ary) <= offset) { + return mrb_nil_value(); + } + return RARRAY_PTR(ary)[offset]; +} + MRB_END_DECL #endif /* MRUBY_ARRAY_H */ diff --git a/mrbgems/mruby-array-ext/src/array.c b/mrbgems/mruby-array-ext/src/array.c index d5c96e2cc..af947303b 100644 --- a/mrbgems/mruby-array-ext/src/array.c +++ b/mrbgems/mruby-array-ext/src/array.c @@ -131,7 +131,7 @@ mrb_ary_to_h(mrb_state *mrb, mrb_value ary) if (mrb_nil_p(v)) { mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)", - mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, RARRAY_PTR(ary)[i])), + mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, ary_elt(ary, i))), mrb_fixnum_value(i) ); } diff --git a/mrbgems/mruby-array-ext/test/array.rb b/mrbgems/mruby-array-ext/test/array.rb index ec1528fc3..09ec8d9e7 100644 --- a/mrbgems/mruby-array-ext/test/array.rb +++ b/mrbgems/mruby-array-ext/test/array.rb @@ -301,6 +301,17 @@ 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 } diff --git a/src/array.c b/src/array.c index df953832b..e8882b7a3 100644 --- a/src/array.c +++ b/src/array.c @@ -16,15 +16,6 @@ #define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value)) #define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1) -static inline mrb_value -ary_elt(mrb_value ary, mrb_int offset) -{ - if (offset < 0 || RARRAY_LEN(ary) <= offset) { - return mrb_nil_value(); - } - return RARRAY_PTR(ary)[offset]; -} - static struct RArray* ary_new_capa(mrb_state *mrb, mrb_int capa) { -- cgit v1.2.3 From 1f554ff8540d61e30d0e649bf80c0ecd27b40ad6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 16 Nov 2016 02:10:44 +0900 Subject: Fixed rindex calling into mrb_equal bug Fixed by Alex Snaps and reported by Mathieu Leduc-Hamel, both from shopify.com. Thank you! --- src/array.c | 5 ++++- test/t/array.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index e8882b7a3..5a319d809 100644 --- a/src/array.c +++ b/src/array.c @@ -868,13 +868,16 @@ static mrb_value mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) { mrb_value obj; - mrb_int i; + mrb_int i, len; mrb_get_args(mrb, "o", &obj); for (i = RARRAY_LEN(self) - 1; i >= 0; i--) { if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { return mrb_fixnum_value(i); } + if (i > (len = RARRAY_LEN(self))) { + i = len; + } } return mrb_nil_value(); } diff --git a/test/t/array.rb b/test/t/array.rb index 538ea0c3f..d887c117b 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -347,3 +347,15 @@ assert("Array (Longish inline array)") do ary.each {|p| h[p.class] += 1} assert_equal({Array=>200}, h) end + +assert("Array#rindex") do + class Sneaky + def ==(*) + $a.clear + $a.replace([1]) + false + end + end + $a = [2, 3, 4, 5, 6, 7, 8, 9, 10, Sneaky.new] + assert_equal 0, $a.rindex(1) +end -- cgit v1.2.3 From 8e0dc6fa8db54d43d6d0dc4b81751cc3db06ebf0 Mon Sep 17 00:00:00 2001 From: Tomasz Dąbrowski Date: Wed, 16 Nov 2016 15:45:47 +0100 Subject: Correct argument specifications for few methods: - Struct#values_at - Module#define_method - String#chop - String#chop! --- mrbgems/mruby-struct/src/struct.c | 2 +- src/class.c | 2 +- src/string.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-struct/src/struct.c b/mrbgems/mruby-struct/src/struct.c index 1a06e0c12..0ccb7f4cb 100644 --- a/mrbgems/mruby-struct/src/struct.c +++ b/mrbgems/mruby-struct/src/struct.c @@ -703,7 +703,7 @@ mrb_mruby_struct_gem_init(mrb_state* mrb) mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE()); mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE()); mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE()); - mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_NONE()); + mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_ANY()); } void diff --git a/src/class.c b/src/class.c index e5d60a693..4fc81689b 100644 --- a/src/class.c +++ b/src/class.c @@ -2287,7 +2287,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, mod, "constants", mrb_mod_constants, MRB_ARGS_OPT(1)); /* 15.2.2.4.24 */ mrb_define_method(mrb, mod, "remove_const", mrb_mod_remove_const, MRB_ARGS_REQ(1)); /* 15.2.2.4.40 */ mrb_define_method(mrb, mod, "const_missing", mrb_mod_const_missing, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, mod, "define_method", mod_define_method, MRB_ARGS_ARG(1,1)); mrb_define_method(mrb, mod, "class_variables", mrb_mod_class_variables, MRB_ARGS_NONE()); /* 15.2.2.4.19 */ mrb_define_method(mrb, mod, "===", mrb_mod_eqq, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, mod, "constants", mrb_mod_s_constants, MRB_ARGS_ANY()); /* 15.2.2.3.1 */ diff --git a/src/string.c b/src/string.c index 15fcc502a..8c46da2bf 100644 --- a/src/string.c +++ b/src/string.c @@ -2723,8 +2723,8 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "capitalize!", mrb_str_capitalize_bang, MRB_ARGS_NONE()); /* 15.2.10.5.8 */ mrb_define_method(mrb, s, "chomp", mrb_str_chomp, MRB_ARGS_ANY()); /* 15.2.10.5.9 */ mrb_define_method(mrb, s, "chomp!", mrb_str_chomp_bang, MRB_ARGS_ANY()); /* 15.2.10.5.10 */ - mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_REQ(1)); /* 15.2.10.5.11 */ - mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_REQ(1)); /* 15.2.10.5.12 */ + mrb_define_method(mrb, s, "chop", mrb_str_chop, MRB_ARGS_NONE()); /* 15.2.10.5.11 */ + mrb_define_method(mrb, s, "chop!", mrb_str_chop_bang, MRB_ARGS_NONE()); /* 15.2.10.5.12 */ mrb_define_method(mrb, s, "downcase", mrb_str_downcase, MRB_ARGS_NONE()); /* 15.2.10.5.13 */ mrb_define_method(mrb, s, "downcase!", mrb_str_downcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.14 */ mrb_define_method(mrb, s, "empty?", mrb_str_empty_p, MRB_ARGS_NONE()); /* 15.2.10.5.16 */ -- cgit v1.2.3 From 176d93d72a9322f7f8e41aea0b06a857b7ba23aa Mon Sep 17 00:00:00 2001 From: ksss Date: Thu, 17 Nov 2016 14:57:30 +0900 Subject: Ranges should not rewrite --- src/range.c | 3 +++ test/t/range.rb | 2 ++ 2 files changed, 5 insertions(+) (limited to 'src') diff --git a/src/range.c b/src/range.c index 079a1035e..41b41237c 100644 --- a/src/range.c +++ b/src/range.c @@ -129,6 +129,9 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) exclusive = FALSE; } /* Ranges are immutable, so that they should be initialized only once. */ + if (mrb_range_ptr(range)->edges) { + mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); + } range_init(mrb, range, beg, end, exclusive); return range; } diff --git a/test/t/range.rb b/test/t/range.rb index 278b26902..c542c8f06 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -57,6 +57,8 @@ assert('Range#initialize', '15.2.14.4.9') do assert_true a.exclude_end? assert_equal (1..10), b assert_false b.exclude_end? + + assert_raise(NameError) { (0..1).send(:initialize, 1, 3) } end assert('Range#last', '15.2.14.4.10') do -- cgit v1.2.3 From 4cca8bac6bbdab02eba11e6527f793f2e9a5e75d Mon Sep 17 00:00:00 2001 From: Tomasz Dąbrowski Date: Wed, 16 Nov 2016 17:43:55 +0100 Subject: inline structures data type for mruby (MRB_TT_INLINE) (fix #3237) Inline structures have no instance variables, no finalizer, and offer as much space as possible in RBASIC object. This means 24 bytes on 64-bit platforms and 12 bytes on 32-bit platforms. mruby-inline-struct gem is only provided for testing. --- include/mruby/inline.h | 47 +++++++++ include/mruby/value.h | 3 +- mrbgems/default.gembox | 3 + mrbgems/mruby-inline-struct/mrbgem.rake | 5 + mrbgems/mruby-inline-struct/test/inline.c | 83 ++++++++++++++++ mrbgems/mruby-inline-struct/test/inline.rb | 151 +++++++++++++++++++++++++++++ src/class.c | 20 ++++ src/etc.c | 1 + src/kernel.c | 4 + src/object.c | 4 +- 10 files changed, 318 insertions(+), 3 deletions(-) create mode 100644 include/mruby/inline.h create mode 100644 mrbgems/mruby-inline-struct/mrbgem.rake create mode 100644 mrbgems/mruby-inline-struct/test/inline.c create mode 100644 mrbgems/mruby-inline-struct/test/inline.rb (limited to 'src') diff --git a/include/mruby/inline.h b/include/mruby/inline.h new file mode 100644 index 000000000..e773aa118 --- /dev/null +++ b/include/mruby/inline.h @@ -0,0 +1,47 @@ +/* +** mruby/inline.h - Inline structures +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_INLINE_H +#define MRUBY_INLINE_H + +#include "common.h" +#include + +/** + * Inline structures that fit in RVALUE + * + * They cannot have finalizer, and cannot have instance variables. + */ +MRB_BEGIN_DECL + +#define INLINE_DATA_SIZE (sizeof(void*) * 3) + +struct RInline { + MRB_OBJECT_HEADER; + char inline_data[INLINE_DATA_SIZE]; +}; + +#define RINLINE(obj) ((struct RInline*)(mrb_ptr(obj))) +#define INLINE_PTR(obj) (RINLINE(obj)->inline_data) + +MRB_INLINE mrb_int mrb_inline_size() +{ + return INLINE_DATA_SIZE; +} + +MRB_INLINE void* mrb_inline_ptr(mrb_value object) +{ + return INLINE_PTR(object); +} + +MRB_INLINE void mrb_inline_copy(mrb_value dest, mrb_value src) +{ + memcpy(INLINE_PTR(dest), INLINE_PTR(src), INLINE_DATA_SIZE); +} + +MRB_END_DECL + +#endif /* MRUBY_INLINE_H */ diff --git a/include/mruby/value.h b/include/mruby/value.h index 4330b9441..eb3f931e1 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -116,7 +116,8 @@ enum mrb_vtype { MRB_TT_ENV, /* 20 */ MRB_TT_DATA, /* 21 */ MRB_TT_FIBER, /* 22 */ - MRB_TT_MAXDEFINE /* 23 */ + MRB_TT_INLINE, /* 23 */ + MRB_TT_MAXDEFINE /* 24 */ }; #include diff --git a/mrbgems/default.gembox b/mrbgems/default.gembox index dab7230aa..e3bd114f3 100644 --- a/mrbgems/default.gembox +++ b/mrbgems/default.gembox @@ -74,6 +74,9 @@ MRuby::GemBox.new do |conf| # Use class/module extension conf.gem :core => "mruby-class-ext" + # Use inline struct + conf.gem :core => "mruby-inline-struct" + # Use mruby-compiler to build other mrbgems conf.gem :core => "mruby-compiler" end diff --git a/mrbgems/mruby-inline-struct/mrbgem.rake b/mrbgems/mruby-inline-struct/mrbgem.rake new file mode 100644 index 000000000..91ad9f44b --- /dev/null +++ b/mrbgems/mruby-inline-struct/mrbgem.rake @@ -0,0 +1,5 @@ +MRuby::Gem::Specification.new('mruby-inline-struct') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'inline structure' +end diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c new file mode 100644 index 000000000..903c08aca --- /dev/null +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +static mrb_value +inline_test_initialize(mrb_state *mrb, mrb_value self) +{ + char *string = mrb_inline_ptr(self); + mrb_int size = mrb_inline_size(); + mrb_value object; + mrb_get_args(mrb, "o", &object); + + if (mrb_float_p(object)) + { + snprintf(string, size, "float(%.3f)", mrb_float(object)); + } + else if (mrb_fixnum_p(object)) + { + snprintf(string, size, "fixnum(%d)", mrb_fixnum(object)); + } + else if (mrb_string_p(object)) + { + snprintf(string, size, "string(%s)", mrb_string_value_cstr(mrb, &object)); + } + + string[size - 1] = 0; // force NULL at the end + return self; +} + +static mrb_value +inline_test_to_s(mrb_state *mrb, mrb_value self) +{ + return mrb_str_new_cstr(mrb, mrb_inline_ptr(self)); +} + +static mrb_value +inline_test_length(mrb_state *mrb, mrb_value self) +{ + return mrb_fixnum_value(mrb_inline_size()); +} + +static mrb_value +inline_test_test_receive(mrb_state *mrb, mrb_value self) +{ + mrb_value object; + mrb_get_args(mrb, "o", &object); + if (mrb_obj_class(mrb, object) != mrb_class_get(mrb, "InlineStructTest")) + { + mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); + } + return mrb_bool_value(((char*)mrb_inline_ptr(object))[0] == 's'); +} + +static mrb_value +inline_test_test_receive_direct(mrb_state *mrb, mrb_value self) +{ + char *ptr; + mrb_get_args(mrb, "I", &ptr); + return mrb_bool_value(ptr[0] == 's'); +} + +static mrb_value +inline_test_mutate(mrb_state *mrb, mrb_value self) +{ + char *ptr = mrb_inline_ptr(self); + memcpy(ptr, "mutate", 6); + return mrb_nil_value(); +} + +void mrb_mruby_inline_struct_gem_test(mrb_state *mrb) +{ + struct RClass *cls; + + cls = mrb_define_class(mrb, "InlineStructTest", mrb->object_class); + MRB_SET_INSTANCE_TT(cls, MRB_TT_INLINE); + mrb_define_method(mrb, cls, "initialize", inline_test_initialize, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cls, "to_s", inline_test_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, cls, "mutate", inline_test_mutate, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "length", inline_test_length, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "test_receive", inline_test_test_receive, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, cls, "test_receive_direct", inline_test_test_receive_direct, MRB_ARGS_REQ(1)); +} diff --git a/mrbgems/mruby-inline-struct/test/inline.rb b/mrbgems/mruby-inline-struct/test/inline.rb new file mode 100644 index 000000000..495859232 --- /dev/null +++ b/mrbgems/mruby-inline-struct/test/inline.rb @@ -0,0 +1,151 @@ +## +# InlineStruct Test + +class InlineStructTest + def extra_method + :ok + end + + def test_ivar_set + @var = :ivar + end + + def test_ivar_get + @vat + end +end + +assert('InlineStructTest#dup') do + obj = InlineStructTest.new(1) + assert_equal obj.to_s, 'fixnum(1)' + assert_equal obj.dup.to_s, 'fixnum(1)' +end + +assert('InlineStructTest#clone') do + obj = InlineStructTest.new(1) + assert_equal obj.to_s, 'fixnum(1)' + assert_equal obj.clone.to_s, 'fixnum(1)' +end + +assert('InlineStruct#object_id') do + obj1 = InlineStructTest.new(1) + obj2 = InlineStructTest.new(1) + assert_not_equal obj1, obj2 + assert_not_equal obj1.object_id, obj2.object_id + assert_not_equal obj1.object_id, obj1.dup.object_id + assert_not_equal obj1.object_id, obj1.clone.object_id +end + +assert('InlineStructTest#mutate (dup)') do + obj1 = InlineStructTest.new("foo") + assert_equal obj1.to_s, "string(foo)" + obj2 = obj1.dup + assert_equal obj2.to_s, "string(foo)" + obj1.mutate + assert_equal obj1.to_s, "mutate(foo)" + assert_equal obj2.to_s, "string(foo)" +end + +assert('InlineStructTest#mutate (clone)') do + obj1 = InlineStructTest.new("foo") + assert_equal obj1.to_s, "string(foo)" + obj2 = obj1.clone + assert_equal obj2.to_s, "string(foo)" + obj1.mutate + assert_equal obj1.to_s, "mutate(foo)" + assert_equal obj2.to_s, "string(foo)" +end + +assert('InlineStructTest#test_receive(string)') do + assert_equal InlineStructTest.test_receive(InlineStructTest.new('a')), true +end + +assert('InlineStructTest#test_receive(float)') do + assert_equal InlineStructTest.test_receive(InlineStructTest.new(1.25)), false +end + +assert('InlineStructTest#test_receive(invalid object)') do + assert_raise(TypeError) do + InlineStructTest.test_receive([]) + end +end + +assert('InlineStructTest#test_receive(string)') do + assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new('a')), true +end + +assert('InlineStructTest#test_receive(float)') do + assert_equal InlineStructTest.test_receive_direct(InlineStructTest.new(1.25)), false +end + +assert('InlineStructTest#test_receive(invalid object)') do + assert_raise(TypeError) do + InlineStructTest.test_receive_direct([]) + end +end + +assert('InlineStructTest#extra_method') do + assert_equal InlineStructTest.new(1).extra_method, :ok +end + +assert('InlineStructTest instance variable') do + obj = InlineStructTest.new(1) + assert_raise(ArgumentError) do + obj.test_ivar_set + end + assert_equal obj.test_ivar_get, nil +end + +# 64-bit mode +if InlineStructTest.length == 24 + assert('InlineStructTest length [64 bit]') do + assert_equal InlineStructTest.length, 3 * 8 + end + + assert('InlineStructTest w/float [64 bit]') do + obj = InlineStructTest.new(1.25) + assert_equal obj.to_s, "float(1.250)" + end + + assert('InlineStructTest w/fixnum [64 bit]') do + obj = InlineStructTest.new(42) + assert_equal obj.to_s, "fixnum(42)" + end + + assert('InlineStructTest w/string [64 bit]') do + obj = InlineStructTest.new("hello") + assert_equal obj.to_s, "string(hello)" + end + + assert('InlineStructTest w/long string [64 bit]') do + obj = InlineStructTest.new("this won't fit in 3 * 8 bytes available for the structure") + assert_equal obj.to_s, "string(this won't fit i" + end +end + +# 32-bit mode +if InlineStructTest.length == 12 + assert('InlineStructTest length [32 bit]') do + assert_equal InlineStructTest.length, 3 * 4 + end + + assert('InlineStructTest w/float [32 bit]') do + obj = InlineStructTest.new(1.25) + assert_equal obj.to_s, "float(1.250" + end + + assert('InlineStructTest w/fixnum [32 bit]') do + obj = InlineStructTest.new(42) + assert_equal obj.to_s, "fixnum(42)" + end + + assert('InlineStructTest w/string [32 bit]') do + obj = InlineStructTest.new("hello") + assert_equal obj.to_s, "string(hell" + end + + assert('InlineStructTest w/long string [32 bit]') do + obj = InlineStructTest.new("this won't fit in 3 * 4 bytes available for the structure") + assert_equal obj.to_s, "string(this" + end +end diff --git a/src/class.c b/src/class.c index 4fc81689b..53354d02a 100644 --- a/src/class.c +++ b/src/class.c @@ -14,6 +14,7 @@ #include #include #include +#include KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -491,6 +492,7 @@ to_sym(mrb_state *mrb, mrb_value ss) b: Boolean [mrb_bool] n: Symbol [mrb_sym] d: Data [void*,mrb_data_type const] 2nd argument will be used to check data type so it won't be modified + I: Inline struct [void*] &: Block [mrb_value] *: rest argument [mrb_value*,mrb_int] Receive the rest of the arguments as an array. |: optional Next argument of '|' and later are optional. @@ -702,6 +704,24 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } break; + case 'I': + { + void* *p; + mrb_value ss; + + p = va_arg(ap, void**); + if (i < argc) { + ss = ARGV[arg_i]; + if (mrb_type(ss) != MRB_TT_INLINE) + { + mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); + } + *p = mrb_inline_ptr(ss); + arg_i++; + i++; + } + } + break; case 'f': { mrb_float *p; diff --git a/src/etc.c b/src/etc.c index 183e2f070..c89549da6 100644 --- a/src/etc.c +++ b/src/etc.c @@ -139,6 +139,7 @@ mrb_obj_id(mrb_value obj) case MRB_TT_EXCEPTION: case MRB_TT_FILE: case MRB_TT_DATA: + case MRB_TT_INLINE: default: return MakeID(mrb_ptr(obj)); } diff --git a/src/kernel.c b/src/kernel.c index df237cd46..4a4b6b414 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -11,6 +11,7 @@ #include #include #include +#include typedef enum { NOEX_PUBLIC = 0x00, @@ -301,6 +302,9 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) case MRB_TT_EXCEPTION: mrb_iv_copy(mrb, dest, obj); break; + case MRB_TT_INLINE: + mrb_inline_copy(dest, obj); + break; default: break; diff --git a/src/object.c b/src/object.c index bb1a4ebc4..af66d93d0 100644 --- a/src/object.c +++ b/src/object.c @@ -348,7 +348,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const { mrb_value v; - if (mrb_type(val) == type && type != MRB_TT_DATA) return val; + if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_INLINE) return val; v = convert_type(mrb, val, tname, method, FALSE); if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value(); return v; @@ -390,7 +390,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) enum mrb_vtype xt; xt = mrb_type(x); - if ((xt != t) || (xt == MRB_TT_DATA)) { + if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_INLINE)) { while (type->type < MRB_TT_MAXDEFINE) { if (type->type == t) { const char *etype; -- cgit v1.2.3 From 8438792d27bac2a236d5eef9824d36f815c0472f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 17 Nov 2016 17:12:11 +0900 Subject: renamed "inline" to "istruct" to represent inline struct; ref #3251 --- include/mruby/inline.h | 47 ------------------------------- include/mruby/istruct.h | 47 +++++++++++++++++++++++++++++++ include/mruby/value.h | 2 +- mrbgems/mruby-inline-struct/test/inline.c | 40 +++++++++++++------------- src/class.c | 6 ++-- src/etc.c | 2 +- src/kernel.c | 6 ++-- src/object.c | 4 +-- 8 files changed, 77 insertions(+), 77 deletions(-) delete mode 100644 include/mruby/inline.h create mode 100644 include/mruby/istruct.h (limited to 'src') diff --git a/include/mruby/inline.h b/include/mruby/inline.h deleted file mode 100644 index e773aa118..000000000 --- a/include/mruby/inline.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -** mruby/inline.h - Inline structures -** -** See Copyright Notice in mruby.h -*/ - -#ifndef MRUBY_INLINE_H -#define MRUBY_INLINE_H - -#include "common.h" -#include - -/** - * Inline structures that fit in RVALUE - * - * They cannot have finalizer, and cannot have instance variables. - */ -MRB_BEGIN_DECL - -#define INLINE_DATA_SIZE (sizeof(void*) * 3) - -struct RInline { - MRB_OBJECT_HEADER; - char inline_data[INLINE_DATA_SIZE]; -}; - -#define RINLINE(obj) ((struct RInline*)(mrb_ptr(obj))) -#define INLINE_PTR(obj) (RINLINE(obj)->inline_data) - -MRB_INLINE mrb_int mrb_inline_size() -{ - return INLINE_DATA_SIZE; -} - -MRB_INLINE void* mrb_inline_ptr(mrb_value object) -{ - return INLINE_PTR(object); -} - -MRB_INLINE void mrb_inline_copy(mrb_value dest, mrb_value src) -{ - memcpy(INLINE_PTR(dest), INLINE_PTR(src), INLINE_DATA_SIZE); -} - -MRB_END_DECL - -#endif /* MRUBY_INLINE_H */ diff --git a/include/mruby/istruct.h b/include/mruby/istruct.h new file mode 100644 index 000000000..293a13788 --- /dev/null +++ b/include/mruby/istruct.h @@ -0,0 +1,47 @@ +/* +** mruby/instruct.h - Inline structures +** +** See Copyright Notice in mruby.h +*/ + +#ifndef MRUBY_ISTRUCT_H +#define MRUBY_ISTRUCT_H + +#include "common.h" +#include + +/** + * Inline structures that fit in RVALUE + * + * They cannot have finalizer, and cannot have instance variables. + */ +MRB_BEGIN_DECL + +#define ISTRUCT_DATA_SIZE (sizeof(void*) * 3) + +struct RIstruct { + MRB_OBJECT_HEADER; + char inline_data[ISTRUCT_DATA_SIZE]; +}; + +#define RISTRUCT(obj) ((struct RIstruct*)(mrb_ptr(obj))) +#define ISTRUCT_PTR(obj) (RISTRUCT(obj)->inline_data) + +MRB_INLINE mrb_int mrb_istruct_size() +{ + return ISTRUCT_DATA_SIZE; +} + +MRB_INLINE void* mrb_istruct_ptr(mrb_value object) +{ + return ISTRUCT_PTR(object); +} + +MRB_INLINE void mrb_istruct_copy(mrb_value dest, mrb_value src) +{ + memcpy(ISTRUCT_PTR(dest), ISTRUCT_PTR(src), ISTRUCT_DATA_SIZE); +} + +MRB_END_DECL + +#endif /* MRUBY_ISTRUCT_H */ diff --git a/include/mruby/value.h b/include/mruby/value.h index eb3f931e1..6b29ab273 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -116,7 +116,7 @@ enum mrb_vtype { MRB_TT_ENV, /* 20 */ MRB_TT_DATA, /* 21 */ MRB_TT_FIBER, /* 22 */ - MRB_TT_INLINE, /* 23 */ + MRB_TT_ISTRUCT, /* 23 */ MRB_TT_MAXDEFINE /* 24 */ }; diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 903c08aca..49ef31d00 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -1,13 +1,13 @@ #include #include #include -#include +#include static mrb_value -inline_test_initialize(mrb_state *mrb, mrb_value self) +istruct_test_initialize(mrb_state *mrb, mrb_value self) { - char *string = mrb_inline_ptr(self); - mrb_int size = mrb_inline_size(); + char *string = mrb_istruct_ptr(self); + mrb_int size = mrb_istruct_size(); mrb_value object; mrb_get_args(mrb, "o", &object); @@ -29,19 +29,19 @@ inline_test_initialize(mrb_state *mrb, mrb_value self) } static mrb_value -inline_test_to_s(mrb_state *mrb, mrb_value self) +istruct_test_to_s(mrb_state *mrb, mrb_value self) { - return mrb_str_new_cstr(mrb, mrb_inline_ptr(self)); + return mrb_str_new_cstr(mrb, mrb_istruct_ptr(self)); } static mrb_value -inline_test_length(mrb_state *mrb, mrb_value self) +istruct_test_length(mrb_state *mrb, mrb_value self) { - return mrb_fixnum_value(mrb_inline_size()); + return mrb_fixnum_value(mrb_istruct_size()); } static mrb_value -inline_test_test_receive(mrb_state *mrb, mrb_value self) +istruct_test_test_receive(mrb_state *mrb, mrb_value self) { mrb_value object; mrb_get_args(mrb, "o", &object); @@ -49,11 +49,11 @@ inline_test_test_receive(mrb_state *mrb, mrb_value self) { mrb_raisef(mrb, E_TYPE_ERROR, "Expected InlineStructTest"); } - return mrb_bool_value(((char*)mrb_inline_ptr(object))[0] == 's'); + return mrb_bool_value(((char*)mrb_istruct_ptr(object))[0] == 's'); } static mrb_value -inline_test_test_receive_direct(mrb_state *mrb, mrb_value self) +istruct_test_test_receive_direct(mrb_state *mrb, mrb_value self) { char *ptr; mrb_get_args(mrb, "I", &ptr); @@ -61,9 +61,9 @@ inline_test_test_receive_direct(mrb_state *mrb, mrb_value self) } static mrb_value -inline_test_mutate(mrb_state *mrb, mrb_value self) +istruct_test_mutate(mrb_state *mrb, mrb_value self) { - char *ptr = mrb_inline_ptr(self); + char *ptr = mrb_istruct_ptr(self); memcpy(ptr, "mutate", 6); return mrb_nil_value(); } @@ -73,11 +73,11 @@ void mrb_mruby_inline_struct_gem_test(mrb_state *mrb) struct RClass *cls; cls = mrb_define_class(mrb, "InlineStructTest", mrb->object_class); - MRB_SET_INSTANCE_TT(cls, MRB_TT_INLINE); - mrb_define_method(mrb, cls, "initialize", inline_test_initialize, MRB_ARGS_REQ(1)); - mrb_define_method(mrb, cls, "to_s", inline_test_to_s, MRB_ARGS_NONE()); - mrb_define_method(mrb, cls, "mutate", inline_test_mutate, MRB_ARGS_NONE()); - mrb_define_class_method(mrb, cls, "length", inline_test_length, MRB_ARGS_NONE()); - mrb_define_class_method(mrb, cls, "test_receive", inline_test_test_receive, MRB_ARGS_REQ(1)); - mrb_define_class_method(mrb, cls, "test_receive_direct", inline_test_test_receive_direct, MRB_ARGS_REQ(1)); + MRB_SET_INSTANCE_TT(cls, MRB_TT_ISTRUCT); + mrb_define_method(mrb, cls, "initialize", istruct_test_initialize, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, cls, "to_s", istruct_test_to_s, MRB_ARGS_NONE()); + mrb_define_method(mrb, cls, "mutate", istruct_test_mutate, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "length", istruct_test_length, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, cls, "test_receive", istruct_test_test_receive, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, cls, "test_receive_direct", istruct_test_test_receive_direct, MRB_ARGS_REQ(1)); } diff --git a/src/class.c b/src/class.c index 53354d02a..d02253c57 100644 --- a/src/class.c +++ b/src/class.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include KHASH_DEFINE(mt, mrb_sym, struct RProc*, TRUE, kh_int_hash_func, kh_int_hash_equal) @@ -712,11 +712,11 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) p = va_arg(ap, void**); if (i < argc) { ss = ARGV[arg_i]; - if (mrb_type(ss) != MRB_TT_INLINE) + if (mrb_type(ss) != MRB_TT_ISTRUCT) { mrb_raisef(mrb, E_TYPE_ERROR, "%S is not inline struct", ss); } - *p = mrb_inline_ptr(ss); + *p = mrb_istruct_ptr(ss); arg_i++; i++; } diff --git a/src/etc.c b/src/etc.c index c89549da6..e0810d589 100644 --- a/src/etc.c +++ b/src/etc.c @@ -139,7 +139,7 @@ mrb_obj_id(mrb_value obj) case MRB_TT_EXCEPTION: case MRB_TT_FILE: case MRB_TT_DATA: - case MRB_TT_INLINE: + case MRB_TT_ISTRUCT: default: return MakeID(mrb_ptr(obj)); } diff --git a/src/kernel.c b/src/kernel.c index 4a4b6b414..8b1ef80a0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include typedef enum { NOEX_PUBLIC = 0x00, @@ -302,8 +302,8 @@ init_copy(mrb_state *mrb, mrb_value dest, mrb_value obj) case MRB_TT_EXCEPTION: mrb_iv_copy(mrb, dest, obj); break; - case MRB_TT_INLINE: - mrb_inline_copy(dest, obj); + case MRB_TT_ISTRUCT: + mrb_istruct_copy(dest, obj); break; default: diff --git a/src/object.c b/src/object.c index af66d93d0..392432b0f 100644 --- a/src/object.c +++ b/src/object.c @@ -348,7 +348,7 @@ mrb_check_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const { mrb_value v; - if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_INLINE) return val; + if (mrb_type(val) == type && type != MRB_TT_DATA && type != MRB_TT_ISTRUCT) return val; v = convert_type(mrb, val, tname, method, FALSE); if (mrb_nil_p(v) || mrb_type(v) != type) return mrb_nil_value(); return v; @@ -390,7 +390,7 @@ mrb_check_type(mrb_state *mrb, mrb_value x, enum mrb_vtype t) enum mrb_vtype xt; xt = mrb_type(x); - if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_INLINE)) { + if ((xt != t) || (xt == MRB_TT_DATA) || (xt == MRB_TT_ISTRUCT)) { while (type->type < MRB_TT_MAXDEFINE) { if (type->type == t) { const char *etype; -- cgit v1.2.3 From 57900d809f7dac7f450eadd475ad225a6cca39cb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 17 Nov 2016 18:02:10 +0900 Subject: String#include? does not take integers --- src/string.c | 18 ++++-------------- test/t/string.rb | 2 -- 2 files changed, 4 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 8c46da2bf..f8ab9478f 100644 --- a/src/string.c +++ b/src/string.c @@ -1530,22 +1530,12 @@ mrb_str_hash_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_str_include(mrb_state *mrb, mrb_value self) { - mrb_int i; mrb_value str2; - mrb_bool include_p; - - mrb_get_args(mrb, "o", &str2); - if (mrb_fixnum_p(str2)) { - include_p = (memchr(RSTRING_PTR(self), mrb_fixnum(str2), RSTRING_LEN(self)) != NULL); - } - else { - str2 = mrb_str_to_str(mrb, str2); - i = str_index(mrb, self, str2, 0); - - include_p = (i != -1); - } - return mrb_bool_value(include_p); + mrb_get_args(mrb, "S", &str2); + if (str_index(mrb, self, str2, 0) < 0) + return mrb_bool_value(FALSE); + return mrb_bool_value(TRUE); } /* 15.2.10.5.22 */ diff --git a/test/t/string.rb b/test/t/string.rb index fbaada451..e67389b5c 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -381,8 +381,6 @@ assert('String#hash', '15.2.10.5.20') do end assert('String#include?', '15.2.10.5.21') do - assert_true 'abc'.include?(97) - assert_false 'abc'.include?(100) assert_true 'abc'.include?('a') assert_false 'abc'.include?('d') end -- cgit v1.2.3 From 4ef591c89705a9ec10aaf8f323d8f73304c0097a Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 18 Nov 2016 10:01:03 +0900 Subject: Fix condition of Range#include? --- src/range.c | 2 +- test/t/range.rb | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/range.c b/src/range.c index 079a1035e..7b304011a 100644 --- a/src/range.c +++ b/src/range.c @@ -229,7 +229,7 @@ mrb_range_include(mrb_state *mrb, mrb_value range) end = r->edges->end; include_p = r_le(mrb, beg, val) && /* beg <= val */ ((r->excl && r_gt(mrb, end, val)) || /* end > val */ - (r_ge(mrb, end, val))); /* end >= val */ + (!r->excl && r_ge(mrb, end, val))); /* end >= val */ return mrb_bool_value(include_p); } diff --git a/test/t/range.rb b/test/t/range.rb index 278b26902..2ff89de4c 100644 --- a/test/t/range.rb +++ b/test/t/range.rb @@ -43,10 +43,11 @@ assert('Range#first', '15.2.14.4.7') do end assert('Range#include?', '15.2.14.4.8') do - a = (1..10) + assert_true (1..10).include?(10) + assert_false (1..10).include?(11) - assert_true a.include?(5) - assert_false a.include?(20) + assert_true (1...10).include?(9) + assert_false (1...10).include?(10) end assert('Range#initialize', '15.2.14.4.9') do -- cgit v1.2.3 From 0ff3ae1fbaed62010c54c43235e29cdc85da2f78 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 18 Nov 2016 11:54:24 +0900 Subject: Range#include?: simplify condition; ref #3255 --- src/range.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/range.c b/src/range.c index 4efae1f93..f0a976e53 100644 --- a/src/range.c +++ b/src/range.c @@ -230,9 +230,9 @@ mrb_range_include(mrb_state *mrb, mrb_value range) beg = r->edges->beg; end = r->edges->end; - include_p = r_le(mrb, beg, val) && /* beg <= val */ - ((r->excl && r_gt(mrb, end, val)) || /* end > val */ - (!r->excl && r_ge(mrb, end, val))); /* end >= val */ + include_p = r_le(mrb, beg, val) && /* beg <= val */ + (r->excl ? r_gt(mrb, end, val) /* end > val */ + : r_ge(mrb, end, val)); /* end >= val */ return mrb_bool_value(include_p); } -- cgit v1.2.3 From 740bf09740388b09714b5cdf70d9eec61d6cf4bd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 22 Nov 2016 17:36:26 +0900 Subject: add bit operators ~,&,|,^ to Float class (mruby special) --- src/numeric.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 327d54177..62ad3dde8 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -271,6 +271,77 @@ flo_eq(mrb_state *mrb, mrb_value x) } } +static int64_t +value_int64(mrb_state *mrb, mrb_value x) +{ + switch (mrb_type(x)) { + case MRB_TT_FIXNUM: + return (int64_t)mrb_fixnum(x); + break; + case MRB_TT_FLOAT: + return (int64_t)mrb_float(x); + default: + mrb_raise(mrb, E_TYPE_ERROR, "cannot convert to Integer"); + break; + } + /* not reached */ + return 0; +} + +static mrb_value +int64_value(mrb_state *mrb, int64_t v) +{ + if (MRB_INT_MIN <= v && v <= MRB_INT_MAX) { + return mrb_fixnum_value((mrb_int)v); + } + return mrb_float_value(mrb, (mrb_float)v); +} + +static mrb_value +flo_rev(mrb_state *mrb, mrb_value x) +{ + int64_t v1; + mrb_get_args(mrb, ""); + v1 = (int64_t)mrb_float(x); + return int64_value(mrb, ~v1); +} + +static mrb_value +flo_and(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 & v2); +} + +static mrb_value +flo_or(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 | v2); +} + +static mrb_value +flo_xor(mrb_state *mrb, mrb_value x) +{ + mrb_value y; + int64_t v1, v2; + mrb_get_args(mrb, "o", &y); + + v1 = (int64_t)mrb_float(x); + v2 = value_int64(mrb, y); + return int64_value(mrb, v1 ^ v2); +} + /* 15.2.8.3.18 */ /* * call-seq: @@ -1199,6 +1270,10 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "*", flo_mul, MRB_ARGS_REQ(1)); /* 15.2.9.3.3 */ mrb_define_method(mrb, fl, "%", flo_mod, MRB_ARGS_REQ(1)); /* 15.2.9.3.5 */ mrb_define_method(mrb, fl, "==", flo_eq, MRB_ARGS_REQ(1)); /* 15.2.9.3.7 */ + mrb_define_method(mrb, fl, "~", flo_rev, MRB_ARGS_NONE()); + mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ -- cgit v1.2.3 From 81122950317117f21b858294fa56d0d1e37436fe Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 22 Nov 2016 17:45:07 +0900 Subject: Removed fix_shift_get_width() Fixnum is usually big enough for shift width. --- src/numeric.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 62ad3dde8..7779cd652 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -921,15 +921,6 @@ rshift(mrb_int val, mrb_int width) return mrb_fixnum_value(val >> width); } -static inline void -fix_shift_get_width(mrb_state *mrb, mrb_int *width) -{ - mrb_value y; - - mrb_get_args(mrb, "o", &y); - *width = mrb_fixnum(bit_coerce(mrb, y)); -} - /* 15.2.8.3.12 */ /* * call-seq: @@ -943,8 +934,7 @@ fix_lshift(mrb_state *mrb, mrb_value x) { mrb_int width, val; - fix_shift_get_width(mrb, &width); - + mrb_get_args(mrb, "i", &width); if (width == 0) { return x; } @@ -968,8 +958,7 @@ fix_rshift(mrb_state *mrb, mrb_value x) { mrb_int width, val; - fix_shift_get_width(mrb, &width); - + mrb_get_args(mrb, "i", &width); if (width == 0) { return x; } -- cgit v1.2.3 From be73905c9c3ab8f684551506da219b170ee9c6dc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 22 Nov 2016 17:57:16 +0900 Subject: accept floats as bit operator operands; fix #3260 --- src/numeric.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 7779cd652..9902b0b94 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -809,17 +809,13 @@ fix_rev(mrb_state *mrb, mrb_value num) return mrb_fixnum_value(~val); } -static mrb_value -bit_coerce(mrb_state *mrb, mrb_value x) -{ - while (!mrb_fixnum_p(x)) { - if (mrb_float_p(x)) { - mrb_raise(mrb, E_TYPE_ERROR, "can't convert Float into Integer"); - } - x = mrb_to_int(mrb, x); - } - return x; -} +static mrb_value flo_and(mrb_state *mrb, mrb_value x); +static mrb_value flo_or(mrb_state *mrb, mrb_value x); +static mrb_value flo_xor(mrb_state *mrb, mrb_value x); +#define bit_op(x,y,op1,op2) do {\ + if (mrb_fixnum_p(y)) return mrb_fixnum_value(mrb_fixnum(x) op2 mrb_fixnum(y));\ + return flo_ ## op1(mrb, mrb_float_value(mrb, mrb_fixnum(x)));\ +} while(0) /* 15.2.8.3.9 */ /* @@ -835,9 +831,7 @@ fix_and(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - y = bit_coerce(mrb, y); - return mrb_fixnum_value(mrb_fixnum(x) & mrb_fixnum(y)); + bit_op(x, y, and, &); } /* 15.2.8.3.10 */ @@ -854,9 +848,7 @@ fix_or(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - y = bit_coerce(mrb, y); - return mrb_fixnum_value(mrb_fixnum(x) | mrb_fixnum(y)); + bit_op(x, y, or, |); } /* 15.2.8.3.11 */ @@ -873,9 +865,7 @@ fix_xor(mrb_state *mrb, mrb_value x) mrb_value y; mrb_get_args(mrb, "o", &y); - - y = bit_coerce(mrb, y); - return mrb_fixnum_value(mrb_fixnum(x) ^ mrb_fixnum(y)); + bit_op(x, y, or, ^); } #define NUMERIC_SHIFT_WIDTH_MAX (MRB_INT_BIT-1) -- cgit v1.2.3 From 8cba708854205ab8f2b6f8aed9aff12085131f12 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 22 Nov 2016 19:11:54 +0900 Subject: int64_value(): use FIXABLE() --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index 9902b0b94..cdf8c8afb 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -291,7 +291,7 @@ value_int64(mrb_state *mrb, mrb_value x) static mrb_value int64_value(mrb_state *mrb, int64_t v) { - if (MRB_INT_MIN <= v && v <= MRB_INT_MAX) { + if (FIXABLE(v)) { return mrb_fixnum_value((mrb_int)v); } return mrb_float_value(mrb, (mrb_float)v); -- cgit v1.2.3 From efebbbbf260e8ac5b8efbd0d4336a777cfeac514 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 23 Nov 2016 09:45:50 +0900 Subject: Implement Float shift methods in C --- mrblib/numeric.rb | 30 +----------------------------- src/numeric.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 29 deletions(-) (limited to 'src') diff --git a/mrblib/numeric.rb b/mrblib/numeric.rb index 6e4c5027f..17155bfd6 100644 --- a/mrblib/numeric.rb +++ b/mrblib/numeric.rb @@ -160,35 +160,7 @@ end # # ISO 15.2.9 class Float - include Integral # mruby special - since mruby integers may be upgraded to floats, # floats should be compatible to integers. - def >> other - n = self.to_i - other = other.to_i - if other < 0 - n << -other - else - other.times { n /= 2 } - if n.abs < 1 - if n >= 0 - 0 - else - -1 - end - else - n.to_i - end - end - end - def << other - n = self.to_i - other = other.to_i - if other < 0 - n >> -other - else - other.times { n *= 2 } - n - end - end + include Integral end diff --git a/src/numeric.c b/src/numeric.c index cdf8c8afb..c86373318 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -15,6 +15,7 @@ #include #ifdef MRB_USE_FLOAT +#define trunc(f) truncf(f) #define floor(f) floorf(f) #define ceil(f) ceilf(f) #define fmod(x,y) fmodf(x,y) @@ -342,6 +343,53 @@ flo_xor(mrb_state *mrb, mrb_value x) return int64_value(mrb, v1 ^ v2); } +static mrb_value +flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) +{ + mrb_float val; + + if (width == 0) { + return x; + } + val = mrb_float(x); + if (width < 0) { + while (width++) { + val /= 2; + } + val = trunc(val); + if (val == 0 && mrb_float(x) < 0) { + return mrb_fixnum_value(-1); + } + } + else { + while (width--) { + val *= 2; + } + } + if (FIXABLE(val)) { + return mrb_fixnum_value(val); + } + return mrb_float_value(mrb, val); +} + +static mrb_value +flo_lshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width; + + mrb_get_args(mrb, "i", &width); + return flo_shift(mrb, x, -width); +} + +static mrb_value +flo_rshift(mrb_state *mrb, mrb_value x) +{ + mrb_int width; + + mrb_get_args(mrb, "i", &width); + return flo_shift(mrb, x, width); +} + /* 15.2.8.3.18 */ /* * call-seq: @@ -1253,6 +1301,8 @@ mrb_init_numeric(mrb_state *mrb) mrb_define_method(mrb, fl, "&", flo_and, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "|", flo_or, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "^", flo_xor, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, ">>", flo_lshift, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, fl, "<<", flo_rshift, MRB_ARGS_REQ(1)); mrb_define_method(mrb, fl, "ceil", flo_ceil, MRB_ARGS_NONE()); /* 15.2.9.3.8 */ mrb_define_method(mrb, fl, "finite?", flo_finite_p, MRB_ARGS_NONE()); /* 15.2.9.3.9 */ mrb_define_method(mrb, fl, "floor", flo_floor, MRB_ARGS_NONE()); /* 15.2.9.3.10 */ -- cgit v1.2.3 From bfbc6b9ea48355785c236826e3a1a217b668aee2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 23 Nov 2016 20:50:14 +0900 Subject: local_variables() should not touch unshared env --- src/kernel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index 8b1ef80a0..74254e636 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1078,7 +1078,8 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) struct REnv *e = proc->env; while (e) { - if (!MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) { + if (MRB_ENV_STACK_SHARED_P(e) && + !MRB_PROC_CFUNC_P(mrb->c->cibase[e->cioff].proc)) { irep = mrb->c->cibase[e->cioff].proc->body.irep; if (irep->lv) { for (i = 0; i + 1 < irep->nlocals; ++i) { -- cgit v1.2.3 From 1af9e363f28810e46e263cd13da918cdf779d71d Mon Sep 17 00:00:00 2001 From: Tomasz Dąbrowski Date: Tue, 22 Nov 2016 13:19:05 +0100 Subject: Fixes for compiling mruby as C++ --- include/mruby.h | 16 ++++++++++++++++ include/mruby/boxing_nan.h | 2 +- mrbgems/mruby-inline-struct/test/inline.c | 6 +++--- mrbgems/mruby-objectspace/src/mruby_objectspace.c | 2 +- mrbgems/mruby-sprintf/src/sprintf.c | 12 ++++++------ src/backtrace.c | 4 ++-- src/string.c | 2 +- 7 files changed, 30 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index e6eaf7f27..d40dce6d9 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -28,10 +28,26 @@ #ifndef MRUBY_H #define MRUBY_H +#ifdef __cplusplus +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS +#define __STDC_FORMAT_MACROS +#endif + #include #include #include +#ifdef __cplusplus +#ifndef SIZE_MAX +#ifdef __SIZE_MAX__ +#define SIZE_MAX __SIZE_MAX__ +#else +#define SIZE_MAX std::numeric_limits::max() +#endif +#endif +#endif + #ifdef MRB_DEBUG #include #define mrb_assert(p) assert(p) diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h index 154150ece..052164ffc 100644 --- a/include/mruby/boxing_nan.h +++ b/include/mruby/boxing_nan.h @@ -53,7 +53,7 @@ typedef struct mrb_value { #define mrb_float_pool(mrb,f) mrb_float_value(mrb,f) #define mrb_tt(o) ((enum mrb_vtype)(((o).value.ttt & 0xfc000)>>14)-1) -#define mrb_type(o) ((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT) +#define mrb_type(o) (enum mrb_vtype)((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT) #define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2)) #define mrb_float(o) (o).f #define mrb_cptr(o) mrb_ptr(o) diff --git a/mrbgems/mruby-inline-struct/test/inline.c b/mrbgems/mruby-inline-struct/test/inline.c index 49ef31d00..772248e9b 100644 --- a/mrbgems/mruby-inline-struct/test/inline.c +++ b/mrbgems/mruby-inline-struct/test/inline.c @@ -6,7 +6,7 @@ static mrb_value istruct_test_initialize(mrb_state *mrb, mrb_value self) { - char *string = mrb_istruct_ptr(self); + char *string = (char*)mrb_istruct_ptr(self); mrb_int size = mrb_istruct_size(); mrb_value object; mrb_get_args(mrb, "o", &object); @@ -31,7 +31,7 @@ istruct_test_initialize(mrb_state *mrb, mrb_value self) static mrb_value istruct_test_to_s(mrb_state *mrb, mrb_value self) { - return mrb_str_new_cstr(mrb, mrb_istruct_ptr(self)); + return mrb_str_new_cstr(mrb, (const char*)mrb_istruct_ptr(self)); } static mrb_value @@ -63,7 +63,7 @@ istruct_test_test_receive_direct(mrb_state *mrb, mrb_value self) static mrb_value istruct_test_mutate(mrb_state *mrb, mrb_value self) { - char *ptr = mrb_istruct_ptr(self); + char *ptr = (char*)mrb_istruct_ptr(self); memcpy(ptr, "mutate", 6); return mrb_nil_value(); } diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index d5cd4f5a1..d0a8effd0 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -49,7 +49,7 @@ static mrb_value os_count_objects(mrb_state *mrb, mrb_value self) { struct os_count_struct obj_count = { 0 }; - enum mrb_vtype i; + mrb_int i; mrb_value hash; if (mrb_get_args(mrb, "|H", &hash) == 0) { diff --git a/mrbgems/mruby-sprintf/src/sprintf.c b/mrbgems/mruby-sprintf/src/sprintf.c index ccee23bd2..696d0939f 100644 --- a/mrbgems/mruby-sprintf/src/sprintf.c +++ b/mrbgems/mruby-sprintf/src/sprintf.c @@ -844,13 +844,13 @@ retry: strncpy(nbuf, RSTRING_PTR(val), sizeof(nbuf)); break; case 8: - snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIo, v); + snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIo, v); break; case 10: - snprintf(nbuf, sizeof(nbuf), "%"MRB_PRId, v); + snprintf(nbuf, sizeof(nbuf), "%" MRB_PRId, v); break; case 16: - snprintf(nbuf, sizeof(nbuf), "%"MRB_PRIx, v); + snprintf(nbuf, sizeof(nbuf), "%" MRB_PRIx, v); break; } s = nbuf; @@ -865,13 +865,13 @@ retry: strncpy(++s, RSTRING_PTR(val), sizeof(nbuf)-1); break; case 8: - snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIo, v); + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIo, v); break; case 10: - snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRId, v); + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRId, v); break; case 16: - snprintf(++s, sizeof(nbuf)-1, "%"MRB_PRIx, v); + snprintf(++s, sizeof(nbuf)-1, "%" MRB_PRIx, v); break; } if (v < 0) { diff --git a/src/backtrace.c b/src/backtrace.c index 11082b705..285af562f 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -160,7 +160,7 @@ static void output_backtrace_i(mrb_state *mrb, struct backtrace_location_raw *loc_raw, void *data) { struct backtrace_location loc; - struct output_backtrace_args *args = data; + struct output_backtrace_args *args = (struct output_backtrace_args *)data; loc.i = loc_raw->i; loc.lineno = loc_raw->lineno; @@ -338,7 +338,7 @@ save_backtrace_i(mrb_state *mrb, else { new_n_allocated = mrb->backtrace.n_allocated * 2; } - mrb->backtrace.entries = + mrb->backtrace.entries = (mrb_backtrace_entry *) mrb_realloc(mrb, mrb->backtrace.entries, sizeof(mrb_backtrace_entry) * new_n_allocated); diff --git a/src/string.c b/src/string.c index f8ab9478f..5e490bf03 100644 --- a/src/string.c +++ b/src/string.c @@ -361,7 +361,7 @@ mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n) return 0; } else if (m == 1) { - const unsigned char *ys = memchr(y, *x, n); + const unsigned char *ys = (const unsigned char *)memchr(y, *x, n); if (ys) return ys - y; -- cgit v1.2.3 From 401ad4586ffe8bc26740f49f9049132ad2c50539 Mon Sep 17 00:00:00 2001 From: Tomasz Dąbrowski Date: Tue, 22 Nov 2016 13:59:11 +0100 Subject: Add constant export declaration for MRBC output compiled as C++ Otherwise, C++ compilers will skip this constant when producing object files. --- src/dump.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/dump.c b/src/dump.c index ea1cd5596..45c595d3b 100644 --- a/src/dump.c +++ b/src/dump.c @@ -1059,6 +1059,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con return MRB_DUMP_WRITE_FAULT; } if (fprintf(fp, + "extern const uint8_t %s[];\n" "const uint8_t\n" "#if defined __GNUC__\n" "__attribute__((aligned(%u)))\n" @@ -1066,6 +1067,7 @@ mrb_dump_irep_cfunc(mrb_state *mrb, mrb_irep *irep, uint8_t flags, FILE *fp, con "__declspec(align(%u))\n" "#endif\n" "%s[] = {", + initname, (uint16_t)MRB_DUMP_ALIGNMENT, (uint16_t)MRB_DUMP_ALIGNMENT, initname) < 0) { mrb_free(mrb, bin); return MRB_DUMP_WRITE_FAULT; -- cgit v1.2.3 From 798c69d1be8d9ab437defb25e5e652d355eef5d4 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 Nov 2016 09:23:55 +0900 Subject: Avoid casting from int to unsigned char for C++; ref #3267 --- src/object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/object.c b/src/object.c index 392432b0f..c61feb342 100644 --- a/src/object.c +++ b/src/object.c @@ -380,7 +380,7 @@ static const struct types { /* {MRB_TT_VARMAP, "Varmap"}, */ /* internal use: dynamic variables */ /* {MRB_TT_NODE, "Node"}, */ /* internal use: syntax tree node */ /* {MRB_TT_UNDEF, "undef"}, */ /* internal use: #undef; should not happen */ - {-1, 0} + {MRB_TT_MAXDEFINE, 0} }; MRB_API void -- cgit v1.2.3 From f5a86ca5305d70c16297b67df30ce37c102af183 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 Nov 2016 09:24:45 +0900 Subject: Add pointer casting from mrb_malloc(); ref #3267 --- src/variable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 29f43e69d..45dc055af 100644 --- a/src/variable.c +++ b/src/variable.c @@ -44,7 +44,7 @@ iv_new(mrb_state *mrb) { iv_tbl *t; - t = mrb_malloc(mrb, sizeof(iv_tbl)); + t = (iv_tbl*)mrb_malloc(mrb, sizeof(iv_tbl)); t->size = 0; t->rootseg = NULL; t->last_len = 0; @@ -102,7 +102,7 @@ iv_put(mrb_state *mrb, iv_tbl *t, mrb_sym sym, mrb_value val) return; } - seg = mrb_malloc(mrb, sizeof(segment)); + seg = (segment*)mrb_malloc(mrb, sizeof(segment)); if (!seg) return; seg->next = NULL; seg->key[0] = sym; -- cgit v1.2.3 From cb5c9d34150c073b5cdde725cadd959839c9bc45 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 Nov 2016 18:09:04 +0900 Subject: always call Hash#default if no key found; fix #3272 --- src/hash.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 015b2d614..4df2babbe 100644 --- a/src/hash.c +++ b/src/hash.c @@ -172,11 +172,8 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) } /* not found */ - if (MRB_RHASH_DEFAULT_P(hash)) { - /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ - return mrb_funcall(mrb, hash, "default", 1, key); - } - return mrb_nil_value(); + /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ + return mrb_funcall(mrb, hash, "default", 1, key); } MRB_API mrb_value -- cgit v1.2.3 From 0c924b92872a96b29f3fe8462ab57d33dfb7b9b6 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 24 Nov 2016 19:30:21 +0900 Subject: fixed a bug in self modifying Array#[]=; fix #3274 --- src/array.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 5a319d809..106353c07 100644 --- a/src/array.c +++ b/src/array.c @@ -309,9 +309,12 @@ ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len) MRB_API void mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other) { + struct RArray *a1 = mrb_ary_ptr(self); struct RArray *a2 = mrb_ary_ptr(other); - ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len); + if (a1 != a2) { + ary_replace(mrb, a1, a2->ptr, a2->len); + } } static mrb_value @@ -554,6 +557,15 @@ mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val); } +static struct RArray* +ary_dup(mrb_state *mrb, struct RArray *a) +{ + struct RArray *d = ary_new_capa(mrb, a->len); + + ary_replace(mrb, d, a->ptr, a->len); + return d; +} + MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl) { @@ -583,6 +595,10 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val if (mrb_array_p(rpl)) { argc = RARRAY_LEN(rpl); argv = RARRAY_PTR(rpl); + if (argv == a->ptr) { + struct RArray *r = ary_dup(mrb, a); + argv = r->ptr; + } } else { argc = 1; -- cgit v1.2.3 From 73bb30c2f4dba7c8da091ec5c5308d6dacf5f52f Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Mon, 21 Nov 2016 16:31:47 -0500 Subject: Copy over INSTANCE_TT when duping class --- src/kernel.c | 1 + test/t/kernel.rb | 8 ++++++++ 2 files changed, 9 insertions(+) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index 74254e636..c63e05596 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -285,6 +285,7 @@ copy_class(mrb_state *mrb, mrb_value dst, mrb_value src) } dc->mt = kh_copy(mt, mrb, sc->mt); dc->super = sc->super; + MRB_SET_INSTANCE_TT(dc, MRB_INSTANCE_TT(sc)); } static void diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 927166283..d240e59dc 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -221,6 +221,14 @@ assert('Kernel#dup', '15.3.1.3.9') do assert_false c.respond_to?(:test) end +assert('Kernel#dup class') do + assert_nothing_raised do + Array.dup.new(200) + Range.dup.new(2, 3) + String.dup.new("a"*50) + end +end + # Kernel#eval is provided by mruby-eval mrbgem '15.3.1.3.12' assert('Kernel#extend', '15.3.1.3.13') do -- cgit v1.2.3 From 4523aaec015ff0bf900710efc2ec3411e8841fb1 Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Wed, 16 Nov 2016 14:01:49 -0500 Subject: Fix segfault when defining class inside instance_exec on primitive --- mrbgems/mruby-object-ext/test/object.rb | 28 ++++++++++++++++++++++++++++ src/vm.c | 14 ++++++++++---- 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-object-ext/test/object.rb b/mrbgems/mruby-object-ext/test/object.rb index fe56f1ec5..f0742f8ce 100644 --- a/mrbgems/mruby-object-ext/test/object.rb +++ b/mrbgems/mruby-object-ext/test/object.rb @@ -23,3 +23,31 @@ assert('Object#tap') do ], ret assert_equal(:tap_ok, Class.new {def m; tap{return :tap_ok}; end}.new.m) end + +assert('instance_exec on primitives with class and module definition') do + begin + class A + 1.instance_exec do + class B + end + end + end + + assert_kind_of Class, A::B + ensure + Object.remove_const :A + end + + begin + class A + 1.instance_exec do + module B + end + end + end + + assert_kind_of Module, A::B + ensure + Object.remove_const :A + end +end diff --git a/src/vm.c b/src/vm.c index a7418e6e7..41e19b0c0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2261,7 +2261,7 @@ RETRY_TRY_BLOCK: CASE(OP_CLASS) { /* A B R(A) := newclass(R(A),Syms(B),R(A+1)) */ - struct RClass *c = 0; + struct RClass *c = 0, *baseclass; int a = GETARG_A(i); mrb_value base, super; mrb_sym id = syms[GETARG_B(i)]; @@ -2269,7 +2269,10 @@ RETRY_TRY_BLOCK: base = regs[a]; super = regs[a+1]; if (mrb_nil_p(base)) { - base = mrb_obj_value(mrb->c->ci->target_class); + baseclass = mrb->c->ci->proc->target_class; + if (!baseclass) baseclass = mrb->c->ci->target_class; + + base = mrb_obj_value(baseclass); } c = mrb_vm_define_class(mrb, base, super, id); regs[a] = mrb_obj_value(c); @@ -2279,14 +2282,17 @@ RETRY_TRY_BLOCK: CASE(OP_MODULE) { /* A B R(A) := newmodule(R(A),Syms(B)) */ - struct RClass *c = 0; + struct RClass *c = 0, *baseclass; int a = GETARG_A(i); mrb_value base; mrb_sym id = syms[GETARG_B(i)]; base = regs[a]; if (mrb_nil_p(base)) { - base = mrb_obj_value(mrb->c->ci->target_class); + baseclass = mrb->c->ci->proc->target_class; + if (!baseclass) baseclass = mrb->c->ci->target_class; + + base = mrb_obj_value(baseclass); } c = mrb_vm_define_module(mrb, base, id); regs[a] = mrb_obj_value(c); -- cgit v1.2.3 From 22f550405449faf5bb424f04a52835376add2ae2 Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Mon, 14 Nov 2016 17:57:43 -0500 Subject: Fix segfault on remove_method with invalid argument Reported by https://hackerone.com/jpenalbae --- src/class.c | 2 +- test/t/class.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index d02253c57..d120f1fec 100644 --- a/src/class.c +++ b/src/class.c @@ -2068,7 +2068,7 @@ mrb_mod_remove_method(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - remove_method(mrb, mod, mrb_symbol(*argv)); + remove_method(mrb, mod, to_sym(mrb, *argv)); argv++; } return mod; diff --git a/test/t/class.rb b/test/t/class.rb index 7bcaaf90d..597999d3e 100644 --- a/test/t/class.rb +++ b/test/t/class.rb @@ -401,3 +401,12 @@ assert('class with non-class/module outer raises TypeError') do assert_raise(TypeError) { class 0::C1; end } assert_raise(TypeError) { class []::C2; end } end + +assert("remove_method doesn't segfault if the passed in argument isn't a symbol") do + klass = Class.new + assert_raise(TypeError) { klass.remove_method nil } + assert_raise(TypeError) { klass.remove_method 123 } + assert_raise(TypeError) { klass.remove_method 1.23 } + assert_raise(NameError) { klass.remove_method "hello" } + assert_raise(TypeError) { klass.remove_method Class.new } +end -- cgit v1.2.3 From 1ec5994377b45b0299a9c4e6e7ab275792d81bc9 Mon Sep 17 00:00:00 2001 From: Francois Chagnon Date: Mon, 14 Nov 2016 16:49:45 -0500 Subject: Fix calling .arity on Proc with undefined `initialize` Reported by @bouk --- mrbgems/mruby-proc-ext/src/proc.c | 3 +++ mrbgems/mruby-proc-ext/test/proc.rb | 11 +++++++++++ src/proc.c | 15 ++++++++------- test/t/proc.rb | 11 +++++++++++ 4 files changed, 33 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-proc-ext/src/proc.c b/mrbgems/mruby-proc-ext/src/proc.c index c8c8f1aa1..34f6230dc 100644 --- a/mrbgems/mruby-proc-ext/src/proc.c +++ b/mrbgems/mruby-proc-ext/src/proc.c @@ -114,6 +114,9 @@ mrb_proc_parameters(mrb_state *mrb, mrb_value self) // TODO cfunc aspec is not implemented yet return mrb_ary_new(mrb); } + if (!irep) { + return mrb_ary_new(mrb); + } if (!irep->lv) { return mrb_ary_new(mrb); } diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 75e11dd93..7a078aabf 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -58,6 +58,17 @@ assert('Proc#parameters') do assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) end +assert('Proc#parameters with uninitialized Proc') do + begin + Proc.alias_method(:original_initialize, :initialize) + Proc.remove_method(:initialize) + assert_equal [], Proc.new{|a, b, c| 1}.parameters + ensure + Proc.alias_method(:initialize, :original_initialize) + Proc.remove_method(:original_initialize) + end +end + assert('Proc#to_proc') do proc = Proc.new {} assert_equal proc, proc.to_proc diff --git a/src/proc.c b/src/proc.c index 1620bddf8..4f770932b 100644 --- a/src/proc.c +++ b/src/proc.c @@ -188,18 +188,13 @@ mrb_proc_call_cfunc(mrb_state *mrb, struct RProc *p, mrb_value self) return (p->body.func)(mrb, self); } -mrb_code* -mrb_proc_iseq(mrb_state *mrb, struct RProc *p) -{ - return p->body.irep->iseq; -} - /* 15.2.17.4.2 */ static mrb_value mrb_proc_arity(mrb_state *mrb, mrb_value self) { struct RProc *p = mrb_proc_ptr(self); - mrb_code *iseq = mrb_proc_iseq(mrb, p); + struct mrb_irep *irep; + mrb_code *iseq; mrb_aspec aspec; int ma, op, ra, pa, arity; @@ -208,6 +203,12 @@ mrb_proc_arity(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(-1); } + irep = p->body.irep; + if (!irep) { + return mrb_fixnum_value(0); + } + + iseq = irep->iseq; /* arity is depend on OP_ENTER */ if (GET_OPCODE(*iseq) != OP_ENTER) { return mrb_fixnum_value(0); diff --git a/test/t/proc.rb b/test/t/proc.rb index 888b7d56a..bc9821f7c 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -46,6 +46,17 @@ assert('Proc#arity', '15.2.17.4.2') do assert_equal(-1, g) end +assert('Proc#arity with unitialized Proc') do + begin + Proc.alias_method(:original_initialize, :initialize) + Proc.remove_method(:initialize) + assert_equal 0, Proc.new{|a, b, c| 1}.arity + ensure + Proc.alias_method(:initialize, :original_initialize) + Proc.remove_method(:original_initialize) + end +end + assert('Proc#call', '15.2.17.4.3') do a = 0 b = Proc.new { a += 1 } -- cgit v1.2.3 From 76a1bdfa29469576112a41b78a132b785616a3f9 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Wed, 16 Nov 2016 10:10:14 -0500 Subject: Get String length after args in String#chomp! Fixes RCE issue Reported by @bouk --- src/string.c | 4 +++- test/t/string.rb | 14 +++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 5e490bf03..f47294291 100644 --- a/src/string.c +++ b/src/string.c @@ -1235,11 +1235,13 @@ mrb_str_chomp_bang(mrb_state *mrb, mrb_value str) char *p, *pp; mrb_int rslen; mrb_int len; + mrb_int argc; struct RString *s = mrb_str_ptr(str); mrb_str_modify(mrb, s); + argc = mrb_get_args(mrb, "|S", &rs); len = RSTR_LEN(s); - if (mrb_get_args(mrb, "|S", &rs) == 0) { + if (argc == 0) { if (len == 0) return mrb_nil_value(); smart_chomp: if (RSTR_PTR(s)[len-1] == '\n') { diff --git a/test/t/string.rb b/test/t/string.rb index e67389b5c..80fcbe6fa 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -251,6 +251,19 @@ assert('String#chomp!', '15.2.10.5.10') do assert_equal 'abc', e end +assert('String#chomp! uses the correct length') do + class A + def to_str + $s.replace("AA") + "A" + end + end + + $s = "AAA" + $s.chomp!(A.new) + assert_equal $s, "A" +end + assert('String#chop', '15.2.10.5.11') do a = ''.chop b = 'abc'.chop @@ -683,4 +696,3 @@ assert('String#freeze') do assert_raise(RuntimeError) { str.upcase! } end - -- cgit v1.2.3 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 --- src/vm.c | 47 +++++++++++++++++++++++++++++++++++++---------- test/t/nomethoderror.rb | 31 +++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index a7418e6e7..fed622b85 100644 --- a/src/vm.c +++ b/src/vm.c @@ -54,6 +54,10 @@ The value below allows about 60000 recursive calls in the simplest case. */ #define ARENA_RESTORE(mrb,ai) (mrb)->gc.arena_idx = (ai) +#define CALL_MAXARGS 127 + +void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); + static inline void stack_clear(mrb_value *from, size_t count) { @@ -362,9 +366,13 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc c = mrb_class(mrb, self); p = mrb_method_search_vm(mrb, &c, mid); if (!p) { + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + p = mrb_method_search_vm(mrb, &c, missing); + if (!p) { + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + mrb_method_missing(mrb, mid, self, args); + } undef = mid; - mid = mrb_intern_lit(mrb, "method_missing"); - p = mrb_method_search_vm(mrb, &c, mid); n++; argc++; } ci = cipush(mrb); @@ -749,10 +757,6 @@ argnum_error(mrb_state *mrb, mrb_int num) #endif -#define CALL_MAXARGS 127 - -void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); - MRB_API mrb_value mrb_vm_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) { @@ -1290,8 +1294,20 @@ RETRY_TRY_BLOCK: c = mrb->c->ci->target_class->super; m = mrb_method_search_vm(mrb, &c, mid); if (!m) { - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; + + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); } @@ -1681,9 +1697,20 @@ RETRY_TRY_BLOCK: m = mrb_method_search_vm(mrb, &c, mid); if (!m) { mrb_value sym = mrb_symbol_value(mid); + mrb_sym missing = mrb_intern_lit(mrb, "method_missing"); + m = mrb_method_search_vm(mrb, &c, missing); + if (!m) { + mrb_value args; - mid = mrb_intern_lit(mrb, "method_missing"); - m = mrb_method_search_vm(mrb, &c, mid); + if (n == CALL_MAXARGS) { + args = regs[a+1]; + } + else { + args = mrb_ary_new_from_values(mrb, n, regs+a+1); + } + mrb_method_missing(mrb, mid, recv, args); + } + mid = missing; if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } 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 36fc1f1431d9aa85c167f91ef30abe0953c56400 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 27 Nov 2016 22:17:51 +0900 Subject: Added Exception check in mrb_exc_set(); close #3292 PR #3293 just checks for NoMethodError. --- src/error.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/error.c b/src/error.c index 13032b136..9ff570bf6 100644 --- a/src/error.c +++ b/src/error.c @@ -278,6 +278,8 @@ 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); } } -- cgit v1.2.3 From 9fc62d28d0e5738368571d70f1be191876e91d8b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 28 Nov 2016 09:52:57 +0900 Subject: pre-allocate arena overflow error --- include/mruby.h | 3 +++ src/error.c | 5 ++++- src/gc.c | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 1e27b93fb..6e222057f 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -221,6 +221,9 @@ typedef struct mrb_state { struct RClass *eException_class; struct RClass *eStandardError_class; struct RObject *nomem_err; /* pre-allocated NoMemoryError */ +#ifdef MRB_GC_FIXED_ARENA + struct RObject *arena_err; /* pre-allocated arena overfow error */ +#endif void *ud; /* auxiliary data */ diff --git a/src/error.c b/src/error.c index 9ff570bf6..b24aed798 100644 --- a/src/error.c +++ b/src/error.c @@ -465,7 +465,7 @@ exception_call: } if (argc > 0) { if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class)) - mrb_raise(mrb, E_TYPE_ERROR, "exception object expected"); + mrb_raise(mrb, mrb->eException_class, "exception object expected"); if (argc > 2) set_backtrace(mrb, mesg, argv[2]); } @@ -532,6 +532,9 @@ mrb_init_exception(mrb_state *mrb) mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */ runtime_error = mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class); /* 15.2.28 */ mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "Out of memory")); +#ifdef MRB_GC_FIXED_ARENA + mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, runtime_error, "arena overflow error")); +#endif script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */ mrb_define_class(mrb, "SystemStackError", exception); diff --git a/src/gc.c b/src/gc.c index b29df1f02..ecc09374e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -403,7 +403,7 @@ gc_protect(mrb_state *mrb, mrb_gc *gc, struct RBasic *p) if (gc->arena_idx >= MRB_GC_ARENA_SIZE) { /* arena overflow error */ gc->arena_idx = MRB_GC_ARENA_SIZE - 4; /* force room in arena */ - mrb_raise(mrb, E_RUNTIME_ERROR, "arena overflow error"); + mrb_exc_raise(mrb, mrb_obj_value(mrb->arena_err)); } #else if (gc->arena_idx >= gc->arena_capa) { @@ -816,6 +816,9 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc) mrb_gc_mark(mrb, (struct RBasic*)mrb->exc); /* mark pre-allocated exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err); +#ifdef MRB_GC_FIXED_ARENA + mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err); +#endif mark_context(mrb, mrb->root_c); if (mrb->root_c->fib) { -- cgit v1.2.3 From 246a9a8acd4e45a184ffd11bdd92a5b7736bf1cd Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 29 Nov 2016 22:36:11 +0900 Subject: ary_concat: support self concatenation; fix #3302 --- src/array.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 106353c07..ed83bd446 100644 --- a/src/array.c +++ b/src/array.c @@ -245,13 +245,15 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value self) } static void -ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen) +ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2) { - mrb_int len = a->len + blen; + mrb_int len = a->len + a2->len; ary_modify(mrb, a); - if (a->aux.capa < len) ary_expand_capa(mrb, a, len); - array_copy(a->ptr+a->len, ptr, blen); + if (a->aux.capa < len) { + ary_expand_capa(mrb, a, len); + } + array_copy(a->ptr+a->len, a2->ptr, a2->len); mrb_write_barrier(mrb, (struct RBasic*)a); a->len = len; } @@ -261,17 +263,16 @@ mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other) { struct RArray *a2 = mrb_ary_ptr(other); - ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len); + ary_concat(mrb, mrb_ary_ptr(self), a2); } static mrb_value mrb_ary_concat_m(mrb_state *mrb, mrb_value self) { - mrb_value *ptr; - mrb_int blen; + mrb_value ary; - mrb_get_args(mrb, "a", &ptr, &blen); - ary_concat(mrb, mrb_ary_ptr(self), ptr, blen); + mrb_get_args(mrb, "A", &ary); + mrb_ary_concat(mrb, self, ary); return self; } -- cgit v1.2.3 From b633aa9ad466277cf583f60b8e424e516362f0bf Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Tue, 29 Nov 2016 10:26:02 -0500 Subject: Use size_t to calculate bytes needed for array. --- src/array.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index ed83bd446..df037a121 100644 --- a/src/array.c +++ b/src/array.c @@ -20,15 +20,12 @@ static struct RArray* ary_new_capa(mrb_state *mrb, mrb_int capa) { struct RArray *a; - mrb_int blen; + size_t blen; if (capa > ARY_MAX_SIZE) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } blen = capa * sizeof(mrb_value); - if (blen < capa) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); - } a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); a->ptr = (mrb_value *)mrb_malloc(mrb, blen); -- cgit v1.2.3 From 630733f34698047e3b7b4e66cf929f626123b14e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 30 Nov 2016 03:38:55 +0900 Subject: check ttype before object allocation; fix #3294 --- src/gc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index ecc09374e..69708e40b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -479,6 +479,17 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) static const RVALUE RVALUE_zero = { { { MRB_TT_FALSE } } }; mrb_gc *gc = &mrb->gc; + if (cls) { + enum mrb_vtype tt = MRB_INSTANCE_TT(cls); + if (tt != MRB_TT_FALSE && + ttype != MRB_TT_SCLASS && + ttype != MRB_TT_ICLASS && + ttype != MRB_TT_ENV && + ttype != tt) { + mrb_raisef(mrb, E_TYPE_ERROR, "allocation failure of %S", mrb_obj_value(cls)); + } + } + #ifdef MRB_GC_STRESS mrb_full_gc(mrb); #endif -- cgit v1.2.3 From 2bb47addadb3eda796520837c21d694c8d6e3320 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 30 Nov 2016 10:36:17 +0900 Subject: Prohibit instantiation of immediate objects --- src/class.c | 3 +++ src/numeric.c | 3 +++ src/object.c | 4 ++++ src/symbol.c | 3 +++ 4 files changed, 13 insertions(+) (limited to 'src') diff --git a/src/class.c b/src/class.c index d120f1fec..bac1d2984 100644 --- a/src/class.c +++ b/src/class.c @@ -1348,6 +1348,9 @@ mrb_instance_alloc(mrb_state *mrb, mrb_value cv) mrb_raise(mrb, E_TYPE_ERROR, "can't create instance of singleton class"); if (ttype == 0) ttype = MRB_TT_OBJECT; + if (ttype <= MRB_TT_CPTR) { + mrb_raisef(mrb, E_TYPE_ERROR, "can't create instance of %S", cv); + } o = (struct RObject*)mrb_obj_alloc(mrb, ttype, c); return mrb_obj_value(o); } diff --git a/src/numeric.c b/src/numeric.c index c86373318..25a411de8 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef MRB_USE_FLOAT #define trunc(f) truncf(f) @@ -1265,6 +1266,7 @@ mrb_init_numeric(mrb_state *mrb) /* Integer Class */ integer = mrb_define_class(mrb, "Integer", numeric); /* 15.2.8 */ + 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()); @@ -1291,6 +1293,7 @@ mrb_init_numeric(mrb_state *mrb) /* Float Class */ mrb->float_class = fl = mrb_define_class(mrb, "Float", numeric); /* 15.2.9 */ + MRB_SET_INSTANCE_TT(fl, MRB_TT_FLOAT); mrb_undef_class_method(mrb, fl, "new"); mrb_define_method(mrb, fl, "+", flo_plus, MRB_ARGS_REQ(1)); /* 15.2.9.3.1 */ mrb_define_method(mrb, fl, "-", flo_minus, MRB_ARGS_REQ(1)); /* 15.2.9.3.2 */ diff --git a/src/object.c b/src/object.c index c61feb342..f76ee68a2 100644 --- a/src/object.c +++ b/src/object.c @@ -8,6 +8,7 @@ #include #include #include +#include MRB_API mrb_bool mrb_obj_eq(mrb_state *mrb, mrb_value v1, mrb_value v2) @@ -265,6 +266,7 @@ mrb_init_object(mrb_state *mrb) struct RClass *f; mrb->nil_class = n = mrb_define_class(mrb, "NilClass", mrb->object_class); + MRB_SET_INSTANCE_TT(n, MRB_TT_TRUE); mrb_undef_class_method(mrb, n, "new"); mrb_define_method(mrb, n, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.4.3.1 */ mrb_define_method(mrb, n, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.4.3.2 */ @@ -274,6 +276,7 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, n, "inspect", nil_inspect, MRB_ARGS_NONE()); mrb->true_class = t = mrb_define_class(mrb, "TrueClass", mrb->object_class); + MRB_SET_INSTANCE_TT(t, MRB_TT_TRUE); mrb_undef_class_method(mrb, t, "new"); mrb_define_method(mrb, t, "&", true_and, MRB_ARGS_REQ(1)); /* 15.2.5.3.1 */ mrb_define_method(mrb, t, "^", true_xor, MRB_ARGS_REQ(1)); /* 15.2.5.3.2 */ @@ -282,6 +285,7 @@ mrb_init_object(mrb_state *mrb) mrb_define_method(mrb, t, "inspect", true_to_s, MRB_ARGS_NONE()); mrb->false_class = f = mrb_define_class(mrb, "FalseClass", mrb->object_class); + MRB_SET_INSTANCE_TT(f, MRB_TT_TRUE); mrb_undef_class_method(mrb, f, "new"); mrb_define_method(mrb, f, "&", false_and, MRB_ARGS_REQ(1)); /* 15.2.6.3.1 */ mrb_define_method(mrb, f, "^", false_xor, MRB_ARGS_REQ(1)); /* 15.2.6.3.2 */ diff --git a/src/symbol.c b/src/symbol.c index 25ae132e1..a3ab05c85 100644 --- a/src/symbol.c +++ b/src/symbol.c @@ -10,6 +10,7 @@ #include #include #include +#include /* ------------------------------------------------------ */ typedef struct symbol_name { @@ -481,6 +482,8 @@ mrb_init_symbol(mrb_state *mrb) struct RClass *sym; mrb->symbol_class = sym = mrb_define_class(mrb, "Symbol", mrb->object_class); /* 15.2.11 */ + MRB_SET_INSTANCE_TT(sym, MRB_TT_SYMBOL); + mrb_undef_class_method(mrb, sym, "new"); mrb_define_method(mrb, sym, "===", sym_equal, MRB_ARGS_REQ(1)); /* 15.2.11.3.1 */ mrb_define_method(mrb, sym, "id2name", mrb_sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.2 */ -- cgit v1.2.3 From acdddb4f1431945e61030a436f4a611307bc4420 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Wed, 30 Nov 2016 13:55:09 -0500 Subject: Prevent array size calculation overflows. --- src/array.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index df037a121..8902f2dda 100644 --- a/src/array.c +++ b/src/array.c @@ -118,7 +118,7 @@ ary_modify(mrb_state *mrb, struct RArray *a) } else { mrb_value *ptr, *p; - mrb_int len; + size_t len; p = a->ptr; len = a->len * sizeof(mrb_value); @@ -244,6 +244,9 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value self) static void ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2) { + if (a2->len > ARY_MAX_SIZE - a->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } mrb_int len = a->len + a2->len; ary_modify(mrb, a); @@ -559,7 +562,7 @@ static struct RArray* ary_dup(mrb_state *mrb, struct RArray *a) { struct RArray *d = ary_new_capa(mrb, a->len); - + ary_replace(mrb, d, a->ptr, a->len); return d; } -- cgit v1.2.3 From ab4ab7c8a0e5226e4a76f7c37bdb79d2c92c004f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 1 Dec 2016 18:37:03 +0900 Subject: Fix compile error by #3309 --- src/array.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 8902f2dda..9013492fb 100644 --- a/src/array.c +++ b/src/array.c @@ -244,10 +244,12 @@ mrb_ary_s_create(mrb_state *mrb, mrb_value self) static void ary_concat(mrb_state *mrb, struct RArray *a, struct RArray *a2) { + mrb_int len; + if (a2->len > ARY_MAX_SIZE - a->len) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } - mrb_int len = a->len + a2->len; + len = a->len + a2->len; ary_modify(mrb, a); if (a->aux.capa < len) { -- cgit v1.2.3 From 2bc3a5fb781056675931c1a3da435c24ad57b4bd Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Wed, 30 Nov 2016 16:30:30 -0500 Subject: Fix more integer overflows. --- src/array.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 9013492fb..f6599bd5b 100644 --- a/src/array.c +++ b/src/array.c @@ -173,11 +173,13 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) capa = ARY_DEFAULT_LEN; } while (capa < len) { - capa *= 2; + if (capa <= ARY_MAX_SIZE / 2) { + capa *= 2; + } else { + capa = ARY_MAX_SIZE; + } } - if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */ - if (capa > a->aux.capa) { mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa); @@ -503,6 +505,9 @@ mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) mrb_int len; mrb_get_args(mrb, "*", &vals, &len); + if (len > ARY_MAX_SIZE - a->len) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } if (ARY_SHARED_P(a) && a->aux.shared->refcnt == 1 /* shared only referenced from this array */ && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ { -- cgit v1.2.3 From 7d07466b437910d560fda2f78d2f7b93205eaa22 Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Tue, 29 Nov 2016 10:54:21 -0500 Subject: Fix stack move segfaulting in OP_ARYCAT Reported by https://hackerone.com/haquaman Testcase (couldn't get it to work as a test): def nil.b b *nil end nil.b --- src/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 41e19b0c0..f0dc338d0 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2134,8 +2134,8 @@ RETRY_TRY_BLOCK: CASE(OP_ARYCAT) { /* A B mrb_ary_concat(R(A),R(B)) */ - mrb_ary_concat(mrb, regs[GETARG_A(i)], - mrb_ary_splat(mrb, regs[GETARG_B(i)])); + mrb_value splat = mrb_ary_splat(mrb, regs[GETARG_B(i)]); + mrb_ary_concat(mrb, regs[GETARG_A(i)], splat); ARENA_RESTORE(mrb, ai); NEXT; } -- cgit v1.2.3 From 9c61e1cd87aca3646fe39a6d53223efdcb11e250 Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Mon, 28 Nov 2016 15:04:27 -0500 Subject: Use mrb_ptr instead of mrb_cptr in Kernel#to_s This is to avoid segfault when WORD_BOXING is enabled Reported by https://hackerone.com/brakhane --- src/object.c | 2 +- test/t/kernel.rb | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/object.c b/src/object.c index f76ee68a2..eb2c23e63 100644 --- a/src/object.c +++ b/src/object.c @@ -444,7 +444,7 @@ mrb_any_to_s(mrb_state *mrb, mrb_value obj) mrb_str_cat_lit(mrb, str, "#<"); mrb_str_cat_cstr(mrb, str, cname); mrb_str_cat_lit(mrb, str, ":"); - mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_cptr(obj))); + mrb_str_concat(mrb, str, mrb_ptr_to_str(mrb, mrb_ptr(obj))); mrb_str_cat_lit(mrb, str, ">"); return str; diff --git a/test/t/kernel.rb b/test/t/kernel.rb index d240e59dc..e59bd6a10 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -520,6 +520,21 @@ assert('Kernel#to_s', '15.3.1.3.46') do assert_equal to_s.class, String end +assert('Kernel#to_s on primitives') do + begin + Fixnum.alias_method :to_s_, :to_s + Fixnum.remove_method :to_s + + assert_nothing_raised do + # segfaults if mrb_cptr is used + 1.to_s + end + ensure + Fixnum.alias_method :to_s, :to_s_ + Fixnum.remove_method :to_s_ + end +end + assert('Kernel.local_variables', '15.3.1.2.7') do a, b = 0, 1 a += b -- cgit v1.2.3 From 1ff4b3f800d369510658b7926a1d6dc9327d0422 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Thu, 24 Nov 2016 15:51:25 -0500 Subject: Fix segfault in mrb_proc_copy. --- src/proc.c | 2 +- test/t/proc.rb | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/proc.c b/src/proc.c index 4f770932b..470547094 100644 --- a/src/proc.c +++ b/src/proc.c @@ -140,7 +140,7 @@ mrb_proc_copy(struct RProc *a, struct RProc *b) { a->flags = b->flags; a->body = b->body; - if (!MRB_PROC_CFUNC_P(a)) { + if (!MRB_PROC_CFUNC_P(a) && a->body.irep) { a->body.irep->refcnt++; } a->target_class = b->target_class; diff --git a/test/t/proc.rb b/test/t/proc.rb index bc9821f7c..29530e8dd 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -163,3 +163,19 @@ assert('&obj call to_proc if defined') do assert_raise(TypeError){ mock(&(Object.new)) } end + +assert('initialize_copy works when initialize is removed') do + begin + Proc.alias_method(:old_initialize, :initialize) + Proc.remove_method(:initialize) + + a = Proc.new {} + b = Proc.new {} + assert_nothing_raised do + a.initialize_copy(b) + end + ensure + Proc.alias_method(:initialize, :old_initialize) + Proc.remove_method(:old_initialize) + end +end -- cgit v1.2.3 From 79a621dd739faf4cc0958e11d6a887331cf79e48 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 3 Dec 2016 12:27:48 +0900 Subject: Check before retrieving struct RRange pointer; fix #3320 range->edges may be NULL for example when #initialize_copy removed. --- include/mruby/range.h | 3 ++- mrbgems/mruby-range-ext/src/range.c | 6 +++--- src/range.c | 39 ++++++++++++++++++++++++------------- 3 files changed, 30 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/include/mruby/range.h b/include/mruby/range.h index cf42ce133..fb602b3f3 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -25,7 +25,8 @@ struct RRange { mrb_bool excl : 1; }; -#define mrb_range_ptr(v) ((struct RRange*)(mrb_ptr(v))) +MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); +#define mrb_range_raw_ptr(v) ((struct RRange*)mrb_ptr(v)) #define mrb_range_value(p) mrb_obj_value((void*)(p)) /* diff --git a/mrbgems/mruby-range-ext/src/range.c b/mrbgems/mruby-range-ext/src/range.c index ccb5a9e45..8aa1379b0 100644 --- a/mrbgems/mruby-range-ext/src/range.c +++ b/mrbgems/mruby-range-ext/src/range.c @@ -44,7 +44,7 @@ static mrb_value mrb_range_cover(mrb_state *mrb, mrb_value range) { mrb_value val; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_get_args(mrb, "o", &val); @@ -87,7 +87,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range) { mrb_value num; mrb_value array; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); if (mrb_get_args(mrb, "|o", &num) == 0) { return r->edges->end; @@ -111,7 +111,7 @@ mrb_range_last(mrb_state *mrb, mrb_value range) static mrb_value mrb_range_size(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_float beg_f, end_f; mrb_bool num_p = TRUE; diff --git a/src/range.c b/src/range.c index f0a976e53..417957420 100644 --- a/src/range.c +++ b/src/range.c @@ -12,6 +12,17 @@ #define RANGE_CLASS (mrb_class_get(mrb, "Range")) +MRB_API struct RRange* +mrb_range_ptr(mrb_state *mrb, mrb_value v) +{ + struct RRange *r = (struct RRange*)mrb_ptr(v); + + if (r->edges == NULL) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "uninitialized range"); + } + return r; +} + static void range_check(mrb_state *mrb, mrb_value a, mrb_value b) { @@ -57,7 +68,7 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl) mrb_value mrb_range_beg(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return r->edges->beg; } @@ -76,7 +87,7 @@ mrb_range_beg(mrb_state *mrb, mrb_value range) mrb_value mrb_range_end(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return r->edges->end; } @@ -90,7 +101,7 @@ mrb_range_end(mrb_state *mrb, mrb_value range) mrb_value mrb_range_excl(mrb_state *mrb, mrb_value range) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); return mrb_bool_value(r->excl); } @@ -98,7 +109,7 @@ mrb_range_excl(mrb_state *mrb, mrb_value range) static void range_init(mrb_state *mrb, mrb_value range, mrb_value beg, mrb_value end, mrb_bool exclude_end) { - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_raw_ptr(range); range_check(mrb, beg, end); r->excl = exclude_end; @@ -129,7 +140,7 @@ mrb_range_initialize(mrb_state *mrb, mrb_value range) exclusive = FALSE; } /* Ranges are immutable, so that they should be initialized only once. */ - if (mrb_range_ptr(range)->edges) { + if (mrb_range_raw_ptr(range)->edges) { mrb_name_error(mrb, mrb_intern_lit(mrb, "initialize"), "`initialize' called twice"); } range_init(mrb, range, beg, end, exclusive); @@ -164,8 +175,8 @@ mrb_range_eq(mrb_state *mrb, mrb_value range) return mrb_false_value(); } - rr = mrb_range_ptr(range); - ro = mrb_range_ptr(obj); + rr = mrb_range_ptr(mrb, range); + ro = mrb_range_ptr(mrb, obj); v1 = mrb_funcall(mrb, rr->edges->beg, "==", 1, ro->edges->beg); v2 = mrb_funcall(mrb, rr->edges->end, "==", 1, ro->edges->end); if (!mrb_bool(v1) || !mrb_bool(v2) || rr->excl != ro->excl) { @@ -222,7 +233,7 @@ mrb_value mrb_range_include(mrb_state *mrb, mrb_value range) { mrb_value val; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); mrb_value beg, end; mrb_bool include_p; @@ -241,7 +252,7 @@ static mrb_bool range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); if (mrb_type(range) != MRB_TT_RANGE) return FALSE; @@ -287,7 +298,7 @@ static mrb_value range_to_s(mrb_state *mrb, mrb_value range) { mrb_value str, str2; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); str = mrb_obj_as_string(mrb, r->edges->beg); str2 = mrb_obj_as_string(mrb, r->edges->end); @@ -312,7 +323,7 @@ static mrb_value range_inspect(mrb_state *mrb, mrb_value range) { mrb_value str, str2; - struct RRange *r = mrb_range_ptr(range); + struct RRange *r = mrb_range_ptr(mrb, range); str = mrb_inspect(mrb, r->edges->beg); str2 = mrb_inspect(mrb, r->edges->end); @@ -352,8 +363,8 @@ range_eql(mrb_state *mrb, mrb_value range) } if (mrb_type(obj) != MRB_TT_RANGE) return mrb_false_value(); - r = mrb_range_ptr(range); - o = mrb_range_ptr(obj); + r = mrb_range_ptr(mrb, range); + o = mrb_range_ptr(mrb, obj); if (!mrb_eql(mrb, r->edges->beg, o->edges->beg) || !mrb_eql(mrb, r->edges->end, o->edges->end) || (r->excl != o->excl)) { @@ -376,7 +387,7 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class"); } - r = mrb_range_ptr(src); + r = mrb_range_ptr(mrb, src); range_init(mrb, copy, r->edges->beg, r->edges->end, r->excl); return copy; -- cgit v1.2.3 From a0fbc46ccd3e129532b05a9fe4f13f42a3c349b2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 3 Dec 2016 18:47:04 +0900 Subject: Import locale insensitive strtod() from Ruby1.8; fix #3270 The function was renamed to `mrb_float_read(const char*, char**)`. --- include/mruby/value.h | 5 +- mrbgems/mruby-compiler/core/codegen.c | 4 +- mrbgems/mruby-compiler/core/parse.y | 2 +- src/string.c | 242 +++++++++++++++++++++++++++++++++- 4 files changed, 245 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/include/mruby/value.h b/include/mruby/value.h index 61110e3dd..54d197f8f 100644 --- a/include/mruby/value.h +++ b/include/mruby/value.h @@ -62,12 +62,12 @@ struct mrb_state; # define MRB_PRIx PRIx32 #endif + +MRB_API double mrb_float_read(const char*, char**); #ifdef MRB_USE_FLOAT typedef float mrb_float; -# define str_to_mrb_float(buf) strtof(buf, NULL) #else typedef double mrb_float; -# define str_to_mrb_float(buf) strtod(buf, NULL) #endif #if defined _MSC_VER && _MSC_VER < 1900 @@ -85,7 +85,6 @@ MRB_API int mrb_msvc_snprintf(char *s, size_t n, const char *format, ...); # define isnan _isnan # define isinf(n) (!_finite(n) && !_isnan(n)) # define signbit(n) (_copysign(1.0, (n)) < 0.0) -# define strtof (float)strtod static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000; # define INFINITY (*(float *)&IEEE754_INFINITY_BITS_SINGLE) # define NAN ((float)(INFINITY - INFINITY)) diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 414ca2627..b2cd12225 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2211,7 +2211,7 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_FLOAT: if (val) { char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); + mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, f)); genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); @@ -2227,7 +2227,7 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_FLOAT: { char *p = (char*)tree; - mrb_float f = str_to_mrb_float(p); + mrb_float f = mrb_float_read(p, NULL); int off = new_lit(s, mrb_float_value(s->mrb, -f)); genop(s, MKOP_ABx(OP_LOADL, cursp(), off)); diff --git a/mrbgems/mruby-compiler/core/parse.y b/mrbgems/mruby-compiler/core/parse.y index e81d191d9..19cb88e5b 100644 --- a/mrbgems/mruby-compiler/core/parse.y +++ b/mrbgems/mruby-compiler/core/parse.y @@ -4912,7 +4912,7 @@ parser_yylex(parser_state *p) char *endp; errno = 0; - d = strtod(tok(p), &endp); + d = mrb_float_read(tok(p), &endp); if (d == 0 && endp == tok(p)) { yywarning_s(p, "corrupted float value %s", tok(p)); } diff --git a/src/string.c b/src/string.c index f47294291..e3a268f78 100644 --- a/src/string.c +++ b/src/string.c @@ -2286,7 +2286,7 @@ mrb_cstr_to_dbl(mrb_state *mrb, const char * p, mrb_bool badcheck) if (!badcheck && p[0] == '0' && (p[1] == 'x' || p[1] == 'X')) { return 0.0; } - d = strtod(p, &end); + d = mrb_float_read(p, &end); if (p == end) { if (badcheck) { bad: @@ -2324,7 +2324,7 @@ bad: return 0.0; } - d = strtod(p, &end); + d = mrb_float_read(p, &end); if (badcheck) { if (!end || p == end) goto bad; while (*end && ISSPACE(*end)) end++; @@ -2749,3 +2749,241 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } + +/* + * Source code for the "strtod" library procedure. + * + * Copyright (c) 1988-1993 The Regents of the University of California. + * Copyright (c) 1994 Sun Microsystems, Inc. + * + * Permission to use, copy, modify, and distribute this + * software and its documentation for any purpose and without + * fee is hereby granted, provided that the above copyright + * notice appear in all copies. The University of California + * makes no representations about the suitability of this + * software for any purpose. It is provided "as is" without + * express or implied warranty. + * + * RCS: @(#) $Id: strtod.c 11708 2007-02-12 23:01:19Z shyouhei $ + */ + +#include +#include +extern int errno; + +#ifndef __STDC__ +# ifdef __GNUC__ +# define const __const__ +# else +# define const +# endif +#endif + +static const int maxExponent = 511; /* Largest possible base 10 exponent. Any + * exponent larger than this will already + * produce underflow or overflow, so there's + * no need to worry about additional digits. + */ +static const double powersOf10[] = {/* Table giving binary powers of 10. Entry */ + 10., /* is 10^2^i. Used to convert decimal */ + 100., /* exponents into floating-point numbers. */ + 1.0e4, + 1.0e8, + 1.0e16, + 1.0e32, + 1.0e64, + 1.0e128, + 1.0e256 +}; + +double +mrb_float_read(const char *string, char **endPtr) +/* const char *string; A decimal ASCII floating-point number, + * optionally preceded by white space. + * Must have form "-I.FE-X", where I is the + * integer part of the mantissa, F is the + * fractional part of the mantissa, and X + * is the exponent. Either of the signs + * may be "+", "-", or omitted. Either I + * or F may be omitted, or both. The decimal + * point isn't necessary unless F is present. + * The "E" may actually be an "e". E and X + * may both be omitted (but not just one). + */ +/* char **endPtr; If non-NULL, store terminating character's + * address here. */ +{ + int sign, expSign = FALSE; + double fraction, dblExp; + const double *d; + register const char *p; + register int c; + int exp = 0; /* Exponent read from "EX" field. */ + int fracExp = 0; /* Exponent that derives from the fractional + * part. Under normal circumstatnces, it is + * the negative of the number of digits in F. + * However, if I is very long, the last digits + * of I get dropped (otherwise a long I with a + * large negative exponent could cause an + * unnecessary overflow on I alone). In this + * case, fracExp is incremented one for each + * dropped digit. */ + int mantSize; /* Number of digits in mantissa. */ + int decPt; /* Number of mantissa digits BEFORE decimal + * point. */ + const char *pExp; /* Temporarily holds location of exponent + * in string. */ + + /* + * Strip off leading blanks and check for a sign. + */ + + p = string; + while (isspace(*p)) { + p += 1; + } + if (*p == '-') { + sign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + sign = FALSE; + } + + /* + * Count the number of digits in the mantissa (including the decimal + * point), and also locate the decimal point. + */ + + decPt = -1; + for (mantSize = 0; ; mantSize += 1) + { + c = *p; + if (!isdigit(c)) { + if ((c != '.') || (decPt >= 0)) { + break; + } + decPt = mantSize; + } + p += 1; + } + + /* + * Now suck up the digits in the mantissa. Use two integers to + * collect 9 digits each (this is faster than using floating-point). + * If the mantissa has more than 18 digits, ignore the extras, since + * they can't affect the value anyway. + */ + + pExp = p; + p -= mantSize; + if (decPt < 0) { + decPt = mantSize; + } else { + mantSize -= 1; /* One of the digits was the point. */ + } + if (mantSize > 18) { + fracExp = decPt - 18; + mantSize = 18; + } else { + fracExp = decPt - mantSize; + } + if (mantSize == 0) { + fraction = 0.0; + p = string; + goto done; + } else { + int frac1, frac2; + frac1 = 0; + for ( ; mantSize > 9; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac1 = 10*frac1 + (c - '0'); + } + frac2 = 0; + for (; mantSize > 0; mantSize -= 1) + { + c = *p; + p += 1; + if (c == '.') { + c = *p; + p += 1; + } + frac2 = 10*frac2 + (c - '0'); + } + fraction = (1.0e9 * frac1) + frac2; + } + + /* + * Skim off the exponent. + */ + + p = pExp; + if ((*p == 'E') || (*p == 'e')) { + p += 1; + if (*p == '-') { + expSign = TRUE; + p += 1; + } else { + if (*p == '+') { + p += 1; + } + expSign = FALSE; + } + while (isdigit(*p)) { + exp = exp * 10 + (*p - '0'); + p += 1; + } + } + if (expSign) { + exp = fracExp - exp; + } else { + exp = fracExp + exp; + } + + /* + * Generate a floating-point number that represents the exponent. + * Do this by processing the exponent one bit at a time to combine + * many powers of 2 of 10. Then combine the exponent with the + * fraction. + */ + + if (exp < 0) { + expSign = TRUE; + exp = -exp; + } else { + expSign = FALSE; + } + if (exp > maxExponent) { + exp = maxExponent; + errno = ERANGE; + } + dblExp = 1.0; + for (d = powersOf10; exp != 0; exp >>= 1, d += 1) { + if (exp & 01) { + dblExp *= *d; + } + } + if (expSign) { + fraction /= dblExp; + } else { + fraction *= dblExp; + } + +done: + if (endPtr != NULL) { + *endPtr = (char *) p; + } + + if (sign) { + return -fraction; + } + return fraction; +} -- cgit v1.2.3 From 5c651d6ce94449df8f096b624bc99fd4de3d698e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 3 Dec 2016 18:55:52 +0900 Subject: add MRB_API to mrb_float_read(); ref #3270 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index e3a268f78..4f722b273 100644 --- a/src/string.c +++ b/src/string.c @@ -2796,7 +2796,7 @@ static const double powersOf10[] = {/* Table giving binary powers of 10. Entry 1.0e256 }; -double +MRB_API double mrb_float_read(const char *string, char **endPtr) /* const char *string; A decimal ASCII floating-point number, * optionally preceded by white space. -- cgit v1.2.3 From ac561a52f583ce154a27622642a37a7a386cbcd9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 4 Dec 2016 10:41:01 +0900 Subject: Add symbol type check for Module#undef_method --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index bac1d2984..e724dbb91 100644 --- a/src/class.c +++ b/src/class.c @@ -1817,7 +1817,7 @@ mrb_mod_undef(mrb_state *mrb, mrb_value mod) mrb_get_args(mrb, "*", &argv, &argc); while (argc--) { - undef_method(mrb, c, mrb_symbol(*argv)); + undef_method(mrb, c, to_sym(mrb, *argv)); argv++; } return mrb_nil_value(); -- cgit v1.2.3 From dffb4d82dc83054eade20679f069979d242d9745 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 6 Dec 2016 11:40:49 +0900 Subject: Add type check for cls before allocation --- src/gc.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 69708e40b..470fffc5f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -480,7 +480,18 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls) mrb_gc *gc = &mrb->gc; if (cls) { - enum mrb_vtype tt = MRB_INSTANCE_TT(cls); + enum mrb_vtype tt; + + switch (cls->tt) { + case MRB_TT_CLASS: + case MRB_TT_SCLASS: + case MRB_TT_MODULE: + case MRB_TT_ENV: + break; + default: + mrb_raise(mrb, E_TYPE_ERROR, "allocation failure"); + } + tt = MRB_INSTANCE_TT(cls); if (tt != MRB_TT_FALSE && ttype != MRB_TT_SCLASS && ttype != MRB_TT_ICLASS && -- cgit v1.2.3 From 6187c21bd96d120c4e58ebeae83749ab9f56a16c Mon Sep 17 00:00:00 2001 From: Felix Jones Date: Wed, 7 Dec 2016 12:46:47 +0000 Subject: Wrapped string.c errno with ifndef macro for platforms that use inbuilt errno macro --- src/string.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 4f722b273..4189d84d0 100644 --- a/src/string.c +++ b/src/string.c @@ -2750,7 +2750,7 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } -/* +/* * Source code for the "strtod" library procedure. * * Copyright (c) 1988-1993 The Regents of the University of California. @@ -2769,7 +2769,9 @@ mrb_init_string(mrb_state *mrb) #include #include +#ifndef errno extern int errno; +#endif #ifndef __STDC__ # ifdef __GNUC__ @@ -2876,7 +2878,7 @@ mrb_float_read(const char *string, char **endPtr) * If the mantissa has more than 18 digits, ignore the extras, since * they can't affect the value anyway. */ - + pExp = p; p -= mantSize; if (decPt < 0) { @@ -2954,7 +2956,7 @@ mrb_float_read(const char *string, char **endPtr) * many powers of 2 of 10. Then combine the exponent with the * fraction. */ - + if (exp < 0) { expSign = TRUE; exp = -exp; -- cgit v1.2.3 From 338e0ff52d645556e644ac08b3efc6ea31868c59 Mon Sep 17 00:00:00 2001 From: Shugo Maeda Date: Wed, 7 Dec 2016 22:39:20 +0900 Subject: Copy default_proc by Hash#dup. --- src/hash.c | 14 +++++++++++++- test/t/hash.rb | 4 ++++ 2 files changed, 17 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index 4df2babbe..93fe656e0 100644 --- a/src/hash.c +++ b/src/hash.c @@ -225,6 +225,7 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash) struct RHash* ret; khash_t(ht) *h, *ret_h; khiter_t k, ret_k; + mrb_value ifnone, vret; h = RHASH_TBL(hash); ret = (struct RHash*)mrb_obj_alloc(mrb, MRB_TT_HASH, mrb->hash_class); @@ -243,7 +244,18 @@ mrb_hash_dup(mrb_state *mrb, mrb_value hash) } } - return mrb_obj_value(ret); + if (MRB_RHASH_DEFAULT_P(hash)) { + ret->flags |= MRB_HASH_DEFAULT; + } + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + ret->flags |= MRB_HASH_PROC_DEFAULT; + } + vret = mrb_obj_value(ret); + ifnone = RHASH_IFNONE(hash); + if (!mrb_nil_p(ifnone)) { + mrb_iv_set(mrb, vret, mrb_intern_lit(mrb, "ifnone"), ifnone); + } + return vret; } MRB_API mrb_value diff --git a/test/t/hash.rb b/test/t/hash.rb index b455812cf..f076db8e5 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -44,6 +44,10 @@ assert('Hash#dup') do b = a.dup a['a'] = 2 assert_equal({'a' => 1}, b) + + c = Hash.new { |h, k| h[k] = k.upcase } + d = c.dup + assert_equal("FOO", d["foo"]) end assert('Hash#default', '15.2.13.4.5') do -- cgit v1.2.3 From fe86cf4c916b2ef89abd1ac7cd7eca63b7ae953e Mon Sep 17 00:00:00 2001 From: Felix Jones Date: Wed, 7 Dec 2016 14:17:09 +0000 Subject: Removed the errno declaration from string.c --- src/string.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 4189d84d0..a9351619b 100644 --- a/src/string.c +++ b/src/string.c @@ -2769,9 +2769,6 @@ mrb_init_string(mrb_state *mrb) #include #include -#ifndef errno -extern int errno; -#endif #ifndef __STDC__ # ifdef __GNUC__ -- cgit v1.2.3 From f7a891fa8979bdb82410e1adc98765013cc29a79 Mon Sep 17 00:00:00 2001 From: Bouke van der Bijl Date: Tue, 6 Dec 2016 10:30:08 -0500 Subject: Mark all the built-in classes during GC sweep Reported by https://hackerone.com/haquaman --- mrbgems/mruby-bin-mruby/bintest/mruby.rb | 14 ++++++++++++++ src/gc.c | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+) (limited to 'src') diff --git a/mrbgems/mruby-bin-mruby/bintest/mruby.rb b/mrbgems/mruby-bin-mruby/bintest/mruby.rb index 01fc94632..ad8ec3a0f 100644 --- a/mrbgems/mruby-bin-mruby/bintest/mruby.rb +++ b/mrbgems/mruby-bin-mruby/bintest/mruby.rb @@ -44,3 +44,17 @@ EOS script.flush assert_equal "\"test\"\n\"fin\"\n", `#{cmd('mruby')} #{script.path}` end + +assert('garbage collecting built-in classes') do + script = Tempfile.new('test.rb') + + script.write <object_class); + + /* mark built-in classes */ + mrb_gc_mark(mrb, (struct RBasic*)mrb->class_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->module_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->proc_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->string_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->array_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->hash_class); + + mrb_gc_mark(mrb, (struct RBasic*)mrb->float_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->fixnum_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->true_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->false_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->nil_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->symbol_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->kernel_module); + + mrb_gc_mark(mrb, (struct RBasic*)mrb->eException_class); + mrb_gc_mark(mrb, (struct RBasic*)mrb->eStandardError_class); + /* mark top_self */ mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self); /* mark exception */ -- cgit v1.2.3 From c2e749f878049204239ad63ac9546253aeb6ceeb Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Thu, 8 Dec 2016 10:22:14 +0900 Subject: fix issues of mrb_gc_unregister introduced in 09b1185 * fixes partial copy of objects in GC root array (due to missing `* sizeof(mrb_value)`) * restores the behavior that permitted an unregistered object to be used as an argument --- src/gc.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 470fffc5f..f928cc49b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -453,7 +453,7 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) mrb_sym root = mrb_intern_lit(mrb, GC_ROOT_NAME); mrb_value table = mrb_gv_get(mrb, root); struct RArray *a; - mrb_int i, len; + mrb_int i; if (mrb_nil_p(table)) return; if (mrb_type(table) != MRB_TT_ARRAY) { @@ -462,14 +462,13 @@ mrb_gc_unregister(mrb_state *mrb, mrb_value obj) } a = mrb_ary_ptr(table); mrb_ary_modify(mrb, a); - len = a->len-1; - for (i=0; ilen; i++) { if (mrb_obj_eq(mrb, a->ptr[i], obj)) { - memmove(&a->ptr[i], &a->ptr[i+1], len-i); + a->len--; + memmove(&a->ptr[i], &a->ptr[i + 1], (a->len - i) * sizeof(a->ptr[i])); break; } } - a->len--; } MRB_API struct RBasic* -- cgit v1.2.3 From eda6c1dc0550249b6e2d92c60aaa683d2b154eaf Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Thu, 8 Dec 2016 15:38:19 +0900 Subject: fix build on vs2013-vs2015 --- include/mruby/compile.h | 1 + src/numeric.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'src') diff --git a/include/mruby/compile.h b/include/mruby/compile.h index 3ccaf9f6a..459d88596 100644 --- a/include/mruby/compile.h +++ b/include/mruby/compile.h @@ -163,6 +163,7 @@ struct mrb_parser_state { MRB_API struct mrb_parser_state* mrb_parser_new(mrb_state*); MRB_API void mrb_parser_free(struct mrb_parser_state*); MRB_API void mrb_parser_parse(struct mrb_parser_state*,mrbc_context*); +MRB_API double mrb_float_read(const char*, char**); MRB_API void mrb_parser_set_filename(struct mrb_parser_state*, char const*); MRB_API char const* mrb_parser_get_filename(struct mrb_parser_state*, uint16_t idx); diff --git a/src/numeric.c b/src/numeric.c index 25a411de8..a9a2a641b 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -357,7 +357,11 @@ flo_shift(mrb_state *mrb, mrb_value x, mrb_int width) while (width++) { val /= 2; } +#if defined(_ISOC99_SOURCE) val = trunc(val); +#else + val = val > 0 ? floor(val) : ceil(val); +#endif if (val == 0 && mrb_float(x) < 0) { return mrb_fixnum_value(-1); } -- cgit v1.2.3 From c27dbfedf4dbd95ef17c6ad2b84933088e56d2cd Mon Sep 17 00:00:00 2001 From: Yasuhiro Matsumoto Date: Thu, 8 Dec 2016 15:56:50 +0900 Subject: disable define const on VS --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index a9351619b..c921ca56d 100644 --- a/src/string.c +++ b/src/string.c @@ -2773,7 +2773,7 @@ mrb_init_string(mrb_state *mrb) #ifndef __STDC__ # ifdef __GNUC__ # define const __const__ -# else +# elif !defined(_MSC_VER) # define const # endif #endif -- cgit v1.2.3 From 2827655b9cf3099ef323cfb7967e5ddaa8ba28e1 Mon Sep 17 00:00:00 2001 From: Felix Jones Date: Thu, 8 Dec 2016 12:38:00 +0000 Subject: Removed unnecessary const macro - const keyword is already a dependency --- src/string.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index c921ca56d..a4f8085ec 100644 --- a/src/string.c +++ b/src/string.c @@ -2770,14 +2770,6 @@ mrb_init_string(mrb_state *mrb) #include #include -#ifndef __STDC__ -# ifdef __GNUC__ -# define const __const__ -# elif !defined(_MSC_VER) -# define const -# endif -#endif - static const int maxExponent = 511; /* Largest possible base 10 exponent. Any * exponent larger than this will already * produce underflow or overflow, so there's -- cgit v1.2.3 From 2ef634edb5ce70331a6a66d1c36726db904492bf Mon Sep 17 00:00:00 2001 From: Kazuho Oku Date: Sat, 10 Dec 2016 15:11:07 +0900 Subject: do not destroy a page with an active TT_ENV (e.g. an env referred from TT_FIBER) --- src/gc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index f928cc49b..5525f0593 100644 --- a/src/gc.c +++ b/src/gc.c @@ -741,10 +741,12 @@ obj_free(mrb_state *mrb, struct RBasic *obj) { struct REnv *e = (struct REnv*)obj; - if (!MRB_ENV_STACK_SHARED_P(e)) { - mrb_free(mrb, e->stack); - e->stack = NULL; + if (MRB_ENV_STACK_SHARED_P(e)) { + /* cannot be freed */ + return; } + mrb_free(mrb, e->stack); + e->stack = NULL; } break; @@ -998,9 +1000,13 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) if (is_dead(gc, &p->as.basic)) { if (p->as.basic.tt != MRB_TT_FREE) { obj_free(mrb, &p->as.basic); - p->as.free.next = page->freelist; - page->freelist = (struct RBasic*)p; - freed++; + if (p->as.basic.tt == MRB_TT_FREE) { + p->as.free.next = page->freelist; + page->freelist = (struct RBasic*)p; + freed++; + } else { + dead_slot = 0; + } } } else { -- cgit v1.2.3 From 0af170fbec1bbf412b009117736d22e6f5c39b03 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 10 Dec 2016 15:34:32 +0900 Subject: gc.c: dead_slot is boolean; ref #3339 --- src/gc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 5525f0593..e8523af79 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1004,15 +1004,16 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) p->as.free.next = page->freelist; page->freelist = (struct RBasic*)p; freed++; - } else { - dead_slot = 0; + } + else { + dead_slot = FALSE; } } } else { if (!is_generational(gc)) paint_partial_white(gc, &p->as.basic); /* next gc target */ - dead_slot = 0; + dead_slot = FALSE; } p++; } -- cgit v1.2.3 From 10bb7ad693e7c7443de924a39c1fedb4461108ba Mon Sep 17 00:00:00 2001 From: Takashi Kokubun Date: Sun, 11 Dec 2016 01:45:38 +0900 Subject: Implement Object#freeze --- include/mruby/class.h | 1 + include/mruby/object.h | 4 ++++ include/mruby/string.h | 5 ----- src/array.c | 4 ++++ src/hash.c | 7 +++++-- src/kernel.c | 10 ++++++++++ src/string.c | 15 ++------------- test/t/array.rb | 7 +++++++ test/t/hash.rb | 7 +++++++ test/t/kernel.rb | 5 +++++ 10 files changed, 45 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/include/mruby/class.h b/include/mruby/class.h index 246e82e59..ce953af3b 100644 --- a/include/mruby/class.h +++ b/include/mruby/class.h @@ -52,6 +52,7 @@ mrb_class(mrb_state *mrb, mrb_value v) } // TODO: figure out where to put user flags +#define MRB_FLAG_IS_FROZEN (1 << 18) #define MRB_FLAG_IS_PREPENDED (1 << 19) #define MRB_FLAG_IS_ORIGIN (1 << 20) #define MRB_CLASS_ORIGIN(c) do {\ diff --git a/include/mruby/object.h b/include/mruby/object.h index 9fbfe34f3..da44027e1 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -22,6 +22,10 @@ struct RBasic { }; #define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) +#define RBASIC_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) +#define RBASIC_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) +#define RBASIC_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) + struct RObject { MRB_OBJECT_HEADER; struct iv_tbl *iv; diff --git a/include/mruby/string.h b/include/mruby/string.h index b30c1ed98..9ccf8f187 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -62,10 +62,6 @@ struct RString { #define RSTR_SET_NOFREE_FLAG(s) ((s)->flags |= MRB_STR_NOFREE) #define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE) -#define RSTR_FROZEN_P(s) ((s)->flags & MRB_STR_FROZEN) -#define RSTR_SET_FROZEN_FLAG(s) ((s)->flags |= MRB_STR_FROZEN) -#define RSTR_UNSET_FROZEN_FLAG(s) ((s)->flags &= ~MRB_STR_FROZEN) - /* * Returns a pointer from a Ruby string */ @@ -80,7 +76,6 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_SHARED 1 #define MRB_STR_NOFREE 2 -#define MRB_STR_FROZEN 4 #define MRB_STR_NO_UTF 8 #define MRB_STR_EMBED 16 #define MRB_STR_EMBED_LEN_MASK 0x3e0 diff --git a/src/array.c b/src/array.c index f6599bd5b..c6bac7b47 100644 --- a/src/array.c +++ b/src/array.c @@ -108,6 +108,10 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify(mrb_state *mrb, struct RArray *a) { + if (RBASIC_FROZEN_P(a)) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array"); + } + if (ARY_SHARED_P(a)) { mrb_shared_array *shared = a->aux.shared; diff --git a/src/hash.c b/src/hash.c index 93fe656e0..d0e865b5c 100644 --- a/src/hash.c +++ b/src/hash.c @@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value mrb_hash_ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key) && !RSTR_FROZEN_P(mrb_str_ptr(key))) { + if (mrb_string_p(key) && !RBASIC_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); - RSTR_SET_FROZEN_FLAG(mrb_str_ptr(key)); + RBASIC_SET_FROZEN_FLAG(mrb_str_ptr(key)); } return key; } @@ -278,6 +278,9 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { + if (RBASIC_FROZEN_P(mrb_hash_ptr(hash))) { + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash"); + } mrb_hash_tbl(mrb, hash); } diff --git a/src/kernel.c b/src/kernel.c index c63e05596..78e57a17a 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -450,6 +450,15 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) return mrb_obj_extend(mrb, argc, argv, self); } +static mrb_value +mrb_obj_freeze(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b = mrb_basic_ptr(self); + + RBASIC_SET_FROZEN_FLAG(b); + return self; +} + /* 15.3.1.3.15 */ /* * call-seq: @@ -1124,6 +1133,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "eql?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.10 */ mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ + mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ diff --git a/src/string.c b/src/string.c index a4f8085ec..7234ecf2b 100644 --- a/src/string.c +++ b/src/string.c @@ -501,7 +501,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) static void check_frozen(mrb_state *mrb, struct RString *s) { - if (RSTR_FROZEN_P(s)) { + if (RBASIC_FROZEN_P(s)) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); } } @@ -700,15 +700,6 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } } -static mrb_value -mrb_str_freeze(mrb_state *mrb, mrb_value str) -{ - struct RString *s = mrb_str_ptr(str); - - RSTR_SET_FROZEN_FLAG(s); - return str; -} - MRB_API mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len) { @@ -2217,7 +2208,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) char *p = RSTR_PTR(ps); if (!p || p[len] != '\0') { - if (RSTR_FROZEN_P(ps)) { + if (RBASIC_FROZEN_P(ps)) { *ptr = str = mrb_str_dup(mrb, str); ps = mrb_str_ptr(str); } @@ -2746,8 +2737,6 @@ mrb_init_string(mrb_state *mrb) mrb_define_method(mrb, s, "upcase!", mrb_str_upcase_bang, MRB_ARGS_NONE()); /* 15.2.10.5.43 */ mrb_define_method(mrb, s, "inspect", mrb_str_inspect, MRB_ARGS_NONE()); /* 15.2.10.5.46(x) */ mrb_define_method(mrb, s, "bytes", mrb_str_bytes, MRB_ARGS_NONE()); - - mrb_define_method(mrb, s, "freeze", mrb_str_freeze, MRB_ARGS_NONE()); } /* diff --git a/test/t/array.rb b/test/t/array.rb index 9cc2f64ad..cf7ed4704 100644 --- a/test/t/array.rb +++ b/test/t/array.rb @@ -373,3 +373,10 @@ assert("Array#rindex") do $a = [2, 3, 4, 5, 6, 7, 8, 9, 10, Sneaky.new] assert_equal 0, $a.rindex(1) end + +assert('Array#freeze') do + a = [].freeze + assert_raise(RuntimeError) do + a[0] = 1 + end +end diff --git a/test/t/hash.rb b/test/t/hash.rb index f076db8e5..c63b8c009 100644 --- a/test/t/hash.rb +++ b/test/t/hash.rb @@ -366,3 +366,10 @@ assert('Hash#rehash') do h.rehash assert_equal("b", h[[:b]]) end + +assert('Hash#freeze') do + h = {}.freeze + assert_raise(RuntimeError) do + h[:a] = 'b' + end +end diff --git a/test/t/kernel.rb b/test/t/kernel.rb index e59bd6a10..42abed9df 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -257,6 +257,11 @@ assert('Kernel#extend works on toplevel', '15.3.1.3.13') do assert_true respond_to?(:test_method) end +assert('Kernel#freeze') do + obj = Object.new + assert_equal obj, obj.freeze +end + assert('Kernel#global_variables', '15.3.1.3.14') do assert_equal Array, global_variables.class end -- cgit v1.2.3 From 92c843dd07211d698a6dac90fbd740e483ae34af Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 12 Dec 2016 00:54:36 +0900 Subject: rename prefix RBASIC_ to MRB_; ref #3340 --- include/mruby/object.h | 6 +++--- src/array.c | 2 +- src/hash.c | 6 +++--- src/kernel.c | 2 +- src/string.c | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/include/mruby/object.h b/include/mruby/object.h index da44027e1..9347981d4 100644 --- a/include/mruby/object.h +++ b/include/mruby/object.h @@ -22,9 +22,9 @@ struct RBasic { }; #define mrb_basic_ptr(v) ((struct RBasic*)(mrb_ptr(v))) -#define RBASIC_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) -#define RBASIC_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) -#define RBASIC_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) +#define MRB_FROZEN_P(o) ((o)->flags & MRB_FLAG_IS_FROZEN) +#define MRB_SET_FROZEN_FLAG(o) ((o)->flags |= MRB_FLAG_IS_FROZEN) +#define MRB_UNSET_FROZEN_FLAG(o) ((o)->flags &= ~MRB_FLAG_IS_FROZEN) struct RObject { MRB_OBJECT_HEADER; diff --git a/src/array.c b/src/array.c index c6bac7b47..7601e9c17 100644 --- a/src/array.c +++ b/src/array.c @@ -108,7 +108,7 @@ ary_fill_with_nil(mrb_value *ptr, mrb_int size) static void ary_modify(mrb_state *mrb, struct RArray *a) { - if (RBASIC_FROZEN_P(a)) { + if (MRB_FROZEN_P(a)) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen array"); } diff --git a/src/hash.c b/src/hash.c index d0e865b5c..c65c8926e 100644 --- a/src/hash.c +++ b/src/hash.c @@ -98,9 +98,9 @@ static void mrb_hash_modify(mrb_state *mrb, mrb_value hash); static inline mrb_value mrb_hash_ht_key(mrb_state *mrb, mrb_value key) { - if (mrb_string_p(key) && !RBASIC_FROZEN_P(mrb_str_ptr(key))) { + if (mrb_string_p(key) && !MRB_FROZEN_P(mrb_str_ptr(key))) { key = mrb_str_dup(mrb, key); - RBASIC_SET_FROZEN_FLAG(mrb_str_ptr(key)); + MRB_SET_FROZEN_FLAG(mrb_str_ptr(key)); } return key; } @@ -278,7 +278,7 @@ mrb_hash_tbl(mrb_state *mrb, mrb_value hash) static void mrb_hash_modify(mrb_state *mrb, mrb_value hash) { - if (RBASIC_FROZEN_P(mrb_hash_ptr(hash))) { + if (MRB_FROZEN_P(mrb_hash_ptr(hash))) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen hash"); } mrb_hash_tbl(mrb, hash); diff --git a/src/kernel.c b/src/kernel.c index 78e57a17a..a5166deb2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -455,7 +455,7 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) { struct RBasic *b = mrb_basic_ptr(self); - RBASIC_SET_FROZEN_FLAG(b); + MRB_SET_FROZEN_FLAG(b); return self; } diff --git a/src/string.c b/src/string.c index 7234ecf2b..ee5aa04f3 100644 --- a/src/string.c +++ b/src/string.c @@ -501,7 +501,7 @@ str_index(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int offset) static void check_frozen(mrb_state *mrb, struct RString *s) { - if (RBASIC_FROZEN_P(s)) { + if (MRB_FROZEN_P(s)) { mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen string"); } } @@ -2208,7 +2208,7 @@ mrb_string_value_cstr(mrb_state *mrb, mrb_value *ptr) char *p = RSTR_PTR(ps); if (!p || p[len] != '\0') { - if (RBASIC_FROZEN_P(ps)) { + if (MRB_FROZEN_P(ps)) { *ptr = str = mrb_str_dup(mrb, str); ps = mrb_str_ptr(str); } -- cgit v1.2.3 From 761562b65f33f47a18eae2c5db26ec48818498fc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 12 Dec 2016 01:00:24 +0900 Subject: freeze instance variables; ref #3340 --- src/variable.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/variable.c b/src/variable.c index 45dc055af..390da5455 100644 --- a/src/variable.c +++ b/src/variable.c @@ -489,6 +489,9 @@ mrb_obj_iv_set(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value v) { iv_tbl *t = obj->iv; + if (MRB_FROZEN_P(obj)) { + mrb_raisef(mrb, E_RUNTIME_ERROR, "can't modify frozen %S", mrb_obj_value(obj)); + } if (!t) { t = obj->iv = iv_new(mrb); } -- cgit v1.2.3 From 1164463a7c21699cfee2e0fb610ae9931b830cc0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 12 Dec 2016 01:05:07 +0900 Subject: freeze classes/modules; ref #3340 --- src/class.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/class.c b/src/class.c index e724dbb91..de68087cb 100644 --- a/src/class.c +++ b/src/class.c @@ -370,6 +370,12 @@ mrb_define_method_raw(mrb_state *mrb, struct RClass *c, mrb_sym mid, struct RPro MRB_CLASS_ORIGIN(c); h = c->mt; + if (MRB_FROZEN_P(c)) { + if (c->tt == MRB_TT_MODULE) + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen module"); + else + mrb_raise(mrb, E_RUNTIME_ERROR, "can't modify frozen class"); + } if (!h) h = c->mt = kh_init(mt, mrb); k = kh_put(mt, mrb, h, mid); kh_value(h, k) = p; -- cgit v1.2.3 From 9cef2654025e6646b1d0ff259086fc9eb02fff84 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 12 Dec 2016 10:34:21 +0900 Subject: should not try to set classpath for frozen classes; ref #3340 --- src/class.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index de68087cb..fed259b5b 100644 --- a/src/class.c +++ b/src/class.c @@ -1589,7 +1589,9 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) name = mrb_sym2name_len(mrb, sym, &len); path = mrb_str_new(mrb, name, len); } - mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path); + if (!MRB_FROZEN_P(c)) { + mrb_obj_iv_set(mrb, (struct RObject*)c, classpath, path); + } } return mrb_str_dup(mrb, path); } -- cgit v1.2.3 From 3a7c3695360e598ce4279a979cc9138a35971615 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 13 Dec 2016 10:48:36 +0900 Subject: Make sure str->capa is under MRB_INT_MAX; fix #3342 --- src/string.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index ee5aa04f3..dfe4fa3b1 100644 --- a/src/string.c +++ b/src/string.c @@ -156,14 +156,14 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) else capa = s->as.heap.aux.capa; - if (RSTR_LEN(s) >= MRB_INT_MAX - (mrb_int)len) { + total = RSTR_LEN(s)+len; + if (total >= MRB_INT_MAX) { mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } - total = RSTR_LEN(s)+len; if (capa <= total) { while (total > capa) { if (capa + 1 >= MRB_INT_MAX / 2) { - capa = (total + 4095) / 4096; + capa = MRB_INT_MAX; break; } capa = (capa + 1) * 2; -- cgit v1.2.3 From 3bedd22d55fafef83f2ddf387cb595cf5ea60e63 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 13 Dec 2016 10:50:04 +0900 Subject: Add assertion to make sure new capacity does not overflow. --- src/string.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index dfe4fa3b1..0049fdd5b 100644 --- a/src/string.c +++ b/src/string.c @@ -118,8 +118,8 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa) return mrb_obj_value(s); } -static inline void -resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity) +static void +resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) { if (RSTR_EMBED_P(s)) { if (RSTRING_EMBED_LEN_MAX < capacity) { @@ -133,6 +133,9 @@ resize_capa(mrb_state *mrb, struct RString *s, mrb_int capacity) } } else { +#if SIZE_MAX > MRB_INT_MAX + mrb_assert(capacity <= MRB_INT_MAX); +#endif s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); s->as.heap.aux.capa = capacity; } -- cgit v1.2.3 From df350766025e97f55b86ee51f71509cfa6b1e005 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 13 Dec 2016 17:17:47 +0900 Subject: Restore callinfo offset in mrb_yield_with_class() --- src/vm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 76f56298f..1ea23afc7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -654,11 +654,13 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value if (MRB_PROC_CFUNC_P(p)) { val = p->body.func(mrb, self); mrb->c->stack = mrb->c->ci->stackent; - cipop(mrb); } else { + int cioff = mrb->c->ci - mrb->c->cibase; val = mrb_run(mrb, p, self); + mrb->c->ci = mrb->c->cibase + cioff; } + cipop(mrb); return val; } -- cgit v1.2.3 From 73ad7395c066c4ffbf9c082be6bb45b2214e9286 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Tue, 13 Dec 2016 10:04:15 -0500 Subject: Check type before calling mrb_range_ptr. --- src/range.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/range.c b/src/range.c index 417957420..73fe7589b 100644 --- a/src/range.c +++ b/src/range.c @@ -252,9 +252,10 @@ static mrb_bool range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; - struct RRange *r = mrb_range_ptr(mrb, range); + struct RRange *r; if (mrb_type(range) != MRB_TT_RANGE) return FALSE; + r = mrb_range_ptr(mrb, range); beg = mrb_int(mrb, r->edges->beg); end = mrb_int(mrb, r->edges->end); -- cgit v1.2.3 From 868d2e528fce86f380a2d099877f6cb8ffd1ff69 Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Thu, 15 Dec 2016 09:36:22 -0500 Subject: Fix crash when exponent is -2147483648 --- src/string.c | 9 ++++++++- test/t/string.rb | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 0049fdd5b..ce27cdaa1 100644 --- a/src/string.c +++ b/src/string.c @@ -2868,7 +2868,11 @@ mrb_float_read(const char *string, char **endPtr) mantSize -= 1; /* One of the digits was the point. */ } if (mantSize > 18) { - fracExp = decPt - 18; + if (decPt - 18 > 29999) { + fracExp = 29999; + } else { + fracExp = decPt - 18; + } mantSize = 18; } else { fracExp = decPt - mantSize; @@ -2922,6 +2926,9 @@ mrb_float_read(const char *string, char **endPtr) } while (isdigit(*p)) { exp = exp * 10 + (*p - '0'); + if (exp > 19999) { + exp = 19999; + } p += 1; } } diff --git a/test/t/string.rb b/test/t/string.rb index 80fcbe6fa..20dc49d92 100644 --- a/test/t/string.rb +++ b/test/t/string.rb @@ -596,10 +596,14 @@ assert('String#to_f', '15.2.10.5.38') do a = ''.to_f b = '123456789'.to_f c = '12345.6789'.to_f + d = '1e-2147483648'.to_f + e = '1e2147483648'.to_f assert_float(0.0, a) assert_float(123456789.0, b) assert_float(12345.6789, c) + assert_float(0, d) + assert_float(Float::INFINITY, e) end assert('String#to_i', '15.2.10.5.39') do -- cgit v1.2.3 From 9781f7f0eace3b39355e65ad8ba0183be4ece417 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 17 Dec 2016 22:25:58 +0900 Subject: Add "not reached" mark in mrb_ary_concat() --- src/array.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/array.c b/src/array.c index 7601e9c17..056d72920 100644 --- a/src/array.c +++ b/src/array.c @@ -937,6 +937,7 @@ mrb_ary_splat(mrb_state *mrb, mrb_value v) recv_class, mrb_obj_value(mrb_obj_class(mrb, a)) ); + /* not reached */ return mrb_undef_value(); } } -- cgit v1.2.3 From 3cba13c249457cfb318c9d7d4456d99003442139 Mon Sep 17 00:00:00 2001 From: ksss Date: Wed, 21 Dec 2016 15:17:05 +0900 Subject: Proc shouldn't have `initialize` method Fix #3356 --- mrbgems/mruby-proc-ext/test/proc.rb | 11 ----------- src/proc.c | 12 ++++++------ test/t/proc.rb | 27 --------------------------- 3 files changed, 6 insertions(+), 44 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-proc-ext/test/proc.rb b/mrbgems/mruby-proc-ext/test/proc.rb index 7a078aabf..75e11dd93 100644 --- a/mrbgems/mruby-proc-ext/test/proc.rb +++ b/mrbgems/mruby-proc-ext/test/proc.rb @@ -58,17 +58,6 @@ assert('Proc#parameters') do assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters) end -assert('Proc#parameters with uninitialized Proc') do - begin - Proc.alias_method(:original_initialize, :initialize) - Proc.remove_method(:initialize) - assert_equal [], Proc.new{|a, b, c| 1}.parameters - ensure - Proc.alias_method(:initialize, :original_initialize) - Proc.remove_method(:original_initialize) - end -end - assert('Proc#to_proc') do proc = Proc.new {} assert_equal proc, proc.to_proc diff --git a/src/proc.c b/src/proc.c index 470547094..0fb38359f 100644 --- a/src/proc.c +++ b/src/proc.c @@ -148,19 +148,19 @@ mrb_proc_copy(struct RProc *a, struct RProc *b) } static mrb_value -mrb_proc_initialize(mrb_state *mrb, mrb_value self) +mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class) { mrb_value blk; + struct RProc *p; mrb_get_args(mrb, "&", &blk); if (mrb_nil_p(blk)) { /* Calling Proc.new without a block is not implemented yet */ mrb_raise(mrb, E_ARGUMENT_ERROR, "tried to create Proc object without a block"); } - else { - mrb_proc_copy(mrb_proc_ptr(self), mrb_proc_ptr(blk)); - } - return self; + p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class)); + mrb_proc_copy(p, mrb_proc_ptr(blk)); + return mrb_obj_value(p); } static mrb_value @@ -268,7 +268,7 @@ mrb_init_proc(mrb_state *mrb) call_irep->iseq = call_iseq; call_irep->ilen = 1; - mrb_define_method(mrb, mrb->proc_class, "initialize", mrb_proc_initialize, MRB_ARGS_NONE()); + mrb_define_class_method(mrb, mrb->proc_class, "new", mrb_proc_s_new, MRB_ARGS_ANY()); mrb_define_method(mrb, mrb->proc_class, "initialize_copy", mrb_proc_init_copy, MRB_ARGS_REQ(1)); mrb_define_method(mrb, mrb->proc_class, "arity", mrb_proc_arity, MRB_ARGS_NONE()); diff --git a/test/t/proc.rb b/test/t/proc.rb index 29530e8dd..888b7d56a 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -46,17 +46,6 @@ assert('Proc#arity', '15.2.17.4.2') do assert_equal(-1, g) end -assert('Proc#arity with unitialized Proc') do - begin - Proc.alias_method(:original_initialize, :initialize) - Proc.remove_method(:initialize) - assert_equal 0, Proc.new{|a, b, c| 1}.arity - ensure - Proc.alias_method(:initialize, :original_initialize) - Proc.remove_method(:original_initialize) - end -end - assert('Proc#call', '15.2.17.4.3') do a = 0 b = Proc.new { a += 1 } @@ -163,19 +152,3 @@ assert('&obj call to_proc if defined') do assert_raise(TypeError){ mock(&(Object.new)) } end - -assert('initialize_copy works when initialize is removed') do - begin - Proc.alias_method(:old_initialize, :initialize) - Proc.remove_method(:initialize) - - a = Proc.new {} - b = Proc.new {} - assert_nothing_raised do - a.initialize_copy(b) - end - ensure - Proc.alias_method(:initialize, :old_initialize) - Proc.remove_method(:old_initialize) - end -end -- cgit v1.2.3 From a68b568911f5dbf762d26ba21e4171bc7a2473e5 Mon Sep 17 00:00:00 2001 From: ksss Date: Wed, 21 Dec 2016 18:31:44 +0900 Subject: Should call initialize method if defined --- src/proc.c | 5 ++++- test/t/proc.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/proc.c b/src/proc.c index 0fb38359f..a75774667 100644 --- a/src/proc.c +++ b/src/proc.c @@ -151,6 +151,7 @@ static mrb_value mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class) { mrb_value blk; + mrb_value proc; struct RProc *p; mrb_get_args(mrb, "&", &blk); @@ -160,7 +161,9 @@ mrb_proc_s_new(mrb_state *mrb, mrb_value proc_class) } p = (struct RProc *)mrb_obj_alloc(mrb, MRB_TT_PROC, mrb_class_ptr(proc_class)); mrb_proc_copy(p, mrb_proc_ptr(blk)); - return mrb_obj_value(p); + proc = mrb_obj_value(p); + mrb_funcall_with_block(mrb, proc, mrb_intern_lit(mrb, "initialize"), 0, NULL, blk); + return proc; } static mrb_value diff --git a/test/t/proc.rb b/test/t/proc.rb index 888b7d56a..ef4566e66 100644 --- a/test/t/proc.rb +++ b/test/t/proc.rb @@ -136,6 +136,18 @@ assert('Proc#return_does_not_break_self') do assert_equal c, c.block.call end +assert('call Proc#initialize if defined') do + a = [] + c = Class.new(Proc) do + define_method(:initialize) do + a << :ok + end + end + + assert_kind_of c, c.new{} + assert_equal [:ok], a +end + assert('&obj call to_proc if defined') do pr = Proc.new{} def mock(&b) -- cgit v1.2.3 From 0de65a88d44c108ec5035be2741bed486ad88de5 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 23 Dec 2016 23:13:23 +0900 Subject: Do nothing when empty string Fix #3361 --- src/string.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index ce27cdaa1..a177aafba 100644 --- a/src/string.c +++ b/src/string.c @@ -754,6 +754,9 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) other = mrb_str_to_str(mrb, other); } s2 = mrb_str_ptr(other); + if (RSTR_LEN(s2) == 0) { + return; + } len = RSTR_LEN(s1) + RSTR_LEN(s2); if (RSTRING_CAPA(self) < len) { -- cgit v1.2.3 From c626b823cabf8ee7acbdf57e44597de3974c5f17 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 23 Dec 2016 23:30:35 +0900 Subject: Check overflow string length Fix #3360 --- src/string.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index ce27cdaa1..2d5006612 100644 --- a/src/string.c +++ b/src/string.c @@ -756,6 +756,9 @@ mrb_str_concat(mrb_state *mrb, mrb_value self, mrb_value other) s2 = mrb_str_ptr(other); len = RSTR_LEN(s1) + RSTR_LEN(s2); + if (len < 0 || len >= MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); + } if (RSTRING_CAPA(self) < len) { resize_capa(mrb, s1, len); } -- cgit v1.2.3 From 5c1c002ac2983fef8ef3254e2d2f3e016918c3cd Mon Sep 17 00:00:00 2001 From: ksss Date: Sat, 24 Dec 2016 22:54:52 +0900 Subject: Fix segv when primitive value Fix #3352 --- src/kernel.c | 18 ++++++++++++++++-- test/t/kernel.rb | 3 ++- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index a5166deb2..5e44d73b4 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -453,9 +453,23 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_freeze(mrb_state *mrb, mrb_value self) { - struct RBasic *b = mrb_basic_ptr(self); + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return self; + default: + break; + } - MRB_SET_FROZEN_FLAG(b); + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + MRB_SET_FROZEN_FLAG(b); + } return self; } diff --git a/test/t/kernel.rb b/test/t/kernel.rb index 42abed9df..ca4b73907 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -260,6 +260,8 @@ end assert('Kernel#freeze') do obj = Object.new assert_equal obj, obj.freeze + assert_equal 0, 0.freeze + assert_equal :a, :a.freeze end assert('Kernel#global_variables', '15.3.1.3.14') do @@ -620,4 +622,3 @@ assert('stack extend') do assert_equal 6, recurse(0, 5) end - -- cgit v1.2.3 From caba1a19dc3f9e31612d8439cfa7fbf60d05bbb0 Mon Sep 17 00:00:00 2001 From: ksss Date: Tue, 27 Dec 2016 15:48:53 +0900 Subject: Check array max size Fix #3354 --- src/array.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/array.c b/src/array.c index 056d72920..2ce4e5dc6 100644 --- a/src/array.c +++ b/src/array.c @@ -619,6 +619,10 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val size = head + argc; if (tail < a->len) size += a->len - tail; + + if (size < 0 || size > ARY_MAX_SIZE) + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + if (size > a->aux.capa) ary_expand_capa(mrb, a, size); -- cgit v1.2.3 From 270ea41b376d82b9685746ea363f64cbc84e79c9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 30 Dec 2016 22:09:32 +0900 Subject: method_missing() may have CALL_MAXARGS-1 arguments; fix #3351 The issue was reported by https://hackerone.com/ston3 --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 1ea23afc7..cca0fd03b 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1143,6 +1143,9 @@ RETRY_TRY_BLOCK: else { value_move(regs+a+2, regs+a+1, ++n); regs[a+1] = sym; + if (n == CALL_MAXARGS) { + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + } } } -- cgit v1.2.3 From 9d84f0d47b474711e8e8d944a1433154a4d85662 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 31 Dec 2016 23:09:56 +0900 Subject: ary_expand_capa(): size calculation by size_t; fix #3353 Also more size checks added. --- src/array.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 2ce4e5dc6..385f603ed 100644 --- a/src/array.c +++ b/src/array.c @@ -165,9 +165,9 @@ ary_make_shared(mrb_state *mrb, struct RArray *a) } static void -ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) +ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len) { - mrb_int capa = a->aux.capa; + size_t capa = a->aux.capa; if (len > ARY_MAX_SIZE) { mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); @@ -177,14 +177,16 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) capa = ARY_DEFAULT_LEN; } while (capa < len) { - if (capa <= ARY_MAX_SIZE / 2) { - capa *= 2; - } else { + capa *= 2; + if (capa > ARY_MAX_SIZE) { capa = ARY_MAX_SIZE; } } + if (capa < len || capa > MRB_INT_MAX) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + } - if (capa > a->aux.capa) { + if (capa > (size_t)a->aux.capa) { mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa); a->aux.capa = capa; -- cgit v1.2.3 From cfdd1e3cc6ec9ac7ba81ec6fad5d5ba4d11334b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 31 Dec 2016 23:22:17 +0900 Subject: ary_expand_capa(): refine conditions to avoid infinite loop; ref #3353 --- src/array.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 385f603ed..54ff26721 100644 --- a/src/array.c +++ b/src/array.c @@ -170,6 +170,7 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len) size_t capa = a->aux.capa; if (len > ARY_MAX_SIZE) { + size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); } @@ -177,13 +178,15 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len) capa = ARY_DEFAULT_LEN; } while (capa < len) { - capa *= 2; - if (capa > ARY_MAX_SIZE) { - capa = ARY_MAX_SIZE; + if (capa <= ARY_MAX_SIZE / 2) { + capa *= 2; + } + else { + goto size_error; } } if (capa < len || capa > MRB_INT_MAX) { - mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); + goto size_error; } if (capa > (size_t)a->aux.capa) { -- cgit v1.2.3 From 342b1de65c5f044e1f3dc08b6e04c9cd0206abc3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 31 Dec 2016 23:31:45 +0900 Subject: str_buf_cat(): should allocate at least RSTRING_EMBED_LEN_MAX+1. --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index 56eeef3a2..d41237f44 100644 --- a/src/string.c +++ b/src/string.c @@ -158,6 +158,8 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) capa = RSTRING_EMBED_LEN_MAX; else capa = s->as.heap.aux.capa; + if (capa <= RSTRING_EMBED_LEN_MAX) + capa = RSTRING_EMBED_LEN_MAX+1; total = RSTR_LEN(s)+len; if (total >= MRB_INT_MAX) { -- cgit v1.2.3 From 1ed4de58d016a25d8a6ae4576e447dab1709535c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 31 Dec 2016 23:33:34 +0900 Subject: str_buf_cat(): better size check added; ref #3342 --- src/string.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index d41237f44..072bf2226 100644 --- a/src/string.c +++ b/src/string.c @@ -163,15 +163,20 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) total = RSTR_LEN(s)+len; if (total >= MRB_INT_MAX) { + size_error: mrb_raise(mrb, E_ARGUMENT_ERROR, "string size too big"); } if (capa <= total) { while (total > capa) { - if (capa + 1 >= MRB_INT_MAX / 2) { - capa = MRB_INT_MAX; - break; + if (capa <= MRB_INT_MAX / 2) { + capa *= 2; + } + else { + goto size_error; } - capa = (capa + 1) * 2; + } + if (capa < total || capa > MRB_INT_MAX) { + goto size_error; } resize_capa(mrb, s, capa); } -- cgit v1.2.3 From 8b779796678b5cbd8e24a0d86f97701d20aa56c0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 1 Jan 2017 00:45:14 +0900 Subject: Initialize potentially uninitialized variable z --- src/numeric.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/numeric.c b/src/numeric.c index a9a2a641b..0306b1363 100644 --- a/src/numeric.c +++ b/src/numeric.c @@ -1044,7 +1044,7 @@ fix_to_f(mrb_state *mrb, mrb_value num) MRB_API mrb_value mrb_flo_to_fixnum(mrb_state *mrb, mrb_value x) { - mrb_int z; + mrb_int z = 0; if (!mrb_float_p(x)) { mrb_raise(mrb, E_TYPE_ERROR, "non float value"); -- cgit v1.2.3 From 30b6648b9c53f8c3f5156910758cb37eb0d654a7 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 2 Jan 2017 16:33:58 +0900 Subject: Small refactoring: should use RSTR_CAPA --- src/string.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 072bf2226..b57f1cec4 100644 --- a/src/string.c +++ b/src/string.c @@ -154,10 +154,7 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) off = ptr - RSTR_PTR(s); } - if (RSTR_EMBED_P(s)) - capa = RSTRING_EMBED_LEN_MAX; - else - capa = s->as.heap.aux.capa; + capa = RSTR_CAPA(s); if (capa <= RSTRING_EMBED_LEN_MAX) capa = RSTRING_EMBED_LEN_MAX+1; -- cgit v1.2.3 From 8a9a24152a23595fba0802f555d49e0c263836af Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 2 Jan 2017 16:54:34 +0900 Subject: Fix memory error on str_buf_cat Modify from nofree to embed string --- src/string.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index b57f1cec4..ae2e5ccc8 100644 --- a/src/string.c +++ b/src/string.c @@ -695,14 +695,21 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) } if (RSTR_NOFREE_P(s)) { char *p = s->as.heap.ptr; + mrb_int len = s->as.heap.len; - s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)s->as.heap.len+1); + RSTR_UNSET_NOFREE_FLAG(s); + if (len < RSTRING_EMBED_LEN_MAX) { + RSTR_SET_EMBED_FLAG(s); + RSTR_SET_EMBED_LEN(s, len); + } + else { + s->as.heap.ptr = (char *)mrb_malloc(mrb, (size_t)len+1); + s->as.heap.aux.capa = len; + } if (p) { - memcpy(RSTR_PTR(s), p, s->as.heap.len); + memcpy(RSTR_PTR(s), p, len); } - RSTR_PTR(s)[s->as.heap.len] = '\0'; - s->as.heap.aux.capa = s->as.heap.len; - RSTR_UNSET_NOFREE_FLAG(s); + RSTR_PTR(s)[len] = '\0'; return; } } -- cgit v1.2.3 From f388b6d612158f4b08cd1bedb92dec8c50e5576d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sun, 1 Jan 2017 01:15:38 +0900 Subject: use size_t instead of int --- src/vm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index cca0fd03b..3023710d4 100644 --- a/src/vm.c +++ b/src/vm.c @@ -134,8 +134,8 @@ static void stack_extend_alloc(mrb_state *mrb, int room, int keep) { mrb_value *oldbase = mrb->c->stbase; - int size = mrb->c->stend - mrb->c->stbase; - int off = mrb->c->stack - mrb->c->stbase; + size_t size = mrb->c->stend - mrb->c->stbase; + size_t off = mrb->c->stack - mrb->c->stbase; #ifdef MRB_STACK_EXTEND_DOUBLING if (room <= size) -- cgit v1.2.3 From 2e0c2b58076ce24508a584091f8af9bf8c22f64d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 5 Jan 2017 16:46:08 +0900 Subject: Add mrb_hash_modify() to Hash#{delete,clear}; ref #3370 This issue was reported by https://hackerone.com/an0n-j --- src/hash.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index c65c8926e..98feaceac 100644 --- a/src/hash.c +++ b/src/hash.c @@ -554,6 +554,7 @@ mrb_hash_delete(mrb_state *mrb, mrb_value self) mrb_value key; mrb_get_args(mrb, "o", &key); + mrb_hash_modify(mrb, self); return mrb_hash_delete_key(mrb, self, key); } @@ -620,6 +621,7 @@ mrb_hash_clear(mrb_state *mrb, mrb_value hash) { khash_t(ht) *h = RHASH_TBL(hash); + mrb_hash_modify(mrb, hash); if (h) kh_clear(ht, mrb, h); return hash; } -- cgit v1.2.3 From 36f5b44578791a12619c189808dbc3cb4758e32a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 5 Jan 2017 17:49:21 +0900 Subject: Add new method Kernel#frozen?; ref #3370 --- src/kernel.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index 5e44d73b4..677c0d519 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -473,6 +473,29 @@ mrb_obj_freeze(mrb_state *mrb, mrb_value self) return self; } +static mrb_value +mrb_obj_frozen(mrb_state *mrb, mrb_value self) +{ + struct RBasic *b; + + switch (mrb_type(self)) { + case MRB_TT_FALSE: + case MRB_TT_TRUE: + case MRB_TT_FIXNUM: + case MRB_TT_SYMBOL: + case MRB_TT_FLOAT: + return mrb_true_value(); + default: + break; + } + + b = mrb_basic_ptr(self); + if (!MRB_FROZEN_P(b)) { + return mrb_false_value(); + } + return mrb_true_value(); +} + /* 15.3.1.3.15 */ /* * call-seq: @@ -1148,6 +1171,7 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "equal?", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.11 */ mrb_define_method(mrb, krn, "extend", mrb_obj_extend_m, MRB_ARGS_ANY()); /* 15.3.1.3.13 */ mrb_define_method(mrb, krn, "freeze", mrb_obj_freeze, MRB_ARGS_NONE()); + mrb_define_method(mrb, krn, "frozen?", mrb_obj_frozen, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "global_variables", mrb_f_global_variables, MRB_ARGS_NONE()); /* 15.3.1.3.14 */ mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ -- cgit v1.2.3 From f53f73f30ca390d27994e9092ff9b6b18aa615bf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 6 Jan 2017 14:25:01 +0900 Subject: Should not deallocate shared string referring static; fix #3373 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index ae2e5ccc8..d011f60ca 100644 --- a/src/string.c +++ b/src/string.c @@ -669,7 +669,7 @@ mrb_str_modify(mrb_state *mrb, struct RString *s) if (RSTR_SHARED_P(s)) { mrb_shared_string *shared = s->as.heap.aux.shared; - if (shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { + if (shared->nofree == 0 && shared->refcnt == 1 && s->as.heap.ptr == shared->ptr) { s->as.heap.ptr = shared->ptr; s->as.heap.aux.capa = shared->len; RSTR_PTR(s)[s->as.heap.len] = '\0'; -- cgit v1.2.3 From 9a76a0bd809e06089e6a09aa72e01ccf82806056 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 6 Jan 2017 14:51:21 +0900 Subject: Move mrb_assert() position. --- src/string.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index d011f60ca..5aaef5826 100644 --- a/src/string.c +++ b/src/string.c @@ -121,6 +121,9 @@ mrb_str_buf_new(mrb_state *mrb, size_t capa) static void resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) { +#if SIZE_MAX > MRB_INT_MAX + mrb_assert(capacity < MRB_INT_MAX); +#endif if (RSTR_EMBED_P(s)) { if (RSTRING_EMBED_LEN_MAX < capacity) { char *const tmp = (char *)mrb_malloc(mrb, capacity+1); @@ -133,9 +136,6 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) } } else { -#if SIZE_MAX > MRB_INT_MAX - mrb_assert(capacity <= MRB_INT_MAX); -#endif s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); s->as.heap.aux.capa = capacity; } -- cgit v1.2.3 From c6a11725923090278bb4941579751650d9aaebce Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 6 Jan 2017 14:52:04 +0900 Subject: Add pointer cast to pacify warnings. --- src/string.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 5aaef5826..976c34687 100644 --- a/src/string.c +++ b/src/string.c @@ -132,12 +132,12 @@ resize_capa(mrb_state *mrb, struct RString *s, size_t capacity) RSTR_UNSET_EMBED_FLAG(s); s->as.heap.ptr = tmp; s->as.heap.len = len; - s->as.heap.aux.capa = capacity; + s->as.heap.aux.capa = (mrb_int)capacity; } } else { - s->as.heap.ptr = (char *)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); - s->as.heap.aux.capa = capacity; + s->as.heap.ptr = (char*)mrb_realloc(mrb, RSTR_PTR(s), capacity+1); + s->as.heap.aux.capa = (mrb_int)capacity; } } -- cgit v1.2.3 From 885d929398cf6962f3b0d292cf44105976f6c848 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 6 Jan 2017 14:53:00 +0900 Subject: Improve capacity enhancing conditions --- src/array.c | 4 ++-- src/string.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 54ff26721..420907866 100644 --- a/src/array.c +++ b/src/array.c @@ -182,10 +182,10 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, size_t len) capa *= 2; } else { - goto size_error; + capa = len; } } - if (capa < len || capa > MRB_INT_MAX) { + if (capa < len || capa > ARY_MAX_SIZE) { goto size_error; } diff --git a/src/string.c b/src/string.c index 976c34687..b4746545a 100644 --- a/src/string.c +++ b/src/string.c @@ -169,7 +169,7 @@ str_buf_cat(mrb_state *mrb, struct RString *s, const char *ptr, size_t len) capa *= 2; } else { - goto size_error; + capa = total; } } if (capa < total || capa > MRB_INT_MAX) { -- cgit v1.2.3 From ddcb30d84bfad619184a504b76e153bed0b875b9 Mon Sep 17 00:00:00 2001 From: ksss Date: Fri, 6 Jan 2017 16:27:19 +0900 Subject: Check intern object returned by mrb_check_string_type --- src/kernel.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index 5e44d73b4..0791bbd92 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -965,14 +965,17 @@ obj_respond_to(mrb_state *mrb, mrb_value self) } else { mrb_value tmp; - if (!mrb_string_p(mid)) { + if (mrb_string_p(mid)) { + tmp = mrb_check_intern_str(mrb, mid); + } + else { tmp = mrb_check_string_type(mrb, mid); if (mrb_nil_p(tmp)) { tmp = mrb_inspect(mrb, mid); mrb_raisef(mrb, E_TYPE_ERROR, "%S is not a symbol", tmp); } + tmp = mrb_check_intern_str(mrb, tmp); } - tmp = mrb_check_intern_str(mrb, mid); if (mrb_nil_p(tmp)) { respond_to_p = FALSE; } -- cgit v1.2.3 From 392d7fbef9aa64134b33ac562f125df45b450ec0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 7 Jan 2017 12:24:56 +0900 Subject: Add ary_modify() checks; close #3379 This issue was reported by https://hackerone.com/an0n-j --- src/array.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/array.c b/src/array.c index 420907866..99f9fc8b2 100644 --- a/src/array.c +++ b/src/array.c @@ -440,6 +440,7 @@ mrb_ary_pop(mrb_state *mrb, mrb_value ary) { struct RArray *a = mrb_ary_ptr(ary); + ary_modify(mrb, a); if (a->len == 0) return mrb_nil_value(); return a->ptr[--a->len]; } @@ -452,6 +453,7 @@ mrb_ary_shift(mrb_state *mrb, mrb_value self) struct RArray *a = mrb_ary_ptr(self); mrb_value val; + ary_modify(mrb, a); if (a->len == 0) return mrb_nil_value(); if (ARY_SHARED_P(a)) { L_SHIFT: @@ -964,6 +966,7 @@ mrb_ary_clear(mrb_state *mrb, mrb_value self) { struct RArray *a = mrb_ary_ptr(self); + ary_modify(mrb, a); if (ARY_SHARED_P(a)) { mrb_ary_decref(mrb, a->aux.shared); ARY_UNSET_SHARED_FLAG(a); -- cgit v1.2.3 From 7523cdf3404230213cb858f38bd91135d478a7f3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 11 Jan 2017 09:51:52 +0900 Subject: Exception#initialize to take arbitrary number of args; ref #3384 --- src/error.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/error.c b/src/error.c index b24aed798..fda2cd15c 100644 --- a/src/error.c +++ b/src/error.c @@ -44,8 +44,10 @@ static mrb_value exc_initialize(mrb_state *mrb, mrb_value exc) { mrb_value mesg; + int argc; + mrb_value *argv; - if (mrb_get_args(mrb, "|o", &mesg) == 1) { + if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) { mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg); } return exc; -- cgit v1.2.3 From 44edc51612536a9e23dabf7c87afc3996efde027 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 11 Jan 2017 09:53:31 +0900 Subject: Raises Exception if raising exception class is redefined close #3384 This issue was reported by https://hackerone.com/brakhane --- include/mruby.h | 44 ++++++++++++++++++++++++++------------------ src/class.c | 14 ++++++++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 76a028ad4..99d06146f 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -607,6 +607,14 @@ MRB_API mrb_bool mrb_class_defined(mrb_state *mrb, const char *name); */ MRB_API struct RClass * mrb_class_get(mrb_state *mrb, const char *name); +/** + * Gets a exception class. + * @param [mrb_state*] mrb The current mruby state. + * @param [const char *] name The name of the class. + * @return [struct RClass *] A reference to the class. +*/ +MRB_API struct RClass * mrb_exc_get(mrb_state *mrb, const char *name); + /** * Returns an mrb_bool. True if inner class was defined, and false if the inner class was not defined. * @@ -1091,23 +1099,23 @@ MRB_API void mrb_print_error(mrb_state *mrb); + those E_* macros requires mrb_state* variable named mrb. + exception objects obtained from those macros are local to mrb */ -#define E_RUNTIME_ERROR (mrb_class_get(mrb, "RuntimeError")) -#define E_TYPE_ERROR (mrb_class_get(mrb, "TypeError")) -#define E_ARGUMENT_ERROR (mrb_class_get(mrb, "ArgumentError")) -#define E_INDEX_ERROR (mrb_class_get(mrb, "IndexError")) -#define E_RANGE_ERROR (mrb_class_get(mrb, "RangeError")) -#define E_NAME_ERROR (mrb_class_get(mrb, "NameError")) -#define E_NOMETHOD_ERROR (mrb_class_get(mrb, "NoMethodError")) -#define E_SCRIPT_ERROR (mrb_class_get(mrb, "ScriptError")) -#define E_SYNTAX_ERROR (mrb_class_get(mrb, "SyntaxError")) -#define E_LOCALJUMP_ERROR (mrb_class_get(mrb, "LocalJumpError")) -#define E_REGEXP_ERROR (mrb_class_get(mrb, "RegexpError")) -#define E_SYSSTACK_ERROR (mrb_class_get(mrb, "SystemStackError")) - -#define E_NOTIMP_ERROR (mrb_class_get(mrb, "NotImplementedError")) -#define E_FLOATDOMAIN_ERROR (mrb_class_get(mrb, "FloatDomainError")) - -#define E_KEY_ERROR (mrb_class_get(mrb, "KeyError")) +#define E_RUNTIME_ERROR (mrb_exc_get(mrb, "RuntimeError")) +#define E_TYPE_ERROR (mrb_exc_get(mrb, "TypeError")) +#define E_ARGUMENT_ERROR (mrb_exc_get(mrb, "ArgumentError")) +#define E_INDEX_ERROR (mrb_exc_get(mrb, "IndexError")) +#define E_RANGE_ERROR (mrb_exc_get(mrb, "RangeError")) +#define E_NAME_ERROR (mrb_exc_get(mrb, "NameError")) +#define E_NOMETHOD_ERROR (mrb_exc_get(mrb, "NoMethodError")) +#define E_SCRIPT_ERROR (mrb_exc_get(mrb, "ScriptError")) +#define E_SYNTAX_ERROR (mrb_exc_get(mrb, "SyntaxError")) +#define E_LOCALJUMP_ERROR (mrb_exc_get(mrb, "LocalJumpError")) +#define E_REGEXP_ERROR (mrb_exc_get(mrb, "RegexpError")) +#define E_SYSSTACK_ERROR (mrb_exc_get(mrb, "SystemStackError")) + +#define E_NOTIMP_ERROR (mrb_exc_get(mrb, "NotImplementedError")) +#define E_FLOATDOMAIN_ERROR (mrb_exc_get(mrb, "FloatDomainError")) + +#define E_KEY_ERROR (mrb_exc_get(mrb, "KeyError")) MRB_API mrb_value mrb_yield(mrb_state *mrb, mrb_value b, mrb_value arg); MRB_API mrb_value mrb_yield_argv(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value *argv); @@ -1160,7 +1168,7 @@ MRB_API mrb_value mrb_fiber_yield(mrb_state *mrb, mrb_int argc, const mrb_value * * @mrbgem mruby-fiber */ -#define E_FIBER_ERROR (mrb_class_get(mrb, "FiberError")) +#define E_FIBER_ERROR (mrb_exc_get(mrb, "FiberError")) /* memory pool implementation */ typedef struct mrb_pool mrb_pool; diff --git a/src/class.c b/src/class.c index fed259b5b..cb7bdfddd 100644 --- a/src/class.c +++ b/src/class.c @@ -317,6 +317,20 @@ mrb_class_get(mrb_state *mrb, const char *name) return mrb_class_get_under(mrb, mrb->object_class, name); } +MRB_API struct RClass * +mrb_exc_get(mrb_state *mrb, const char *name) +{ + struct RClass *exc = mrb_class_get_under(mrb, mrb->object_class, name); + struct RClass *e = exc; + + while (e) { + if (e == mrb->eException_class) + return exc; + e = e->super; + } + return mrb->eException_class; +} + MRB_API struct RClass * mrb_module_get_under(mrb_state *mrb, struct RClass *outer, const char *name) { -- cgit v1.2.3 From 06b2e6a76c562b7a83669d0ffe7e4ac43a2636db Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 11 Jan 2017 11:30:52 +0900 Subject: Check if ci->target_class is NULL before dereferencing close #3389 This issue was reported by https://hackerone.com/ston3 --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 3023710d4..7b38659a7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1288,7 +1288,7 @@ RETRY_TRY_BLOCK: int a = GETARG_A(i); int n = GETARG_C(i); - if (mid == 0) { + if (mid == 0 || !mrb->c->ci->target_class) { mrb_value exc; exc = mrb_exc_new_str_lit(mrb, E_NOMETHOD_ERROR, "super called outside of method"); -- cgit v1.2.3 From e1ff71029f95e3274136263adbdc51c662ec52de Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 11 Jan 2017 17:51:11 +0900 Subject: String#replace should check replacing string; fix #3374 This issue was reported by https://hackerone.com/tunz --- src/string.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index b4746545a..d6bdd6975 100644 --- a/src/string.c +++ b/src/string.c @@ -519,6 +519,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) long len; check_frozen(mrb, s1); + if (s1 == s2) return mrb_obj_value(s1); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { str_decref(mrb, s1->as.heap.aux.shared); -- cgit v1.2.3 From db1bd078bedcc33bfd3ca4c45f46bc553786bfd8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 11 Jan 2017 17:59:56 +0900 Subject: Use temporary variable to avoid potential crash; fix #3387 This issue was original reported by https://hackerone.com/icanthack https://hackerone.com/titanous suggested the solution. `regs` may be reallocated in the function call. --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 7b38659a7..4352b8463 100644 --- a/src/vm.c +++ b/src/vm.c @@ -2411,7 +2411,8 @@ RETRY_TRY_BLOCK: CASE(OP_RANGE) { /* A B C R(A) := range_new(R(B),R(B+1),C) */ int b = GETARG_B(i); - regs[GETARG_A(i)] = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); + mrb_value val = mrb_range_new(mrb, regs[b], regs[b+1], GETARG_C(i)); + regs[GETARG_A(i)] = val; ARENA_RESTORE(mrb, ai); NEXT; } -- cgit v1.2.3 From bc4c90de075fd77ecb844daca0a456a06922786b Mon Sep 17 00:00:00 2001 From: Clayton Smith Date: Wed, 11 Jan 2017 09:05:02 -0500 Subject: Use mrb_int for argc. --- src/error.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/error.c b/src/error.c index fda2cd15c..0292910dd 100644 --- a/src/error.c +++ b/src/error.c @@ -44,7 +44,7 @@ static mrb_value exc_initialize(mrb_state *mrb, mrb_value exc) { mrb_value mesg; - int argc; + mrb_int argc; mrb_value *argv; if (mrb_get_args(mrb, "|o*", &mesg, &argv, &argc) >= 1) { -- 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 'src') 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 38acb9ec36bdd56123e6680885499fbf7f729f21 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 12 Jan 2017 21:43:23 +0900 Subject: Kernel#initialize should not break existing mt; fix #3397 This issue was reported by https://hackerone.com/icanthack The solution is suggested by @clayton-shopify. --- src/class.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index cb7bdfddd..45827f5ba 100644 --- a/src/class.c +++ b/src/class.c @@ -915,7 +915,9 @@ boot_defclass(mrb_state *mrb, struct RClass *super) static void boot_initmod(mrb_state *mrb, struct RClass *mod) { - mod->mt = kh_init(mt, mrb); + if (!mod->mt) { + mod->mt = kh_init(mt, mrb); + } } static struct RClass* -- cgit v1.2.3 From a3571240e5fdbdac9210be27e2445e3f82239f44 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 12 Jan 2017 23:08:58 +0900 Subject: Add proper stack size calculation; fix #3398 This issue was reported by https://hackerone.com/ssarong --- src/vm.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 4352b8463..9cc29ed5a 100644 --- a/src/vm.c +++ b/src/vm.c @@ -373,7 +373,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc mrb_method_missing(mrb, mid, self, args); } undef = mid; - n++; argc++; + argc++; } ci = cipush(mrb); ci->mid = mid; @@ -389,8 +389,18 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci->nregs = argc + 2; stack_extend(mrb, ci->nregs, 0); } + else if (argc >= CALL_MAXARGS) { + mrb_value args = mrb_ary_new_from_values(mrb, argc, argv); + stack_extend(mrb, ci->nregs, 0); + mrb->c->stack[1] = args; + if (undef) { + mrb_ary_unshift(mrb, mrb->c->stack[1], mrb_symbol_value(undef)); + } + ci->argc = -1; + argc = 1; + } else { - ci->nregs = p->body.irep->nregs + n; + ci->nregs = p->body.irep->nregs + argc; stack_extend(mrb, ci->nregs, argc+2); } if (voff >= 0) { @@ -403,7 +413,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc stack_copy(mrb->c->stack+2, argv, argc-1); } } - else if (argc > 0) { + else if (ci->argc > 0) { stack_copy(mrb->c->stack+1, argv, argc); } mrb->c->stack[argc+1] = blk; @@ -2478,7 +2488,12 @@ RETRY_TRY_BLOCK: MRB_API mrb_value mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) { - return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + if (mrb->c->ci->argc < 0) { + return mrb_vm_run(mrb, proc, self, 3); /* receiver, args and block) */ + } + else { + return mrb_vm_run(mrb, proc, self, mrb->c->ci->argc + 2); /* argc + 2 (receiver and block) */ + } } MRB_API mrb_value -- cgit v1.2.3 From 8d61f2120c7b3c637ce61df4c13e4b066029a4d5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 12 Jan 2017 23:14:35 +0900 Subject: Add proper given argument number in the wrong-number-argument error. --- src/vm.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 9cc29ed5a..5d2e04383 100644 --- a/src/vm.c +++ b/src/vm.c @@ -717,15 +717,22 @@ argnum_error(mrb_state *mrb, mrb_int num) { mrb_value exc; mrb_value str; + mrb_int argc = mrb->c->ci->argc; + if (argc < 0) { + mrb_value args = mrb->c->stack[1]; + if (mrb_array_p(args)) { + argc = RARRAY_LEN(args); + } + } if (mrb->c->ci->mid) { str = mrb_format(mrb, "'%S': wrong number of arguments (%S for %S)", mrb_sym2str(mrb, mrb->c->ci->mid), - mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num)); + mrb_fixnum_value(argc), mrb_fixnum_value(num)); } else { str = mrb_format(mrb, "wrong number of arguments (%S for %S)", - mrb_fixnum_value(mrb->c->ci->argc), mrb_fixnum_value(num)); + mrb_fixnum_value(argc), mrb_fixnum_value(num)); } exc = mrb_exc_new_str(mrb, E_ARGUMENT_ERROR, str); mrb_exc_set(mrb, exc); -- cgit v1.2.3 From fe0e45505b0d0fbf627c9a7df0b8df52d0c72321 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 18 Jan 2017 17:53:08 +0900 Subject: Initialize callinfo->acc; ref #3243 --- src/vm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 5d2e04383..c32fb0c0a 100644 --- a/src/vm.c +++ b/src/vm.c @@ -238,6 +238,7 @@ cipush(mrb_state *mrb) ci->pc = 0; ci->err = 0; ci->proc = 0; + ci->acc = 0; return ci; } -- cgit v1.2.3 From c48aef0b653ba83452c97b1d1017869de2a846b9 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 21 Jan 2017 17:59:49 +0900 Subject: Stack position may be bigger than stack bottom; fix #3401 This issue was reported by https://hackerone.com/titanous --- src/vm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index c32fb0c0a..77372d937 100644 --- a/src/vm.c +++ b/src/vm.c @@ -137,6 +137,7 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep) size_t size = mrb->c->stend - mrb->c->stbase; size_t off = mrb->c->stack - mrb->c->stbase; + if (off > size) size = off; #ifdef MRB_STACK_EXTEND_DOUBLING if (room <= size) size *= 2; -- cgit v1.2.3 From 65c9baae7cea2f67c5cd38b772abe48259f839df Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 22 Jan 2017 14:06:23 +0900 Subject: Rewrite mrb_ary_splice Referenced to CRuby's array.c(rb_ary_splice) fix #3405 --- src/array.c | 52 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 20 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 99f9fc8b2..00a716bad 100644 --- a/src/array.c +++ b/src/array.c @@ -589,7 +589,6 @@ MRB_API mrb_value mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl) { struct RArray *a = mrb_ary_ptr(ary); - mrb_int tail, size; const mrb_value *argv; mrb_int i, argc; @@ -608,7 +607,6 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val if (a->len < len || a->len < head + len) { len = a->len - head; } - tail = head + len; /* size check */ if (mrb_array_p(rpl)) { @@ -623,30 +621,44 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val argc = 1; argv = &rpl; } - size = head + argc; - - if (tail < a->len) size += a->len - tail; - - if (size < 0 || size > ARY_MAX_SIZE) - mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); - - if (size > a->aux.capa) - ary_expand_capa(mrb, a, size); - - if (head > a->len) { + if (head >= a->len) { + if (head > ARY_MAX_SIZE - argc) { + mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(head)); + } + len = head + argc; + if (len > a->aux.capa) { + ary_expand_capa(mrb, a, head + argc); + } ary_fill_with_nil(a->ptr + a->len, head - a->len); + if (argc > 0) { + for (int i = 0; i < argc; i++) { + a->ptr[head + i] = argv[i]; + } + } + a->len = len; } - else if (head < a->len) { - value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail); - } + else { + mrb_int alen; + if (a->len - len > ARY_MAX_SIZE - argc) { + mrb_raisef(mrb, E_INDEX_ERROR, "index %S too big", mrb_fixnum_value(a->len + argc - len)); + } + alen = a->len + argc - len; + if (alen > a->aux.capa) { + ary_expand_capa(mrb, a, alen); + } + + if (len != argc) { + value_move(a->ptr + head + argc, a->ptr + head + len, a->len - (head + len)); + a->len = alen; + } + if (argc > 0) { + value_move(a->ptr + head, argv, argc); + } + } for (i = 0; i < argc; i++) { - *(a->ptr + head + i) = *(argv + i); mrb_field_write_barrier_value(mrb, (struct RBasic*)a, argv[i]); } - - a->len = size; - return ary; } -- cgit v1.2.3 From b49bd70f5967d32a46bce624b87595620664403c Mon Sep 17 00:00:00 2001 From: ksss Date: Sun, 22 Jan 2017 17:50:54 +0900 Subject: Should raise RuntimeError when object frozen --- src/array.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/array.c b/src/array.c index 99f9fc8b2..669e90d02 100644 --- a/src/array.c +++ b/src/array.c @@ -796,6 +796,7 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) mrb_value v1, v2, v3; mrb_int i, len; + mrb_ary_modify(mrb, mrb_ary_ptr(self)); if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { switch (mrb_type(v1)) { /* a[n..m] = v */ -- cgit v1.2.3 From fdec607cd06bc12c844fd71bdb75db74f909ff74 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 10:30:14 +0900 Subject: Remove unnecessary inline declaration; ref #3409 --- src/array.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index f634070e2..da54b3d6b 100644 --- a/src/array.c +++ b/src/array.c @@ -631,7 +631,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val } ary_fill_with_nil(a->ptr + a->len, head - a->len); if (argc > 0) { - for (int i = 0; i < argc; i++) { + for (i = 0; i < argc; i++) { a->ptr[head + i] = argv[i]; } } -- cgit v1.2.3 From 49fd7590df4f510c611f31652235887c0aaaa962 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 10:32:33 +0900 Subject: Use mrb_write_barrier() instead of mrb_field_write_barrier_value() ref #3409 --- src/array.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index da54b3d6b..f9155d173 100644 --- a/src/array.c +++ b/src/array.c @@ -656,9 +656,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val value_move(a->ptr + head, argv, argc); } } - for (i = 0; i < argc; i++) { - mrb_field_write_barrier_value(mrb, (struct RBasic*)a, argv[i]); - } + mrb_write_barrier(mrb, (struct RBasic*)a); return ary; } -- cgit v1.2.3 From 708088c5fafd469d04a1b428fc49b8b7c27607d2 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 10:52:40 +0900 Subject: Should not make empty strings shared; fix #3407 --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index d6bdd6975..02c7ce426 100644 --- a/src/string.c +++ b/src/string.c @@ -423,7 +423,7 @@ byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) mrb_shared_string *shared; orig = mrb_str_ptr(str); - if (RSTR_EMBED_P(orig)) { + if (RSTR_EMBED_P(orig) || RSTR_LEN(orig) == 0) { s = str_new(mrb, orig->as.ary+beg, len); } else { -- cgit v1.2.3 From 5e1d923381072ebcbe002d70bc198a6e95c31f50 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 14:35:26 +0900 Subject: Changed the behavior of mrb_range_beg_len(); close #3411 The new API is: int mrb_range_beg_len(mrb, range, &beg, &len, len, trunc) The new argument `trunc` is a boolean value that specifies whether the function truncates the range. The new return value is an integer instead of a boolean, that is: 0: not a range 1: range with proper edges 2: out of range To get the old behavior, you have to rewrite: mrb_range_beg_len(mrb, range, &beg, &len, len) to: mrn_range_beg_len(mrb, range, &beg, &len, len, TRUE) == 1 [Breaking Change] --- include/mruby/range.h | 2 +- mrbgems/mruby-kernel-ext/src/kernel.c | 2 +- mrbgems/mruby-string-ext/src/string.c | 8 +++++++- src/array.c | 19 ++++++++----------- src/range.c | 20 +++++++------------- src/string.c | 27 +++++++++++++++------------ 6 files changed, 39 insertions(+), 39 deletions(-) (limited to 'src') diff --git a/include/mruby/range.h b/include/mruby/range.h index fb602b3f3..41e4f1254 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -41,7 +41,7 @@ MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); */ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude); -MRB_API mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len); +MRB_API int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); MRB_END_DECL diff --git a/mrbgems/mruby-kernel-ext/src/kernel.c b/mrbgems/mruby-kernel-ext/src/kernel.c index 1aa40260e..7bb4dea68 100644 --- a/mrbgems/mruby-kernel-ext/src/kernel.c +++ b/mrbgems/mruby-kernel-ext/src/kernel.c @@ -22,7 +22,7 @@ mrb_f_caller(mrb_state *mrb, mrb_value self) case 1: if (mrb_type(v) == MRB_TT_RANGE) { mrb_int beg, len; - if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len)) { + if (mrb_range_beg_len(mrb, v, &beg, &len, bt_len, TRUE) == 1) { lev = beg; n = len; } diff --git a/mrbgems/mruby-string-ext/src/string.c b/mrbgems/mruby-string-ext/src/string.c index c6a9e1d0b..7e87b3db4 100644 --- a/mrbgems/mruby-string-ext/src/string.c +++ b/mrbgems/mruby-string-ext/src/string.c @@ -56,8 +56,14 @@ mrb_str_byteslice(mrb_state *mrb, mrb_value str) mrb_int beg; len = RSTRING_LEN(str); - if (mrb_range_beg_len(mrb, a1, &beg, &len, len)) { + switch (mrb_range_beg_len(mrb, a1, &beg, &len, len, TRUE)) { + case 0: /* not range */ + break; + case 1: /* range */ return mrb_str_substr(mrb, str, beg, len); + case 2: /* out of range */ + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", a1); + break; } return mrb_nil_value(); } diff --git a/src/array.c b/src/array.c index f9155d173..e41183d68 100644 --- a/src/array.c +++ b/src/array.c @@ -742,7 +742,7 @@ mrb_ary_aget(mrb_state *mrb, mrb_value self) switch (mrb_type(index)) { /* a[n..m] */ case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) { + if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) { return ary_subseq(mrb, a, i, len); } else { @@ -808,19 +808,16 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) mrb_ary_modify(mrb, mrb_ary_ptr(self)); if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { - switch (mrb_type(v1)) { /* a[n..m] = v */ - case MRB_TT_RANGE: - if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) { - mrb_ary_splice(mrb, self, i, len, v2); - } + switch (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self), FALSE)) { + case 0: /* not range */ + mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); break; - /* a[n] = v */ - case MRB_TT_FIXNUM: - mrb_ary_set(mrb, self, mrb_fixnum(v1), v2); + case 1: /* range */ + mrb_ary_splice(mrb, self, i, len, v2); break; - default: - mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); + case 2: /* out of range */ + mrb_raisef(mrb, E_RANGE_ERROR, "%S out of range", v1); break; } return v2; diff --git a/src/range.c b/src/range.c index 73fe7589b..800e64611 100644 --- a/src/range.c +++ b/src/range.c @@ -248,13 +248,13 @@ mrb_range_include(mrb_state *mrb, mrb_value range) return mrb_bool_value(include_p); } -static mrb_bool -range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) +int +mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; struct RRange *r; - if (mrb_type(range) != MRB_TT_RANGE) return FALSE; + if (mrb_type(range) != MRB_TT_RANGE) return 0; r = mrb_range_ptr(mrb, range); beg = mrb_int(mrb, r->edges->beg); @@ -262,11 +262,11 @@ range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb if (beg < 0) { beg += len; - if (beg < 0) return FALSE; + if (beg < 0) return 2; } if (trunc) { - if (beg > len) return FALSE; + if (beg > len) return 2; if (end > len) end = len; } @@ -278,13 +278,7 @@ range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb *begp = beg; *lenp = len; - return TRUE; -} - -MRB_API mrb_bool -mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len) -{ - return range_beg_len(mrb, range, begp, lenp, len, TRUE); + return 1; } /* 15.2.14.4.12(x) */ @@ -405,7 +399,7 @@ mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, con if (mrb_fixnum_p(argv[i])) { mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i]))); } - else if (range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE)) { + else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen, FALSE) == 1) { mrb_int const end = olen < beg + len ? olen : beg + len; for (j = beg; j < end; ++j) { mrb_ary_push(mrb, result, func(mrb, obj, j)); diff --git a/src/string.c b/src/string.c index 02c7ce426..7a75bb63e 100644 --- a/src/string.c +++ b/src/string.c @@ -1091,22 +1091,25 @@ num_index: return mrb_nil_value(); case MRB_TT_RANGE: - /* check if indx is Range */ - { - mrb_int beg, len; + goto range_arg; - len = RSTRING_CHAR_LEN(str); - if (mrb_range_beg_len(mrb, indx, &beg, &len, len)) { - return str_subseq(mrb, str, beg, len); - } - else { - return mrb_nil_value(); - } - } - case MRB_TT_FLOAT: default: indx = mrb_Integer(mrb, indx); if (mrb_nil_p(indx)) { + range_arg: + { + mrb_int beg, len; + + len = RSTRING_CHAR_LEN(str); + switch (mrb_range_beg_len(mrb, indx, &beg, &len, len, TRUE)) { + case 1: + return str_subseq(mrb, str, beg, len); + case 2: + return mrb_nil_value(); + default: + break; + } + } mrb_raise(mrb, E_TYPE_ERROR, "can't convert to Fixnum"); } idx = mrb_fixnum(indx); -- cgit v1.2.3 From 4d38cad31b2107d23fa393561eb5dae5da16c82c Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 15:05:12 +0900 Subject: Add MRB_API to mrb_range_beg_len(); ref #3411 --- src/range.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/range.c b/src/range.c index 800e64611..5553171b9 100644 --- a/src/range.c +++ b/src/range.c @@ -248,7 +248,7 @@ mrb_range_include(mrb_state *mrb, mrb_value range) return mrb_bool_value(include_p); } -int +MRB_API int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; -- cgit v1.2.3 From 78a395d44607b52a256cd41016210ece1a739538 Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 23 Jan 2017 15:18:12 +0900 Subject: Refactoring: Use array_copy instead of for loop --- src/array.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index e41183d68..9e5b90061 100644 --- a/src/array.c +++ b/src/array.c @@ -590,7 +590,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val { struct RArray *a = mrb_ary_ptr(ary); const mrb_value *argv; - mrb_int i, argc; + mrb_int argc; ary_modify(mrb, a); @@ -631,9 +631,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val } ary_fill_with_nil(a->ptr + a->len, head - a->len); if (argc > 0) { - for (i = 0; i < argc; i++) { - a->ptr[head + i] = argv[i]; - } + array_copy(a->ptr + head, argv, argc); } a->len = len; } -- cgit v1.2.3 From 28b7b9ec6441d96d63f309b93f7b486074b807e3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 16:22:55 +0900 Subject: Skip non string values in backtraces; ref #3408 --- src/backtrace.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/backtrace.c b/src/backtrace.c index 285af562f..b499cee5a 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -219,7 +219,9 @@ print_backtrace(mrb_state *mrb, mrb_value backtrace) for (i = 0; i < n; i++) { mrb_value entry = RARRAY_PTR(backtrace)[i]; - fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry)); + if (mrb_string_p(entry)) { + fprintf(stream, "\t[%d] %.*s\n", i, (int)RSTRING_LEN(entry), RSTRING_PTR(entry)); + } } } -- cgit v1.2.3 From 324887d0d61ce2127dfd839930a88507c1641b75 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 16:23:48 +0900 Subject: Backtrace list must be an array of strings; fix #3408 --- src/error.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'src') diff --git a/src/error.c b/src/error.c index 8e456ff1a..a71ee548f 100644 --- a/src/error.c +++ b/src/error.c @@ -208,6 +208,19 @@ exc_set_backtrace(mrb_state *mrb, mrb_value exc) mrb_value backtrace; mrb_get_args(mrb, "o", &backtrace); + if (!mrb_array_p(backtrace)) { + type_err: + mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String"); + } + else { + const mrb_value *p = RARRAY_PTR(backtrace); + const mrb_value *pend = p + RARRAY_LEN(backtrace); + + while (p < pend) { + if (!mrb_string_p(*p)) goto type_err; + p++; + } + } mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); return backtrace; -- cgit v1.2.3 From ffb5e5ab08624c899de03b5347966eb3e070dce5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 16:44:11 +0900 Subject: The ensure clause should keep its ci after its execution; fix #3406 This issue was reported by https://hackerone.com/ston3 --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 77372d937..8c91ae1e7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -280,12 +280,14 @@ ecall(mrb_state *mrb, int i) mrb_callinfo *ci; mrb_value *self = mrb->c->stack; struct RObject *exc; + int cioff; if (i<0) return; p = mrb->c->ensure[i]; if (!p) return; if (mrb->c->ci->eidx > i) mrb->c->ci->eidx = i; + cioff = mrb->c->ci - mrb->c->cibase; ci = cipush(mrb); ci->stackent = mrb->c->stack; ci->mid = ci[-1].mid; @@ -298,6 +300,7 @@ ecall(mrb_state *mrb, int i) exc = mrb->exc; mrb->exc = 0; mrb_run(mrb, p, *self); mrb->c->ensure[i] = NULL; + mrb->c->ci = mrb->c->cibase + cioff; if (!mrb->exc) mrb->exc = exc; } -- cgit v1.2.3 From f0f095bc135c4d2e6f6d54d6b5683db77708369b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 16:53:31 +0900 Subject: Fix a double free problem in codegen.c; fix #3378 This issue was first reported by https://hackerone.com/geeknik The fix was proposed by @titanous --- include/mruby/irep.h | 1 + mrbgems/mruby-compiler/core/codegen.c | 4 +--- src/state.c | 5 ++++- 3 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 8922f4b76..35ae2bbaa 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -39,6 +39,7 @@ typedef struct mrb_irep { struct mrb_locals *lv; /* debug info */ + mrb_bool own_filename; const char *filename; uint16_t *lines; struct mrb_irep_debug_info* debug_info; diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index fae12b288..eae0492ce 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -2844,6 +2844,7 @@ scope_finish(codegen_scope *s) memcpy(fname, s->filename, fname_len); fname[fname_len] = '\0'; irep->filename = fname; + irep->own_filename = TRUE; } irep->nlocals = s->nlocals; @@ -2951,9 +2952,6 @@ mrb_generate_code(mrb_state *mrb, parser_state *p) return proc; } MRB_CATCH(&scope->jmp) { - if (scope->filename == scope->irep->filename) { - scope->irep->filename = NULL; - } mrb_irep_decref(mrb, scope->irep); mrb_pool_close(scope->mpool); return NULL; diff --git a/src/state.c b/src/state.c index 1259ac3a0..11b71dd63 100644 --- a/src/state.c +++ b/src/state.c @@ -159,7 +159,9 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) } mrb_free(mrb, irep->reps); mrb_free(mrb, irep->lv); - mrb_free(mrb, (void *)irep->filename); + if (irep->own_filename) { + mrb_free(mrb, (void *)irep->filename); + } mrb_free(mrb, irep->lines); mrb_debug_info_free(mrb, irep->debug_info); mrb_free(mrb, irep); @@ -261,6 +263,7 @@ mrb_add_irep(mrb_state *mrb) irep = (mrb_irep *)mrb_malloc(mrb, sizeof(mrb_irep)); *irep = mrb_irep_zero; irep->refcnt = 1; + irep->own_filename = FALSE; return irep; } -- cgit v1.2.3 From 28cf7a549dda15a5f76944d314ad5e20d5362df5 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 23 Jan 2017 22:18:29 +0900 Subject: Change return type of mrb_range_beg_len() from `int` to `mrb_int`. ref #3411 --- include/mruby/range.h | 2 +- src/range.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/include/mruby/range.h b/include/mruby/range.h index 41e4f1254..b166e586b 100644 --- a/include/mruby/range.h +++ b/include/mruby/range.h @@ -41,7 +41,7 @@ MRB_API struct RRange* mrb_range_ptr(mrb_state *mrb, mrb_value v); */ MRB_API mrb_value mrb_range_new(mrb_state *mrb, mrb_value start, mrb_value end, mrb_bool exclude); -MRB_API int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); +MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc); mrb_value mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int)); MRB_END_DECL diff --git a/src/range.c b/src/range.c index 5553171b9..2cb6f2361 100644 --- a/src/range.c +++ b/src/range.c @@ -248,7 +248,7 @@ mrb_range_include(mrb_state *mrb, mrb_value range) return mrb_bool_value(include_p); } -MRB_API int +MRB_API mrb_int mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc) { mrb_int beg, end; -- cgit v1.2.3 From 72bff2932ba983b4e8aaedda50fa5663dcc5c3ed Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 24 Jan 2017 11:36:27 +0900 Subject: Use size_t to avoid integer overflow in mrb_ary_splice(); fix #3413 --- src/array.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/array.c b/src/array.c index 9e5b90061..c7499ab36 100644 --- a/src/array.c +++ b/src/array.c @@ -591,6 +591,7 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val struct RArray *a = mrb_ary_ptr(ary); const mrb_value *argv; mrb_int argc; + size_t tail; ary_modify(mrb, a); @@ -604,7 +605,8 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val mrb_raise(mrb, E_INDEX_ERROR, "index is out of array"); } } - if (a->len < len || a->len < head + len) { + tail = head + len; + if (a->len < len || (size_t)a->len < tail) { len = a->len - head; } @@ -647,7 +649,8 @@ mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_val } if (len != argc) { - value_move(a->ptr + head + argc, a->ptr + head + len, a->len - (head + len)); + tail = head + len; + value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail); a->len = alen; } if (argc > 0) { -- cgit v1.2.3 From b3ce364537cf1f745112d6e5acd71f009dcd872f Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 24 Jan 2017 17:54:05 +0900 Subject: Outer class may be same as the class; fix #3382 --- src/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 45827f5ba..81b312fd0 100644 --- a/src/class.c +++ b/src/class.c @@ -1586,7 +1586,7 @@ mrb_class_path(mrb_state *mrb, struct RClass *c) if (sym == 0) { return mrb_nil_value(); } - else if (outer && outer != mrb->object_class) { + else if (outer && outer != c && outer != mrb->object_class) { mrb_value base = mrb_class_path(mrb, outer); path = mrb_str_buf_new(mrb, 0); if (mrb_nil_p(base)) { -- cgit v1.2.3 From ac88f85a9eb0d03707fc382cbaa442da146d9203 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 25 Jan 2017 11:09:15 +0900 Subject: Copy mrb_float values from pool when MRB_WORD_BOXING; ref #3396 --- src/vm.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 8c91ae1e7..9684dabfd 100644 --- a/src/vm.c +++ b/src/vm.c @@ -859,7 +859,15 @@ RETRY_TRY_BLOCK: CASE(OP_LOADL) { /* A Bx R(A) := Pool(Bx) */ +#ifdef MRB_WORD_BOXING + mrb_value val = pool[GETARG_Bx(i)]; + if (mrb_float_p(val)) { + val = mrb_float_value(mrb, mrb_float(val)); + } + regs[GETARG_A(i)] = val; +#else regs[GETARG_A(i)] = pool[GETARG_Bx(i)]; +#endif NEXT; } -- cgit v1.2.3 From 8e0f2313302871ddd713c3e8e6a9d4731426f308 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 4 Feb 2017 12:59:08 +0900 Subject: Mark `mrb->backtrace.exc` as GC root; fix #3388 --- src/gc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index c75a0f9aa..225ca095c 100644 --- a/src/gc.c +++ b/src/gc.c @@ -857,6 +857,7 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc) mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self); /* mark exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->exc); + mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.exc); /* mark pre-allocated exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err); #ifdef MRB_GC_FIXED_ARENA -- cgit v1.2.3 From 8f52b88ee75fb3ca62931a1d3975c9cd78eae2d8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 4 Feb 2017 13:48:23 +0900 Subject: No need to make env unshared in the finalization; fix #3425 --- src/gc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 225ca095c..88d157d9c 100644 --- a/src/gc.c +++ b/src/gc.c @@ -367,7 +367,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc) #endif } -static void obj_free(mrb_state *mrb, struct RBasic *obj); +static void obj_free(mrb_state *mrb, struct RBasic *obj, int end); void free_heap(mrb_state *mrb, mrb_gc *gc) @@ -381,7 +381,7 @@ free_heap(mrb_state *mrb, mrb_gc *gc) page = page->next; for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; pas.free.tt != MRB_TT_FREE) - obj_free(mrb, &p->as.basic); + obj_free(mrb, &p->as.basic, TRUE); } mrb_free(mrb, tmp); } @@ -699,7 +699,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj) } static void -obj_free(mrb_state *mrb, struct RBasic *obj) +obj_free(mrb_state *mrb, struct RBasic *obj, int end) { DEBUG(printf("obj_free(%p,tt=%d)\n",obj,obj->tt)); switch (obj->tt) { @@ -753,7 +753,7 @@ obj_free(mrb_state *mrb, struct RBasic *obj) case MRB_TT_FIBER: { struct mrb_context *c = ((struct RFiber*)obj)->cxt; - if (c && c != mrb->root_c) { + if (!end && c && c != mrb->root_c) { mrb_callinfo *ci = c->ci; mrb_callinfo *ce = c->cibase; @@ -1020,7 +1020,7 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) while (pas.basic)) { if (p->as.basic.tt != MRB_TT_FREE) { - obj_free(mrb, &p->as.basic); + obj_free(mrb, &p->as.basic, FALSE); if (p->as.basic.tt == MRB_TT_FREE) { p->as.free.next = page->freelist; page->freelist = (struct RBasic*)p; -- cgit v1.2.3 From bf4e79cc62af809138bc7db7e54ece67080b5fa8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 4 Feb 2017 14:07:33 +0900 Subject: `argv` may be modified when `mrb_funcall()` is called; fix #3419 Calling `mrb_funcall()` and `mrb_yield()` (and their related functions) are discouraged unless absolutely necessary, because it can cause this kind of issues very easily. --- src/kernel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index 76bd59469..5ca1736c3 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -445,8 +445,11 @@ mrb_obj_extend_m(mrb_state *mrb, mrb_value self) { mrb_value *argv; mrb_int argc; + mrb_value args; mrb_get_args(mrb, "*", &argv, &argc); + args = mrb_ary_new_from_values(mrb, argc, argv); + argv = (mrb_value*)RARRAY_PTR(args); return mrb_obj_extend(mrb, argc, argv, self); } -- cgit v1.2.3 From 48e0bbbfeea8268b09ad0a6bbc840834cc443fe0 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 4 Feb 2017 16:19:31 +0900 Subject: Make `eval` to use trampoline technique; fix #3415 Now `eval()` can call Fiber.yield etc. --- mrbgems/mruby-eval/src/eval.c | 17 +++++++-------- src/vm.c | 49 ++++++++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 26dd728ba..81bc80280 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -5,6 +5,9 @@ #include #include +mrb_value mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p); +mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); + static struct mrb_irep * get_closure_irep(mrb_state *mrb, int level) { @@ -209,22 +212,15 @@ f_eval(mrb_state *mrb, mrb_value self) mrb_value binding = mrb_nil_value(); char *file = NULL; mrb_int line = 1; - mrb_value ret; struct RProc *proc; mrb_get_args(mrb, "s|ozi", &s, &len, &binding, &file, &line); proc = create_proc_from_string(mrb, s, len, binding, file, line); - ret = mrb_top_run(mrb, proc, mrb->c->stack[0], 0); - if (mrb->exc) { - mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); - } - - return ret; + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + return mrb_exec_irep(mrb, self, proc); } -mrb_value mrb_obj_instance_eval(mrb_state *mrb, mrb_value self); - #define CI_ACC_SKIP -1 static mrb_value @@ -250,7 +246,8 @@ f_instance_eval(mrb_state *mrb, mrb_value self) c->ci->target_class = mrb_class_ptr(cv); proc = create_proc_from_string(mrb, s, len, mrb_nil_value(), file, line); mrb->c->ci->env = NULL; - return mrb_vm_run(mrb, proc, mrb->c->stack[0], 0); + mrb_assert(!MRB_PROC_CFUNC_P(proc)); + return mrb_exec_irep(mrb, self, proc); } else { mrb_get_args(mrb, "&", &b); diff --git a/src/vm.c b/src/vm.c index 9684dabfd..0c0f5a4bb 100644 --- a/src/vm.c +++ b/src/vm.c @@ -447,6 +447,33 @@ mrb_funcall_argv(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc, cons return mrb_funcall_with_block(mrb, self, mid, argc, argv, mrb_nil_value()); } +mrb_value +mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) +{ + mrb_callinfo *ci = mrb->c->ci; + + ci->proc = p; + if (MRB_PROC_CFUNC_P(p)) { + return p->body.func(mrb, self); + } + if (ci->argc < 0) { + stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3); + } + else { + stack_extend(mrb, p->body.irep->nregs, ci->argc+2); + } + + ci->nregs = p->body.irep->nregs; + ci = cipush(mrb); + ci->nregs = 0; + ci->target_class = 0; + ci->pc = p->body.irep->iseq; + ci->stackent = mrb->c->stack; + ci->acc = 0; + + return self; +} + /* 15.3.1.3.4 */ /* 15.3.1.3.44 */ /* @@ -488,7 +515,6 @@ mrb_f_send(mrb_state *mrb, mrb_value self) ci = mrb->c->ci; ci->mid = name; ci->target_class = c; - ci->proc = p; regs = mrb->c->stack+1; /* remove first symbol from arguments */ if (ci->argc >= 0) { @@ -501,26 +527,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) mrb_ary_shift(mrb, regs[0]); } - if (MRB_PROC_CFUNC_P(p)) { - return p->body.func(mrb, self); - } - - if (ci->argc < 0) { - stack_extend(mrb, (p->body.irep->nregs < 3) ? 3 : p->body.irep->nregs, 3); - } - else { - stack_extend(mrb, p->body.irep->nregs, ci->argc+2); - } - - ci->nregs = p->body.irep->nregs; - ci = cipush(mrb); - ci->nregs = 0; - ci->target_class = 0; - ci->pc = p->body.irep->iseq; - ci->stackent = mrb->c->stack; - ci->acc = 0; - - return self; + return mrb_exec_irep(mrb, self, p); } static mrb_value -- cgit v1.2.3 From bd72dba8c05056693e42c74b35d90691221f0d0d Mon Sep 17 00:00:00 2001 From: ksss Date: Mon, 6 Feb 2017 11:04:42 +0900 Subject: Kernel#local_variables: Make result array unique --- src/kernel.c | 11 ++++++----- test/t/kernel.rb | 7 +++---- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/kernel.c b/src/kernel.c index 5ca1736c3..8b00d701b 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -1106,8 +1107,8 @@ mrb_obj_ceqq(mrb_state *mrb, mrb_value self) static mrb_value mrb_local_variables(mrb_state *mrb, mrb_value self) { - mrb_value ret; struct RProc *proc; + mrb_value vars; struct mrb_irep *irep; size_t i; @@ -1121,10 +1122,10 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) if (!irep->lv) { return mrb_ary_new(mrb); } - ret = mrb_ary_new_capa(mrb, irep->nlocals - 1); + vars = mrb_hash_new(mrb); for (i = 0; i + 1 < irep->nlocals; ++i) { if (irep->lv[i].name) { - mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); } } if (proc->env) { @@ -1137,7 +1138,7 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) if (irep->lv) { for (i = 0; i + 1 < irep->nlocals; ++i) { if (irep->lv[i].name) { - mrb_ary_push(mrb, ret, mrb_symbol_value(irep->lv[i].name)); + mrb_hash_set(mrb, vars, mrb_symbol_value(irep->lv[i].name), mrb_true_value()); } } } @@ -1146,7 +1147,7 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) } } - return ret; + return mrb_hash_keys(mrb, vars); } void diff --git a/test/t/kernel.rb b/test/t/kernel.rb index ca4b73907..aff2dd461 100644 --- a/test/t/kernel.rb +++ b/test/t/kernel.rb @@ -549,11 +549,10 @@ assert('Kernel.local_variables', '15.3.1.2.7') do vars = Kernel.local_variables.sort assert_equal [:a, :b, :vars], vars - Proc.new { + assert_equal [:a, :b, :c, :vars], Proc.new { |a, b| c = 2 - vars = Kernel.local_variables.sort - assert_equal [:a, :b, :c, :vars], vars - }.call + Kernel.local_variables.sort + }.call(-1, -2) end assert('Kernel#!=') do -- cgit v1.2.3 From 46e4e342f4a1bf216c027838e343919556703547 Mon Sep 17 00:00:00 2001 From: Edgar Boda-Majer Date: Tue, 7 Feb 2017 13:33:53 +0100 Subject: Fix interpolation escaping in String.inspect --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 7a75bb63e..c370e0723 100644 --- a/src/string.c +++ b/src/string.c @@ -2644,7 +2644,7 @@ mrb_str_inspect(mrb_state *mrb, mrb_value str) } #endif c = *p; - if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p, pend))) { + if (c == '"'|| c == '\\' || (c == '#' && IS_EVSTR(p+1, pend))) { buf[0] = '\\'; buf[1] = c; mrb_str_cat(mrb, result, buf, 2); continue; -- cgit v1.2.3 From be550f04e48ee3bfd7ca6967c6042db0599675dc Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 8 Feb 2017 09:45:55 +0900 Subject: codedump.c: OP_POPERR does not have register access. --- src/codedump.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src') diff --git a/src/codedump.c b/src/codedump.c index 4b13d4361..59ba4fdae 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -416,8 +416,7 @@ codedump(mrb_state *mrb, mrb_irep *irep) print_lv(mrb, irep, c, RA); break; case OP_POPERR: - printf("OP_POPERR\t%d\t\t", GETARG_A(c)); - print_lv(mrb, irep, c, RA); + printf("OP_POPERR\t%d\t\t\n", GETARG_A(c)); break; case OP_EPOP: printf("OP_EPOP\t%d\n", GETARG_A(c)); -- cgit v1.2.3 From f3d4ff16d39b34585d41c31ffc09a0ffb512ff81 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 8 Feb 2017 16:22:48 +0900 Subject: Fixed a bug in ci address shifting; fix #3423 Dinko Galetic and Denis Kasak reported the issue and the fix. (via https://hackerone.com/dgaletic). --- src/vm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 0c0f5a4bb..c174c0b43 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1705,9 +1705,10 @@ RETRY_TRY_BLOCK: mrb->jmp = prev_jmp; return v; } - cipop(mrb); + ci = mrb->c->ci; acc = ci->acc; mrb->c->stack = ci->stackent; + cipop(mrb); if (acc == CI_ACC_SKIP) { mrb->jmp = prev_jmp; return v; -- cgit v1.2.3 From b277c58e783f187cfff1b7bb5843d2e95d3c3b0b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 8 Feb 2017 16:31:37 +0900 Subject: Mark classes referenced from saved backtrace. Maybe related to #3438 --- src/gc.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src') diff --git a/src/gc.c b/src/gc.c index 88d157d9c..1608dbcb2 100644 --- a/src/gc.c +++ b/src/gc.c @@ -857,7 +857,12 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc) mrb_gc_mark(mrb, (struct RBasic*)mrb->top_self); /* mark exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->exc); + /* mark backtrace */ mrb_gc_mark(mrb, (struct RBasic*)mrb->backtrace.exc); + e = (size_t)mrb->backtrace.n; + for (i=0; ibacktrace.entries[i].klass); + } /* mark pre-allocated exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err); #ifdef MRB_GC_FIXED_ARENA -- cgit v1.2.3 From 76135e757f96ad640e3c44b4d46f73e512fbfc50 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 8 Feb 2017 19:01:09 +0900 Subject: Check if m->env is NULL before dereferencing it; fix #3436 --- src/vm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index c174c0b43..287b18518 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1309,7 +1309,9 @@ RETRY_TRY_BLOCK: else { stack_extend(mrb, irep->nregs, ci->argc+2); } - regs[0] = m->env->stack[0]; + if(m->env) { + regs[0] = m->env->stack[0]; + } pc = irep->iseq; JUMP; } -- cgit v1.2.3 From af4d74fc7df9788a1c0013a4dc66e9bbac951b20 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 8 Feb 2017 21:13:22 +0900 Subject: Add MRB_TT_PROC check to OP_SUPER as well; fix #3432 --- src/vm.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 287b18518..e734775e2 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1366,11 +1366,22 @@ RETRY_TRY_BLOCK: ci->mid = mid; ci->proc = m; ci->stackent = mrb->c->stack; - if (n == CALL_MAXARGS) { - ci->argc = -1; - } - else { - ci->argc = n; + { + int bidx; + mrb_value blk; + + if (n == CALL_MAXARGS) { + ci->argc = -1; + bidx = a+2; + } + else { + ci->argc = n; + bidx = a+n+1; + } + blk = regs[bidx]; + if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { + regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); + } } ci->target_class = c; ci->pc = pc + 1; -- cgit v1.2.3 From 4b32e651a55e8bd55a9e43474823c01e999ba79e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 8 Feb 2017 23:10:25 +0900 Subject: Check if irep is NULL before print_backtrace() According to the valgrind log attached to #3438, proc->body.irep may be NULL in some cases. --- src/backtrace.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/backtrace.c b/src/backtrace.c index b499cee5a..051d5d4e0 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -118,6 +118,7 @@ each_backtrace(mrb_state *mrb, mrb_int ciidx, mrb_code *pc0, each_backtrace_func if (MRB_PROC_CFUNC_P(ci->proc)) continue; irep = ci->proc->body.irep; + if (!irep) continue; if (mrb->c->cibase[i].err) { pc = mrb->c->cibase[i].err; -- cgit v1.2.3 From d1bc7caecaf337976351934d5910726106601bd9 Mon Sep 17 00:00:00 2001 From: Tomasz Dabrowski Date: Fri, 10 Feb 2017 15:17:42 +0100 Subject: Optimization for String#* for 1-byte strings --- src/string.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index c370e0723..2e8ebda32 100644 --- a/src/string.c +++ b/src/string.c @@ -870,7 +870,9 @@ mrb_str_times(mrb_state *mrb, mrb_value self) str2 = str_new(mrb, 0, len); str_with_class(mrb, str2, self); p = RSTR_PTR(str2); - if (len > 0) { + if (len == 1) { + memset(p, RSTRING_PTR(self)[0], len); + } else if (len > 0) { n = RSTRING_LEN(self); memcpy(p, RSTRING_PTR(self), n); while (n <= len/2) { -- cgit v1.2.3 From 6cb7aef56318a345fd7dd9afa3c25e33eb7dd03e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 11 Feb 2017 16:00:26 +0900 Subject: Add type cast to pacify warning --- src/string.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index 2e8ebda32..5e37abee1 100644 --- a/src/string.c +++ b/src/string.c @@ -1773,7 +1773,7 @@ mrb_str_reverse_bang(mrb_state *mrb, mrb_value str) mrb_str_modify(mrb, mrb_str_ptr(str)); len = RSTRING_LEN(str); - buf = mrb_malloc(mrb, (size_t)len); + buf = (char*)mrb_malloc(mrb, (size_t)len); p = buf; e = buf + len; -- cgit v1.2.3 From 8f4a929e1a01c8d6176fb53a9ef5dff6de632959 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 11 Feb 2017 16:27:07 +0900 Subject: String#replace should update s->flags for MRB_STR_NO_UTF. Otherwise String#size may return wrong length; fix #3448 --- src/string.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/string.c b/src/string.c index 5e37abee1..abe8ad865 100644 --- a/src/string.c +++ b/src/string.c @@ -519,6 +519,8 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2) long len; check_frozen(mrb, s1); + s1->flags &= ~MRB_STR_NO_UTF; + s1->flags |= s2->flags&MRB_STR_NO_UTF; if (s1 == s2) return mrb_obj_value(s1); len = RSTR_LEN(s2); if (RSTR_SHARED_P(s1)) { -- cgit v1.2.3 From 642ab8ecdace909b7bd294190e342e58c67ce6c8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 11 Feb 2017 18:13:39 +0900 Subject: `ecall()` should preserve stack address referenced from ci[1]. OP_RETURN accesses ci[1]->stackent that might be broken; fix #3442 --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index e734775e2..276e2ab6d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -281,6 +281,7 @@ ecall(mrb_state *mrb, int i) mrb_value *self = mrb->c->stack; struct RObject *exc; int cioff; + mrb_value *nstk; if (i<0) return; p = mrb->c->ensure[i]; @@ -289,6 +290,7 @@ ecall(mrb_state *mrb, int i) mrb->c->ci->eidx = i; cioff = mrb->c->ci - mrb->c->cibase; ci = cipush(mrb); + nstk = ci->stackent; ci->stackent = mrb->c->stack; ci->mid = ci[-1].mid; ci->acc = CI_ACC_SKIP; @@ -300,6 +302,7 @@ ecall(mrb_state *mrb, int i) exc = mrb->exc; mrb->exc = 0; mrb_run(mrb, p, *self); mrb->c->ensure[i] = NULL; + ci->stackent = nstk; mrb->c->ci = mrb->c->cibase + cioff; if (!mrb->exc) mrb->exc = exc; } -- cgit v1.2.3 From 90f262f6426ca2b8c588d0e7083c1a4c97fccee9 Mon Sep 17 00:00:00 2001 From: Tomasz Dabrowski Date: Sat, 11 Feb 2017 13:02:48 +0100 Subject: Revert "Optimization for String#* for 1-byte strings" This reverts commit d1bc7caecaf337976351934d5910726106601bd9. --- src/string.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/string.c b/src/string.c index abe8ad865..acf32167d 100644 --- a/src/string.c +++ b/src/string.c @@ -872,9 +872,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self) str2 = str_new(mrb, 0, len); str_with_class(mrb, str2, self); p = RSTR_PTR(str2); - if (len == 1) { - memset(p, RSTRING_PTR(self)[0], len); - } else if (len > 0) { + if (len > 0) { n = RSTRING_LEN(self); memcpy(p, RSTRING_PTR(self), n); while (n <= len/2) { -- cgit v1.2.3 From 1f2d786e3220ecb6b3ff95e31f538ce338374c54 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 11 Feb 2017 21:21:19 +0900 Subject: Avoid direct return from ecall(); fix #3441 There's incompatibility left for mruby. When you return from `ensure` clause, mruby simply ignores the return value. CRuby returns from the method squashing the exception raised. ``` def f no_such_method() # NoMethodError ensure return 22 end p f() # CRuby prints `22` ``` --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 276e2ab6d..70583864e 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1652,7 +1652,7 @@ RETRY_TRY_BLOCK: switch (GETARG_B(i)) { case OP_R_RETURN: /* Fall through to OP_R_NORMAL otherwise */ - if (proc->env && !MRB_PROC_STRICT_P(proc)) { + if (ci->acc >=0 && proc->env && !MRB_PROC_STRICT_P(proc)) { struct REnv *e = top_env(mrb, proc); if (!MRB_ENV_STACK_SHARED_P(e)) { -- cgit v1.2.3 From f198530444f4b5ebfd011c3287114951c8553e5e Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Feb 2017 18:18:09 +0900 Subject: Fixed too much value_copy() when block is not given; fix #3440 The issue was reported by https://hackerone.com/titanous --- src/vm.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 70583864e..f2af6f950 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1151,12 +1151,14 @@ RETRY_TRY_BLOCK: } if (GET_OPCODE(i) != OP_SENDB) { SET_NIL_VALUE(regs[bidx]); + bidx = 0; } else { mrb_value blk = regs[bidx]; if (!mrb_nil_p(blk) && mrb_type(blk) != MRB_TT_PROC) { regs[bidx] = mrb_convert_type(mrb, blk, MRB_TT_PROC, "Proc", "to_proc"); } + bidx = 1; } c = mrb_class(mrb, recv); m = mrb_method_search_vm(mrb, &c, mid); @@ -1177,15 +1179,17 @@ RETRY_TRY_BLOCK: mrb_method_missing(mrb, mid, recv, args); } mid = missing; + if (n == CALL_MAXARGS-1) { + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + n++; + } if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], sym); } else { - value_move(regs+a+2, regs+a+1, ++n); + value_move(regs+a+2, regs+a+1, n+bidx); regs[a+1] = sym; - if (n == CALL_MAXARGS) { - regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); - } + n++; } } @@ -1355,6 +1359,10 @@ RETRY_TRY_BLOCK: mrb_method_missing(mrb, mid, recv, args); } mid = missing; + if (n == CALL_MAXARGS-1) { + regs[a+1] = mrb_ary_new_from_values(mrb, n, regs+a+1); + n++; + } if (n == CALL_MAXARGS) { mrb_ary_unshift(mrb, regs[a+1], mrb_symbol_value(ci->mid)); } -- cgit v1.2.3 From c2ddcd451724c9399014ab24a6d47815ed1a1c7d Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Mon, 13 Feb 2017 18:45:20 +0900 Subject: Should handle `break` from funcall(); fix #3434 This issue was reported by https://hackerone.com/d4nny --- src/vm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index f2af6f950..b89b6d0c5 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1733,7 +1733,7 @@ RETRY_TRY_BLOCK: acc = ci->acc; mrb->c->stack = ci->stackent; cipop(mrb); - if (acc == CI_ACC_SKIP) { + if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) { mrb->jmp = prev_jmp; return v; } -- cgit v1.2.3 From 719f700adf7598d0ad910dcd3a94aad2ef354033 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 14 Feb 2017 00:15:58 +0900 Subject: Extend mruby stack when keep is bigger than room; fix #3421 But #3421 still cause stack overflow error due to infinite recursion. To prevent overflow, we need to add different stack depth check. --- src/vm.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index b89b6d0c5..8bb446fa9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -169,6 +169,9 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep) static inline void stack_extend(mrb_state *mrb, int room, int keep) { + if (room < keep) { + room = keep; + } if (mrb->c->stack + room >= mrb->c->stend) { stack_extend_alloc(mrb, room, keep); } -- cgit v1.2.3 From 30aa5218543cd44df7c1d90a5c10cf6f622f5a8a Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 14 Feb 2017 00:22:12 +0900 Subject: Do not use mrb_funcall() if Hash#default is not overridden; ref #3421 This change reduces the recursion level, but does not solve the stack overflow issue entirely. --- include/mruby.h | 1 + src/hash.c | 21 ++++++++++++++++++++- src/kernel.c | 14 ++++++++++---- 3 files changed, 31 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 99d06146f..6950cf904 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -1147,6 +1147,7 @@ MRB_API mrb_value mrb_attr_get(mrb_state *mrb, mrb_value obj, mrb_sym id); MRB_API mrb_bool mrb_respond_to(mrb_state *mrb, mrb_value obj, mrb_sym mid); MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c); +MRB_API mrb_bool mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func); /* diff --git a/src/hash.c b/src/hash.c index 98feaceac..b7bd648c0 100644 --- a/src/hash.c +++ b/src/hash.c @@ -159,6 +159,9 @@ mrb_hash_new(mrb_state *mrb) return mrb_hash_new_capa(mrb, 0); } +static mrb_value mrb_hash_default(mrb_state *mrb, mrb_value hash); +static mrb_value hash_default(mrb_state *mrb, mrb_value hash, mrb_value key); + MRB_API mrb_value mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { @@ -171,7 +174,9 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) return kh_value(h, k).v; } - /* not found */ + if (mrb_func_basic_p(mrb, hash, mrb_intern_lit(mrb, "default"), mrb_hash_default)) { + return hash_default(mrb, hash, key); + } /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ return mrb_funcall(mrb, hash, "default", 1, key); } @@ -366,6 +371,20 @@ mrb_hash_aget(mrb_state *mrb, mrb_value self) return mrb_hash_get(mrb, self, key); } +static mrb_value +hash_default(mrb_state *mrb, mrb_value hash, mrb_value key) +{ + if (MRB_RHASH_DEFAULT_P(hash)) { + if (MRB_RHASH_PROCDEFAULT_P(hash)) { + return mrb_funcall(mrb, RHASH_PROCDEFAULT(hash), "call", 2, hash, key); + } + else { + return RHASH_IFNONE(hash); + } + } + return mrb_nil_value(); +} + /* 15.2.13.4.5 */ /* * call-seq: diff --git a/src/kernel.c b/src/kernel.c index 8b00d701b..02bb3c99b 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -28,15 +28,21 @@ typedef enum { NOEX_RESPONDS = 0x80 } mrb_method_flag_t; -static mrb_bool -mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) +MRB_API mrb_bool +mrb_func_basic_p(mrb_state *mrb, mrb_value obj, mrb_sym mid, mrb_func_t func) { - struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mrb_intern_lit(mrb, "to_s")); - if (MRB_PROC_CFUNC_P(me) && (me->body.func == mrb_any_to_s)) + struct RProc *me = mrb_method_search(mrb, mrb_class(mrb, obj), mid); + if (MRB_PROC_CFUNC_P(me) && (me->body.func == func)) return TRUE; return FALSE; } +static mrb_bool +mrb_obj_basic_to_s_p(mrb_state *mrb, mrb_value obj) +{ + return mrb_func_basic_p(mrb, obj, mrb_intern_lit(mrb, "to_s"), mrb_any_to_s); +} + /* 15.3.1.3.17 */ /* * call-seq: -- cgit v1.2.3 From 04296925ac81537e029af46ed7622471d8374ce8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 09:24:35 +0900 Subject: Use mrb_funcall_argv() instead of mrb_funcall() --- src/hash.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/hash.c b/src/hash.c index b7bd648c0..d15faa206 100644 --- a/src/hash.c +++ b/src/hash.c @@ -167,6 +167,7 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) { khash_t(ht) *h = RHASH_TBL(hash); khiter_t k; + mrb_sym mid; if (h) { k = kh_get(ht, mrb, h, key); @@ -174,11 +175,12 @@ mrb_hash_get(mrb_state *mrb, mrb_value hash, mrb_value key) return kh_value(h, k).v; } - if (mrb_func_basic_p(mrb, hash, mrb_intern_lit(mrb, "default"), mrb_hash_default)) { + mid = mrb_intern_lit(mrb, "default"); + if (mrb_func_basic_p(mrb, hash, mid, mrb_hash_default)) { return hash_default(mrb, hash, key); } /* xxx mrb_funcall_tailcall(mrb, hash, "default", 1, key); */ - return mrb_funcall(mrb, hash, "default", 1, key); + return mrb_funcall_argv(mrb, hash, mid, 1, &key); } MRB_API mrb_value -- cgit v1.2.3 From dd24f9f5cc6cc878ae00cf96ce08ae1486d8c0cb Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 09:25:09 +0900 Subject: Avoid calling hook methods if they are not overridden. --- src/class.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 81b312fd0..84cc08a10 100644 --- a/src/class.c +++ b/src/class.c @@ -240,12 +240,22 @@ mrb_define_class(mrb_state *mrb, const char *name, struct RClass *super) return mrb_define_class_id(mrb, mrb_intern_cstr(mrb, name), super); } +static mrb_value mrb_bob_init(mrb_state *mrb, mrb_value cv); + static void mrb_class_inherited(mrb_state *mrb, struct RClass *super, struct RClass *klass) { + mrb_value s; + mrb_sym mid; + if (!super) super = mrb->object_class; - mrb_funcall(mrb, mrb_obj_value(super), "inherited", 1, mrb_obj_value(klass)); + s = mrb_obj_value(super); + mid = mrb_intern_lit(mrb, "inherited"); + if (!mrb_func_basic_p(mrb, s, mid, mrb_bob_init)) { + mrb_value c = mrb_obj_value(klass); + mrb_funcall_argv(mrb, mrb_obj_value(super), mid, 1, &c); + } } MRB_API struct RClass* @@ -1407,10 +1417,13 @@ MRB_API mrb_value mrb_obj_new(mrb_state *mrb, struct RClass *c, mrb_int argc, const mrb_value *argv) { mrb_value obj; + mrb_sym mid; obj = mrb_instance_alloc(mrb, mrb_obj_value(c)); - mrb_funcall_argv(mrb, obj, mrb_intern_lit(mrb, "initialize"), argc, argv); - + mid = mrb_intern_lit(mrb, "initialize"); + if (!mrb_func_basic_p(mrb, obj, mid, mrb_bob_init)) { + mrb_funcall_argv(mrb, obj, mid, argc, argv); + } return obj; } @@ -1432,13 +1445,17 @@ mrb_class_new_class(mrb_state *mrb, mrb_value cv) mrb_int n; mrb_value super, blk; mrb_value new_class; + mrb_sym mid; n = mrb_get_args(mrb, "|C&", &super, &blk); if (n == 0) { super = mrb_obj_value(mrb->object_class); } new_class = mrb_obj_value(mrb_class_new(mrb, mrb_class_ptr(super))); - mrb_funcall_with_block(mrb, new_class, mrb_intern_lit(mrb, "initialize"), n, &super, blk); + mid = mrb_intern_lit(mrb, "initialize"); + if (!mrb_func_basic_p(mrb, new_class, mid, mrb_bob_init)) { + mrb_funcall_with_block(mrb, new_class, mid, n, &super, blk); + } mrb_class_inherited(mrb, mrb_class_ptr(super), mrb_class_ptr(new_class)); return new_class; } -- cgit v1.2.3 From 8efa7b00df2842eaff31cdabc95651a856e40549 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 11:59:47 +0900 Subject: Preallocate SystemStackError; ref #3421 --- include/mruby.h | 2 +- src/backtrace.c | 2 +- src/error.c | 5 +++-- src/gc.c | 1 + src/vm.c | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/include/mruby.h b/include/mruby.h index 6950cf904..8adce289b 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -221,6 +221,7 @@ typedef struct mrb_state { struct RClass *eException_class; struct RClass *eStandardError_class; struct RObject *nomem_err; /* pre-allocated NoMemoryError */ + struct RObject *stack_err; /* pre-allocated SysStackError */ #ifdef MRB_GC_FIXED_ARENA struct RObject *arena_err; /* pre-allocated arena overfow error */ #endif @@ -1110,7 +1111,6 @@ MRB_API void mrb_print_error(mrb_state *mrb); #define E_SYNTAX_ERROR (mrb_exc_get(mrb, "SyntaxError")) #define E_LOCALJUMP_ERROR (mrb_exc_get(mrb, "LocalJumpError")) #define E_REGEXP_ERROR (mrb_exc_get(mrb, "RegexpError")) -#define E_SYSSTACK_ERROR (mrb_exc_get(mrb, "SystemStackError")) #define E_NOTIMP_ERROR (mrb_exc_get(mrb, "NotImplementedError")) #define E_FLOATDOMAIN_ERROR (mrb_exc_get(mrb, "FloatDomainError")) diff --git a/src/backtrace.c b/src/backtrace.c index 051d5d4e0..529b0b1c9 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -263,7 +263,7 @@ mrb_print_backtrace(mrb_state *mrb) { mrb_value backtrace; - if (!mrb->exc || mrb_obj_is_kind_of(mrb, mrb_obj_value(mrb->exc), E_SYSSTACK_ERROR)) { + if (!mrb->exc) { return; } diff --git a/src/error.c b/src/error.c index a71ee548f..7916ca65b 100644 --- a/src/error.c +++ b/src/error.c @@ -532,7 +532,7 @@ mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, void mrb_init_exception(mrb_state *mrb) { - struct RClass *exception, *runtime_error, *script_error; + struct RClass *exception, *runtime_error, *script_error, *stack_error; mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */ MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION); @@ -553,5 +553,6 @@ mrb_init_exception(mrb_state *mrb) #endif script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class); /* 15.2.37 */ mrb_define_class(mrb, "SyntaxError", script_error); /* 15.2.38 */ - mrb_define_class(mrb, "SystemStackError", exception); + stack_error = mrb_define_class(mrb, "SystemStackError", exception); + mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep")); } diff --git a/src/gc.c b/src/gc.c index 1608dbcb2..63eab8e00 100644 --- a/src/gc.c +++ b/src/gc.c @@ -865,6 +865,7 @@ root_scan_phase(mrb_state *mrb, mrb_gc *gc) } /* mark pre-allocated exception */ mrb_gc_mark(mrb, (struct RBasic*)mrb->nomem_err); + mrb_gc_mark(mrb, (struct RBasic*)mrb->stack_err); #ifdef MRB_GC_FIXED_ARENA mrb_gc_mark(mrb, (struct RBasic*)mrb->arena_err); #endif diff --git a/src/vm.c b/src/vm.c index 8bb446fa9..91612a0da 100644 --- a/src/vm.c +++ b/src/vm.c @@ -162,7 +162,7 @@ stack_extend_alloc(mrb_state *mrb, int room, int keep) to prevent infinite recursion. However, do this only after resizing the stack, so mrb_raise has stack space to work with. */ if (size > MRB_STACK_MAX) { init_new_stack_space(mrb, room, keep); - mrb_raise(mrb, E_SYSSTACK_ERROR, "stack level too deep. (limit=" MRB_STRINGIZE(MRB_STACK_MAX) ")"); + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } } -- cgit v1.2.3 From 1e57fefbcf1ab327113699eebf2b08d9ec450dfe Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 12:01:52 +0900 Subject: Do not funcall() Exception#set_backtrace from runtime. This change reduce flexibility but makes mruby simpler and faster. --- src/error.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/error.c b/src/error.c index 7916ca65b..3fa18fcb3 100644 --- a/src/error.c +++ b/src/error.c @@ -202,12 +202,9 @@ exc_get_backtrace(mrb_state *mrb, mrb_value exc) return backtrace; } -static mrb_value -exc_set_backtrace(mrb_state *mrb, mrb_value exc) +static void +set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace) { - mrb_value backtrace; - - mrb_get_args(mrb, "o", &backtrace); if (!mrb_array_p(backtrace)) { type_err: mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String"); @@ -222,7 +219,15 @@ exc_set_backtrace(mrb_state *mrb, mrb_value exc) } } mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace); +} +static mrb_value +exc_set_backtrace(mrb_state *mrb, mrb_value exc) +{ + mrb_value backtrace; + + mrb_get_args(mrb, "o", &backtrace); + set_backtrace(mrb, exc, backtrace); return backtrace; } @@ -253,12 +258,6 @@ exc_debug_info(mrb_state *mrb, struct RObject *exc) } } -static void -set_backtrace(mrb_state *mrb, mrb_value info, mrb_value bt) -{ - mrb_funcall(mrb, info, "set_backtrace", 1, bt); -} - static mrb_bool have_backtrace(mrb_state *mrb, struct RObject *exc) { -- cgit v1.2.3 From 1e5b5b14d7468ca4fedaa9ba1c9dba0ff67d7ea8 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 12:06:32 +0900 Subject: Prohibit too deep `mrb_funcall()` recursion; ref #3421 `mrb_funcall()` recursion can cause stack overflow easily, so recursion depth is now limited to MRB_FUNCALL_DEPTH_MAX, which default value is 512. --- src/vm.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src') diff --git a/src/vm.c b/src/vm.c index 91612a0da..96a9966a2 100644 --- a/src/vm.c +++ b/src/vm.c @@ -40,6 +40,11 @@ void abort(void); #define MRB_STACK_GROWTH 128 #endif +/* Maximum mrb_funcall() depth. Should be set lower on memory constrained systems. */ +#ifndef MRB_FUNCALL_DEPTH_MAX +#define MRB_FUNCALL_DEPTH_MAX 512 +#endif + /* Maximum stack depth. Should be set lower on memory constrained systems. The value below allows about 60000 recursive calls in the simplest case. */ #ifndef MRB_STACK_MAX @@ -386,6 +391,9 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc undef = mid; argc++; } + if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { + mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); + } ci = cipush(mrb); ci->mid = mid; ci->proc = p; -- 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 'src') 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 From 8b4bd3158b365cd1baddc4e9f9e5f770717022cf Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 13:07:53 +0900 Subject: Move #== and #!= to BasicObject; ref #3417 --- src/class.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/kernel.c | 52 +--------------------------------------------------- 2 files changed, 52 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 0b7521e61..21a4d3f20 100644 --- a/src/class.c +++ b/src/class.c @@ -1486,6 +1486,55 @@ mrb_bob_not(mrb_state *mrb, mrb_value cv) return mrb_bool_value(!mrb_test(cv)); } +/* 15.3.1.3.1 */ +/* 15.3.1.3.10 */ +/* 15.3.1.3.11 */ +/* + * call-seq: + * obj == other -> true or false + * obj.equal?(other) -> true or false + * obj.eql?(other) -> true or false + * + * Equality---At the Object level, == returns + * true only if obj and other are the + * same object. Typically, this method is overridden in descendant + * classes to provide class-specific meaning. + * + * Unlike ==, the equal? method should never be + * overridden by subclasses: it is used to determine object identity + * (that is, a.equal?(b) iff a is the same + * object as b). + * + * The eql? method returns true if + * obj and anObject have the same value. Used by + * Hash to test members for equality. For objects of + * class Object, eql? is synonymous with + * ==. Subclasses normally continue this tradition, but + * there are exceptions. Numeric types, for example, + * perform type conversion across ==, but not across + * eql?, so: + * + * 1 == 1.0 #=> true + * 1.eql? 1.0 #=> false + */ +mrb_value +mrb_obj_equal_m(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_bool_value(mrb_obj_equal(mrb, self, arg)); +} + +static mrb_value +mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self) +{ + mrb_value arg; + + mrb_get_args(mrb, "o", &arg); + return mrb_bool_value(!mrb_equal(mrb, self, arg)); +} + MRB_API mrb_bool mrb_obj_respond_to(mrb_state *mrb, struct RClass* c, mrb_sym mid) { @@ -2235,6 +2284,8 @@ 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, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ + mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); 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 fd00d0484..e21a99352 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -66,55 +66,6 @@ mrb_obj_inspect(mrb_state *mrb, mrb_value obj) return mrb_any_to_s(mrb, obj); } -/* 15.3.1.3.1 */ -/* 15.3.1.3.10 */ -/* 15.3.1.3.11 */ -/* - * call-seq: - * obj == other -> true or false - * obj.equal?(other) -> true or false - * obj.eql?(other) -> true or false - * - * Equality---At the Object level, == returns - * true only if obj and other are the - * same object. Typically, this method is overridden in descendant - * classes to provide class-specific meaning. - * - * Unlike ==, the equal? method should never be - * overridden by subclasses: it is used to determine object identity - * (that is, a.equal?(b) iff a is the same - * object as b). - * - * The eql? method returns true if - * obj and anObject have the same value. Used by - * Hash to test members for equality. For objects of - * class Object, eql? is synonymous with - * ==. Subclasses normally continue this tradition, but - * there are exceptions. Numeric types, for example, - * perform type conversion across ==, but not across - * eql?, so: - * - * 1 == 1.0 #=> true - * 1.eql? 1.0 #=> false - */ -static mrb_value -mrb_obj_equal_m(mrb_state *mrb, mrb_value self) -{ - mrb_value arg; - - mrb_get_args(mrb, "o", &arg); - return mrb_bool_value(mrb_obj_equal(mrb, self, arg)); -} - -static mrb_value -mrb_obj_not_equal_m(mrb_state *mrb, mrb_value self) -{ - mrb_value arg; - - mrb_get_args(mrb, "o", &arg); - return mrb_bool_value(!mrb_equal(mrb, self, arg)); -} - /* 15.3.1.3.2 */ /* * call-seq: @@ -1227,6 +1178,7 @@ mrb_local_variables(mrb_state *mrb, mrb_value self) return mrb_hash_keys(mrb, vars); } +mrb_value mrb_obj_equal_m(mrb_state *mrb, mrb_value); void mrb_init_kernel(mrb_state *mrb) { @@ -1242,8 +1194,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); - mrb_define_method(mrb, krn, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ - mrb_define_method(mrb, krn, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ mrb_define_method(mrb, krn, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ -- cgit v1.2.3 From 3dbda9178834a4e55d884c97677ed2ecf46c2289 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 13:12:05 +0900 Subject: Move #__send__ to BasicObject; ref #3417 --- src/class.c | 1 + src/kernel.c | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 21a4d3f20..086833eaf 100644 --- a/src/class.c +++ b/src/class.c @@ -2286,6 +2286,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ 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 e21a99352..95ebcfbd8 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1196,7 +1196,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ - mrb_define_method(mrb, krn, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */ mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ -- cgit v1.2.3 From 612d636b77edd7c0969e8850583aefd895638284 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 13:15:58 +0900 Subject: Move #instance_eval to BasicObject; ref #3417 --- src/class.c | 4 ++++ src/kernel.c | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index 086833eaf..f3146ca15 100644 --- a/src/class.c +++ b/src/class.c @@ -2245,6 +2245,9 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod) return mod; } +/* implementation of instance_eval */ +mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); + void mrb_init_class(mrb_state *mrb) { @@ -2287,6 +2290,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ + mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ 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 95ebcfbd8..04bcbe6c2 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -489,9 +489,6 @@ mrb_obj_init_copy(mrb_state *mrb, mrb_value self) } -/* implementation of instance_eval */ -mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); - MRB_API mrb_bool mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) { @@ -1209,7 +1206,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "hash", mrb_obj_hash, MRB_ARGS_NONE()); /* 15.3.1.3.15 */ mrb_define_method(mrb, krn, "initialize_copy", mrb_obj_init_copy, MRB_ARGS_REQ(1)); /* 15.3.1.3.16 */ mrb_define_method(mrb, krn, "inspect", mrb_obj_inspect, MRB_ARGS_NONE()); /* 15.3.1.3.17 */ - mrb_define_method(mrb, krn, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ mrb_define_method(mrb, krn, "instance_of?", obj_is_instance_of, MRB_ARGS_REQ(1)); /* 15.3.1.3.19 */ mrb_define_method(mrb, krn, "instance_variable_defined?", mrb_obj_ivar_defined, MRB_ARGS_REQ(1)); /* 15.3.1.3.20 */ mrb_define_method(mrb, krn, "instance_variable_get", mrb_obj_ivar_get, MRB_ARGS_REQ(1)); /* 15.3.1.3.21 */ -- cgit v1.2.3 From 517e9313bf6e6d4697095a9257598915ac857ff3 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Wed, 15 Feb 2017 13:19:21 +0900 Subject: Move #__id__ to BasicObject; ref #3417 --- src/class.c | 3 +++ src/kernel.c | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/class.c b/src/class.c index f3146ca15..0922b3cff 100644 --- a/src/class.c +++ b/src/class.c @@ -2245,6 +2245,8 @@ mrb_mod_module_function(mrb_state *mrb, mrb_value mod) return mod; } +/* implementation of __id__ */ +mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self); /* implementation of instance_eval */ mrb_value mrb_obj_instance_eval(mrb_state*, mrb_value); @@ -2289,6 +2291,7 @@ mrb_init_class(mrb_state *mrb) mrb_define_method(mrb, bob, "!", mrb_bob_not, MRB_ARGS_NONE()); mrb_define_method(mrb, bob, "==", mrb_obj_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.1 */ mrb_define_method(mrb, bob, "!=", mrb_obj_not_equal_m, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, bob, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ mrb_define_method(mrb, bob, "__send__", mrb_f_send, MRB_ARGS_ANY()); /* 15.3.1.3.4 */ mrb_define_method(mrb, bob, "instance_eval", mrb_obj_instance_eval, MRB_ARGS_ANY()); /* 15.3.1.3.18 */ diff --git a/src/kernel.c b/src/kernel.c index 04bcbe6c2..6cb2e3ad5 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -101,7 +101,7 @@ mrb_equal_m(mrb_state *mrb, mrb_value self) * :name notation, which returns the symbol id of * name. Replaces the deprecated Object#id. */ -static mrb_value +mrb_value mrb_obj_id_m(mrb_state *mrb, mrb_value self) { return mrb_fixnum_value(mrb_obj_id(self)); @@ -1192,7 +1192,6 @@ mrb_init_kernel(mrb_state *mrb) mrb_define_method(mrb, krn, "singleton_class", mrb_singleton_class, MRB_ARGS_NONE()); mrb_define_method(mrb, krn, "===", mrb_equal_m, MRB_ARGS_REQ(1)); /* 15.3.1.3.2 */ - mrb_define_method(mrb, krn, "__id__", mrb_obj_id_m, MRB_ARGS_NONE()); /* 15.3.1.3.3 */ mrb_define_method(mrb, krn, "block_given?", mrb_f_block_given_p_m, MRB_ARGS_NONE()); /* 15.3.1.3.6 */ mrb_define_method(mrb, krn, "class", mrb_obj_class_m, MRB_ARGS_NONE()); /* 15.3.1.3.7 */ mrb_define_method(mrb, krn, "clone", mrb_obj_clone, MRB_ARGS_NONE()); /* 15.3.1.3.8 */ -- cgit v1.2.3