eval_error.c: fix loop on exception in message

* error.c (rb_get_message): accessor to the message.

* eval_error.c (rb_ec_error_print): handle exceptions on fetching
  the message.  [Bug #14566]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63133 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
nobu 2018-04-11 08:03:43 +00:00
parent a7c7cfb874
commit aa2b32ae4b
3 changed files with 35 additions and 13 deletions

16
error.c
View File

@ -980,7 +980,16 @@ exc_to_s(VALUE exc)
} }
/* FIXME: Include eval_error.c */ /* FIXME: Include eval_error.c */
void rb_error_write(VALUE errinfo, VALUE errat, VALUE str, VALUE highlight, VALUE reverse); void rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlight, VALUE reverse);
VALUE
rb_get_message(VALUE exc)
{
VALUE e = rb_check_funcall(exc, id_message, 0, 0);
if (e == Qundef) return Qnil;
if (!RB_TYPE_P(e, T_STRING)) e = rb_check_string_type(e);
return e;
}
/* /*
* call-seq: * call-seq:
@ -1015,7 +1024,7 @@ exc_s_to_tty_p(VALUE self)
static VALUE static VALUE
exc_full_message(int argc, VALUE *argv, VALUE exc) exc_full_message(int argc, VALUE *argv, VALUE exc)
{ {
VALUE opt, str, errat; VALUE opt, str, emesg, errat;
enum {kw_highlight, kw_order, kw_max_}; enum {kw_highlight, kw_order, kw_max_};
static ID kw[kw_max_]; static ID kw[kw_max_];
VALUE args[kw_max_] = {Qnil, Qnil}; VALUE args[kw_max_] = {Qnil, Qnil};
@ -1051,8 +1060,9 @@ exc_full_message(int argc, VALUE *argv, VALUE exc)
} }
str = rb_str_new2(""); str = rb_str_new2("");
errat = rb_get_backtrace(exc); errat = rb_get_backtrace(exc);
emesg = rb_get_message(exc);
rb_error_write(exc, errat, str, args[kw_highlight], args[kw_order]); rb_error_write(exc, emesg, errat, str, args[kw_highlight], args[kw_order]);
return str; return str;
} }

View File

@ -221,9 +221,9 @@ print_backtrace(const VALUE eclass, const VALUE errat, const VALUE str, int reve
} }
void void
rb_error_write(VALUE errinfo, VALUE errat, VALUE str, VALUE highlight, VALUE reverse) rb_error_write(VALUE errinfo, VALUE emesg, VALUE errat, VALUE str, VALUE highlight, VALUE reverse)
{ {
volatile VALUE eclass = Qundef, emesg = Qundef; volatile VALUE eclass;
if (NIL_P(errinfo)) if (NIL_P(errinfo))
return; return;
@ -231,13 +231,7 @@ rb_error_write(VALUE errinfo, VALUE errat, VALUE str, VALUE highlight, VALUE rev
if (errat == Qundef) { if (errat == Qundef) {
errat = Qnil; errat = Qnil;
} }
if ((eclass = CLASS_OF(errinfo)) != Qundef) { eclass = CLASS_OF(errinfo);
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 (NIL_P(reverse) || NIL_P(highlight)) { if (NIL_P(reverse) || NIL_P(highlight)) {
VALUE tty = (VALUE)rb_stderr_tty_p(); VALUE tty = (VALUE)rb_stderr_tty_p();
if (NIL_P(reverse)) reverse = tty; if (NIL_P(reverse)) reverse = tty;
@ -269,11 +263,14 @@ rb_error_write(VALUE errinfo, VALUE errat, VALUE str, VALUE highlight, VALUE rev
} }
} }
VALUE rb_get_message(VALUE exc);
void void
rb_ec_error_print(rb_execution_context_t * volatile ec, volatile VALUE errinfo) rb_ec_error_print(rb_execution_context_t * volatile ec, volatile VALUE errinfo)
{ {
volatile int raised_flag = ec->raised_flag; volatile int raised_flag = ec->raised_flag;
volatile VALUE errat = Qundef; volatile VALUE errat = Qundef;
volatile VALUE emesg = Qundef;
if (NIL_P(errinfo)) if (NIL_P(errinfo))
return; return;
@ -283,8 +280,12 @@ rb_ec_error_print(rb_execution_context_t * volatile ec, volatile VALUE errinfo)
if (EC_EXEC_TAG() == TAG_NONE) { if (EC_EXEC_TAG() == TAG_NONE) {
errat = rb_get_backtrace(errinfo); errat = rb_get_backtrace(errinfo);
} }
if (emesg == Qundef) {
emesg = Qnil;
emesg = rb_get_message(errinfo);
}
rb_error_write(errinfo, errat, Qnil, Qnil, Qnil); rb_error_write(errinfo, emesg, errat, Qnil, Qnil, Qnil);
EC_POP_TAG(); EC_POP_TAG();
ec->errinfo = errinfo; ec->errinfo = errinfo;

View File

@ -1309,4 +1309,15 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status|
assert_operator(message, :end_with?, top) assert_operator(message, :end_with?, top)
end end
end end
def test_exception_in_message
code = "#{<<~"begin;"}\n#{<<~'end;'}"
begin;
class Bug14566 < StandardError
def message; raise self.class; end
end
raise Bug14566
end;
assert_in_out_err([], code, [], /Bug14566/, success: false, timeout: 1)
end
end end