diff --git a/eval.c b/eval.c index ed1eacead1969b..a37e2afc779791 100644 --- a/eval.c +++ b/eval.c @@ -461,6 +461,12 @@ exc_setup_cause(VALUE exc, VALUE cause) return exc; } +static inline int +sysstack_error_p(VALUE exc) +{ + return exc == sysstack_error || (!SPECIAL_CONST_P(exc) && RBASIC_CLASS(exc) == rb_eSysStackError); +} + static void setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg) { @@ -487,8 +493,7 @@ setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg) rb_iv_set(mesg, "bt", at); } else { - at = get_backtrace(mesg); - if (NIL_P(at)) { + if (sysstack_error_p(mesg) || NIL_P(at = get_backtrace(mesg))) { at = rb_vm_backtrace_object(); if (OBJ_FROZEN(mesg)) { mesg = rb_obj_dup(mesg); @@ -657,7 +662,7 @@ make_exception(int argc, VALUE *argv, int isstr) exc = argv[0]; n = 1; exception_call: - if (exc == sysstack_error) return exc; + if (sysstack_error_p(exc)) return exc; CONST_ID(exception, "exception"); mesg = rb_check_funcall(exc, exception, n, argv+1); if (mesg == Qundef) { diff --git a/proc.c b/proc.c index a13452329de747..54e948da43c8a6 100644 --- a/proc.c +++ b/proc.c @@ -2623,6 +2623,7 @@ Init_Proc(void) sysstack_error = rb_exc_new3(rb_eSysStackError, rb_obj_freeze(rb_str_new2("stack level too deep"))); OBJ_TAINT(sysstack_error); + OBJ_FREEZE(sysstack_error); /* utility functions */ rb_define_global_function("proc", rb_block_proc, 0); diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index c3314568c13491..1568233ce27de5 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -496,7 +496,8 @@ def m; end def test_stackoverflow - assert_raise(SystemStackError){m} + e = assert_raise(SystemStackError){m} + assert_operator(e.backtrace.size, :>, 10) end def test_machine_stackoverflow diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 7a081d2b7406ec..b8f03323a23de9 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -27,7 +27,10 @@ static rb_control_frame_t *vm_get_ruby_level_caller_cfp(rb_thread_t *th, rb_cont static void vm_stackoverflow(void) { - rb_exc_raise(sysstack_error); + void rb_obj_copy_ivar(VALUE dest, VALUE obj); + VALUE e = rb_obj_alloc(rb_eSysStackError); + rb_obj_copy_ivar(e, sysstack_error); + rb_exc_raise(e); } static inline rb_control_frame_t *