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