diff --git a/NEWS b/NEWS index db4253988..34cf84528 100644 --- a/NEWS +++ b/NEWS @@ -1,12 +1,64 @@ NEWS ---- -This document is a list of user visible feature changes made between -releases except for bug fixes. +# User visible changes in `mruby3.2` -Note that each entry is kept so brief that no reason behind or -reference information is supplied with. For a full list of changes -with all sufficient information, see the ChangeLog file. +# The language +- Now `a::B = c` should evaluate `a` then `c`. +- Anonymous arguments `*`, `**`, `&` can be passed for forwarding. +- Multi-precision integer is available now via `mruby-bigint` gem. -** Information about first release v1.0.0 +# mruby VM and bytecode + +- `OP_ARYDUP` was renamed to `OP_ARYSPLAT`. The instruction name + was changed but instruction number and basic behavior have not + changed (except that `ARYDUP nil` makes `[]`). + +# Tools + +## `mruby` + +- `-b` only specifies the script is the binary. The files loaded by `-r` are not affected by the option. +- `mruby` now loads complied binary if the suffix is `.mrb`. + +## `mrbc` + +- Add `--no-optimize` option to disable optimization. + +# mrbgems + +## mruby-class-ext + +- Add `Class#subclasses` method. +- Add `Module#undefined_instance_methods` method. + +## New bundled gems + +- mruby-errno from [https://github.com/iij/mruby-errno.git] +- mruby-set from [https://github.com/yui-knk/mruby-set.git] +- mruby-dir from [https://github.com/iij/mruby-dir.git] + +# CVEs + +Following CVEs are fixed. + +- [CVE-2022-0080](https://nvd.nist.gov/vuln/detail/CVE-2022-0080) +- [CVE-2022-0240](https://nvd.nist.gov/vuln/detail/CVE-2022-0240) +- [CVE-2022-0326](https://nvd.nist.gov/vuln/detail/CVE-2022-0326) +- [CVE-2022-0631](https://nvd.nist.gov/vuln/detail/CVE-2022-0631) +- [CVE-2022-0481](https://nvd.nist.gov/vuln/detail/CVE-2022-0481) +- [CVE-2022-0525](https://nvd.nist.gov/vuln/detail/CVE-2022-0525) +- [CVE-2022-0570](https://nvd.nist.gov/vuln/detail/CVE-2022-0570) +- [CVE-2022-0614](https://nvd.nist.gov/vuln/detail/CVE-2022-0614) +- [CVE-2022-0623](https://nvd.nist.gov/vuln/detail/CVE-2022-0623) +- [CVE-2022-0630](https://nvd.nist.gov/vuln/detail/CVE-2022-0630) +- [CVE-2022-0631](https://nvd.nist.gov/vuln/detail/CVE-2022-0631) +- [CVE-2022-0632](https://nvd.nist.gov/vuln/detail/CVE-2022-0632) +- [CVE-2022-0717](https://nvd.nist.gov/vuln/detail/CVE-2022-0717) +- [CVE-2022-0890](https://nvd.nist.gov/vuln/detail/CVE-2022-0890) +- [CVE-2022-1106](https://nvd.nist.gov/vuln/detail/CVE-2022-1106) +- [CVE-2022-1212](https://nvd.nist.gov/vuln/detail/CVE-2022-1212) +- [CVE-2022-1276](https://nvd.nist.gov/vuln/detail/CVE-2022-1276) +- [CVE-2022-1286](https://nvd.nist.gov/vuln/detail/CVE-2022-1286) +- [CVE-2022-1934](https://nvd.nist.gov/vuln/detail/CVE-2022-1934) diff --git a/doc/mruby3.2.md b/doc/mruby3.2.md index 1cf97a87b..1ca18d6b4 100644 --- a/doc/mruby3.2.md +++ b/doc/mruby3.2.md @@ -35,6 +35,25 @@ - mruby-errno from [https://github.com/iij/mruby-errno.git] - mruby-set from [https://github.com/yui-knk/mruby-set.git] - mruby-dir from [https://github.com/iij/mruby-dir.git] +- mruby-data + +# Breaking Changes + +## `mrb_vm_run()` may detach top-level local variables referenced from blocks + +When the `mrb_vm_run()` function (including `mrb_top_run()`) is called, +the previous top-level local variables referenced from blocks is detached under either of the following conditions. + +- If the `stack_keep` parameter is given as 0. +- If the number of variables in `irep` to be executed is less than the number of previous top-level local variables. + +This change also affects API functions such as `mrb_load_string()` and `mrb_load_file()`. +The conditions under which the previous top-level local variables referenced from blocks is detached in these functions are as follows: + +- If the function has no `mrbc_context` pointer parameter, or the `mrbc_context` pointer parameter is set to `NULL`. +- If the number of variables held in the `mrbc_context` pointer is less than the number of previous top-level local variables. + +Intentional reliance on previous behavior may cause compatibility problems in your application. # CVEs diff --git a/include/mruby/internal.h b/include/mruby/internal.h index ac5ecfbc2..db64fd38f 100644 --- a/include/mruby/internal.h +++ b/include/mruby/internal.h @@ -22,6 +22,7 @@ mrb_value mrb_class_find_path(mrb_state*, struct RClass*); mrb_value mrb_mod_to_s(mrb_state *, mrb_value); void mrb_method_added(mrb_state *mrb, struct RClass *c, mrb_sym mid); mrb_noreturn void mrb_method_missing(mrb_state *mrb, mrb_sym name, mrb_value self, mrb_value args); +mrb_method_t mrb_vm_find_method(mrb_state *mrb, struct RClass *c, struct RClass **cp, mrb_sym mid); #endif /* debug */ diff --git a/mrbgems/mruby-eval/src/eval.c b/mrbgems/mruby-eval/src/eval.c index 19145300e..ff65b0fa1 100644 --- a/mrbgems/mruby-eval/src/eval.c +++ b/mrbgems/mruby-eval/src/eval.c @@ -29,14 +29,14 @@ create_proc_from_string(mrb_state *mrb, const char *s, mrb_int len, mrb_value bi mrb_obj_class(mrb, binding)); } scope_obj = mrb_iv_get(mrb, binding, MRB_SYM(proc)); - mrb_assert(mrb_proc_p(scope_obj)); + mrb_check_type(mrb, scope_obj, MRB_TT_PROC); scope = mrb_proc_ptr(scope_obj); if (MRB_PROC_CFUNC_P(scope)) { e = NULL; } else { mrb_value env = mrb_iv_get(mrb, binding, MRB_SYM(env)); - mrb_assert(mrb_env_p(env)); + mrb_check_type(mrb, env, MRB_TT_ENV); e = (struct REnv *)mrb_obj_ptr(env); mrb_assert(e != NULL); } diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 5ef60d039..ebe19930a 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -339,7 +339,7 @@ io_alloc(mrb_state *mrb) #define NOFILE 64 #endif -#ifdef NO_IO_POPEN +#ifdef MRB_NO_IO_POPEN # define io_s_popen mrb_notimplement_m #else static int @@ -770,7 +770,7 @@ fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet) fptr->fd2 = -1; } -#ifndef NO_IO_POPEN +#ifndef MRB_NO_IO_POPEN if (fptr->pid != 0) { #if !defined(_WIN32) && !defined(_WIN64) pid_t pid; @@ -1714,10 +1714,10 @@ io_find_index(struct mrb_io *fptr, const char *rs, mrb_int rslen) mrb_assert(rslen > 0); const char c = rs[0]; const mrb_int limit = buf->len - rslen; - for (mrb_int i=buf->start; imem[i] == c) { - if (memcmp(buf->mem+i, rs, rslen) == 0) - return i; + const char *p = buf->mem+buf->start; + for (mrb_int i=0; ilen >= limit) { + for (;;) { + if (rs_given) { /* with RS */ + int rslen = RSTRING_LEN(rs); + mrb_int idx = io_find_index(fptr, RSTRING_PTR(rs), rslen); + if (idx >= 0) { /* found */ + mrb_int n = idx+rslen; + if (limit_given && limit < n) { + n = limit; + } + io_buf_cat(mrb, outbuf, fptr, n); + return outbuf; + } + } + if (limit_given) { + if (limit <= buf->len) { io_buf_cat(mrb, outbuf, fptr, limit); return outbuf; } - io_buf_cat_all(mrb, outbuf, fptr); - io_buf_fill(mrb, fptr); - if (fptr->eof) { - if (RSTRING_LEN(outbuf) == 0) return mrb_nil_value(); - return outbuf; - } - } - } - - for (;;) { /* with RS */ - int rslen = RSTRING_LEN(rs); - mrb_int idx = io_find_index(fptr, RSTRING_PTR(rs), rslen); - if (idx >= 0) { /* found */ - mrb_int n = idx+rslen; - if (limit_given && limit < n) { - n = limit; - } - io_buf_cat(mrb, outbuf, fptr, n); - return outbuf; - } - if (limit_given && buf->len < limit) { - io_buf_cat(mrb, outbuf, fptr, limit); - return outbuf; + limit -= buf->len; } io_buf_cat_all(mrb, outbuf, fptr); io_buf_fill(mrb, fptr); diff --git a/mrbgems/mruby-io/test/io.rb b/mrbgems/mruby-io/test/io.rb index 610216ab0..024a71acd 100644 --- a/mrbgems/mruby-io/test/io.rb +++ b/mrbgems/mruby-io/test/io.rb @@ -369,6 +369,7 @@ assert('IO#gets') do # gets with rs io.pos = 0 assert_equal $mrbtest_io_msg[0, 6], io.gets(' '), "gets with rs" + assert_equal $mrbtest_io_msg[6, 3], io.gets(' '), "gets with rs(2)" # gets with rs, limit io.pos = 0 diff --git a/src/class.c b/src/class.c index f990c37ee..6cd40cfd3 100644 --- a/src/class.c +++ b/src/class.c @@ -244,6 +244,23 @@ mt_free(mrb_state *mrb, mt_tbl *t) mrb_free(mrb, t); } +static inline mrb_method_t +create_method_value(mrb_state *mrb, mrb_sym key, union mt_ptr val) +{ + mrb_method_t m; + + if (key & MT_FUNC_P) { + MRB_METHOD_FROM_FUNC(m, val.func); + } + else { + MRB_METHOD_FROM_PROC(m, val.proc); + } + if (key & MT_NOARG_P) { + MRB_METHOD_NOARG_SET(m); + } + return m; +} + MRB_API void mrb_mt_foreach(mrb_state *mrb, struct RClass *c, mrb_mt_foreach_func *fn, void *p) { @@ -259,19 +276,7 @@ mrb_mt_foreach(mrb_state *mrb, struct RClass *c, mrb_mt_foreach_func *fn, void * for (i=0; ialloc; i++) { mrb_sym key = keys[i]; if (MT_KEY_SYM(key)) { - mrb_method_t m; - - if (key & MT_FUNC_P) { - MRB_METHOD_FROM_FUNC(m, vals[i].func); - } - else { - MRB_METHOD_FROM_PROC(m, vals[i].proc); - } - if (key & MT_NOARG_P) { - MRB_METHOD_NOARG_SET(m); - } - - if (fn(mrb, MT_KEY_SYM(key), m, p) != 0) + if (fn(mrb, MT_KEY_SYM(key), create_method_value(mrb, key, vals[i]), p) != 0) return; } } @@ -1765,11 +1770,10 @@ mc_clear_by_id(mrb_state *mrb, mrb_sym id) } #endif -MRB_API mrb_method_t -mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) +mrb_method_t +mrb_vm_find_method(mrb_state *mrb, struct RClass *c, struct RClass **cp, mrb_sym mid) { mrb_method_t m; - struct RClass *c = *cp; #ifndef MRB_NO_METHOD_CACHE struct RClass *oc = c; int h = kh_int_hash_func(mrb, ((intptr_t)oc) ^ mid) & (MRB_METHOD_CACHE_SIZE-1); @@ -1790,15 +1794,7 @@ mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) if (ret) { if (ptr.proc == 0) break; *cp = c; - if (ret & MT_FUNC_P) { - MRB_METHOD_FROM_FUNC(m, ptr.func); - } - else { - MRB_METHOD_FROM_PROC(m, ptr.proc); - } - if (ret & MT_NOARG_P) { - MRB_METHOD_NOARG_SET(m); - } + m = create_method_value(mrb, ret, ptr); #ifndef MRB_NO_METHOD_CACHE mc->c = oc; mc->c0 = c; @@ -1814,6 +1810,12 @@ mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) return m; /* no method */ } +MRB_API mrb_method_t +mrb_method_search_vm(mrb_state *mrb, struct RClass **cp, mrb_sym mid) +{ + return mrb_vm_find_method(mrb, *cp, cp, mid); +} + MRB_API mrb_method_t mrb_method_search(mrb_state *mrb, struct RClass* c, mrb_sym mid) { diff --git a/src/vm.c b/src/vm.c index 323324d39..475f02ab1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -562,7 +562,7 @@ prepare_missing(mrb_state *mrb, mrb_callinfo *ci, mrb_value recv, mrb_sym mid, m if (mid != missing) { ci->u.target_class = mrb_class(mrb, recv); } - m = mrb_method_search_vm(mrb, &ci->u.target_class, missing); + m = mrb_vm_find_method(mrb, ci->u.target_class, &ci->u.target_class, missing); if (MRB_METHOD_UNDEF_P(m)) goto method_missing; /* just in case */ mrb_stack_extend(mrb, 4); @@ -662,7 +662,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc ci = cipush(mrb, n, CINFO_DIRECT, NULL, NULL, BLK_PTR(blk), 0, 0); funcall_args_capture(mrb, 0, argc, argv, blk, ci); ci->u.target_class = mrb_class(mrb, self); - m = mrb_method_search_vm(mrb, &ci->u.target_class, mid); + m = mrb_vm_find_method(mrb, ci->u.target_class, &ci->u.target_class, mid); if (MRB_METHOD_UNDEF_P(m)) { m = prepare_missing(mrb, ci, self, mid, mrb_nil_value(), FALSE); } @@ -816,7 +816,7 @@ mrb_f_send(mrb_state *mrb, mrb_value self) } c = mrb_class(mrb, self); - m = mrb_method_search_vm(mrb, &c, name); + m = mrb_vm_find_method(mrb, c, &c, name); if (MRB_METHOD_UNDEF_P(m)) { /* call method_mising */ goto funcall; } @@ -1769,7 +1769,7 @@ RETRY_TRY_BLOCK: ci = cipush(mrb, a, CINFO_DIRECT, NULL, NULL, BLK_PTR(blk), 0, c); recv = regs[0]; ci->u.target_class = (insn == OP_SUPER) ? CI_TARGET_CLASS(ci - 1)->super : mrb_class(mrb, recv); - m = mrb_method_search_vm(mrb, &ci->u.target_class, mid); + m = mrb_vm_find_method(mrb, ci->u.target_class, &ci->u.target_class, mid); if (MRB_METHOD_UNDEF_P(m)) { m = prepare_missing(mrb, ci, recv, mid, blk, (insn == OP_SUPER)); }