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)
25 static VALUE
error_pos_str(void);
28 error_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
);
60 set_backtrace(VALUE info
, VALUE bt
)
62 ID set_backtrace
= rb_intern("set_backtrace");
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
);
73 rb_check_funcall(info
, set_backtrace
, 1, &bt
);
77 error_print(rb_execution_context_t
*ec
)
79 rb_ec_error_print(ec
, ec
->errinfo
);
83 write_warnq(VALUE out
, VALUE str
, const char *ptr
, long len
)
86 const char *beg
= ptr
;
87 const long olen
= len
;
88 for (; len
> 0; --len
, ++ptr
) {
89 unsigned char c
= *ptr
;
91 case '\n': case '\t': continue;
96 if (ptr
> beg
) rb_write_error2(beg
, ptr
- beg
);
98 cc
= ruby_escaped_char(c
);
100 rb_write_error2(cc
, strlen(cc
));
103 rb_write_error2(buf
, snprintf(buf
, sizeof(buf
), "\\x%02X", c
));
106 else if (c
== '\\') {
107 rb_write_error2(beg
, ptr
- beg
+ 1);
112 if (beg
== RSTRING_PTR(str
) && olen
== RSTRING_LEN(str
))
113 rb_write_error_str(str
);
115 rb_write_error2(beg
, ptr
- beg
);
119 rb_str_cat(out
, ptr
, len
);
123 #define CSI_BEGIN "\033["
126 static const char underline
[] = CSI_BEGIN
"1;4"CSI_SGR
;
127 static const char bold
[] = CSI_BEGIN
"1"CSI_SGR
;
128 static const char reset
[] = CSI_BEGIN
""CSI_SGR
;
131 print_errinfo(const VALUE eclass
, const VALUE errat
, const VALUE emesg
, const VALUE str
, int highlight
)
133 const char *einfo
= "";
137 if (emesg
!= Qundef
) {
138 if (NIL_P(errat
) || RARRAY_LEN(errat
) == 0 ||
139 NIL_P(mesg
= RARRAY_AREF(errat
, 0))) {
143 write_warn_str(str
, mesg
);
144 write_warn(str
, ": ");
148 einfo
= RSTRING_PTR(emesg
);
149 elen
= RSTRING_LEN(emesg
);
153 if (eclass
== rb_eRuntimeError
&& elen
== 0) {
154 if (highlight
) write_warn(str
, underline
);
155 write_warn(str
, "unhandled exception");
156 if (highlight
) write_warn(str
, reset
);
157 write_warn2(str
, "\n", 1);
162 epath
= rb_class_name(eclass
);
164 if (highlight
) write_warn(str
, underline
);
165 write_warn_str(str
, epath
);
166 if (highlight
) write_warn(str
, reset
);
167 write_warn(str
, "\n");
170 /* emesg is a String instance */
171 const char *tail
= 0;
173 if (highlight
) write_warn(str
, bold
);
174 if (RSTRING_PTR(epath
)[0] == '#')
176 if ((tail
= memchr(einfo
, '\n', elen
)) != 0) {
177 write_warnq(str
, emesg
, einfo
, tail
- einfo
);
178 tail
++; /* skip newline */
181 write_warnq(str
, emesg
, einfo
, elen
);
184 write_warn(str
, " (");
185 if (highlight
) write_warn(str
, underline
);
186 write_warn_str(str
, epath
);
188 write_warn(str
, reset
);
189 write_warn(str
, bold
);
191 write_warn2(str
, ")", 1);
192 if (highlight
) write_warn(str
, reset
);
193 write_warn2(str
, "\n", 1);
195 if (tail
&& einfo
+elen
> tail
) {
197 write_warnq(str
, emesg
, tail
, einfo
+elen
-tail
);
198 if (einfo
[elen
-1] != '\n') write_warn2(str
, "\n", 1);
201 elen
-= tail
- einfo
;
204 tail
= memchr(einfo
, '\n', elen
);
205 if (!tail
|| tail
> einfo
) {
206 write_warn(str
, bold
);
207 write_warnq(str
, emesg
, einfo
, tail
? tail
-einfo
: elen
);
208 write_warn(str
, reset
);
210 write_warn2(str
, "\n", 1);
214 elen
-= tail
- einfo
;
216 do ++tail
; while (tail
< einfo
+elen
&& *tail
== '\n');
217 write_warnq(str
, emesg
, einfo
, tail
-einfo
);
218 elen
-= tail
- einfo
;
224 write_warn2(str
, "\n", 1);
231 print_backtrace(const VALUE eclass
, const VALUE errat
, const VALUE str
, int reverse
, long backtrace_limit
)
235 long len
= RARRAY_LEN(errat
);
236 const int threshold
= 1000000000;
237 int width
= (len
<= 1) ? INT_MIN
: ((int)log10((double)(len
> threshold
?
238 ((len
- 1) / threshold
) :
240 (len
< threshold
? 0 : 9) + 1);
242 long skip_start
= -1, skip_len
= 0;
244 // skip for stackoverflow
245 if (eclass
== rb_eSysStackError
) {
248 long trace_max
= trace_head
+ trace_tail
+ 5;
249 if (len
> trace_max
) {
250 skip_start
= trace_head
;
251 skip_len
= len
- trace_max
+ 5;
255 // skip for explicit limit
256 if (backtrace_limit
>= 0 && len
> backtrace_limit
+ 2) {
257 skip_start
= backtrace_limit
+ 1;
258 skip_len
= len
- skip_start
;
261 for (i
= 1; i
< len
; i
++) {
262 if (i
== skip_start
) {
263 write_warn_str(str
, rb_sprintf("\t ... %ld levels...\n", skip_len
));
267 VALUE line
= RARRAY_AREF(errat
, reverse
? len
- i
: i
);
268 if (RB_TYPE_P(line
, T_STRING
)) {
269 VALUE bt
= rb_str_new_cstr("\t");
270 if (reverse
) rb_str_catf(bt
, "%*ld: ", width
, len
- i
);
271 write_warn_str(str
, rb_str_catf(bt
, "from %"PRIsVALUE
"\n", line
));
277 VALUE
rb_get_message(VALUE exc
);
280 shown_cause_p(VALUE cause
, VALUE
*shown_causes
)
282 VALUE shown
= *shown_causes
;
284 *shown_causes
= shown
= rb_obj_hide(rb_ident_hash_new());
286 if (rb_hash_has_key(shown
, cause
)) return TRUE
;
287 rb_hash_aset(shown
, cause
, Qtrue
);
292 show_cause(VALUE errinfo
, VALUE str
, VALUE highlight
, VALUE reverse
, long backtrace_limit
, VALUE
*shown_causes
)
294 VALUE cause
= rb_attr_get(errinfo
, id_cause
);
295 if (!NIL_P(cause
) && rb_obj_is_kind_of(cause
, rb_eException
) &&
296 !shown_cause_p(cause
, shown_causes
)) {
297 volatile VALUE eclass
= CLASS_OF(cause
);
298 VALUE errat
= rb_get_backtrace(cause
);
299 VALUE emesg
= rb_get_message(cause
);
301 show_cause(cause
, str
, highlight
, reverse
, backtrace_limit
, shown_causes
);
302 print_backtrace(eclass
, errat
, str
, TRUE
, backtrace_limit
);
303 print_errinfo(eclass
, errat
, emesg
, str
, highlight
!=0);
306 print_errinfo(eclass
, errat
, emesg
, str
, highlight
!=0);
307 print_backtrace(eclass
, errat
, str
, FALSE
, backtrace_limit
);
308 show_cause(cause
, str
, highlight
, reverse
, backtrace_limit
, shown_causes
);
314 rb_error_write(VALUE errinfo
, VALUE emesg
, VALUE errat
, VALUE str
, VALUE highlight
, VALUE reverse
)
316 volatile VALUE eclass
;
317 VALUE shown_causes
= 0;
318 long backtrace_limit
= rb_backtrace_length_limit
;
323 if (errat
== Qundef
) {
326 eclass
= CLASS_OF(errinfo
);
327 if (NIL_P(reverse
)) reverse
= Qfalse
;
328 if (NIL_P(highlight
)) {
329 VALUE tty
= (VALUE
)rb_stderr_tty_p();
330 if (NIL_P(highlight
)) highlight
= tty
;
333 static const char traceback
[] = "Traceback "
334 "(most recent call last):\n";
335 const int bold_part
= rb_strlen_lit("Traceback");
336 char buff
[sizeof(traceback
)+sizeof(bold
)+sizeof(reset
)-2], *p
= buff
;
337 const char *msg
= traceback
;
338 long len
= sizeof(traceback
) - 1;
340 #define APPEND(s, l) (memcpy(p, s, l), p += (l))
341 APPEND(bold
, sizeof(bold
)-1);
342 APPEND(traceback
, bold_part
);
343 APPEND(reset
, sizeof(reset
)-1);
344 APPEND(traceback
+ bold_part
, sizeof(traceback
)-bold_part
-1);
346 len
= p
- (msg
= buff
);
348 write_warn2(str
, msg
, len
);
349 show_cause(errinfo
, str
, highlight
, reverse
, backtrace_limit
, &shown_causes
);
350 print_backtrace(eclass
, errat
, str
, TRUE
, backtrace_limit
);
351 print_errinfo(eclass
, errat
, emesg
, str
, highlight
!=0);
354 print_errinfo(eclass
, errat
, emesg
, str
, highlight
!=0);
355 print_backtrace(eclass
, errat
, str
, FALSE
, backtrace_limit
);
356 show_cause(errinfo
, str
, highlight
, reverse
, backtrace_limit
, &shown_causes
);
361 rb_ec_error_print(rb_execution_context_t
* volatile ec
, volatile VALUE errinfo
)
363 volatile uint8_t raised_flag
= ec
->raised_flag
;
364 volatile VALUE errat
= Qundef
;
365 volatile VALUE emesg
= Qundef
;
366 volatile bool written
= false;
370 rb_ec_raised_clear(ec
);
373 if (EC_EXEC_TAG() == TAG_NONE
) {
374 errat
= rb_get_backtrace(errinfo
);
376 if (emesg
== Qundef
) {
378 emesg
= rb_get_message(errinfo
);
383 rb_error_write(errinfo
, emesg
, errat
, Qnil
, Qnil
, Qfalse
);
387 ec
->errinfo
= errinfo
;
388 rb_ec_raised_set(ec
, raised_flag
);
391 #define undef_mesg_for(v, k) rb_fstring_lit("undefined"v" method `%1$s' for "k" `%2$s'")
392 #define undef_mesg(v) ( \
394 undef_mesg_for(v, "module") : \
395 undef_mesg_for(v, "class"))
398 rb_print_undef(VALUE klass
, ID id
, rb_method_visibility_t visi
)
400 const int is_mod
= RB_TYPE_P(klass
, T_MODULE
);
402 switch (visi
& METHOD_VISI_MASK
) {
403 case METHOD_VISI_UNDEF
:
404 case METHOD_VISI_PUBLIC
: mesg
= undef_mesg(""); break;
405 case METHOD_VISI_PRIVATE
: mesg
= undef_mesg(" private"); break;
406 case METHOD_VISI_PROTECTED
: mesg
= undef_mesg(" protected"); break;
407 default: UNREACHABLE
;
409 rb_name_err_raise_str(mesg
, klass
, ID2SYM(id
));
413 rb_print_undef_str(VALUE klass
, VALUE name
)
415 const int is_mod
= RB_TYPE_P(klass
, T_MODULE
);
416 rb_name_err_raise_str(undef_mesg(""), klass
, name
);
419 #define inaccessible_mesg_for(v, k) rb_fstring_lit("method `%1$s' for "k" `%2$s' is "v)
420 #define inaccessible_mesg(v) ( \
422 inaccessible_mesg_for(v, "module") : \
423 inaccessible_mesg_for(v, "class"))
426 rb_print_inaccessible(VALUE klass
, ID id
, rb_method_visibility_t visi
)
428 const int is_mod
= RB_TYPE_P(klass
, T_MODULE
);
430 switch (visi
& METHOD_VISI_MASK
) {
431 case METHOD_VISI_UNDEF
:
432 case METHOD_VISI_PUBLIC
: mesg
= inaccessible_mesg(""); break;
433 case METHOD_VISI_PRIVATE
: mesg
= inaccessible_mesg("private"); break;
434 case METHOD_VISI_PROTECTED
: mesg
= inaccessible_mesg("protected"); break;
435 default: UNREACHABLE
;
437 rb_name_err_raise_str(mesg
, klass
, ID2SYM(id
));
441 sysexit_status(VALUE err
)
443 VALUE st
= rb_ivar_get(err
, id_status
);
447 #define unknown_longjmp_status(status) \
448 rb_bug("Unknown longjmp status %d", status)
451 error_handle(rb_execution_context_t
*ec
, int ex
)
453 int status
= EXIT_FAILURE
;
455 if (rb_ec_set_raised(ec
))
457 switch (ex
& TAG_MASK
) {
459 status
= EXIT_SUCCESS
;
464 warn_print("unexpected return\n");
468 warn_print("unexpected next\n");
472 warn_print("unexpected break\n");
476 warn_print("unexpected redo\n");
480 warn_print("retry outside of rescue clause\n");
485 warn_print("unexpected throw\n");
488 VALUE errinfo
= ec
->errinfo
;
489 if (rb_obj_is_kind_of(errinfo
, rb_eSystemExit
)) {
490 status
= sysexit_status(errinfo
);
492 else if (rb_obj_is_instance_of(errinfo
, rb_eSignal
) &&
493 rb_ivar_get(errinfo
, id_signo
) != INT2FIX(SIGSEGV
)) {
494 /* no message when exiting by signal */
496 else if (rb_obj_is_kind_of(errinfo
, rb_eSystemCallError
) &&
497 FIXNUM_P(rb_attr_get(errinfo
, id_signo
))) {
498 /* no message when exiting by error to be mapped to signal */
501 rb_ec_error_print(ec
, errinfo
);
509 unknown_longjmp_status(ex
);
512 rb_ec_reset_raised(ec
);