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#ifdef HAVE_BUILTIN___BUILTIN_CONSTANT_P
11#define warn_print(x) RB_GNUC_EXTENSION_BLOCK( \
12 (__builtin_constant_p(x)) ? \
13 rb_write_error2((x), (long)strlen(x)) : \
17#define warn_print(x) rb_write_error(x)
20#define warn_print2(x,l) rb_write_error2((x),(l))
22#define write_warn_str(str,x) NIL_P(str) ? rb_write_error_str(x) : (void)rb_str_concat((str), (x))
23#define warn_print_str(x) rb_write_error_str(x)
25static VALUE error_pos_str(
void);
28error_pos(
const VALUE str)
30 VALUE pos = error_pos_str();
32 write_warn_str(str, pos);
40 VALUE sourcefile = rb_source_location(&sourceline);
42 if (!
NIL_P(sourcefile)) {
44 if (sourceline == 0) {
45 return rb_sprintf(
"%"PRIsVALUE
": ", sourcefile);
47 else if ((caller_name = rb_frame_callee()) != 0) {
48 return rb_sprintf(
"%"PRIsVALUE
":%d:in `%"PRIsVALUE
"': ",
49 sourcefile, sourceline,
50 rb_id2str(caller_name));
53 return rb_sprintf(
"%"PRIsVALUE
":%d: ", sourcefile, sourceline);
64 if (rb_backtrace_p(bt)) {
65 if (rb_method_basic_definition_p(
CLASS_OF(info), set_backtrace)) {
66 rb_exc_set_backtrace(info, bt);
70 bt = rb_backtrace_to_str_ary(bt);
76#define CSI_BEGIN "\033["
79static const char underline[] = CSI_BEGIN
"1;4"CSI_SGR;
80static const char bold[] = CSI_BEGIN
"1"CSI_SGR;
81static const char reset[] = CSI_BEGIN
""CSI_SGR;
84print_errinfo(
const VALUE eclass,
const VALUE errat,
const VALUE emesg,
const VALUE str,
int highlight)
94 write_warn_str(str, mesg);
95 write_warn(str,
": ");
103 if (highlight) write_warn(str, underline);
104 write_warn(str,
"unhandled exception");
105 if (highlight) write_warn(str, reset);
106 write_warn2(str,
"\n", 1);
113 if (highlight) write_warn(str, underline);
114 write_warn_str(str, epath);
115 if (highlight) write_warn(str, reset);
116 write_warn(str,
"\n");
119 write_warn_str(str, emesg);
120 write_warn(str,
"\n");
126rb_decorate_message(
const VALUE eclass,
const VALUE emesg,
int highlight)
128 const char *einfo =
"";
138 if (highlight) write_warn(str, underline);
139 write_warn(str,
"unhandled exception");
140 if (highlight) write_warn(str, reset);
147 if (highlight) write_warn(str, underline);
148 write_warn_str(str, epath);
149 if (highlight) write_warn(str, reset);
153 const char *tail = 0;
155 if (highlight) write_warn(str, bold);
158 if ((tail = memchr(einfo,
'\n', elen)) != 0) {
159 write_warn2(str, einfo, tail - einfo);
163 write_warn_str(str, emesg);
166 write_warn(str,
" (");
167 if (highlight) write_warn(str, underline);
168 write_warn_str(str, epath);
170 write_warn(str, reset);
171 write_warn(str, bold);
173 write_warn2(str,
")", 1);
174 if (highlight) write_warn(str, reset);
176 if (tail && einfo+elen > tail) {
178 write_warn2(str,
"\n", 1);
179 write_warn2(str, tail, einfo+elen-tail);
182 elen -= tail - einfo;
184 write_warn2(str,
"\n", 1);
186 tail = memchr(einfo,
'\n', elen);
187 if (!tail || tail > einfo) {
188 write_warn(str, bold);
189 write_warn2(str, einfo, tail ? tail-einfo : elen);
190 write_warn(str, reset);
195 elen -= tail - einfo;
197 do ++tail;
while (tail < einfo+elen && *tail ==
'\n');
198 write_warn2(str, einfo, tail-einfo);
199 elen -= tail - einfo;
211print_backtrace(
const VALUE eclass,
const VALUE errat,
const VALUE str,
int reverse,
long backtrace_limit)
216 const int threshold = 1000000000;
217 int width = (len <= 1) ? INT_MIN : ((int)log10((double)(len > threshold ?
218 ((len - 1) / threshold) :
220 (len < threshold ? 0 : 9) + 1);
222 long skip_start = -1, skip_len = 0;
228 long trace_max = trace_head + trace_tail + 5;
229 if (len > trace_max) {
230 skip_start = trace_head;
231 skip_len = len - trace_max + 5;
236 if (backtrace_limit >= 0 && len > backtrace_limit + 2) {
237 skip_start = backtrace_limit + 1;
238 skip_len = len - skip_start;
241 for (i = 1; i < len; i++) {
242 if (i == skip_start) {
243 write_warn_str(str,
rb_sprintf(
"\t ... %ld levels...\n", skip_len));
250 if (reverse)
rb_str_catf(bt,
"%*ld: ", width, len - i);
251 write_warn_str(str,
rb_str_catf(bt,
"from %"PRIsVALUE
"\n", line));
260shown_cause_p(
VALUE cause,
VALUE *shown_causes)
262 VALUE shown = *shown_causes;
264 *shown_causes = shown =
rb_obj_hide(rb_ident_hash_new());
266 if (rb_hash_has_key(shown, cause))
return TRUE;
267 rb_hash_aset(shown, cause,
Qtrue);
276 !shown_cause_p(cause, shown_causes)) {
278 VALUE errat = rb_get_backtrace(cause);
279 VALUE emesg = rb_get_detailed_message(cause, opt);
281 show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes);
282 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
283 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
286 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
287 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
288 show_cause(cause, str, opt, highlight, reverse, backtrace_limit, shown_causes);
294rb_exc_check_circular_cause(
VALUE exc)
296 VALUE cause = exc, shown_causes = 0;
298 if (shown_cause_p(cause, &shown_causes)) {
307 volatile VALUE eclass;
308 VALUE shown_causes = 0;
309 long backtrace_limit = rb_backtrace_length_limit;
314 if (UNDEF_P(errat)) {
319 static const char traceback[] =
"Traceback "
320 "(most recent call last):\n";
322 char buff[
sizeof(traceback)+
sizeof(bold)+
sizeof(reset)-2], *p = buff;
323 const char *msg = traceback;
324 long len =
sizeof(traceback) - 1;
325 if (
RTEST(highlight)) {
326#define APPEND(s, l) (memcpy(p, s, l), p += (l))
327 APPEND(bold,
sizeof(bold)-1);
328 APPEND(traceback, bold_part);
329 APPEND(reset,
sizeof(reset)-1);
330 APPEND(traceback + bold_part,
sizeof(traceback)-bold_part-1);
332 len = p - (msg = buff);
334 write_warn2(str, msg, len);
335 show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes);
336 print_backtrace(eclass, errat, str, TRUE, backtrace_limit);
337 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
340 print_errinfo(eclass, errat, emesg, str,
RTEST(highlight));
341 print_backtrace(eclass, errat, str, FALSE, backtrace_limit);
342 show_cause(errinfo, str, opt, highlight, reverse, backtrace_limit, &shown_causes);
349 volatile uint8_t raised_flag = ec->raised_flag;
351 volatile bool written =
false;
352 volatile VALUE emesg = emesg0;
354 VALUE opt = rb_hash_new();
360 rb_ec_raised_clear(ec);
363 if (EC_EXEC_TAG() == TAG_NONE) {
364 errat = rb_get_backtrace(errinfo);
366 if (UNDEF_P(emesg)) {
368 emesg = rb_get_detailed_message(errinfo, opt);
373 rb_error_write(errinfo, emesg, errat, str, opt, highlight,
Qfalse);
377 ec->errinfo = errinfo;
378 rb_ec_raised_set(ec, raised_flag);
384 rb_ec_error_print_detailed(ec, errinfo,
Qnil,
Qundef);
387#define undef_mesg_for(v, k) rb_fstring_lit("undefined"v" method `%1$s' for "k" `%2$s'")
388#define undef_mesg(v) ( \
390 undef_mesg_for(v, "module") : \
391 undef_mesg_for(v, "class"))
394rb_print_undef(
VALUE klass,
ID id, rb_method_visibility_t visi)
398 switch (visi & METHOD_VISI_MASK) {
399 case METHOD_VISI_UNDEF:
400 case METHOD_VISI_PUBLIC: mesg = undef_mesg(
"");
break;
401 case METHOD_VISI_PRIVATE: mesg = undef_mesg(
" private");
break;
402 case METHOD_VISI_PROTECTED: mesg = undef_mesg(
" protected");
break;
405 rb_name_err_raise_str(mesg, klass,
ID2SYM(
id));
412 rb_name_err_raise_str(undef_mesg(
""), klass, name);
415#define inaccessible_mesg_for(v, k) rb_fstring_lit("method `%1$s' for "k" `%2$s' is "v)
416#define inaccessible_mesg(v) ( \
418 inaccessible_mesg_for(v, "module") : \
419 inaccessible_mesg_for(v, "class"))
422rb_print_inaccessible(
VALUE klass,
ID id, rb_method_visibility_t visi)
426 switch (visi & METHOD_VISI_MASK) {
427 case METHOD_VISI_UNDEF:
428 case METHOD_VISI_PUBLIC: mesg = inaccessible_mesg(
"");
break;
429 case METHOD_VISI_PRIVATE: mesg = inaccessible_mesg(
"private");
break;
430 case METHOD_VISI_PROTECTED: mesg = inaccessible_mesg(
"protected");
break;
433 rb_name_err_raise_str(mesg, klass,
ID2SYM(
id));
437sysexit_status(
VALUE err)
444 EXITING_WITH_MESSAGE = 1,
445 EXITING_WITH_STATUS = 2,
446 EXITING_WITH_SIGNAL = 4
449exiting_split(
VALUE errinfo,
volatile int *exitcode,
volatile int *sigstatus)
451 int ex = EXIT_SUCCESS;
456 if (
NIL_P(errinfo))
return 0;
458 if (THROW_DATA_P(errinfo)) {
459 int throw_state = ((
const struct vm_throw_data *)errinfo)->throw_state;
460 ex = throw_state & VM_THROW_STATE_MASK;
461 result |= EXITING_WITH_STATUS;
464 ex = sysexit_status(errinfo);
465 result |= EXITING_WITH_STATUS;
470 result |= EXITING_WITH_SIGNAL;
474 result |= EXITING_WITH_MESSAGE;
479 result |= EXITING_WITH_SIGNAL;
484 result |= EXITING_WITH_STATUS | EXITING_WITH_MESSAGE;
487 if (exitcode && (result & EXITING_WITH_STATUS))
489 if (sigstatus && (result & EXITING_WITH_SIGNAL))
495#define unknown_longjmp_status(status) \
496 rb_bug("Unknown longjmp status %d", status)
501 int status = EXIT_FAILURE;
503 if (rb_ec_set_raised(ec))
505 switch (ex & TAG_MASK) {
507 status = EXIT_SUCCESS;
512 warn_print(
"unexpected return\n");
516 warn_print(
"unexpected next\n");
520 warn_print(
"unexpected break\n");
524 warn_print(
"unexpected redo\n");
528 warn_print(
"retry outside of rescue clause\n");
533 warn_print(
"unexpected throw\n");
536 if (!(exiting_split(errinfo, &status, NULL) & EXITING_WITH_MESSAGE)) {
541 rb_ec_error_print(ec, errinfo);
544 unknown_longjmp_status(ex);
547 rb_ec_reset_raised(ec);
#define rb_str_new2
Old name of rb_str_new_cstr.
#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.
void rb_raise(VALUE exc, const char *fmt,...)
Exception entry point.
VALUE rb_eSystemExit
SystemExit exception.
VALUE rb_eRuntimeError
RuntimeError exception.
VALUE rb_eArgError
ArgumentError 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.
#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_attr_get(VALUE obj, ID name)
Identical to rb_ivar_get()
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().
ID rb_intern(const char *name)
Finds or creates a symbol of the given name.
VALUE rb_sprintf(const char *fmt,...)
Ruby's extended sprintf(3).
VALUE rb_str_catf(VALUE dst, const char *fmt,...)
Identical to rb_sprintf(), except it renders the output to the specified object rather than creating ...
#define RARRAY_LEN
Just another name of rb_array_len.
#define RARRAY_AREF(a, i)
static long RSTRING_LEN(VALUE str)
Queries the length of the string.
static char * RSTRING_PTR(VALUE str)
Queries the contents pointer of the string.
#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.