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 --- src/vm.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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/vm.c') 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/vm.c') 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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/vm.c') 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/vm.c') 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/vm.c') 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 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/vm.c') 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 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/vm.c') 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