aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--insns.def2
-rw-r--r--test/ruby/test_exception.rb9
-rw-r--r--vm.c15
-rw-r--r--vm_core.h12
-rw-r--r--vm_eval.c3
-rw-r--r--vm_insnhelper.c22
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 <ko1@atdot.net>
+
+ * 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 <nobu@ruby-lang.org>
* 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; i<argc; i++) {
cfp->sp[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;
}