6#define write_warn(str, x) \
7 (NIL_P(str) ? warn_print(x) : (void)rb_str_cat_cstr(str, x))
8#define write_warn2(str, x, l) \
9 (NIL_P(str) ? warn_print2(x, l) : (void)rb_str_cat(str, x, l))
10#define write_warn_enc(str, x, l, enc) \
11 (NIL_P(str) ? warn_print2(x, l) : (void)rb_enc_str_buf_cat(str, x, l, enc))
12#ifdef HAVE_BUILTIN___BUILTIN_CONSTANT_P
13#define warn_print(x) RB_GNUC_EXTENSION_BLOCK( \
14 (__builtin_constant_p(x)) ? \
15 rb_write_error2((x), (long)strlen(x)) : \
19#define warn_print(x) rb_write_error(x)
22#define warn_print2(x,l) rb_write_error2((x),(l))
24#define write_warn_str(str,x) NIL_P(str) ? rb_write_error_str(x) : (void)rb_str_concat((str), (x))
25#define warn_print_str(x) rb_write_error_str(x)
27static VALUE error_pos_str(
void);
30error_pos(
const VALUE str)
32 VALUE pos = error_pos_str();
34 write_warn_str(str, pos);
42 VALUE sourcefile = rb_source_location(&sourceline);
44 if (!
NIL_P(sourcefile)) {
46 if (sourceline == 0) {
47 return rb_sprintf(
"%"PRIsVALUE
": ", sourcefile);
50 return rb_sprintf(
"%"PRIsVALUE
":%d:in '%"PRIsVALUE
"': ",
51 sourcefile, sourceline,
52 rb_id2str(caller_name));
55 return rb_sprintf(
"%"PRIsVALUE
":%d: ", sourcefile, sourceline);
64 ID set_backtrace = rb_intern(
"set_backtrace");
66 if (rb_backtrace_p(bt)) {
67 if (rb_method_basic_definition_p(
CLASS_OF(info), set_backtrace)) {
68 rb_exc_set_backtrace(info, bt);
72 bt = rb_backtrace_to_str_ary(bt);
78#define CSI_BEGIN "\033["
81static const char underline[] = CSI_BEGIN
"1;4"CSI_SGR;
82static const char bold[] = CSI_BEGIN
"1"CSI_SGR;
83static const char reset[] = CSI_BEGIN
""CSI_SGR;
86print_errinfo(
const VALUE eclass,
const VALUE errat,
const VALUE emesg,
const VALUE str,
int highlight)
96 write_warn_str(str, mesg);
97 write_warn(str,
": ");
101 elen = RSTRING_LEN(emesg);
105 if (highlight) write_warn(str, underline);
106 write_warn(str,
"unhandled exception");
107 if (highlight) write_warn(str, reset);
108 write_warn(str,
"\n");
115 if (highlight) write_warn(str, underline);
116 write_warn_str(str, epath);
117 if (highlight) write_warn(str, reset);
118 write_warn(str,
"\n");
121 write_warn_str(str, emesg);
122 write_warn(str,
"\n");
128rb_decorate_message(
const VALUE eclass,
VALUE emesg,
int highlight)
130 const char *einfo =
"";
136 if (!
NIL_P(emesg) && rb_enc_asciicompat(eenc = rb_enc_get(emesg))) {
137 einfo = RSTRING_PTR(emesg);
138 elen = RSTRING_LEN(emesg);
144 if (highlight) write_warn(str, underline);
145 write_warn(str,
"unhandled exception");
146 if (highlight) write_warn(str, reset);
153 if (highlight) write_warn(str, underline);
154 write_warn_str(str, epath);
155 if (highlight) write_warn(str, reset);
159 const char *tail = 0;
161 if (highlight) write_warn(str, bold);
162 if (RSTRING_PTR(epath)[0] ==
'#')
164 if ((tail = memchr(einfo,
'\n', elen)) != 0) {
165 write_warn_enc(str, einfo, tail - einfo, eenc);
169 write_warn_str(str, emesg);
172 write_warn(str,
" (");
173 if (highlight) write_warn(str, underline);
174 write_warn_str(str, epath);
176 write_warn(str, reset);
177 write_warn(str, bold);
179 write_warn(str,
")");
180 if (highlight) write_warn(str, reset);
182 if (tail && einfo+elen > tail) {
184 write_warn(str,
"\n");
185 write_warn_enc(str, tail, einfo+elen-tail, eenc);
188 elen -= tail - einfo;
190 write_warn(str,
"\n");
192 tail = memchr(einfo,
'\n', elen);
193 if (!tail || tail > einfo) {
194 write_warn(str, bold);
195 write_warn_enc(str, einfo, tail ? tail-einfo : elen, eenc);
196 write_warn(str, reset);
201 elen -= tail - einfo;
203 do ++tail;
while (tail < einfo+elen && *tail ==
'\n');
204 write_warn_enc(str, einfo, tail-einfo, eenc);
205 elen -= tail - einfo;
219print_backtrace(
const VALUE eclass,
const VALUE errat,
const VALUE str,
int reverse,
long backtrace_limit)
224 const int threshold = 1000000000;
225 int width = (
len <= 1) ? INT_MIN : ((int)log10((double)(
len > threshold ?
226 ((
len - 1) / threshold) :
228 (
len < threshold ? 0 : 9) + 1);
230 long skip_start = -1, skip_len = 0;
236 long trace_max = trace_head + trace_tail + 5;
237 if (
len > trace_max) {
238 skip_start = trace_head;
239 skip_len =
len - trace_max + 5;
244 if (backtrace_limit >= 0 &&
len > backtrace_limit + 2) {
245 skip_start = backtrace_limit + 1;
246 skip_len =
len - skip_start;
249 for (i = 1; i <
len; i++) {
250 if (i == skip_start) {
251 write_warn_str(str, rb_sprintf(
"\t ... %ld levels...\n", skip_len));
258 if (reverse) rb_str_catf(bt,
"%*ld: ", width,
len - i);
259 write_warn_str(str, rb_str_catf(bt,
"from %"PRIsVALUE
"\n", line));
268shown_cause_p(
VALUE cause,
VALUE *shown_causes)
270 VALUE shown = *shown_causes;
272 *shown_causes = shown =
rb_obj_hide(rb_ident_hash_new());
274 if (rb_hash_has_key(shown, cause))
return TRUE;
275 rb_hash_aset(shown, cause,
Qtrue);
280add_shown_cause(
VALUE cause,
VALUE *shown_causes)
282 if (!NIL_OR_UNDEF_P(cause) &&
283 !THROW_DATA_P(cause) &&
285 shown_cause_p(cause, shown_causes);
292 VALUE cause = rb_attr_get(errinfo, id_cause);
294 !shown_cause_p(cause, shown_causes)) {
296 VALUE errat = rb_get_backtrace(cause);
297 VALUE emesg = rb_get_detailed_message(cause, opt);
299 show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes);
300 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
301 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
304 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
305 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
306 show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes);
312rb_exc_check_circular_cause(
VALUE exc)
314 VALUE cause = exc, shown_causes = 0;
316 if (shown_cause_p(cause, &shown_causes)) {
317 rb_raise(rb_eArgError,
"circular causes");
319 }
while (!
NIL_P(cause = rb_attr_get(cause, id_cause)));
325 volatile VALUE eclass;
326 VALUE local_shown_causes = 0;
327 long backtrace_limit = rb_backtrace_length_limit;
332 shown_causes = &local_shown_causes;
335 if (UNDEF_P(errat)) {
340 static const char traceback[] =
"Traceback "
341 "(most recent call last):\n";
343 char buff[
sizeof(traceback)+
sizeof(bold)+
sizeof(reset)-2], *p = buff;
344 const char *msg = traceback;
345 long len =
sizeof(traceback) - 1;
346 if (
RTEST(highlight)) {
347#define APPEND(s, l) (memcpy(p, s, l), p += (l))
348 APPEND(bold,
sizeof(bold)-1);
349 APPEND(traceback, bold_part);
350 APPEND(reset,
sizeof(reset)-1);
351 APPEND(traceback + bold_part,
sizeof(traceback)-bold_part-1);
353 len = p - (msg = buff);
355 write_warn2(str, msg,
len);
356 show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, shown_causes);
357 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
358 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
361 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
362 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
363 show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, shown_causes);
370 rb_error_write0(errinfo, emesg, errat, str, opt, highlight, reverse, NULL);
374rb_ec_error_print_detailed0(rb_execution_context_t *
const ec,
const VALUE errinfo,
const VALUE str,
VALUE emesg0,
VALUE *shown_causes)
376 volatile uint8_t raised_flag = ec->raised_flag;
378 volatile bool written =
false;
379 volatile VALUE emesg = emesg0;
387 rb_ec_raised_clear(ec);
390 if (EC_EXEC_TAG() == TAG_NONE) {
391 errat = rb_get_backtrace(errinfo);
393 if (UNDEF_P(emesg)) {
395 emesg = rb_get_detailed_message(errinfo, opt);
400 rb_error_write0(errinfo, emesg, errat, str, opt, highlight,
Qfalse, shown_causes);
404 ec->errinfo = errinfo;
405 rb_ec_raised_set(ec, raised_flag);
409rb_ec_error_print_detailed(rb_execution_context_t *
const ec,
const VALUE errinfo,
const VALUE str,
VALUE emesg0)
411 rb_ec_error_print_detailed0(ec, errinfo, str, emesg0, NULL);
415rb_ec_error_print(rb_execution_context_t *
volatile ec,
volatile VALUE errinfo)
417 rb_ec_error_print_detailed(ec, errinfo,
Qnil,
Qundef);
420#define undef_mesg_for(v, k) rb_fstring_lit("undefined"v" method '%1$s' for "k" '%2$s'")
421#define undef_mesg(v) ( \
423 undef_mesg_for(v, "module") : \
424 undef_mesg_for(v, "class"))
427rb_print_undef(
VALUE klass,
ID id, rb_method_visibility_t visi)
431 switch (visi & METHOD_VISI_MASK) {
432 case METHOD_VISI_UNDEF:
433 case METHOD_VISI_PUBLIC: mesg = undef_mesg(
"");
break;
434 case METHOD_VISI_PRIVATE: mesg = undef_mesg(
" private");
break;
435 case METHOD_VISI_PROTECTED: mesg = undef_mesg(
" protected");
break;
438 rb_name_err_raise_str(mesg, klass,
ID2SYM(
id));
445 rb_name_err_raise_str(undef_mesg(
""), klass, name);
448#define inaccessible_mesg_for(v, k) rb_fstring_lit("method '%1$s' for "k" '%2$s' is "v)
449#define inaccessible_mesg(v) ( \
451 inaccessible_mesg_for(v, "module") : \
452 inaccessible_mesg_for(v, "class"))
455rb_print_inaccessible(
VALUE klass,
ID id, rb_method_visibility_t visi)
459 switch (visi & METHOD_VISI_MASK) {
460 case METHOD_VISI_UNDEF:
461 case METHOD_VISI_PUBLIC: mesg = inaccessible_mesg(
"");
break;
462 case METHOD_VISI_PRIVATE: mesg = inaccessible_mesg(
"private");
break;
463 case METHOD_VISI_PROTECTED: mesg = inaccessible_mesg(
"protected");
break;
466 rb_name_err_raise_str(mesg, klass,
ID2SYM(
id));
470sysexit_status(
VALUE err)
477 EXITING_WITH_MESSAGE = 1,
478 EXITING_WITH_STATUS = 2,
479 EXITING_WITH_SIGNAL = 4
482exiting_split(
VALUE errinfo,
volatile int *exitcode,
volatile int *sigstatus)
484 int ex = EXIT_SUCCESS;
489 if (
NIL_P(errinfo))
return 0;
491 if (THROW_DATA_P(errinfo)) {
492 int throw_state = ((
const struct vm_throw_data *)errinfo)->throw_state;
493 ex = throw_state & VM_THROW_STATE_MASK;
494 result |= EXITING_WITH_STATUS;
497 ex = sysexit_status(errinfo);
498 result |= EXITING_WITH_STATUS;
503 result |= EXITING_WITH_SIGNAL;
507 result |= EXITING_WITH_MESSAGE;
510 FIXNUM_P(signo = rb_attr_get(errinfo, id_signo))) {
512 result |= EXITING_WITH_SIGNAL;
517 result |= EXITING_WITH_STATUS | EXITING_WITH_MESSAGE;
520 if (exitcode && (result & EXITING_WITH_STATUS))
522 if (sigstatus && (result & EXITING_WITH_SIGNAL))
528#define unknown_longjmp_status(status) \
529 rb_bug("Unknown longjmp status %d", status)
532error_handle_with_shown_causes(rb_execution_context_t *ec,
VALUE errinfo,
enum ruby_tag_type ex,
VALUE *shown_causes)
534 int status = EXIT_FAILURE;
536 if (rb_ec_set_raised(ec))
538 switch (ex & TAG_MASK) {
540 status = EXIT_SUCCESS;
545 warn_print(
"unexpected return\n");
549 warn_print(
"unexpected next\n");
553 warn_print(
"unexpected break\n");
557 warn_print(
"unexpected redo\n");
561 warn_print(
"retry outside of rescue clause\n");
566 warn_print(
"unexpected throw\n");
569 if (!(exiting_split(errinfo, &status, NULL) & EXITING_WITH_MESSAGE)) {
574 rb_ec_error_print_detailed0(ec, errinfo,
Qnil,
Qundef, shown_causes);
577 unknown_longjmp_status(ex);
580 rb_ec_reset_raised(ec);
585error_handle(rb_execution_context_t *ec,
VALUE errinfo,
enum ruby_tag_type ex)
587 return error_handle_with_shown_causes(ec, errinfo, ex, NULL);
#define T_STRING
Old name of RUBY_T_STRING.
#define Qundef
Old name of RUBY_Qundef.
#define INT2FIX
Old name of RB_INT2FIX.
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
#define ID2SYM
Old name of RB_ID2SYM.
#define CLASS_OF
Old name of rb_class_of.
#define FIX2INT
Old name of RB_FIX2INT.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define Qtrue
Old name of RUBY_Qtrue.
#define NUM2INT
Old name of RB_NUM2INT.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
VALUE rb_eSystemExit
SystemExit exception.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_eException
Mother of all exceptions.
VALUE rb_eSysStackError
SystemStackError exception.
VALUE rb_eSystemCallError
SystemCallError exception.
VALUE rb_eSignal
SignalException exception.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_obj_is_instance_of(VALUE obj, VALUE klass)
Queries if the given object is a direct instance of the given class.
VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass)
Queries if the given object is an instance (of possibly descendants) of the given class.
ID rb_frame_callee(void)
Identical to rb_frame_this_func(), except it returns the named used to call the method.
VALUE rb_hash_new(void)
Creates a new, empty hash object.
#define rb_usascii_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "US ASCII" encoding.
#define rb_strlen_lit(str)
Length of a string literal.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_ivar_get(VALUE obj, ID name)
Identical to rb_iv_get(), except it accepts the name as an ID instead of a C string.
VALUE rb_class_name(VALUE obj)
Queries the name of the given object's class.
VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv(), except it returns RUBY_Qundef instead of raising rb_eNoMethodError.
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
int len
Length of the buffer.
#define RB_GC_GUARD(v)
Prevents premature destruction of local objects.
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
#define RTEST
This is an old name of RB_TEST.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.