From 5318154fe1ac6f8dff014988488b9e063988a105 Mon Sep 17 00:00:00 2001 From: nobu Date: Wed, 22 Feb 2017 08:50:25 +0000 Subject: [PATCH] eval_error.c: backstrace in reverse order * eval_error.c (rb_threadptr_error_print): print backtrace and error message in reverse order if STDERR is unchanged and a tty. [Feature #8661] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57685 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- eval_error.c | 108 ++++++++++++++++++++++++++++++--------------------- internal.h | 1 + io.c | 8 ++++ 3 files changed, 72 insertions(+), 45 deletions(-) diff --git a/eval_error.c b/eval_error.c index b6f680748c..597f5d8d14 100644 --- a/eval_error.c +++ b/eval_error.c @@ -72,54 +72,29 @@ error_print(rb_thread_t *th) rb_threadptr_error_print(th, th->errinfo); } -void -rb_threadptr_error_print(rb_thread_t *volatile th, volatile VALUE errinfo) +static void +print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg) { - volatile VALUE errat = Qundef; - volatile int raised_flag = th->raised_flag; - volatile VALUE eclass = Qundef, e = Qundef; - const char *volatile einfo; - volatile long elen; + const char *einfo = ""; + long elen = 0; VALUE mesg; - if (NIL_P(errinfo)) - return; - rb_thread_raised_clear(th); + if (emesg != Qundef) { + if (NIL_P(errat) || RARRAY_LEN(errat) == 0 || + NIL_P(mesg = RARRAY_AREF(errat, 0))) { + error_pos(); + } + else { + warn_print_str(mesg); + warn_print(": "); + } - TH_PUSH_TAG(th); - if (TH_EXEC_TAG() == 0) { - errat = rb_get_backtrace(errinfo); - } - else if (errat == Qundef) { - errat = Qnil; - } - else if (eclass == Qundef || e != Qundef) { - goto error; - } - else { - goto no_message; - } - if (NIL_P(errat) || RARRAY_LEN(errat) == 0 || - NIL_P(mesg = RARRAY_AREF(errat, 0))) { - error_pos(); - } - else { - warn_print_str(mesg); - warn_print(": "); + if (!NIL_P(emesg)) { + einfo = RSTRING_PTR(emesg); + elen = RSTRING_LEN(emesg); + } } - eclass = CLASS_OF(errinfo); - if (eclass != Qundef && - (e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0)) != Qundef && - (RB_TYPE_P(e, T_STRING) || !NIL_P(e = rb_check_string_type(e)))) { - einfo = RSTRING_PTR(e); - elen = RSTRING_LEN(e); - } - else { - no_message: - einfo = ""; - elen = 0; - } if (eclass == rb_eRuntimeError && elen == 0) { warn_print("unhandled exception\n"); } @@ -141,19 +116,23 @@ rb_threadptr_error_print(rb_thread_t *volatile th, volatile VALUE errinfo) len = tail - einfo; tail++; /* skip newline */ } - warn_print_str(tail ? rb_str_subseq(e, 0, len) : e); + warn_print_str(tail ? rb_str_subseq(emesg, 0, len) : emesg); if (epath) { warn_print(" ("); warn_print_str(epath); warn_print(")\n"); } if (tail) { - warn_print_str(rb_str_subseq(e, tail - einfo, elen - len - 1)); + warn_print_str(rb_str_subseq(emesg, tail - einfo, elen - len - 1)); } if (tail ? einfo[elen-1] != '\n' : !epath) warn_print2("\n", 1); } } +} +static void +print_backtrace(const VALUE eclass, const VALUE errat, int reverse) +{ if (!NIL_P(errat)) { long i; long len = RARRAY_LEN(errat); @@ -164,7 +143,7 @@ rb_threadptr_error_print(rb_thread_t *volatile th, volatile VALUE errinfo) #define TRACE_TAIL 5 for (i = 1; i < len; i++) { - VALUE line = RARRAY_AREF(errat, i); + VALUE line = RARRAY_AREF(errat, reverse ? len - i : i); if (RB_TYPE_P(line, T_STRING)) { warn_print_str(rb_sprintf("\tfrom %"PRIsVALUE"\n", line)); } @@ -175,6 +154,45 @@ rb_threadptr_error_print(rb_thread_t *volatile th, volatile VALUE errinfo) } } } +} + +void +rb_threadptr_error_print(rb_thread_t *volatile th, volatile VALUE errinfo) +{ + volatile VALUE errat = Qundef; + volatile int raised_flag = th->raised_flag; + volatile VALUE eclass = Qundef, emesg = Qundef; + + if (NIL_P(errinfo)) + return; + rb_thread_raised_clear(th); + + TH_PUSH_TAG(th); + if (TH_EXEC_TAG() == 0) { + errat = rb_get_backtrace(errinfo); + } + else if (errat == Qundef) { + errat = Qnil; + } + else if (eclass == Qundef || emesg != Qundef) { + goto error; + } + if ((eclass = CLASS_OF(errinfo)) != Qundef) { + VALUE e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0); + if (e != Qundef) { + if (!RB_TYPE_P(e, T_STRING)) e = rb_check_string_type(e); + emesg = e; + } + } + if (rb_stderr_tty_p()) { + if (0) warn_print("Traceback (most recent call last):\n"); + print_backtrace(eclass, errat, TRUE); + print_errinfo(eclass, errat, emesg); + } + else { + print_errinfo(eclass, errat, emesg); + print_backtrace(eclass, errat, FALSE); + } error: TH_POP_TAG(); th->errinfo = errinfo; diff --git a/internal.h b/internal.h index f74852369a..e74b91f667 100644 --- a/internal.h +++ b/internal.h @@ -1193,6 +1193,7 @@ ssize_t rb_io_bufread(VALUE io, void *buf, size_t size); void rb_stdio_set_default_encoding(void); VALUE rb_io_flush_raw(VALUE, int); size_t rb_io_memsize(const rb_io_t *); +int rb_stderr_tty_p(void); /* load.c */ VALUE rb_get_load_path(void); diff --git a/io.c b/io.c index 9bb4570d26..89a8c7ad95 100644 --- a/io.c +++ b/io.c @@ -7400,6 +7400,14 @@ rb_write_error_str(VALUE mesg) } } +int +rb_stderr_tty_p(void) +{ + if (rb_stderr == orig_stderr || RFILE(orig_stderr)->fptr->fd < 0) + return isatty(fileno(stderr)); + return 0; +} + static void must_respond_to(ID mid, VALUE val, ID id) {