diff --git a/.gitattributes b/.gitattributes index 4f72709808f1145a2484ec934325796a0e886c10..12b4a01c97918771b3afd2d871cc3ef2292f3f9d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -531,6 +531,7 @@ testfont binary /src/peep.in foreign_ident /src/peep_t.c foreign_ident /src/pike-module.in foreign_ident +/src/pike_error.h foreign_ident /src/pike_macros.h foreign_ident /src/pike_memory.c foreign_ident /src/pike_memory.h foreign_ident diff --git a/src/pike_error.h b/src/pike_error.h new file mode 100644 index 0000000000000000000000000000000000000000..06cb2c28f767813224e4c7cfc6df6c8903a61e43 --- /dev/null +++ b/src/pike_error.h @@ -0,0 +1,302 @@ +/*\ +||| This file a part of Pike, and is copyright by Fredrik Hubinette +||| Pike is distributed as GPL (General Public License) +||| See the files COPYING and DISCLAIMER for more information. +\*/ + +/* + * $Id: pike_error.h,v 1.1 2000/12/01 06:17:40 hubbe Exp $ + */ +#ifndef ERROR_H +#define ERROR_H + +#include "machine.h" + +#ifdef HAVE_SETJMP_H +#include <setjmp.h> +#undef HAVE_SETJMP_H +#endif + +#include <stdarg.h> + +#include "svalue.h" + + +typedef void (*error_call)(void *); + +#ifndef STRUCT_FRAME_DECLARED +#define STRUCT_FRAME_DECLARED +struct pike_frame; +#endif + +#define THROW_ERROR 10 +#define THROW_THREAD_EXIT 20 +#define THROW_THREAD_KILLED 30 +#define THROW_EXIT 40 +#define THROW_MAX_SEVERITY 100 + +/* #define ONERROR_DEBUG */ + +#ifdef ONERROR_DEBUG +#define OED_FPRINTF(X) fprintf X +#else /* !ONERROR_DEBUG */ +#define OED_FPRINTF(X) +#endif /* ONERROR_DEBUG */ + +typedef struct ONERROR +{ + struct ONERROR *previous; + error_call func; + void *arg; +#ifdef PIKE_DEBUG + const char *file; + int line; +#endif /* PIKE_DEBUG */ +} ONERROR; + +typedef struct JMP_BUF +{ + struct JMP_BUF *previous; + jmp_buf recovery; + struct pike_frame *frame_pointer; + ptrdiff_t stack_pointer; + ptrdiff_t mark_sp; + INT32 severity; + ONERROR *onerror; +#ifdef PIKE_DEBUG + int line; + char *file; +#endif +} JMP_BUF; + +extern struct svalue throw_value; +extern int throw_severity; + +#ifdef PIKE_DEBUG +#define UNSETJMP(X) do{ \ + check_recovery_context(); \ + OED_FPRINTF((stderr, "unsetjmp(%p) %s:%d\n", \ + &(X), __FILE__, __LINE__)); \ + if(Pike_interpreter.recoveries != &X) { \ + if(Pike_interpreter.recoveries) \ + fatal("UNSETJMP out of sync! (last SETJMP at %s:%d)!\n",Pike_interpreter.recoveries->file,Pike_interpreter.recoveries->line); \ + else \ + fatal("UNSETJMP out of sync! (Pike_interpreter.recoveries = 0)\n"); \ + } \ + Pike_interpreter.recoveries=X.previous; \ + check_recovery_context(); \ + }while (0) +#define DEBUG_LINE_ARGS ,int line, char *file +#define SETJMP(X) setjmp((init_recovery(&X,__LINE__,__FILE__)->recovery)) +#else +#define DEBUG_LINE_ARGS +#define SETJMP(X) setjmp((init_recovery(&X)->recovery)) +#define UNSETJMP(X) Pike_interpreter.recoveries=X.previous +#endif + + +#ifdef PIKE_DEBUG +#define SET_ONERROR(X,Y,Z) \ + do{ \ + check_recovery_context(); \ + OED_FPRINTF((stderr, "SET_ONERROR(%p, %p, %p) %s:%d\n", \ + &(X), (Y), (void *)(Z), __FILE__, __LINE__)); \ + X.func=(error_call)(Y); \ + DO_IF_DMALLOC( if( X.func == free ) X.func=dmalloc_free;) \ + X.arg=(void *)(Z); \ + if(!Pike_interpreter.recoveries) break; \ + X.previous=Pike_interpreter.recoveries->onerror; \ + X.file = __FILE__; \ + X.line = __LINE__; \ + Pike_interpreter.recoveries->onerror=&X; \ + }while(0) + +#define UNSET_ONERROR(X) do {\ + check_recovery_context(); \ + OED_FPRINTF((stderr, "UNSET_ONERROR(%p) %s:%d\n", \ + &(X), __FILE__, __LINE__)); \ + if(!Pike_interpreter.recoveries) break; \ + if(Pike_interpreter.recoveries->onerror != &(X)) { \ + fprintf(stderr,"LAST SETJMP: %s:%d\n",Pike_interpreter.recoveries->file,Pike_interpreter.recoveries->line); \ + if (Pike_interpreter.recoveries->onerror) { \ + fatal("UNSET_ONERROR out of sync (%p != %p).\n" \ + "Last SET_ONERROR is from %s:%d\n",\ + Pike_interpreter.recoveries->onerror, &(X), \ + Pike_interpreter.recoveries->onerror->file, Pike_interpreter.recoveries->onerror->line ); \ + } else { \ + fatal("UNSET_ONERROR out of sync. No Pike_interpreter.recoveries left.\n"); \ + } \ + } \ + Pike_interpreter.recoveries->onerror=(X).previous; \ + } while(0) + +#define ASSERT_ONERROR(X) \ + do{ \ + if (!Pike_interpreter.recoveries) break; \ + if (Pike_interpreter.recoveries->onerror != &X) { \ + fatal("%s:%d ASSERT_ONERROR(%p) failed\n", \ + __FILE__, __LINE__, &(X)); \ + } \ + }while(0) +#else /* !PIKE_DEBUG */ +#define SET_ONERROR(X,Y,Z) \ + do{ \ + X.func=(error_call)(Y); \ + X.arg=(void *)(Z); \ + if(!Pike_interpreter.recoveries) break; \ + X.previous=Pike_interpreter.recoveries->onerror; \ + Pike_interpreter.recoveries->onerror=&X; \ + }while(0) + +#define UNSET_ONERROR(X) Pike_interpreter.recoveries && (Pike_interpreter.recoveries->onerror=X.previous) + +#define ASSERT_ONERROR(X) +#endif /* PIKE_DEBUG */ + +#define CALL_AND_UNSET_ONERROR(X) do { \ + X.func(X.arg); \ + UNSET_ONERROR(X); \ + }while(0) + +#if defined(PIKE_DEBUG) && 0 +/* Works, but probably not interresting for most people + * /grubba 1998-04-11 + */ +#define PIKE_ERROR(NAME, TEXT, SP, ARGS) new_error(NAME, TEXT, SP, ARGS, __FILE__, __LINE__); +#else +#define PIKE_ERROR(NAME, TEXT, SP, ARGS) new_error(NAME, TEXT, SP, ARGS, NULL, 0); +#endif /* PIKE_DEBUG */ + +/* Prototypes begin here */ +void check_recovery_context(void); +PMOD_EXPORT void pike_gdb_breakpoint(void); +PMOD_EXPORT JMP_BUF *init_recovery(JMP_BUF *r DEBUG_LINE_ARGS); +PMOD_EXPORT DECLSPEC(noreturn) void pike_throw(void) ATTRIBUTE((noreturn)); +PMOD_EXPORT void push_error(char *description); +PMOD_EXPORT DECLSPEC(noreturn) void low_error(char *buf) ATTRIBUTE((noreturn)); +void va_error(const char *fmt, va_list args) ATTRIBUTE((noreturn)); +PMOD_EXPORT DECLSPEC(noreturn) void new_error(const char *name, const char *text, struct svalue *oldsp, + INT32 args, const char *file, int line) ATTRIBUTE((noreturn)); +PMOD_EXPORT void exit_on_error(void *msg); +PMOD_EXPORT void fatal_on_error(void *msg); +PMOD_EXPORT DECLSPEC(noreturn) void Pike_error(const char *fmt,...) ATTRIBUTE((noreturn,format (printf, 1, 2))); +PMOD_EXPORT DECLSPEC(noreturn) void debug_fatal(const char *fmt, ...) ATTRIBUTE((noreturn,format (printf, 1, 2))); +void f_error_cast(INT32 args); +void f_error_index(INT32 args); +void f_error_describe(INT32 args); +void f_error_backtrace(INT32 args); +void DECLSPEC(noreturn) generic_error_va(struct object *o, + char *func, + struct svalue *base_sp, int args, + char *fmt, + va_list foo) + ATTRIBUTE((noreturn)); +void DECLSPEC(noreturn) generic_error( + char *func, + struct svalue *base_sp, int args, + char *desc, ...) ATTRIBUTE((noreturn,format (printf, 4, 5))); +void DECLSPEC(noreturn) index_error( + char *func, + struct svalue *base_sp, int args, + struct svalue *val, + struct svalue *ind, + char *desc, ...) ATTRIBUTE((noreturn,format (printf, 6, 7))); +void DECLSPEC(noreturn) bad_arg_error( + char *func, + struct svalue *base_sp, int args, + int which_arg, + char *expected_type, + struct svalue *got, + char *desc, ...) ATTRIBUTE((noreturn,format (printf, 7, 8))); +void DECLSPEC(noreturn) math_error( + char *func, + struct svalue *base_sp, int args, + struct svalue *number, + char *desc, ...) ATTRIBUTE((noreturn,format (printf, 5, 6))); +void DECLSPEC(noreturn) resource_error( + char *func, + struct svalue *base_sp, int args, + char *resource_type, + size_t howmuch, + char *desc, ...) ATTRIBUTE((noreturn,format (printf, 6, 7))); +void DECLSPEC(noreturn) permission_error( + char *func, + struct svalue *base_sp, int args, + char *permission_type, + char *desc, ...) ATTRIBUTE((noreturn, format(printf, 5, 6))); +void wrong_number_of_args_error(char *name, int args, int expected); +void init_error(void); +void cleanup_error(void); +/* Prototypes end here */ + +#define fatal \ + fprintf(stderr,"%s:%d: Fatal Pike_error:\n",__FILE__,__LINE__),debug_fatal + +/* Some useful Pike_error macros. */ + +#define SIMPLE_BAD_ARG_ERROR(FUNC, ARG, EXPECT) \ + bad_arg_error(FUNC, Pike_sp-args, args, ARG, EXPECT, Pike_sp+ARG-1-args,\ + "Bad argument %d to %s(). Expected %s\n", \ + ARG, FUNC, EXPECT) + +#define SIMPLE_TOO_FEW_ARGS_ERROR(FUNC, ARG) \ + bad_arg_error(FUNC, Pike_sp-args, args, ARG, "void", 0,\ + "Too few arguments to %s().\n",FUNC) + +#define SIMPLE_OUT_OF_MEMORY_ERROR(FUNC, AMOUNT) \ + resource_error(FUNC, Pike_sp-args, args, "memory", AMOUNT, "Out of memory.\n") + +#define SIMPLE_DIVISION_BY_ZERO_ERROR(FUNC) \ + math_error(FUNC, Pike_sp-args, args, 0, "Division by zero.\n") + +#ifndef PIKE_DEBUG +#define check_recovery_context() ((void)0) +#endif + +/* Experimental convenience exception macros. */ + +#define exception_try \ + do \ + { \ + int __exception_rethrow, __is_exception; \ + JMP_BUF exception; \ + __is_exception = SETJMP(exception); \ + __exception_rethrow = 0; \ + if(__is_exception) /* rethrow needs this */ \ + UNSETJMP(exception); \ + if(!__is_exception) + +#define exception_catch_if \ + else if + +#define exception_catch(e) \ + exception_catch_if(exception->severity = (e)) + +#define exception_catch_all \ + exception_catch_if(1) + +#define exception_semicatch_all \ + exception_catch_if((__exception_rethrow = 1)) + +#define rethrow \ + pike_throw() + +#define exception_endtry \ + else \ + __exception_rethrow = 1; \ + if(!__is_exception) \ + UNSETJMP(exception); \ + if(__exception_rethrow) \ + rethrow; \ + } \ + while(0) + +#ifndef NO_PIKE_SHORTHAND +#define error Pike_error +#endif + +/* Generic Pike_error stuff */ +#define ERR_EXT_DECLARE +#include "errors.h" + +#endif