From 22468a4f92c7fa7a08e53a674285183b1af49ed4 Mon Sep 17 00:00:00 2001 From: ko1 Date: Tue, 6 Aug 2013 08:33:05 +0000 Subject: * vm_insnhelper.c (vm_push_frame): fix stack overflow check codes. Stack overflow check should be done *after* pushing a stack frame. However, some stack overflow checking codes checked *before* pushing a stack frame with iseq->stack_max. To solve this problem, add a new parameter `stack_max' to specify a possible consuming stack size. * vm_core.h (CHECK_VM_STACK_OVERFLOW0): add to share the stack overflow checking code. * insns.def: catch up this change. * vm.c, vm_eval.c: ditto. * test/ruby/test_exception.rb: add a stack overflow test. This code is reported by nobu. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42398 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 19 +++++++++++++++++++ insns.def | 2 +- test/ruby/test_exception.rb | 9 +++++++++ vm.c | 15 ++++++--------- vm_core.h | 12 +++++++----- vm_eval.c | 3 +-- vm_insnhelper.c | 22 +++++++++------------- 7 files changed, 52 insertions(+), 30 deletions(-) diff --git a/ChangeLog b/ChangeLog index e302acfe9b..3e20edca7e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +Tue Aug 6 17:21:38 2013 Koichi Sasada + + * vm_insnhelper.c (vm_push_frame): fix stack overflow check codes. + Stack overflow check should be done *after* pushing a stack frame. + However, some stack overflow checking codes checked *before* + pushing a stack frame with iseq->stack_max. + To solve this problem, add a new parameter `stack_max' to specify + a possible consuming stack size. + + * vm_core.h (CHECK_VM_STACK_OVERFLOW0): add to share the stack overflow + checking code. + + * insns.def: catch up this change. + + * vm.c, vm_eval.c: ditto. + + * test/ruby/test_exception.rb: add a stack overflow test. + This code is reported by nobu. + Tue Aug 6 17:02:17 2013 Nobuyoshi Nakada * win32/win32.c (rb_w32_conv_from_wchar): use WideCharToMultiByte(), diff --git a/insns.def b/insns.def index 2a51424a0d..b5ca35c44b 100644 --- a/insns.def +++ b/insns.def @@ -972,7 +972,7 @@ defineclass vm_push_frame(th, class_iseq, VM_FRAME_MAGIC_CLASS, klass, 0, VM_ENVVAL_BLOCK_PTR(GET_BLOCK_PTR()), class_iseq->iseq_encoded, GET_SP(), - class_iseq->local_size, 0); + class_iseq->local_size, 0, class_iseq->stack_max); RESTORE_REGS(); INC_VM_STATE_VERSION(); diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 4a0edc3f1a..b7b41db1cd 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -456,4 +456,13 @@ end.join s = e.to_s assert_equal(false, s.tainted?) end + + def m; + m &->{return 0}; + 42; + end + + def test_stackoverflow + assert_raise(SystemStackError){m} + end end diff --git a/vm.c b/vm.c index 3150ee8ac6..a8246d4c24 100644 --- a/vm.c +++ b/vm.c @@ -141,10 +141,9 @@ vm_set_top_stack(rb_thread_t * th, VALUE iseqval) } /* for return */ - CHECK_VM_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max); vm_push_frame(th, iseq, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, th->top_self, rb_cObject, VM_ENVVAL_BLOCK_PTR(0), - iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0); + iseq->iseq_encoded, th->cfp->sp, iseq->local_size, 0, iseq->stack_max); } static void @@ -153,11 +152,10 @@ vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref, rb_block_t rb_iseq_t *iseq; GetISeqPtr(iseqval, iseq); - CHECK_VM_STACK_OVERFLOW(th->cfp, iseq->local_size + iseq->stack_max); vm_push_frame(th, iseq, VM_FRAME_MAGIC_EVAL | VM_FRAME_FLAG_FINISH, base_block->self, base_block->klass, VM_ENVVAL_PREV_EP_PTR(base_block->ep), iseq->iseq_encoded, - th->cfp->sp, iseq->local_size, 0); + th->cfp->sp, iseq->local_size, 0, iseq->stack_max); if (cref) { th->cfp->ep[-1] = (VALUE)cref; @@ -622,7 +620,6 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, VM_FRAME_MAGIC_LAMBDA : VM_FRAME_MAGIC_BLOCK; cfp = th->cfp; - CHECK_VM_STACK_OVERFLOW(cfp, argc + iseq->stack_max); for (i=0; isp[i] = argv[i]; @@ -636,7 +633,7 @@ invoke_block_from_c(rb_thread_t *th, const rb_block_t *block, VM_ENVVAL_PREV_EP_PTR(block->ep), iseq->iseq_encoded + opt_pc, cfp->sp + arg_size, iseq->local_size - arg_size, - th->passed_me); + th->passed_me, iseq->stack_max); th->passed_me = 0; if (cref) { @@ -1382,7 +1379,7 @@ vm_exec(rb_thread_t *th) catch_iseq->iseq_encoded, cfp->sp + 1 /* push value */, catch_iseq->local_size - 1, - cfp->me); + cfp->me, catch_iseq->stack_max); state = 0; th->state = 0; @@ -1524,7 +1521,7 @@ rb_vm_call_cfunc(VALUE recv, VALUE (*func)(VALUE), VALUE arg, VALUE val; vm_push_frame(th, DATA_PTR(iseqval), VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, - recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0); + recv, CLASS_OF(recv), VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, 0, 0); val = (*func)(arg); @@ -1967,7 +1964,7 @@ th_init(rb_thread_t *th, VALUE self) th->cfp = (void *)(th->stack + th->stack_size); vm_push_frame(th, 0 /* dummy iseq */, VM_FRAME_MAGIC_TOP | VM_FRAME_FLAG_FINISH, - Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0); + Qnil /* dummy self */, Qnil /* dummy klass */, VM_ENVVAL_BLOCK_PTR(0), 0 /* dummy pc */, th->stack, 1, 0, 0); th->status = THREAD_RUNNABLE; th->errinfo = Qnil; diff --git a/vm_core.h b/vm_core.h index 0701c5c4a9..1b5d8deea3 100644 --- a/vm_core.h +++ b/vm_core.h @@ -854,11 +854,13 @@ int rb_autoloading_value(VALUE mod, ID id, VALUE* value); #define sysstack_error GET_VM()->special_exceptions[ruby_error_sysstack] -#define CHECK_VM_STACK_OVERFLOW(cfp, margin) do \ - if ((VALUE *)((char *)(((VALUE *)(cfp)->sp) + (margin)) + sizeof(rb_control_frame_t)) >= ((VALUE *)(cfp))) { \ - vm_stackoverflow(); \ - } \ -while (0) +#define CHECK_VM_STACK_OVERFLOW0(cfp, sp, margin) do { \ + if ((VALUE *)((char *)((VALUE *)(sp) + (margin)) + sizeof(rb_control_frame_t)) >= ((VALUE *)(cfp))) { \ + vm_stackoverflow(); \ + } \ +} while (0) + +#define CHECK_VM_STACK_OVERFLOW(cfp, margin) CHECK_VM_STACK_OVERFLOW0((cfp), (cfp)->sp, margin) /* for thread */ diff --git a/vm_eval.c b/vm_eval.c index 4493c1c929..efd22a4371 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -109,7 +109,7 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv rb_control_frame_t *reg_cfp = th->cfp; vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, - VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, me); + VM_ENVVAL_BLOCK_PTR(blockptr), 0, reg_cfp->sp, 1, me, 0); if (len >= 0) rb_check_arity(argc, len, len); @@ -1266,7 +1266,6 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *cref, volatile V } /* kick */ - CHECK_VM_STACK_OVERFLOW(th->cfp, iseq->stack_max); result = vm_exec(th); } TH_POP_TAG(); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 36d877bbdd..b4f2b83010 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -40,15 +40,15 @@ vm_push_frame(rb_thread_t *th, const VALUE *pc, VALUE *sp, int local_size, - const rb_method_entry_t *me) + const rb_method_entry_t *me, + int stack_max) { rb_control_frame_t *const cfp = th->cfp - 1; int i; /* check stack overflow */ - if ((void *)(sp + local_size) >= (void *)cfp) { - vm_stackoverflow(); - } + CHECK_VM_STACK_OVERFLOW0(cfp, sp, local_size + stack_max); + th->cfp = cfp; /* setup vm value stack */ @@ -1283,8 +1283,6 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info rb_iseq_t *iseq = ci->me->def->body.iseq; VALUE *sp = argv + iseq->arg_size; - CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max); - /* clear local variables */ for (i = 0; i < iseq->local_size - iseq->arg_size; i++) { *sp++ = Qnil; @@ -1292,7 +1290,7 @@ vm_call_iseq_setup_normal(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_info vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD, ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr), - iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me); + iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max); cfp->sp = argv - 1 /* recv */; return Qundef; @@ -1310,7 +1308,6 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in cfp = th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp); /* pop cf */ - CHECK_VM_STACK_OVERFLOW(cfp, iseq->stack_max); RUBY_VM_CHECK_INTS(th); sp_orig = sp = cfp->sp; @@ -1331,7 +1328,7 @@ vm_call_iseq_setup_tailcall(rb_thread_t *th, rb_control_frame_t *cfp, rb_call_in vm_push_frame(th, iseq, VM_FRAME_MAGIC_METHOD | finish_flag, ci->recv, ci->defined_class, VM_ENVVAL_BLOCK_PTR(ci->blockptr), - iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me); + iseq->iseq_encoded + ci->aux.opt_pc, sp, 0, ci->me, iseq->stack_max); cfp->sp = sp_orig; return Qundef; @@ -1484,7 +1481,7 @@ vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_i EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef); vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class, - VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me); + VM_ENVVAL_BLOCK_PTR(blockptr), 0, th->cfp->sp, 1, me, 0); if (len >= 0) rb_check_arity(argc, len, len); @@ -2102,7 +2099,7 @@ vm_yield_with_cfunc(rb_thread_t *th, const rb_block_t *block, vm_push_frame(th, (rb_iseq_t *)ifunc, VM_FRAME_MAGIC_IFUNC, self, 0, VM_ENVVAL_PREV_EP_PTR(block->ep), 0, - th->cfp->sp, 1, 0); + th->cfp->sp, 1, 0, 0); val = (*ifunc->nd_cfnc) (arg, ifunc->nd_tval, argc, argv, blockarg); @@ -2334,7 +2331,6 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci VALUE * const rsp = GET_SP() - ci->argc; SET_SP(rsp); - CHECK_VM_STACK_OVERFLOW(GET_CFP(), iseq->stack_max); opt_pc = vm_yield_setup_args(th, iseq, ci->argc, rsp, 0, block_proc_is_lambda(block->proc)); vm_push_frame(th, iseq, VM_FRAME_MAGIC_BLOCK, block->self, @@ -2342,7 +2338,7 @@ vm_invoke_block(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci VM_ENVVAL_PREV_EP_PTR(block->ep), iseq->iseq_encoded + opt_pc, rsp + arg_size, - iseq->local_size - arg_size, 0); + iseq->local_size - arg_size, 0, iseq->stack_max); return Qundef; } -- cgit v1.2.3