Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / src / error.c
1 /*
2 ** error.c - Exception class
3 **
4 ** See Copyright Notice in mruby.h
5 */
6
7 #include <errno.h>
8 #include <stdarg.h>
9 #include <stdlib.h>
10 #include <mruby.h>
11 #include <mruby/array.h>
12 #include <mruby/irep.h>
13 #include <mruby/proc.h>
14 #include <mruby/string.h>
15 #include <mruby/variable.h>
16 #include <mruby/debug.h>
17 #include <mruby/error.h>
18 #include <mruby/class.h>
19 #include <mruby/throw.h>
20
21 MRB_API mrb_value
22 mrb_exc_new(mrb_state *mrb, struct RClass *c, const char *ptr, size_t len)
23 {
24   mrb_value arg = mrb_str_new(mrb, ptr, len);
25   return mrb_obj_new(mrb, c, 1, &arg);
26 }
27
28 MRB_API mrb_value
29 mrb_exc_new_str(mrb_state *mrb, struct RClass* c, mrb_value str)
30 {
31   mrb_to_str(mrb, str);
32   return mrb_obj_new(mrb, c, 1, &str);
33 }
34
35 /*
36  * call-seq:
37  *    Exception.new(msg = nil)   ->  exception
38  *
39  *  Construct a new Exception object, optionally passing in
40  *  a message.
41  */
42
43 static mrb_value
44 exc_initialize(mrb_state *mrb, mrb_value exc)
45 {
46   mrb_value mesg;
47   mrb_int argc;
48   mrb_value *argv;
49
50   if (mrb_get_args(mrb, "|o*!", &mesg, &argv, &argc) >= 1) {
51     mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), mesg);
52   }
53   return exc;
54 }
55
56 /*
57  *  Document-method: exception
58  *
59  *  call-seq:
60  *     exc.exception(string)  ->  an_exception or exc
61  *
62  *  With no argument, or if the argument is the same as the receiver,
63  *  return the receiver. Otherwise, create a new
64  *  exception object of the same class as the receiver, but with a
65  *  message equal to <code>string</code>.
66  *
67  */
68
69 static mrb_value
70 exc_exception(mrb_state *mrb, mrb_value self)
71 {
72   mrb_value exc;
73   mrb_value a;
74   mrb_int argc;
75
76   argc = mrb_get_args(mrb, "|o", &a);
77   if (argc == 0) return self;
78   if (mrb_obj_equal(mrb, self, a)) return self;
79   exc = mrb_obj_clone(mrb, self);
80   mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "mesg"), a);
81
82   return exc;
83 }
84
85 /*
86  * call-seq:
87  *   exception.to_s   ->  string
88  *
89  * Returns exception's message (or the name of the exception if
90  * no message is set).
91  */
92
93 static mrb_value
94 exc_to_s(mrb_state *mrb, mrb_value exc)
95 {
96   mrb_value mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
97   struct RObject *p;
98
99   if (!mrb_string_p(mesg)) {
100     return mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, exc));
101   }
102   p = mrb_obj_ptr(mesg);
103   if (!p->c) {
104     p->c = mrb->string_class;
105   }
106   return mesg;
107 }
108
109 /*
110  * call-seq:
111  *   exception.message   ->  string
112  *
113  * Returns the result of invoking <code>exception.to_s</code>.
114  * Normally this returns the exception's message or name.
115  */
116
117 static mrb_value
118 exc_message(mrb_state *mrb, mrb_value exc)
119 {
120   return mrb_funcall(mrb, exc, "to_s", 0);
121 }
122
123 /*
124  * call-seq:
125  *   exception.inspect   -> string
126  *
127  * Returns this exception's file name, line number,
128  * message and class name.
129  * If file name or line number is not set,
130  * returns message and class name.
131  */
132
133 static mrb_value
134 exc_inspect(mrb_state *mrb, mrb_value exc)
135 {
136   mrb_value str, mesg, file, line;
137   mrb_bool append_mesg;
138   const char *cname;
139
140   mesg = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "mesg"));
141   file = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "file"));
142   line = mrb_attr_get(mrb, exc, mrb_intern_lit(mrb, "line"));
143
144   append_mesg = !mrb_nil_p(mesg);
145   if (append_mesg) {
146     mesg = mrb_obj_as_string(mrb, mesg);
147     append_mesg = RSTRING_LEN(mesg) > 0;
148   }
149
150   cname = mrb_obj_classname(mrb, exc);
151   str = mrb_str_new_cstr(mrb, cname);
152   if (mrb_string_p(file) && mrb_fixnum_p(line)) {
153     if (append_mesg) {
154       str = mrb_format(mrb, "%S:%S: %S (%S)", file, line, mesg, str);
155     }
156     else {
157       str = mrb_format(mrb, "%S:%S: %S", file, line, str);
158     }
159   }
160   else if (append_mesg) {
161     str = mrb_format(mrb, "%S: %S", str, mesg);
162   }
163   return str;
164 }
165
166 void mrb_keep_backtrace(mrb_state *mrb, mrb_value exc);
167
168 static void
169 set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
170 {
171   if (!mrb_array_p(backtrace)) {
172   type_err:
173     mrb_raise(mrb, E_TYPE_ERROR, "backtrace must be Array of String");
174   }
175   else {
176     const mrb_value *p = RARRAY_PTR(backtrace);
177     const mrb_value *pend = p + RARRAY_LEN(backtrace);
178
179     while (p < pend) {
180       if (!mrb_string_p(*p)) goto type_err;
181       p++;
182     }
183   }
184   mrb_iv_set(mrb, exc, mrb_intern_lit(mrb, "backtrace"), backtrace);
185 }
186
187 static mrb_value
188 exc_set_backtrace(mrb_state *mrb, mrb_value exc)
189 {
190   mrb_value backtrace;
191
192   mrb_get_args(mrb, "o", &backtrace);
193   set_backtrace(mrb, exc, backtrace);
194   return backtrace;
195 }
196
197 static void
198 exc_debug_info(mrb_state *mrb, struct RObject *exc)
199 {
200   mrb_callinfo *ci = mrb->c->ci;
201   mrb_code *pc = ci->pc;
202
203   if (mrb_obj_iv_defined(mrb, exc, mrb_intern_lit(mrb, "file"))) return;
204   while (ci >= mrb->c->cibase) {
205     mrb_code *err = ci->err;
206
207     if (!err && pc) err = pc - 1;
208     if (err && ci->proc && !MRB_PROC_CFUNC_P(ci->proc)) {
209       mrb_irep *irep = ci->proc->body.irep;
210
211       int32_t const line = mrb_debug_get_line(mrb, irep, err - irep->iseq);
212       char const* file = mrb_debug_get_filename(mrb, irep, err - irep->iseq);
213       if (line != -1 && file) {
214         mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "file"), mrb_str_new_cstr(mrb, file));
215         mrb_obj_iv_set(mrb, exc, mrb_intern_lit(mrb, "line"), mrb_fixnum_value(line));
216         return;
217       }
218     }
219     pc = ci->pc;
220     ci--;
221   }
222 }
223
224 void
225 mrb_exc_set(mrb_state *mrb, mrb_value exc)
226 {
227   if (mrb_nil_p(exc)) {
228     mrb->exc = 0;
229   }
230   else {
231     mrb->exc = mrb_obj_ptr(exc);
232     if (mrb->gc.arena_idx > 0 &&
233         (struct RBasic*)mrb->exc == mrb->gc.arena[mrb->gc.arena_idx-1]) {
234       mrb->gc.arena_idx--;
235     }
236     if (!mrb->gc.out_of_memory && !MRB_FROZEN_P(mrb->exc)) {
237       exc_debug_info(mrb, mrb->exc);
238       mrb_keep_backtrace(mrb, exc);
239     }
240   }
241 }
242
243 MRB_API mrb_noreturn void
244 mrb_exc_raise(mrb_state *mrb, mrb_value exc)
245 {
246   if (!mrb_obj_is_kind_of(mrb, exc, mrb->eException_class)) {
247     mrb_raise(mrb, E_TYPE_ERROR, "exception object expected");
248   }
249   mrb_exc_set(mrb, exc);
250   if (!mrb->jmp) {
251     mrb_p(mrb, exc);
252     abort();
253   }
254   MRB_THROW(mrb->jmp);
255 }
256
257 MRB_API mrb_noreturn void
258 mrb_raise(mrb_state *mrb, struct RClass *c, const char *msg)
259 {
260   mrb_exc_raise(mrb, mrb_exc_new_str(mrb, c, mrb_str_new_cstr(mrb, msg)));
261 }
262
263 MRB_API mrb_value
264 mrb_vformat(mrb_state *mrb, const char *format, va_list ap)
265 {
266   const char *p = format;
267   const char *b = p;
268   ptrdiff_t size;
269   int ai0 = mrb_gc_arena_save(mrb);
270   mrb_value ary = mrb_ary_new_capa(mrb, 4);
271   int ai = mrb_gc_arena_save(mrb);
272
273   while (*p) {
274     const char c = *p++;
275
276     if (c == '%') {
277       if (*p == 'S') {
278         mrb_value val;
279
280         size = p - b - 1;
281         mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
282         val = va_arg(ap, mrb_value);
283         mrb_ary_push(mrb, ary, mrb_obj_as_string(mrb, val));
284         b = p + 1;
285       }
286     }
287     else if (c == '\\') {
288       if (*p) {
289         size = p - b - 1;
290         mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
291         mrb_ary_push(mrb, ary, mrb_str_new(mrb, p, 1));
292         b = ++p;
293       }
294       else {
295         break;
296       }
297     }
298     mrb_gc_arena_restore(mrb, ai);
299   }
300   if (b == format) {
301     mrb_gc_arena_restore(mrb, ai0);
302     return mrb_str_new_cstr(mrb, format);
303   }
304   else {
305     mrb_value val;
306
307     size = p - b;
308     if (size > 0) {
309       mrb_ary_push(mrb, ary, mrb_str_new(mrb, b, size));
310     }
311     val = mrb_ary_join(mrb, ary, mrb_nil_value());
312     mrb_gc_arena_restore(mrb, ai0);
313     mrb_gc_protect(mrb, val);
314     return val;
315   }
316 }
317
318 MRB_API mrb_value
319 mrb_format(mrb_state *mrb, const char *format, ...)
320 {
321   va_list ap;
322   mrb_value str;
323
324   va_start(ap, format);
325   str = mrb_vformat(mrb, format, ap);
326   va_end(ap);
327
328   return str;
329 }
330
331 static mrb_noreturn void
332 raise_va(mrb_state *mrb, struct RClass *c, const char *fmt, va_list ap, int argc, mrb_value *argv)
333 {
334   mrb_value mesg;
335
336   mesg = mrb_vformat(mrb, fmt, ap);
337   if (argv == NULL) {
338     argv = &mesg;
339   }
340   else {
341     argv[0] = mesg;
342   }
343   mrb_exc_raise(mrb, mrb_obj_new(mrb, c, argc+1, argv));
344 }
345
346 MRB_API mrb_noreturn void
347 mrb_raisef(mrb_state *mrb, struct RClass *c, const char *fmt, ...)
348 {
349   va_list args;
350
351   va_start(args, fmt);
352   raise_va(mrb, c, fmt, args, 0, NULL);
353   va_end(args);
354 }
355
356 MRB_API mrb_noreturn void
357 mrb_name_error(mrb_state *mrb, mrb_sym id, const char *fmt, ...)
358 {
359   mrb_value argv[2];
360   va_list args;
361
362   va_start(args, fmt);
363   argv[1] = mrb_symbol_value(id);
364   raise_va(mrb, E_NAME_ERROR, fmt, args, 1, argv);
365   va_end(args);
366 }
367
368 MRB_API void
369 mrb_warn(mrb_state *mrb, const char *fmt, ...)
370 {
371 #ifndef MRB_DISABLE_STDIO
372   va_list ap;
373   mrb_value str;
374
375   va_start(ap, fmt);
376   str = mrb_vformat(mrb, fmt, ap);
377   fputs("warning: ", stderr);
378   fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
379   putc('\n', stderr);
380   va_end(ap);
381 #endif
382 }
383
384 MRB_API mrb_noreturn void
385 mrb_bug(mrb_state *mrb, const char *fmt, ...)
386 {
387 #ifndef MRB_DISABLE_STDIO
388   va_list ap;
389   mrb_value str;
390
391   va_start(ap, fmt);
392   str = mrb_vformat(mrb, fmt, ap);
393   fputs("bug: ", stderr);
394   fwrite(RSTRING_PTR(str), RSTRING_LEN(str), 1, stderr);
395   va_end(ap);
396 #endif
397   exit(EXIT_FAILURE);
398 }
399
400 MRB_API mrb_value
401 mrb_make_exception(mrb_state *mrb, mrb_int argc, const mrb_value *argv)
402 {
403   mrb_value mesg;
404   int n;
405
406   mesg = mrb_nil_value();
407   switch (argc) {
408     case 0:
409     break;
410     case 1:
411       if (mrb_nil_p(argv[0]))
412         break;
413       if (mrb_string_p(argv[0])) {
414         mesg = mrb_exc_new_str(mrb, E_RUNTIME_ERROR, argv[0]);
415         break;
416       }
417       n = 0;
418       goto exception_call;
419
420     case 2:
421     case 3:
422       n = 1;
423 exception_call:
424       {
425         mrb_sym exc = mrb_intern_lit(mrb, "exception");
426         if (mrb_respond_to(mrb, argv[0], exc)) {
427           mesg = mrb_funcall_argv(mrb, argv[0], exc, n, argv+1);
428         }
429         else {
430           /* undef */
431           mrb_raise(mrb, E_TYPE_ERROR, "exception class/object expected");
432         }
433       }
434
435       break;
436     default:
437       mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 0..3)", mrb_fixnum_value(argc));
438       break;
439   }
440   if (argc > 0) {
441     if (!mrb_obj_is_kind_of(mrb, mesg, mrb->eException_class))
442       mrb_raise(mrb, mrb->eException_class, "exception object expected");
443     if (argc > 2)
444       set_backtrace(mrb, mesg, argv[2]);
445   }
446
447   return mesg;
448 }
449
450 MRB_API void
451 mrb_sys_fail(mrb_state *mrb, const char *mesg)
452 {
453   struct RClass *sce;
454   mrb_int no;
455
456   no = (mrb_int)errno;
457   if (mrb_class_defined(mrb, "SystemCallError")) {
458     sce = mrb_class_get(mrb, "SystemCallError");
459     if (mesg != NULL) {
460       mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 2, mrb_fixnum_value(no), mrb_str_new_cstr(mrb, mesg));
461     }
462     else {
463       mrb_funcall(mrb, mrb_obj_value(sce), "_sys_fail", 1, mrb_fixnum_value(no));
464     }
465   }
466   else {
467     mrb_raise(mrb, E_RUNTIME_ERROR, mesg);
468   }
469 }
470
471 MRB_API mrb_noreturn void
472 mrb_no_method_error(mrb_state *mrb, mrb_sym id, mrb_value args, char const* fmt, ...)
473 {
474   mrb_value exc;
475   mrb_value argv[3];
476   va_list ap;
477
478   va_start(ap, fmt);
479   argv[0] = mrb_vformat(mrb, fmt, ap);
480   argv[1] = mrb_symbol_value(id);
481   argv[2] = args;
482   va_end(ap);
483   exc = mrb_obj_new(mrb, E_NOMETHOD_ERROR, 3, argv);
484   mrb_exc_raise(mrb, exc);
485 }
486
487 void
488 mrb_init_exception(mrb_state *mrb)
489 {
490   struct RClass *exception, *script_error, *stack_error, *nomem_error;
491
492   mrb->eException_class = exception = mrb_define_class(mrb, "Exception", mrb->object_class); /* 15.2.22 */
493   MRB_SET_INSTANCE_TT(exception, MRB_TT_EXCEPTION);
494   mrb_define_class_method(mrb, exception, "exception", mrb_instance_new,  MRB_ARGS_ANY());
495   mrb_define_method(mrb, exception, "exception",       exc_exception,     MRB_ARGS_ANY());
496   mrb_define_method(mrb, exception, "initialize",      exc_initialize,    MRB_ARGS_ANY());
497   mrb_define_method(mrb, exception, "to_s",            exc_to_s,          MRB_ARGS_NONE());
498   mrb_define_method(mrb, exception, "message",         exc_message,       MRB_ARGS_NONE());
499   mrb_define_method(mrb, exception, "inspect",         exc_inspect,       MRB_ARGS_NONE());
500   mrb_define_method(mrb, exception, "backtrace",       mrb_exc_backtrace, MRB_ARGS_NONE());
501   mrb_define_method(mrb, exception, "set_backtrace",   exc_set_backtrace, MRB_ARGS_REQ(1));
502
503   mrb->eStandardError_class = mrb_define_class(mrb, "StandardError", mrb->eException_class); /* 15.2.23 */
504   mrb_define_class(mrb, "RuntimeError", mrb->eStandardError_class);          /* 15.2.28 */
505   script_error = mrb_define_class(mrb, "ScriptError", mrb->eException_class);                /* 15.2.37 */
506   mrb_define_class(mrb, "SyntaxError", script_error);                                        /* 15.2.38 */
507   stack_error = mrb_define_class(mrb, "SystemStackError", exception);
508   mrb->stack_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, stack_error, "stack level too deep"));
509
510   nomem_error = mrb_define_class(mrb, "NoMemoryError", exception);
511   mrb->nomem_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "Out of memory"));
512 #ifdef MRB_GC_FIXED_ARENA
513   mrb->arena_err = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, nomem_error, "arena overflow error"));
514 #endif
515 }