2 Copyright (C) 2001-2010, Parrot Foundation.
7 src/exceptions.c - Exceptions
11 Define the the core subsystem for exceptions.
13 =head2 Exception Functions
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
,
33 ARGIN(const char *format
),
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 */
56 =item C<PMC * Parrot_ex_build_exception(PARROT_INTERP, INTVAL severity, long
59 Constructs a new exception object from the passed in arguments.
65 PARROT_CAN_RETURN_NULL
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
);
76 VTABLE_set_string_native(interp
, exception
, msg
);
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.
91 PARROT_DOES_NOT_RETURN
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
));
110 Parrot_io_flush(interp
, Parrot_io_STDERR(interp
));
113 Interp
* interpdeb
= interp
->pdb
->debugger
;
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
, ""))) {
122 Parrot_io_eprintf(interp
, "%S\n", message
);
124 char * const msg
= Parrot_str_to_cstring(interp
, message
);
126 fprintf(stderr
, "\n%s\n", msg
);
127 Parrot_str_free_cstring(msg
);
130 /* caution against output swap (with PDB_backtrace) */
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"));
139 Parrot_io_eprintf(interp
, "No exception handler and no message\n");
140 /* caution against output swap (with PDB_backtrace) */
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
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
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.
203 PARROT_CAN_RETURN_NULL
205 Parrot_ex_throw_from_op(PARROT_INTERP
, ARGIN(PMC
*exception
), ARGIN_NULLOK(void *dest
))
207 ASSERT_ARGS(Parrot_ex_throw_from_op
)
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
);
219 Parrot_io_eprintf(interp
, "%S\n", CONST_STRING(interp
, "Warning"));
222 /* caution against output swap (with PDB_backtrace) */
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 */
248 =item C<static void setup_exception_args(PARROT_INTERP, const char *sig, ...)>
250 Sets up arguments to the exception handler invocation.
256 PARROT_CAN_RETURN_NULL
258 setup_exception_args(PARROT_INTERP
, ARGIN(const char *sig
), ...)
260 ASSERT_ARGS(setup_exception_args
)
265 sig_obj
= Parrot_pcc_build_call_from_varargs(interp
, PMCNULL
, sig
, &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*
286 PARROT_CANNOT_RETURN_NULL
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. */
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
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.
329 PARROT_DOES_NOT_RETURN
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
;
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
);
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()>.
393 PARROT_CAN_RETURN_NULL
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
)
402 va_start(arglist
, format
);
403 exception
= build_exception_from_args(interp
, ex_type
, format
, 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()>.
427 PARROT_DOES_NOT_RETURN
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
)
437 va_start(arglist
, format
);
438 exception
= build_exception_from_args(interp
, exitcode
, format
, 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.
457 PARROT_WARN_UNUSED_RESULT
458 PARROT_CAN_RETURN_NULL
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
481 PARROT_DOES_NOT_RETURN
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.
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
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.
528 PARROT_DOES_NOT_RETURN_WHEN_FALSE
530 Parrot_assert(INTVAL condition
, ARGIN(const char *condition_string
),
531 ARGIN(const char *file
), unsigned int line
)
533 ASSERT_ARGS(Parrot_assert
)
535 Parrot_confess(condition_string
, file
, line
);
540 =item C<void Parrot_confess(const char *cond, const char *file, unsigned int
543 Prints a backtrace and message for a failed assertion.
550 PARROT_DOES_NOT_RETURN
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();
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>.
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
582 /* stolen from http://www.delorie.com/gnu/docs/glibc/libc_665.html */
583 void *array
[BACKTRACE_DEPTH
];
586 const int size
= backtrace(array
, BACKTRACE_DEPTH
);
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
++) {
594 const int found
= dladdr(array
[i
], &frameInfo
);
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
);
604 fprintf(stderr
, "(unknown)\n");
608 { /* Scope for strings */
609 char ** strings
= backtrace_symbols(array
, size
);
611 for (i
= 0; i
< size
; i
++)
612 fprintf(stderr
, "%s\n", strings
[i
]);
613 /* backtrace_symbols gets memory using malloc */
617 fputs("Not enough memory for backtrace_symbols\n", stderr
);
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).
644 PARROT_DOES_NOT_RETURN
647 exit_fatal(int exitcode
, ARGIN(const char *format
), ...)
649 ASSERT_ARGS(exit_fatal
)
651 va_start(arglist
, format
);
652 vfprintf(stderr
, format
, arglist
);
653 fprintf(stderr
, "\n");
654 /* caution against output swap (with PDB_backtrace) */
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. */
664 # define DUMPCORE() \
665 fprintf(stderr, "Sorry, coredump is not yet implemented " \
666 "for this platform.\n\n"); \
672 =item C<void do_panic(NULLOK_INTERP, const char *message, const char *file,
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
683 PARROT_DOES_NOT_RETURN
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");
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");
717 fprintf(stderr
, "Interp Flags: %#x\n", (unsigned int)interp
->flags
);
719 fprintf(stderr
, "Interp Flags: (no interpreter)\n");
720 fprintf(stderr
, "Exceptions : %s\n", "(missing from core)");
721 fprintf(stderr
, "\nDumping Core...\n");
733 F<include/parrot/exceptions.h>.
742 * c-file-style: "parrot"
744 * vim: expandtab shiftwidth=4: