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