Ruby  2.1.3p242(2014-09-19revision47630)
eval_error.c
Go to the documentation of this file.
1 /* -*-c-*- */
2 /*
3  * included by eval.c
4  */
5 
6 static void
7 warn_printf(const char *fmt, ...)
8 {
9  VALUE str;
10  va_list args;
11 
12  va_init_list(args, fmt);
13  str = rb_vsprintf(fmt, args);
14  va_end(args);
15  rb_write_error_str(str);
16 }
17 
18 #define warn_print(x) rb_write_error(x)
19 #define warn_print2(x,l) rb_write_error2((x),(l))
20 #define warn_print_str(x) rb_write_error_str(x)
21 
22 static void
23 error_pos(void)
24 {
25  const char *sourcefile = rb_sourcefile();
26  int sourceline = rb_sourceline();
27 
28  if (sourcefile) {
29  ID caller_name;
30  if (sourceline == 0) {
31  warn_printf("%s", sourcefile);
32  }
33  else if ((caller_name = rb_frame_callee()) != 0) {
34  warn_printf("%s:%d:in `%s'", sourcefile, sourceline,
35  rb_id2name(caller_name));
36  }
37  else {
38  warn_printf("%s:%d", sourcefile, sourceline);
39  }
40  }
41 }
42 
43 static VALUE
45 {
46  if (NIL_P(info))
47  return Qnil;
48  info = rb_funcall(info, rb_intern("backtrace"), 0);
49  if (NIL_P(info))
50  return Qnil;
51  return rb_check_backtrace(info);
52 }
53 
54 VALUE
56 {
57  return get_backtrace(info);
58 }
59 
61 
62 static void
64 {
65  ID set_backtrace = rb_intern("set_backtrace");
66 
67  if (rb_backtrace_p(bt)) {
68  if (rb_method_basic_definition_p(CLASS_OF(info), set_backtrace)) {
69  rb_exc_set_backtrace(info, bt);
70  return;
71  }
72  else {
73  bt = rb_backtrace_to_str_ary(bt);
74  }
75  }
76  rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
77 }
78 
79 static void
81 {
82  volatile VALUE errat = Qundef;
83  rb_thread_t *th = GET_THREAD();
84  VALUE errinfo = th->errinfo;
85  int raised_flag = th->raised_flag;
86  volatile VALUE eclass = Qundef, e = Qundef;
87  const char *volatile einfo;
88  volatile long elen;
89 
90  if (NIL_P(errinfo))
91  return;
93 
94  TH_PUSH_TAG(th);
95  if (TH_EXEC_TAG() == 0) {
96  errat = get_backtrace(errinfo);
97  }
98  else if (errat == Qundef) {
99  errat = Qnil;
100  }
101  else if (eclass == Qundef || e != Qundef) {
102  goto error;
103  }
104  else {
105  goto no_message;
106  }
107  if (NIL_P(errat)) {
108  const char *file = rb_sourcefile();
109  int line = rb_sourceline();
110  if (!file)
111  warn_printf("%d", line);
112  else if (!line)
113  warn_printf("%s", file);
114  else
115  warn_printf("%s:%d", file, line);
116  }
117  else if (RARRAY_LEN(errat) == 0) {
118  error_pos();
119  }
120  else {
121  VALUE mesg = RARRAY_AREF(errat, 0);
122 
123  if (NIL_P(mesg))
124  error_pos();
125  else {
126  warn_print_str(mesg);
127  }
128  }
129 
130  eclass = CLASS_OF(errinfo);
131  if (eclass != Qundef &&
132  (e = rb_check_funcall(errinfo, rb_intern("message"), 0, 0)) != Qundef &&
133  (RB_TYPE_P(e, T_STRING) || !NIL_P(e = rb_check_string_type(e)))) {
134  einfo = RSTRING_PTR(e);
135  elen = RSTRING_LEN(e);
136  }
137  else {
138  no_message:
139  einfo = "";
140  elen = 0;
141  }
142  if (eclass == rb_eRuntimeError && elen == 0) {
143  warn_print(": unhandled exception\n");
144  }
145  else {
146  VALUE epath;
147 
148  epath = rb_class_name(eclass);
149  if (elen == 0) {
150  warn_print(": ");
151  warn_print_str(epath);
152  warn_print("\n");
153  }
154  else {
155  char *tail = 0;
156  long len = elen;
157 
158  if (RSTRING_PTR(epath)[0] == '#')
159  epath = 0;
160  if ((tail = memchr(einfo, '\n', elen)) != 0) {
161  len = tail - einfo;
162  tail++; /* skip newline */
163  }
164  warn_print(": ");
165  warn_print2(einfo, len);
166  if (epath) {
167  warn_print(" (");
168  warn_print_str(epath);
169  warn_print(")\n");
170  }
171  if (tail) {
172  warn_print2(tail, elen - len - 1);
173  if (einfo[elen-1] != '\n') warn_print2("\n", 1);
174  }
175  }
176  }
177 
178  if (!NIL_P(errat)) {
179  long i;
180  long len = RARRAY_LEN(errat);
181  int skip = eclass == rb_eSysStackError;
182 
183 #define TRACE_MAX (TRACE_HEAD+TRACE_TAIL+5)
184 #define TRACE_HEAD 8
185 #define TRACE_TAIL 5
186 
187  for (i = 1; i < len; i++) {
188  VALUE line = RARRAY_AREF(errat, i);
189  if (RB_TYPE_P(line, T_STRING)) {
190  warn_printf("\tfrom %"PRIsVALUE"\n", line);
191  }
192  if (skip && i == TRACE_HEAD && len > TRACE_MAX) {
193  warn_printf("\t ... %ld levels...\n",
194  len - TRACE_HEAD - TRACE_TAIL);
195  i = len - TRACE_TAIL;
196  }
197  }
198  }
199  error:
200  TH_POP_TAG();
201  th->errinfo = errinfo;
202  rb_thread_raised_set(th, raised_flag);
203 }
204 
205 void
207 {
208  error_print();
209 }
210 
211 void
212 rb_print_undef(VALUE klass, ID id, int scope)
213 {
214  const char *v;
215 
216  switch (scope) {
217  default:
218  case NOEX_PUBLIC: v = ""; break;
219  case NOEX_PRIVATE: v = " private"; break;
220  case NOEX_PROTECTED: v = " protected"; break;
221  }
222  rb_name_error(id, "undefined%s method `%"PRIsVALUE"' for %s `%"PRIsVALUE"'", v,
223  QUOTE_ID(id),
224  (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class",
225  rb_class_name(klass));
226 }
227 
228 void
230 {
231  rb_name_error_str(name, "undefined method `%"PRIsVALUE"' for %s `%"PRIsVALUE"'",
232  QUOTE(name),
233  (RB_TYPE_P(klass, T_MODULE)) ? "module" : "class",
234  rb_class_name(klass));
235 }
236 
237 static int
239 {
240  VALUE st = rb_iv_get(err, "status");
241  return NUM2INT(st);
242 }
243 
244 static int
246 {
247  int status = EXIT_FAILURE;
248  rb_thread_t *th = GET_THREAD();
249 
250  if (rb_threadptr_set_raised(th))
251  return EXIT_FAILURE;
252  switch (ex & TAG_MASK) {
253  case 0:
254  status = EXIT_SUCCESS;
255  break;
256 
257  case TAG_RETURN:
258  error_pos();
259  warn_print(": unexpected return\n");
260  break;
261  case TAG_NEXT:
262  error_pos();
263  warn_print(": unexpected next\n");
264  break;
265  case TAG_BREAK:
266  error_pos();
267  warn_print(": unexpected break\n");
268  break;
269  case TAG_REDO:
270  error_pos();
271  warn_print(": unexpected redo\n");
272  break;
273  case TAG_RETRY:
274  error_pos();
275  warn_print(": retry outside of rescue clause\n");
276  break;
277  case TAG_THROW:
278  /* TODO: fix me */
279  error_pos();
280  warn_printf(": unexpected throw\n");
281  break;
282  case TAG_RAISE: {
283  VALUE errinfo = GET_THREAD()->errinfo;
284  if (rb_obj_is_kind_of(errinfo, rb_eSystemExit)) {
285  status = sysexit_status(errinfo);
286  }
287  else if (rb_obj_is_instance_of(errinfo, rb_eSignal)) {
288  /* no message when exiting by signal */
289  }
290  else {
291  error_print();
292  }
293  break;
294  }
295  case TAG_FATAL:
296  error_print();
297  break;
298  default:
299  rb_bug("Unknown longjmp status %d", ex);
300  break;
301  }
303  return status;
304 }
305