* 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
This commit is contained in:
parent
8ea8dfd88c
commit
22468a4f92
19
ChangeLog
19
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(),
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
15
vm.c
15
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;
|
||||
|
12
vm_core.h
12
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 */
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user