Ruby  2.0.0p481(2014-05-08revision45883)
eval_error.c
Go to the documentation of this file.
00001 /* -*-c-*- */
00002 /*
00003  * included by eval.c
00004  */
00005 
00006 static void
00007 warn_printf(const char *fmt, ...)
00008 {
00009     VALUE str;
00010     va_list args;
00011 
00012     va_init_list(args, fmt);
00013     str = rb_vsprintf(fmt, args);
00014     va_end(args);
00015     rb_write_error_str(str);
00016 }
00017 
00018 #define warn_print(x) rb_write_error(x)
00019 #define warn_print2(x,l) rb_write_error2((x),(l))
00020 #define warn_print_str(x) rb_write_error_str(x)
00021 
00022 static void
00023 error_pos(void)
00024 {
00025     const char *sourcefile = rb_sourcefile();
00026     int sourceline = rb_sourceline();
00027 
00028     if (sourcefile) {
00029         if (sourceline == 0) {
00030             warn_printf("%s", sourcefile);
00031         }
00032         else if (rb_frame_callee()) {
00033             warn_printf("%s:%d:in `%s'", sourcefile, sourceline,
00034                         rb_id2name(rb_frame_callee()));
00035         }
00036         else {
00037             warn_printf("%s:%d", sourcefile, sourceline);
00038         }
00039     }
00040 }
00041 
00042 static VALUE
00043 get_backtrace(VALUE info)
00044 {
00045     if (NIL_P(info))
00046         return Qnil;
00047     info = rb_funcall(info, rb_intern("backtrace"), 0);
00048     if (NIL_P(info))
00049         return Qnil;
00050     return rb_check_backtrace(info);
00051 }
00052 
00053 VALUE
00054 rb_get_backtrace(VALUE info)
00055 {
00056     return get_backtrace(info);
00057 }
00058 
00059 VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt);
00060 
00061 static void
00062 set_backtrace(VALUE info, VALUE bt)
00063 {
00064     ID set_backtrace = rb_intern("set_backtrace");
00065 
00066     if (rb_backtrace_p(bt)) {
00067         if (rb_method_basic_definition_p(CLASS_OF(info), set_backtrace)) {
00068             rb_exc_set_backtrace(info, bt);
00069             return;
00070         }
00071         else {
00072             bt = rb_backtrace_to_str_ary(bt);
00073         }
00074     }
00075     rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
00076 }
00077 
00078 static void
00079 error_print(void)
00080 {
00081     volatile VALUE errat = Qnil;                /* OK */
00082     rb_thread_t *th = GET_THREAD();
00083     VALUE errinfo = th->errinfo;
00084     int raised_flag = th->raised_flag;
00085     volatile VALUE eclass, e;
00086     const char *volatile einfo;
00087     volatile long elen;
00088 
00089     if (NIL_P(errinfo))
00090         return;
00091     rb_thread_raised_clear(th);
00092 
00093     TH_PUSH_TAG(th);
00094     if (TH_EXEC_TAG() == 0) {
00095         errat = get_backtrace(errinfo);
00096     }
00097     else {
00098         errat = Qnil;
00099     }
00100     if (TH_EXEC_TAG())
00101         goto error;
00102     if (NIL_P(errat)) {
00103         const char *file = rb_sourcefile();
00104         int line = rb_sourceline();
00105         if (!file)
00106             warn_printf("%d", line);
00107         else if (!line)
00108             warn_printf("%s", file);
00109         else
00110             warn_printf("%s:%d", file, line);
00111     }
00112     else if (RARRAY_LEN(errat) == 0) {
00113         error_pos();
00114     }
00115     else {
00116         VALUE mesg = RARRAY_PTR(errat)[0];
00117 
00118         if (NIL_P(mesg))
00119             error_pos();
00120         else {
00121             warn_print_str(mesg);
00122         }
00123     }
00124 
00125     eclass = CLASS_OF(errinfo);
00126     if (TH_EXEC_TAG() == 0) {
00127         e = rb_funcall(errinfo, rb_intern("message"), 0, 0);
00128         StringValue(e);
00129         einfo = RSTRING_PTR(e);
00130         elen = RSTRING_LEN(e);
00131     }
00132     else {
00133         einfo = "";
00134         elen = 0;
00135     }
00136     if (TH_EXEC_TAG())
00137         goto error;
00138     if (eclass == rb_eRuntimeError && elen == 0) {
00139         warn_print(": unhandled exception\n");
00140     }
00141     else {
00142         VALUE epath;
00143 
00144         epath = rb_class_name(eclass);
00145         if (elen == 0) {
00146             warn_print(": ");
00147             warn_print_str(epath);
00148             warn_print("\n");
00149         }
00150         else {
00151             char *tail = 0;
00152             long len = elen;
00153 
00154             if (RSTRING_PTR(epath)[0] == '#')
00155                 epath = 0;
00156             if ((tail = memchr(einfo, '\n', elen)) != 0) {
00157                 len = tail - einfo;
00158                 tail++;         /* skip newline */
00159             }
00160             warn_print(": ");
00161             warn_print2(einfo, len);
00162             if (epath) {
00163                 warn_print(" (");
00164                 warn_print_str(epath);
00165                 warn_print(")\n");
00166             }
00167             if (tail) {
00168                 warn_print2(tail, elen - len - 1);
00169                 if (einfo[elen-1] != '\n') warn_print2("\n", 1);
00170             }
00171         }
00172     }
00173 
00174     if (!NIL_P(errat)) {
00175         long i;
00176         long len = RARRAY_LEN(errat);
00177         VALUE *ptr = RARRAY_PTR(errat);
00178         int skip = eclass == rb_eSysStackError;
00179 
00180 #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
00181 #define TRACE_HEAD 8
00182 #define TRACE_TAIL 5
00183 
00184         for (i = 1; i < len; i++) {
00185             if (RB_TYPE_P(ptr[i], T_STRING)) {
00186                 warn_printf("\tfrom %"PRIsVALUE"\n", ptr[i]);
00187             }
00188             if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
00189                 warn_printf("\t ... %ld levels...\n",
00190                             len - TRACE_HEAD - TRACE_TAIL);
00191                 i = len - TRACE_TAIL;
00192             }
00193         }
00194     }
00195   error:
00196     TH_POP_TAG();
00197     rb_thread_raised_set(th, raised_flag);
00198 }
00199 
00200 void
00201 ruby_error_print(void)
00202 {
00203     error_print();
00204 }
00205 
00206 void
00207 rb_print_undef(VALUE klass, ID id, int scope)
00208 {
00209     const char *v;
00210 
00211     switch (scope) {
00212       default:
00213       case NOEX_PUBLIC: v = ""; break;
00214       case NOEX_PRIVATE: v = " private"; break;
00215       case NOEX_PROTECTED: v = " protected"; break;
00216     }
00217     rb_name_error(id, "undefined%s method `%"PRIsVALUE"' for %s `%"PRIsVALUE"'", v,
00218                   QUOTE_ID(id),
00219                   (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class",
00220                   rb_class_name(klass));
00221 }
00222 
00223 void
00224 rb_print_undef_str(VALUE klass, VALUE name)
00225 {
00226     rb_name_error_str(name, "undefined method `%"PRIsVALUE"' for %s `%"PRIsVALUE"'",
00227                       QUOTE(name),
00228                       (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class",
00229                       rb_class_name(klass));
00230 }
00231 
00232 static int
00233 sysexit_status(VALUE err)
00234 {
00235     VALUE st = rb_iv_get(err, "status");
00236     return NUM2INT(st);
00237 }
00238 
00239 static int
00240 error_handle(int ex)
00241 {
00242     int status = EXIT_FAILURE;
00243     rb_thread_t *th = GET_THREAD();
00244 
00245     if (rb_threadptr_set_raised(th))
00246         return EXIT_FAILURE;
00247     switch (ex & TAG_MASK) {
00248       case 0:
00249         status = EXIT_SUCCESS;
00250         break;
00251 
00252       case TAG_RETURN:
00253         error_pos();
00254         warn_print(": unexpected return\n");
00255         break;
00256       case TAG_NEXT:
00257         error_pos();
00258         warn_print(": unexpected next\n");
00259         break;
00260       case TAG_BREAK:
00261         error_pos();
00262         warn_print(": unexpected break\n");
00263         break;
00264       case TAG_REDO:
00265         error_pos();
00266         warn_print(": unexpected redo\n");
00267         break;
00268       case TAG_RETRY:
00269         error_pos();
00270         warn_print(": retry outside of rescue clause\n");
00271         break;
00272       case TAG_THROW:
00273         /* TODO: fix me */
00274         error_pos();
00275         warn_printf(": unexpected throw\n");
00276         break;
00277       case TAG_RAISE: {
00278         VALUE errinfo = GET_THREAD()->errinfo;
00279         if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
00280             status = sysexit_status(errinfo);
00281         }
00282         else if (rb_obj_is_instance_of(errinfo, rb_eSignal)) {
00283             /* no message when exiting by signal */
00284         }
00285         else {
00286             error_print();
00287         }
00288         break;
00289       }
00290       case TAG_FATAL:
00291         error_print();
00292         break;
00293       default:
00294         rb_bug("Unknown longjmp status %d", ex);
00295         break;
00296     }
00297     rb_threadptr_reset_raised(th);
00298     return status;
00299 }
00300