summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--eval.c11
-rw-r--r--proc.c1
-rw-r--r--test/ruby/test_exception.rb3
-rw-r--r--vm_insnhelper.c4
5 files changed, 24 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 356a074fcc..700e8c26ad 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,13 @@
-Mon Jun 23 11:32:59 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+Mon Jun 23 11:35:01 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * eval.c (setup_exception): set backtrace in system stack error
+ other than the pre-allocated sysstack_error. [Feature #6216]
+
+ * proc.c (Init_Proc): freeze the pre-allocated sysstack_error.
+
+ * vm_insnhelper.c (vm_stackoverflow): raise new instance for each
+ times without calling any methods to keep the backtrace with no
+ further stack overflow.
* object.c (rb_obj_copy_ivar): extract function to copy instance
variables only for T_OBJECT from init_copy.
diff --git a/eval.c b/eval.c
index afad73c735..4dada48882 100644
--- a/eval.c
+++ b/eval.c
@@ -460,6 +460,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, VALUE cause)
{
@@ -497,8 +503,7 @@ setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg, VALUE cause)
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);
@@ -697,7 +702,7 @@ make_exception(int argc, const 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 befa8834cd..34159480e0 100644
--- a/proc.c
+++ b/proc.c
@@ -2748,6 +2748,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 b80cf00cac..a92050c1d3 100644
--- a/test/ruby/test_exception.rb
+++ b/test/ruby/test_exception.rb
@@ -529,7 +529,8 @@ end.join
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 64e58f0842..e9dc27139a 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -27,7 +27,9 @@ 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);
+ VALUE e = rb_obj_alloc(rb_eSysStackError);
+ rb_obj_copy_ivar(e, sysstack_error);
+ rb_exc_raise(e);
}
static inline rb_control_frame_t *