[TT# 1592][t] Improve test for open opcode delegation. All tests in the file pass...
[parrot.git] / src / exceptions.c
blob9e3c176915f6072f54c17e529745e9d46a5b7588
1 /*
2 Copyright (C) 2001-2010, Parrot Foundation.
3 $Id$
5 =head1 NAME
7 src/exceptions.c - Exceptions
9 =head1 DESCRIPTION
11 Define the the core subsystem for exceptions.
13 =head2 Exception Functions
15 =over 4
17 =cut
21 #include "parrot/parrot.h"
22 #include "exceptions.str"
23 #include "pmc/pmc_continuation.h"
25 /* HEADERIZER HFILE: include/parrot/exceptions.h */
27 /* HEADERIZER BEGIN: static */
28 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
30 PARROT_CANNOT_RETURN_NULL
31 static PMC * build_exception_from_args(PARROT_INTERP,
32 int ex_type,
33 ARGIN(const char *format),
34 va_list arglist)
35 __attribute__nonnull__(1)
36 __attribute__nonnull__(3);
38 PARROT_CAN_RETURN_NULL
39 static void setup_exception_args(PARROT_INTERP, ARGIN(const char *sig), ...)
40 __attribute__nonnull__(1)
41 __attribute__nonnull__(2);
43 #define ASSERT_ARGS_build_exception_from_args __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
44 PARROT_ASSERT_ARG(interp) \
45 , PARROT_ASSERT_ARG(format))
46 #define ASSERT_ARGS_setup_exception_args __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
47 PARROT_ASSERT_ARG(interp) \
48 , PARROT_ASSERT_ARG(sig))
49 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
50 /* HEADERIZER END: static */
52 #include <stdarg.h>
56 =item C<PMC * Parrot_ex_build_exception(PARROT_INTERP, INTVAL severity, long
57 error, STRING *msg)>
59 Constructs a new exception object from the passed in arguments.
61 =cut
64 PARROT_EXPORT
65 PARROT_CAN_RETURN_NULL
66 PMC *
67 Parrot_ex_build_exception(PARROT_INTERP, INTVAL severity,
68 long error, ARGIN_NULLOK(STRING *msg))
70 ASSERT_ARGS(Parrot_ex_build_exception)
71 PMC *exception = Parrot_pmc_new(interp, enum_class_Exception);
73 VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "severity"), severity);
74 VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "type"), error);
75 if (msg)
76 VTABLE_set_string_native(interp, exception, msg);
78 return exception;
83 =item C<void die_from_exception(PARROT_INTERP, PMC *exception)>
85 Print a stack trace for C<exception>, a message if there is one, and then exit.
87 =cut
91 PARROT_DOES_NOT_RETURN
92 PARROT_COLD
93 void
94 die_from_exception(PARROT_INTERP, ARGIN(PMC *exception))
96 ASSERT_ARGS(die_from_exception)
97 STRING * const message = VTABLE_get_string(interp, exception);
98 INTVAL exit_status = 1;
99 const INTVAL severity = VTABLE_get_integer_keyed_str(interp, exception, CONST_STRING(interp, "severity"));
101 /* In some cases we have a fatal exception before the IO system
102 * is completely initialized. Do some attempt to output the
103 * message to stderr, to help diagnosing. */
104 int use_perr = !PMC_IS_NULL(Parrot_io_STDERR(interp));
106 /* flush interpreter output to get things printed in order */
107 if (!PMC_IS_NULL(Parrot_io_STDOUT(interp)))
108 Parrot_io_flush(interp, Parrot_io_STDOUT(interp));
109 if (use_perr)
110 Parrot_io_flush(interp, Parrot_io_STDERR(interp));
112 if (interp->pdb) {
113 Interp * interpdeb = interp->pdb->debugger;
114 if (interpdeb) {
115 Parrot_io_flush(interpdeb, Parrot_io_STDOUT(interpdeb));
116 Parrot_io_flush(interpdeb, Parrot_io_STDERR(interpdeb));
120 if (Parrot_str_not_equal(interp, message, CONST_STRING(interp, ""))) {
121 if (use_perr)
122 Parrot_io_eprintf(interp, "%S\n", message);
123 else {
124 char * const msg = Parrot_str_to_cstring(interp, message);
125 fflush(stderr);
126 fprintf(stderr, "\n%s\n", msg);
127 Parrot_str_free_cstring(msg);
130 /* caution against output swap (with PDB_backtrace) */
131 fflush(stderr);
132 PDB_backtrace(interp);
134 else if (severity == EXCEPT_exit) {
135 /* TODO: get exit status based on type */
136 exit_status = VTABLE_get_integer_keyed_str(interp, exception, CONST_STRING(interp, "exit_code"));
138 else {
139 Parrot_io_eprintf(interp, "No exception handler and no message\n");
140 /* caution against output swap (with PDB_backtrace) */
141 fflush(stderr);
142 PDB_backtrace(interp);
146 * returning NULL from here returns resume address NULL to the
147 * runloop, which will terminate the thread function finally
149 * TT #1287 this check should better be in Parrot_exit
152 /* no exception handler, but this is not the main thread */
153 if (interp->thread_data && interp->thread_data->tid)
154 pt_thread_detach(interp->thread_data->tid);
157 * only main should run the destroy functions - exit handler chain
158 * is freed during Parrot_exit
160 Parrot_exit(interp, exit_status);
165 =item C<void Parrot_ex_add_c_handler(PARROT_INTERP, Parrot_runloop *jp)>
167 Adds a new exception handler (defined in C) to the concurrency scheduler. Since
168 the exception handler is C code, it stores a runloop jump point to the start of
169 the handler code.
171 =cut
175 PARROT_EXPORT
176 void
177 Parrot_ex_add_c_handler(PARROT_INTERP, ARGIN(Parrot_runloop *jp))
179 ASSERT_ARGS(Parrot_ex_add_c_handler)
180 PMC * const handler = Parrot_pmc_new(interp, enum_class_ExceptionHandler);
181 /* Flag to mark a C exception handler */
182 PObj_get_FLAGS(handler) |= SUB_FLAG_C_HANDLER;
183 VTABLE_set_pointer(interp, handler, jp);
184 Parrot_cx_add_handler_local(interp, handler);
189 =item C<opcode_t * Parrot_ex_throw_from_op(PARROT_INTERP, PMC *exception, void
190 *dest)>
192 Throw an exception from inside an op. Looks for an exception handler in the
193 current concurrency scheduler. If a suitable handler is found, invoke it and
194 return the address where execution should continue. If no handler is found,
195 the exception message is printed along with the current line number
196 annotation and a backtrace before exiting Parrot.
198 =cut
202 PARROT_EXPORT
203 PARROT_CAN_RETURN_NULL
204 opcode_t *
205 Parrot_ex_throw_from_op(PARROT_INTERP, ARGIN(PMC *exception), ARGIN_NULLOK(void *dest))
207 ASSERT_ARGS(Parrot_ex_throw_from_op)
208 opcode_t *address;
209 PMC * const handler = Parrot_cx_find_handler_local(interp, exception);
210 if (PMC_IS_NULL(handler)) {
211 STRING * const message = VTABLE_get_string(interp, exception);
212 const INTVAL severity = VTABLE_get_integer_keyed_str(interp, exception, CONST_STRING(interp, "severity"));
213 if (severity < EXCEPT_error) {
214 PMC * const resume = VTABLE_get_attr_str(interp, exception, CONST_STRING(interp, "resume"));
215 if (Parrot_str_not_equal(interp, message, CONST_STRING(interp, ""))) {
216 Parrot_io_eprintf(interp, "%S\n", message);
218 else {
219 Parrot_io_eprintf(interp, "%S\n", CONST_STRING(interp, "Warning"));
222 /* caution against output swap (with PDB_backtrace) */
223 fflush(stderr);
224 /* PDB_backtrace(interp); */
226 if (!PMC_IS_NULL(resume)) {
227 return VTABLE_invoke(interp, resume, NULL);
230 die_from_exception(interp, exception);
233 address = VTABLE_invoke(interp, handler, dest);
234 setup_exception_args(interp, "P", exception);
236 if (PObj_get_FLAGS(handler) & SUB_FLAG_C_HANDLER) {
237 /* it's a C exception handler */
238 Parrot_runloop * const jump_point = (Parrot_runloop *)address;
239 longjmp(jump_point->resume, 1);
242 /* return the address of the handler */
243 return address;
248 =item C<static void setup_exception_args(PARROT_INTERP, const char *sig, ...)>
250 Sets up arguments to the exception handler invocation.
252 =cut
256 PARROT_CAN_RETURN_NULL
257 static void
258 setup_exception_args(PARROT_INTERP, ARGIN(const char *sig), ...)
260 ASSERT_ARGS(setup_exception_args)
261 va_list args;
262 PMC *sig_obj;
264 va_start(args, sig);
265 sig_obj = Parrot_pcc_build_call_from_varargs(interp, PMCNULL, sig, &args);
266 va_end(args);
268 CALLSIGNATURE_is_exception_SET(sig_obj);
270 Parrot_pcc_set_signature(interp, CURRENT_CONTEXT(interp), sig_obj);
275 =item C<static PMC * build_exception_from_args(PARROT_INTERP, int ex_type, const
276 char *format, va_list arglist)>
278 Builds an exception PMC with the given integer type C<ex_type>, and the string
279 message given as a format/arglist combo, like is used by the Parrot_vsprintf*
280 family of functions.
282 =cut
286 PARROT_CANNOT_RETURN_NULL
287 static PMC *
288 build_exception_from_args(PARROT_INTERP, int ex_type,
289 ARGIN(const char *format), va_list arglist)
291 ASSERT_ARGS(build_exception_from_args)
292 /* Make and set exception message. */
293 STRING * const msg =
294 strchr(format, '%')
295 ? Parrot_vsprintf_c(interp, format, arglist)
296 : string_make(interp, format, strlen(format), NULL, 0);
298 return Parrot_ex_build_exception(interp, EXCEPT_error, ex_type, msg);
303 =item C<void Parrot_ex_throw_from_c(PARROT_INTERP, PMC *exception)>
305 Throws an exception object from any location in C code. A suitable handler
306 is retrieved from the concurrency scheduler. If the handler is found, control
307 flow is passed to it. Handlers can be either C-level or PIR-level routines. If
308 no suitable handler is found, Parrot exits with the stored exception error
309 message.
311 See also C<exit_fatal()>, which signals fatal errors, and
312 C<Parrot_ex_throw_from_op> which throws an exception from within an op.
314 The 'invoke' vtable function doesn't actually execute a
315 sub/continuation/handler, it only sets up the environment for invocation and
316 returns the address of the start of the sub's code. That address then becomes
317 the next op in the runloop.
319 Exceptions thrown from C and caught by a continuation-based handler are
320 resumable at the level of a C instruction. When handled, they return the
321 exception object. Any values returned from the handler to the C code that threw
322 the exception can be stored in the exception's payload.
324 =cut
328 PARROT_EXPORT
329 PARROT_DOES_NOT_RETURN
330 PARROT_COLD
331 void
332 Parrot_ex_throw_from_c(PARROT_INTERP, ARGIN(PMC *exception))
334 ASSERT_ARGS(Parrot_ex_throw_from_c)
336 Parrot_runloop *return_point = interp->current_runloop;
337 opcode_t *address;
338 PMC * const handler =
339 Parrot_cx_find_handler_local(interp, exception);
341 if (PMC_IS_NULL(handler))
342 die_from_exception(interp, exception);
344 if (Interp_debug_TEST(interp, PARROT_BACKTRACE_DEBUG_FLAG)) {
345 STRING * const exit_code = CONST_STRING(interp, "exit_code");
346 STRING * const msg = VTABLE_get_string(interp, exception);
347 int exitcode = VTABLE_get_integer_keyed_str(interp,
348 exception, exit_code);
350 Parrot_io_eprintf(interp,
351 "Parrot_ex_throw_from_c (severity:%d error:%d): %Ss\n",
352 EXCEPT_error, exitcode, msg);
353 PDB_backtrace(interp);
356 /* Note the thrower.
357 * XXX TT #596 - pass in current context instead when we have context PMCs. */
358 /* Don't split line. It will break CONST_STRING handling */
359 VTABLE_set_attr_str(interp, exception, CONST_STRING(interp, "thrower"), Parrot_pcc_get_continuation(interp, CURRENT_CONTEXT(interp)));
362 /* it's a C exception handler */
363 if (PObj_get_FLAGS(handler) & SUB_FLAG_C_HANDLER) {
364 Parrot_runloop * const jump_point =
365 (Parrot_runloop * const)VTABLE_get_pointer(interp, handler);
366 longjmp(jump_point->resume, 1);
369 /* Run the handler. */
370 address = VTABLE_invoke(interp, handler, NULL);
371 setup_exception_args(interp, "P", exception);
372 PARROT_ASSERT(return_point->handler_start == NULL);
373 return_point->handler_start = address;
374 longjmp(return_point->resume, 2);
379 =item C<opcode_t * Parrot_ex_throw_from_op_args(PARROT_INTERP, void *dest, int
380 ex_type, const char *format, ...)>
382 Throws an exception from an opcode, with an error message constructed
383 from a format string and arguments. Constructs an Exception PMC, and passes it
384 to C<Parrot_ex_throw_from_op>.
386 See also C<Parrot_ex_throw_from_c> and C<exit_fatal()>.
388 =cut
392 PARROT_EXPORT
393 PARROT_CAN_RETURN_NULL
394 opcode_t *
395 Parrot_ex_throw_from_op_args(PARROT_INTERP, ARGIN_NULLOK(void *dest),
396 int ex_type, ARGIN(const char *format), ...)
398 ASSERT_ARGS(Parrot_ex_throw_from_op_args)
399 PMC *exception;
401 va_list arglist;
402 va_start(arglist, format);
403 exception = build_exception_from_args(interp, ex_type, format, arglist);
404 va_end(arglist);
406 return Parrot_ex_throw_from_op(interp, exception, dest);
411 =item C<void Parrot_ex_throw_from_c_args(PARROT_INTERP, void *ret_addr, int
412 exitcode, const char *format, ...)>
414 Throws an exception, with an error message constructed from a format string and
415 arguments. C<ret_addr> is the address from which to resume, if some handler
416 decides that is appropriate, or zero to make the error non-resumable.
417 C<exitcode> is a C<exception_type_enum> value. Constructs an Exception PMC
418 and passes it to C<Parrot_ex_throw_from_c>.
420 See also C<Parrot_ex_throw_from_op> and C<exit_fatal()>.
422 =cut
426 PARROT_EXPORT
427 PARROT_DOES_NOT_RETURN
428 PARROT_COLD
429 void
430 Parrot_ex_throw_from_c_args(PARROT_INTERP, SHIM(void *ret_addr),
431 int exitcode, ARGIN(const char *format), ...)
433 ASSERT_ARGS(Parrot_ex_throw_from_c_args)
434 PMC *exception;
436 va_list arglist;
437 va_start(arglist, format);
438 exception = build_exception_from_args(interp, exitcode, format, arglist);
439 va_end(arglist);
441 Parrot_ex_throw_from_c(interp, exception);
446 =item C<opcode_t * Parrot_ex_rethrow_from_op(PARROT_INTERP, PMC *exception)>
448 Rethrow the given exception from an op, if it has previously been thrown and
449 not handled by the provided handler. Marks the exception object as being
450 unhandled and throws it again.
452 =cut
456 PARROT_EXPORT
457 PARROT_WARN_UNUSED_RESULT
458 PARROT_CAN_RETURN_NULL
459 opcode_t *
460 Parrot_ex_rethrow_from_op(PARROT_INTERP, ARGIN(PMC *exception))
462 ASSERT_ARGS(Parrot_ex_rethrow_from_op)
464 Parrot_ex_mark_unhandled(interp, exception);
466 return Parrot_ex_throw_from_op(interp, exception, NULL);
471 =item C<void Parrot_ex_rethrow_from_c(PARROT_INTERP, PMC *exception)>
473 Rethrow the exception from C code. Marks the Exception PMC as being unhandled
474 and throws it again.
476 =cut
480 PARROT_EXPORT
481 PARROT_DOES_NOT_RETURN
482 PARROT_COLD
483 void
484 Parrot_ex_rethrow_from_c(PARROT_INTERP, ARGIN(PMC *exception))
486 ASSERT_ARGS(Parrot_ex_rethrow_from_c)
487 Parrot_ex_mark_unhandled(interp, exception);
489 Parrot_ex_throw_from_c(interp, exception);
494 =item C<void Parrot_ex_mark_unhandled(PARROT_INTERP, PMC *exception)>
496 Mark an exception as unhandled, as part of rethrowing it.
498 =back
500 =cut
504 PARROT_EXPORT
505 void
506 Parrot_ex_mark_unhandled(PARROT_INTERP, ARGIN(PMC *exception))
508 ASSERT_ARGS(Parrot_ex_mark_unhandled)
509 VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "handled"), -1);
514 =head2 Error Functions
516 =over 4
518 =item C<void Parrot_assert(INTVAL condition, const char *condition_string, const
519 char *file, unsigned int line)>
521 A better version of assert() that gives a backtrace.
523 =cut
527 PARROT_EXPORT
528 PARROT_DOES_NOT_RETURN_WHEN_FALSE
529 void
530 Parrot_assert(INTVAL condition, ARGIN(const char *condition_string),
531 ARGIN(const char *file), unsigned int line)
533 ASSERT_ARGS(Parrot_assert)
534 if (!condition)
535 Parrot_confess(condition_string, file, line);
540 =item C<void Parrot_confess(const char *cond, const char *file, unsigned int
541 line)>
543 Prints a backtrace and message for a failed assertion.
545 =cut
549 PARROT_EXPORT
550 PARROT_DOES_NOT_RETURN
551 PARROT_COLD
552 void
553 Parrot_confess(ARGIN(const char *cond), ARGIN(const char *file), unsigned int line)
555 ASSERT_ARGS(Parrot_confess)
556 fprintf(stderr, "%s:%u: failed assertion '%s'\n", file, line, cond);
557 Parrot_print_backtrace();
558 abort();
563 =item C<void Parrot_print_backtrace(void)>
565 Displays the primrose path to disaster, (the stack frames leading up to the
566 abort). Used by C<Parrot_confess>.
568 =cut
572 void
573 Parrot_print_backtrace(void)
575 ASSERT_ARGS(Parrot_print_backtrace)
576 #ifdef PARROT_HAS_BACKTRACE
577 # define BACKTRACE_DEPTH 32
578 /*# define BACKTRACE_VERBOSE */
579 # ifndef PARROT_HAS_DLINFO
580 # define BACKTRACE_VERBOSE
581 # endif
582 /* stolen from http://www.delorie.com/gnu/docs/glibc/libc_665.html */
583 void *array[BACKTRACE_DEPTH];
584 int i;
586 const int size = backtrace(array, BACKTRACE_DEPTH);
588 fprintf(stderr,
589 "Backtrace - Obtained %d stack frames (max trace depth is %d).\n",
590 size, BACKTRACE_DEPTH);
591 # ifndef BACKTRACE_VERBOSE
592 for (i = 0; i < size; i++) {
593 Dl_info frameInfo;
594 const int found = dladdr(array[i], &frameInfo);
596 /* always indent */
597 const int indent = 2 + (2 * i);
599 fprintf(stderr, "%*s", indent, "");
601 if (found && frameInfo.dli_sname)
602 fprintf(stderr, "%s\n", frameInfo.dli_sname);
603 else
604 fprintf(stderr, "(unknown)\n");
607 # else
608 { /* Scope for strings */
609 char ** strings = backtrace_symbols(array, size);
610 if (strings) {
611 for (i = 0; i < size; i++)
612 fprintf(stderr, "%s\n", strings[i]);
613 /* backtrace_symbols gets memory using malloc */
614 free(strings);
616 else
617 fputs("Not enough memory for backtrace_symbols\n", stderr);
619 # endif
621 # undef BACKTRACE_DEPTH
622 #endif /* ifdef PARROT_HAS_BACKTRACE */
627 =item C<void exit_fatal(int exitcode, const char *format, ...)>
629 Signal a fatal error condition. This should only be used with dire errors that
630 cannot throw an exception (because no interpreter is available, or the nature
631 of the error would interfere with the exception system).
633 This involves printing an error message to stderr, and calling C<exit> to exit
634 the process with the given exitcode. It is not possible for Parrot bytecode to
635 intercept a fatal error (for that, use C<Parrot_ex_throw_from_c_args>).
636 C<exit_fatal> does not call C<Parrot_exit> to invoke exit handlers (that would
637 require an interpreter).
639 =cut
643 PARROT_EXPORT
644 PARROT_DOES_NOT_RETURN
645 PARROT_COLD
646 void
647 exit_fatal(int exitcode, ARGIN(const char *format), ...)
649 ASSERT_ARGS(exit_fatal)
650 va_list arglist;
651 va_start(arglist, format);
652 vfprintf(stderr, format, arglist);
653 fprintf(stderr, "\n");
654 /* caution against output swap (with PDB_backtrace) */
655 fflush(stderr);
656 va_end(arglist);
657 exit(exitcode);
660 /* The DUMPCORE macro is defined for most platforms, but defined here if not
661 * found elsewhere, so we're sure it's safe to call. */
663 #ifndef DUMPCORE
664 # define DUMPCORE() \
665 fprintf(stderr, "Sorry, coredump is not yet implemented " \
666 "for this platform.\n\n"); \
667 exit(EXIT_FAILURE);
668 #endif
672 =item C<void do_panic(NULLOK_INTERP, const char *message, const char *file,
673 unsigned int line)>
675 Panic handler. Things have gone very wrong in an unexpected way. Print out an
676 error message and instructions for the user to report the error to the
677 developers
679 =cut
683 PARROT_DOES_NOT_RETURN
684 PARROT_COLD
685 void
686 do_panic(NULLOK_INTERP, ARGIN_NULLOK(const char *message),
687 ARGIN_NULLOK(const char *file), unsigned int line)
689 ASSERT_ARGS(do_panic)
690 /* Note: we can't format any floats in here--Parrot_sprintf
691 ** may panic because of floats.
692 ** and we don't use Parrot_sprintf or such, because we are
693 ** already in panic --leo
695 fprintf(stderr, "Parrot VM: PANIC: %s!\n",
696 message ? message : "(no message available)");
698 fprintf(stderr, "C file %s, line %u\n",
699 file ? file : "(not available)", line);
701 fprintf(stderr, "Parrot file (not available), ");
702 fprintf(stderr, "line (not available)\n");
704 fprintf(stderr, "\n\
705 We highly suggest you notify the Parrot team if you have not been working on\n\
706 Parrot. Use parrotbug (located in parrot's root directory) or send an\n\
707 e-mail to parrot-dev@lists.parrot.org.\n\
708 Include the entire text of this error message and the text of the script that\n\
709 generated the error. If you've made any modifications to Parrot, please\n\
710 describe them as well.\n\n");
712 fprintf(stderr, "Version : %s\n", PARROT_VERSION);
713 fprintf(stderr, "Configured : %s\n", PARROT_CONFIG_DATE);
714 fprintf(stderr, "Architecture: %s\n", PARROT_ARCHNAME);
715 fprintf(stderr, "JIT Capable : %s\n", JIT_CAPABLE ? "Yes" : "No");
716 if (interp)
717 fprintf(stderr, "Interp Flags: %#x\n", (unsigned int)interp->flags);
718 else
719 fprintf(stderr, "Interp Flags: (no interpreter)\n");
720 fprintf(stderr, "Exceptions : %s\n", "(missing from core)");
721 fprintf(stderr, "\nDumping Core...\n");
723 DUMPCORE();
729 =back
731 =head1 SEE ALSO
733 F<include/parrot/exceptions.h>.
735 =cut
741 * Local variables:
742 * c-file-style: "parrot"
743 * End:
744 * vim: expandtab shiftwidth=4: