static void print_errinfo(const VALUE eclass, const VALUE errat, const VALUE emesg) { const char *einfo = ""; long elen = 0; VALUE mesg; 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(": "); } if (!NIL_P(emesg)) { einfo = RSTRING_PTR(emesg); elen = RSTRING_LEN(emesg); } } if (eclass == rb_eRuntimeError && elen == 0) { warn_print("unhandled exception\n"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print_str(epath); warn_print("\n"); } else { const char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } 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(emesg, tail - einfo, elen - len - 1)); } if (tail ? einfo[elen-1] != '\n' : !epath) warn_print2("\n", 1); } } }
void rb_threadptr_error_print(rb_thread_t *th, VALUE errinfo) { volatile VALUE errat = Qundef; int raised_flag = th->raised_flag; volatile VALUE eclass = Qundef, e = Qundef; const char *volatile einfo; volatile long elen; VALUE mesg; 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 || 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(": "); } 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"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print_str(epath); warn_print("\n"); } else { const char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } warn_print_str(tail ? rb_str_subseq(e, 0, len) : e); 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)); } if (tail ? einfo[elen-1] != '\n' : !epath) warn_print2("\n", 1); } } if (!NIL_P(errat)) { long i; long len = RARRAY_LEN(errat); int skip = eclass == rb_eSysStackError; #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) #define TRACE_HEAD 8 #define TRACE_TAIL 5 for (i = 1; i < len; i++) { VALUE line = RARRAY_AREF(errat, i); if (RB_TYPE_P(line, T_STRING)) { warn_print_str(rb_sprintf("\tfrom %"PRIsVALUE"\n", line)); } if (skip && i == TRACE_HEAD && len > TRACE_MAX) { warn_print_str(rb_sprintf("\t ... %ld levels...\n", len - TRACE_HEAD - TRACE_TAIL)); i = len - TRACE_TAIL; } } } error: TH_POP_TAG(); th->errinfo = errinfo; rb_thread_raised_set(th, raised_flag); }
static int error_handle(int ex) { int status = EXIT_FAILURE; rb_thread_t *th = GET_THREAD(); if (rb_threadptr_set_raised(th)) return EXIT_FAILURE; switch (ex & TAG_MASK) { case 0: status = EXIT_SUCCESS; break; case TAG_RETURN: error_pos(); warn_print("unexpected return\n"); break; case TAG_NEXT: error_pos(); warn_print("unexpected next\n"); break; case TAG_BREAK: error_pos(); warn_print("unexpected break\n"); break; case TAG_REDO: error_pos(); warn_print("unexpected redo\n"); break; case TAG_RETRY: error_pos(); warn_print("retry outside of rescue clause\n"); break; case TAG_THROW: /* TODO: fix me */ error_pos(); warn_print("unexpected throw\n"); break; case TAG_RAISE: { VALUE errinfo = th->errinfo; if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) { status = sysexit_status(errinfo); } else if (rb_obj_is_instance_of(errinfo, rb_eSignal) && rb_ivar_get(errinfo, id_signo) != INT2FIX(SIGSEGV)) { /* no message when exiting by signal */ } else { error_print(th); } break; } case TAG_FATAL: error_print(th); break; default: unknown_longjmp_status(ex); break; } rb_threadptr_reset_raised(th); return status; }
static void error_print(FILE *out, int state, int cgi, int mode, VALUE code) { char buff[BUFSIZ]; #if RUBY_VERSION_CODE < 180 rb_defout = rb_stdout; #endif if (cgi) { char *imgdir; if ((imgdir = getenv("SCRIPT_NAME")) == NULL) imgdir = "UNKNOWN_IMG_DIR"; if (mode == MODE_NPHCGI) print_http_headers(); fprintf(out, "Content-Type: text/html\r\n"); fprintf(out, "Content-Style-Type: text/css\r\n"); fprintf(out, "\r\n"); fprintf(out, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\">\n"); fprintf(out, "<html>\n"); fprintf(out, "<head>\n"); fprintf(out, "<title>eRuby</title>\n"); fprintf(out, "<style type=\"text/css\">\n"); fprintf(out, "<!--\n"); fprintf(out, "body { background-color: #ffffff }\n"); fprintf(out, "table { width: 100%%; padding: 5pt; border-style: none }\n"); fprintf(out, "th { color: #6666ff; background-color: #b0d0d0; text-align: left }\n"); fprintf(out, "td { color: #336666; background-color: #d0ffff }\n"); fprintf(out, "strong { color: #ff0000; font-weight: bold }\n"); fprintf(out, "div.backtrace { text-indent: 15%% }\n"); fprintf(out, "#version { color: #ff9900 }\n"); fprintf(out, "-->\n"); fprintf(out, "</style>\n"); fprintf(out, "</head>\n"); fprintf(out, "<body>\n"); fprintf(out, "<table summary=\"eRuby error information\">\n"); fprintf(out, "<caption>\n"); fprintf(out, "<img src=\"%s/logo.png\" alt=\"eRuby\">\n", imgdir); fprintf(out, "<span id=version>version: %s</span>\n", ERUBY_VERSION); fprintf(out, "</caption>\n"); fprintf(out, "<tr><th id=\"error\">\n"); fprintf(out, "ERROR\n"); fprintf(out, "</th></tr>\n"); fprintf(out, "<tr><td headers=\"error\">\n"); } switch (state) { case TAG_RETURN: error_pos(out, cgi); fprintf(out, ": unexpected return\n"); break; case TAG_NEXT: error_pos(out, cgi); fprintf(out, ": unexpected next\n"); break; case TAG_BREAK: error_pos(out, cgi); fprintf(out, ": unexpected break\n"); break; case TAG_REDO: error_pos(out, cgi); fprintf(out, ": unexpected redo\n"); break; case TAG_RETRY: error_pos(out, cgi); fprintf(out, ": retry outside of rescue clause\n"); break; case TAG_RAISE: case TAG_FATAL: exception_print(out, cgi); break; default: error_pos(out, cgi); snprintf(buff, BUFSIZ, ": unknown longjmp status %d", state); fputs(buff, out); break; } if (cgi) { fprintf(out, "</td></tr>\n"); } if (!NIL_P(code)) print_generated_code(out, code, cgi); if (cgi) { fprintf(out, "</table>\n"); fprintf(out, "</body>\n"); fprintf(out, "</html>\n"); } }
static void exception_print(FILE *out, int cgi) { VALUE errat; VALUE eclass; VALUE einfo; if (NIL_P(ruby_errinfo)) return; errat = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0); if (!NIL_P(errat)) { VALUE mesg = RARRAY_PTR(errat)[0]; if (NIL_P(mesg)) { error_pos(out, cgi); } else { if (cgi) write_escaping_html(out, RSTRING_PTR(mesg), RSTRING_LEN(mesg)); else fwrite(RSTRING_PTR(mesg), 1, RSTRING_LEN(mesg), out); } } eclass = CLASS_OF(ruby_errinfo); einfo = rb_obj_as_string(ruby_errinfo); if (eclass == rb_eRuntimeError && RSTRING_LEN(einfo) == 0) { fprintf(out, ": unhandled exception\n"); } else { VALUE epath; epath = rb_class_path(eclass); if (RSTRING_LEN(einfo) == 0) { fprintf(out, ": "); if (cgi) write_escaping_html(out, RSTRING_PTR(epath), RSTRING_LEN(epath)); else fwrite(RSTRING_PTR(epath), 1, RSTRING_LEN(epath), out); if (cgi) fprintf(out, "<br>\n"); else fprintf(out, "\n"); } else { char *tail = 0; int len = RSTRING_LEN(einfo); if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = strchr(RSTRING_PTR(einfo), '\n')) != NULL) { len = tail - RSTRING_PTR(einfo); tail++; /* skip newline */ } fprintf(out, ": "); if (cgi) write_escaping_html(out, RSTRING_PTR(einfo), len); else fwrite(RSTRING_PTR(einfo), 1, len, out); if (epath) { fprintf(out, " ("); if (cgi) write_escaping_html(out, RSTRING_PTR(epath), RSTRING_LEN(epath)); else fwrite(RSTRING_PTR(epath), 1, RSTRING_LEN(epath), out); if (cgi) fprintf(out, ")<br>\n"); else fprintf(out, ")\n"); } if (tail) { if (cgi) write_escaping_html(out, tail, RSTRING_LEN(einfo) - len - 1); else fwrite(tail, 1, RSTRING_LEN(einfo) - len - 1, out); if (cgi) fprintf(out, "<br>\n"); else fprintf(out, "\n"); } } } if (!NIL_P(errat)) { int i; struct RArray *ep = RARRAY(errat); #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) #define TRACE_HEAD 8 #define TRACE_TAIL 5 rb_ary_pop(errat); ep = RARRAY(errat); for (i=1; i<RARRAY_LEN(ep); i++) { if (TYPE(RARRAY_PTR(ep)[i]) == T_STRING) { if (cgi) { fprintf(out, "<div class=\"backtrace\">from "); write_escaping_html(out, RSTRING_PTR(RARRAY_PTR(ep)[i]), RSTRING_LEN(RARRAY_PTR(ep)[i])); } else { fprintf(out, " from "); fwrite(RSTRING_PTR(RARRAY_PTR(ep)[i]), 1, RSTRING_LEN(RARRAY_PTR(ep)[i]), out); } if (cgi) fprintf(out, "<br></div>\n"); else fprintf(out, "\n"); } if (i == TRACE_HEAD && RARRAY_LEN(ep) > TRACE_MAX) { char buff[BUFSIZ]; if (cgi) snprintf(buff, BUFSIZ, "<div class=\"backtrace\">... %ld levels...\n", RARRAY_LEN(ep) - TRACE_HEAD - TRACE_TAIL); else snprintf(buff, BUFSIZ, " ... %ld levels...<br></div>\n", RARRAY_LEN(ep) - TRACE_HEAD - TRACE_TAIL); if (cgi) write_escaping_html(out, buff, strlen(buff)); else fputs(buff, out); i = RARRAY_LEN(ep) - TRACE_TAIL; } } } }
static void error_print(void) { volatile VALUE errat = Qnil; /* OK */ VALUE errinfo = GET_THREAD()->errinfo; volatile VALUE eclass, e; const char *volatile einfo; volatile long elen; if (NIL_P(errinfo)) return; PUSH_TAG(); if (EXEC_TAG() == 0) { errat = get_backtrace(errinfo); } else { errat = Qnil; } if (EXEC_TAG()) goto error; if (NIL_P(errat)) { const char *file = rb_sourcefile(); int line = rb_sourceline(); if (!file) warn_printf("%d", line); else if (!line) warn_printf("%s", file); else warn_printf("%s:%d", file, line); } else if (RARRAY_LEN(errat) == 0) { error_pos(); } else { VALUE mesg = RARRAY_PTR(errat)[0]; if (NIL_P(mesg)) error_pos(); else { warn_print2(RSTRING_PTR(mesg), RSTRING_LEN(mesg)); } } eclass = CLASS_OF(errinfo); if (EXEC_TAG() == 0) { e = rb_funcall(errinfo, rb_intern("message"), 0, 0); StringValue(e); einfo = RSTRING_PTR(e); elen = RSTRING_LEN(e); } else { einfo = ""; elen = 0; } if (EXEC_TAG()) goto error; if (eclass == rb_eRuntimeError && elen == 0) { warn_print(": unhandled exception\n"); } else { VALUE epath; epath = rb_class_name(eclass); if (elen == 0) { warn_print(": "); warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath)); warn_print("\n"); } else { char *tail = 0; long len = elen; if (RSTRING_PTR(epath)[0] == '#') epath = 0; if ((tail = memchr(einfo, '\n', elen)) != 0) { len = tail - einfo; tail++; /* skip newline */ } warn_print(": "); warn_print2(einfo, len); if (epath) { warn_print(" ("); warn_print2(RSTRING_PTR(epath), RSTRING_LEN(epath)); warn_print(")\n"); } if (tail) { warn_print2(tail, elen - len - 1); if (einfo[elen-1] != '\n') warn_print2("\n", 1); } } } if (!NIL_P(errat)) { long i; long len = RARRAY_LEN(errat); VALUE *ptr = RARRAY_PTR(errat); int skip = eclass == rb_eSysStackError; #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5) #define TRACE_HEAD 8 #define TRACE_TAIL 5 for (i = 1; i < len; i++) { if (TYPE(ptr[i]) == T_STRING) { warn_printf("\tfrom %s\n", RSTRING_PTR(ptr[i])); } if (skip && i == TRACE_HEAD && len > TRACE_MAX) { warn_printf("\t ... %ld levels...\n", len - TRACE_HEAD - TRACE_TAIL); i = len - TRACE_TAIL; } } } error: POP_TAG(); }