cb22561995-10-11Fredrik Hübinette (Hubbe) /*\
06983f1996-09-22Fredrik Hübinette (Hubbe) ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License)
cb22561995-10-11Fredrik Hübinette (Hubbe) ||| See the files COPYING and DISCLAIMER for more information. \*/
2f748a1999-02-20Henrik Grubbström (Grubba) /**/
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "global.h"
bb55f81997-03-16Fredrik Hübinette (Hubbe) #include "pike_macros.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "error.h" #include "interpret.h" #include "stralloc.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "builtin_functions.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "array.h" #include "object.h"
ef7c761998-03-24Fredrik Hübinette (Hubbe) #include "main.h" #include "builtin_functions.h"
c08c8b1998-04-05Fredrik Hübinette (Hubbe) #include "backend.h"
4406cf1998-04-13Henrik Grubbström (Grubba) #include "operators.h"
81299f1999-03-19Fredrik Hübinette (Hubbe) #include "module_support.h"
db40ab1999-04-15Fredrik Hübinette (Hubbe) #include "threads.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) 
64dc4c1999-04-17Henrik Grubbström (Grubba) RCSID("$Id: error.c,v 1.34 1999/04/17 13:47:16 grubba Exp $");
24ddc71998-03-28Henrik Grubbström (Grubba) 
e9f9141996-09-29Fredrik Hübinette (Hubbe) #undef ATTRIBUTE #define ATTRIBUTE(X)
cb22561995-10-11Fredrik Hübinette (Hubbe) JMP_BUF *recoveries=0;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
c857761999-03-16Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG void check_recovery_context(void) { char foo; #define TESTILITEST ((((char *)recoveries)-((char *)&foo))*STACK_DIRECTION) if(recoveries && TESTILITEST > 0) fatal("Recoveries is out biking (recoveries=%p, sp=%p, %d)!\n",recoveries, &foo,TESTILITEST); /* Add more stuff here when required */ } #endif
5196c51998-07-16Fredrik Hübinette (Hubbe) JMP_BUF *init_recovery(JMP_BUF *r DEBUG_LINE_ARGS)
5267b71995-08-09Fredrik Hübinette (Hubbe) {
c857761999-03-16Fredrik Hübinette (Hubbe)  check_recovery_context();
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
5196c51998-07-16Fredrik Hübinette (Hubbe)  r->line=line; r->file=file;
c857761999-03-16Fredrik Hübinette (Hubbe)  OED_FPRINTF((stderr, "init_recovery(%p) %s:%d\n", r, file, line));
5196c51998-07-16Fredrik Hübinette (Hubbe) #endif
5267b71995-08-09Fredrik Hübinette (Hubbe)  r->fp=fp;
f0cd981996-06-21Fredrik Hübinette (Hubbe)  r->sp=sp-evaluator_stack; r->mark_sp=mark_sp - mark_stack;
5267b71995-08-09Fredrik Hübinette (Hubbe)  r->previous=recoveries;
07513e1996-10-04Fredrik Hübinette (Hubbe)  r->onerror=0;
61e9a01998-01-25Fredrik Hübinette (Hubbe)  r->severity=THROW_ERROR;
5267b71995-08-09Fredrik Hübinette (Hubbe)  recoveries=r;
c857761999-03-16Fredrik Hübinette (Hubbe)  check_recovery_context();
e9f9141996-09-29Fredrik Hübinette (Hubbe)  return r;
5267b71995-08-09Fredrik Hübinette (Hubbe) }
5a7ab61998-01-31Fredrik Hübinette (Hubbe) void pike_throw(void) ATTRIBUTE((noreturn))
5267b71995-08-09Fredrik Hübinette (Hubbe) {
61e9a01998-01-25Fredrik Hübinette (Hubbe)  while(recoveries && throw_severity > recoveries->severity) { while(recoveries->onerror) { (*recoveries->onerror->func)(recoveries->onerror->arg); recoveries->onerror=recoveries->onerror->previous; } recoveries=recoveries->previous; }
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!recoveries) fatal("No error recovery context.\n");
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
f0cd981996-06-21Fredrik Hübinette (Hubbe)  if(sp - evaluator_stack < recoveries->sp)
294dc51997-08-03Fredrik Hübinette (Hubbe)  fatal("Stack error in error.\n");
5267b71995-08-09Fredrik Hübinette (Hubbe) #endif while(fp != recoveries->fp) {
4218011999-01-31Fredrik Hübinette (Hubbe)  struct pike_frame *tmp=fp;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(!fp) fatal("Popped out of stack frames.\n"); #endif
4218011999-01-31Fredrik Hübinette (Hubbe)  fp = tmp->next; tmp->next=0; free_pike_frame(tmp);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
f0cd981996-06-21Fredrik Hübinette (Hubbe)  pop_n_elems(sp - evaluator_stack - recoveries->sp); mark_sp = mark_stack + recoveries->mark_sp;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
07513e1996-10-04Fredrik Hübinette (Hubbe)  while(recoveries->onerror)
cb22561995-10-11Fredrik Hübinette (Hubbe)  {
07513e1996-10-04Fredrik Hübinette (Hubbe)  (*recoveries->onerror->func)(recoveries->onerror->arg); recoveries->onerror=recoveries->onerror->previous;
cb22561995-10-11Fredrik Hübinette (Hubbe)  }
5267b71995-08-09Fredrik Hübinette (Hubbe)  longjmp(recoveries->recovery,1); }
f52cf61998-04-10Henrik Grubbström (Grubba) void push_error(char *description) { push_text(description); f_backtrace(0); f_aggregate(2); }
5267b71995-08-09Fredrik Hübinette (Hubbe) struct svalue throw_value = { T_INT };
61e9a01998-01-25Fredrik Hübinette (Hubbe) int throw_severity;
4406cf1998-04-13Henrik Grubbström (Grubba) static const char *in_error;
db40ab1999-04-15Fredrik Hübinette (Hubbe)  void low_error(char *buf) { push_error(buf); free_svalue(& throw_value); throw_value = *--sp; throw_severity=THROW_ERROR; in_error=0; pike_throw(); /* Hope someone is catching, or we will be out of balls. */ }
f52cf61998-04-10Henrik Grubbström (Grubba) /* FIXME: NOTE: This function uses a static buffer. * Check sizes of arguments passed! */
4406cf1998-04-13Henrik Grubbström (Grubba) void va_error(const char *fmt, va_list args) ATTRIBUTE((noreturn))
5267b71995-08-09Fredrik Hübinette (Hubbe) {
52cf141998-05-15Henrik Grubbström (Grubba)  char buf[4096];
db40ab1999-04-15Fredrik Hübinette (Hubbe)  SWAP_IN_THREAD_IF_REQUIRED();
5267b71995-08-09Fredrik Hübinette (Hubbe)  if(in_error) {
4406cf1998-04-13Henrik Grubbström (Grubba)  const char *tmp=in_error;
5267b71995-08-09Fredrik Hübinette (Hubbe)  in_error=0;
5fe7a71995-11-06Fredrik Hübinette (Hubbe)  fatal("Recursive error() calls, original error: %s",tmp);
5267b71995-08-09Fredrik Hübinette (Hubbe)  }
5fe7a71995-11-06Fredrik Hübinette (Hubbe)  in_error=buf;
5267b71995-08-09Fredrik Hübinette (Hubbe) 
52cf141998-05-15Henrik Grubbström (Grubba) #ifdef HAVE_VSNPRINTF
f00ecc1998-05-16Fredrik Hübinette (Hubbe)  vsnprintf(buf, 4090, fmt, args);
52cf141998-05-15Henrik Grubbström (Grubba) #else /* !HAVE_VSNPRINTF */
5267b71995-08-09Fredrik Hübinette (Hubbe)  VSPRINTF(buf, fmt, args);
52cf141998-05-15Henrik Grubbström (Grubba) #endif /* HAVE_VSNPRINTF */
5267b71995-08-09Fredrik Hübinette (Hubbe) 
dceabb1996-10-09Fredrik Hübinette (Hubbe)  if(!recoveries)
06983f1996-09-22Fredrik Hübinette (Hubbe)  {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
06983f1996-09-22Fredrik Hübinette (Hubbe)  dump_backlog(); #endif
dceabb1996-10-09Fredrik Hübinette (Hubbe)  fprintf(stderr,"No error recovery context!\n%s",buf);
06983f1996-09-22Fredrik Hübinette (Hubbe)  exit(99); }
6b92161996-05-16Fredrik Hübinette (Hubbe)  if((long)strlen(buf) >= (long)sizeof(buf))
5267b71995-08-09Fredrik Hübinette (Hubbe)  fatal("Buffer overflow in error()\n");
db40ab1999-04-15Fredrik Hübinette (Hubbe)  low_error(buf);
f52cf61998-04-10Henrik Grubbström (Grubba) }
4406cf1998-04-13Henrik Grubbström (Grubba) void new_error(const char *name, const char *text, struct svalue *oldsp, INT32 args, const char *file, int line) ATTRIBUTE((noreturn))
f52cf61998-04-10Henrik Grubbström (Grubba) { int i;
db40ab1999-04-15Fredrik Hübinette (Hubbe)  ASSERT_THREAD_SWAPPED_IN();
f52cf61998-04-10Henrik Grubbström (Grubba)  if(in_error) {
4406cf1998-04-13Henrik Grubbström (Grubba)  const char *tmp=in_error;
f52cf61998-04-10Henrik Grubbström (Grubba)  in_error=0; fatal("Recursive error() calls, original error: %s",tmp); } in_error=text; if(!recoveries) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
f52cf61998-04-10Henrik Grubbström (Grubba)  dump_backlog(); #endif fprintf(stderr,"No error recovery context!\n%s():%s",name,text); exit(99); } push_text(text);
5267b71995-08-09Fredrik Hübinette (Hubbe)  f_backtrace(0);
f52cf61998-04-10Henrik Grubbström (Grubba)  if (file) { push_text(file); push_int(line); } else { push_int(0); push_int(0); } push_text(name); for (i=-args; i; i++) { push_svalue(oldsp + i); } f_aggregate(args + 3); f_aggregate(1); f_add(2);
5267b71995-08-09Fredrik Hübinette (Hubbe)  f_aggregate(2);
f52cf61998-04-10Henrik Grubbström (Grubba) 
5267b71995-08-09Fredrik Hübinette (Hubbe)  free_svalue(& throw_value);
864d3c1998-01-29Fredrik Hübinette (Hubbe)  throw_value = *--sp;
61e9a01998-01-25Fredrik Hübinette (Hubbe)  throw_severity=THROW_ERROR;
5267b71995-08-09Fredrik Hübinette (Hubbe)  in_error=0;
dc7cc91998-01-14Fredrik Hübinette (Hubbe)  pike_throw(); /* Hope someone is catching, or we will be out of balls. */
5267b71995-08-09Fredrik Hübinette (Hubbe) }
dceabb1996-10-09Fredrik Hübinette (Hubbe) void exit_on_error(void *msg) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
dceabb1996-10-09Fredrik Hübinette (Hubbe)  dump_backlog(); #endif fprintf(stderr,"%s\n",(char *)msg); exit(1); } void fatal_on_error(void *msg) {
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
dceabb1996-10-09Fredrik Hübinette (Hubbe)  dump_backlog(); #endif fprintf(stderr,"%s\n",(char *)msg); abort(); }
4406cf1998-04-13Henrik Grubbström (Grubba) void error(const char *fmt,...) ATTRIBUTE((noreturn,format (printf, 1, 2)))
5267b71995-08-09Fredrik Hübinette (Hubbe) { va_list args; va_start(args,fmt); va_error(fmt,args); va_end(args); }
4406cf1998-04-13Henrik Grubbström (Grubba) void debug_fatal(const char *fmt, ...) ATTRIBUTE((noreturn,format (printf, 1, 2)))
5267b71995-08-09Fredrik Hübinette (Hubbe) { va_list args; static int in_fatal = 0; va_start(args,fmt); /* Prevent double fatal. */ if (in_fatal) { (void)VFPRINTF(stderr, fmt, args); abort(); } in_fatal = 1;
71f3a21998-11-22Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG
5267b71995-08-09Fredrik Hübinette (Hubbe)  dump_backlog(); #endif (void)VFPRINTF(stderr, fmt, args);
ef7c761998-03-24Fredrik Hübinette (Hubbe)  d_flag=t_flag=0;
f52cf61998-04-10Henrik Grubbström (Grubba)  push_error("Attempting to dump backlog (may fail).\n");
ef7c761998-03-24Fredrik Hübinette (Hubbe)  APPLY_MASTER("describe_backtrace",1); if(sp[-1].type==T_STRING) write_to_stderr(sp[-1].u.string->str, sp[-1].u.string->len);
5267b71995-08-09Fredrik Hübinette (Hubbe)  fflush(stderr); abort(); }
c857761999-03-16Fredrik Hübinette (Hubbe) 
81299f1999-03-19Fredrik Hübinette (Hubbe) #if 1
c857761999-03-16Fredrik Hübinette (Hubbe) 
81299f1999-03-19Fredrik Hübinette (Hubbe) #define ERR_DECLARE #include "errors.h" void f_error_cast(INT32 args) { char *s; get_all_args("error->cast",args,"%s",&s); if(!strncmp(s,"array",5)) { pop_n_elems(args); ref_push_string(GENERIC_ERROR_THIS->desc); ref_push_array(GENERIC_ERROR_THIS->backtrace); f_aggregate(2); }else{ /* do an error here! */ } } void f_error_index(INT32 args) { int ind; get_all_args("error->`[]",args,"%i",&ind); pop_n_elems(args); switch(ind) { case 0: ref_push_string(GENERIC_ERROR_THIS->desc); break; case 1: ref_push_array(GENERIC_ERROR_THIS->backtrace); break; default: /* do an index out of range error here! */
2aba401999-03-23Marcus Comstedt  ;
81299f1999-03-19Fredrik Hübinette (Hubbe)  } } void f_error_describe(INT32 args) { pop_n_elems(args); ref_push_object(fp->current_object); APPLY_MASTER("describe_backtrace",1); } void f_error_backtrace(INT32 args) { pop_n_elems(args); ref_push_array(GENERIC_ERROR_THIS->backtrace); } #define INIT_ERROR(FEL)\ va_list foo; \
db40ab1999-04-15Fredrik Hübinette (Hubbe)  struct object *o; \ va_start(foo,desc); \ ASSERT_THREAD_SWAPPED_IN(); \ o=low_clone(PIKE_CONCAT(FEL,_error_program));
81299f1999-03-19Fredrik Hübinette (Hubbe)  #define ERROR_DONE(FOO) \ PIKE_CONCAT(FOO,_error_va(o,func, \ base_sp, args, \ desc,foo)); \ va_end(foo) #define ERROR_STRUCT(STRUCT,O) \ ((struct PIKE_CONCAT(STRUCT,_error_struct) *)((O)->storage + PIKE_CONCAT(STRUCT,_error_offset))) #define ERROR_COPY(STRUCT,X) \ ERROR_STRUCT(STRUCT,o)->X=X #define ERROR_COPY_SVALUE(STRUCT,X) \ assign_svalue_no_free( & ERROR_STRUCT(STRUCT,o)->X, X) #define ERROR_COPY_REF(STRUCT,X) \ add_ref( ERROR_STRUCT(STRUCT,o)->X=X ) void generic_error_va(struct object *o, char *func, struct svalue *base_sp, int args, char *fmt, va_list foo) ATTRIBUTE((noreturn))
c857761999-03-16Fredrik Hübinette (Hubbe) { char buf[8192];
81299f1999-03-19Fredrik Hübinette (Hubbe)  struct pike_string *desc; struct array *backtrace; int i;
c857761999-03-16Fredrik Hübinette (Hubbe)  #ifdef HAVE_VSNPRINTF
81299f1999-03-19Fredrik Hübinette (Hubbe)  vsnprintf(buf, sizeof(buf)-1, fmt, foo);
c857761999-03-16Fredrik Hübinette (Hubbe) #else /* !HAVE_VSNPRINTF */
81299f1999-03-19Fredrik Hübinette (Hubbe)  VSPRINTF(buf, fmt, foo);
c857761999-03-16Fredrik Hübinette (Hubbe)  if((long)strlen(buf) >= (long)sizeof(buf)) fatal("Buffer overflow in error()\n"); #endif /* HAVE_VSNPRINTF */
81299f1999-03-19Fredrik Hübinette (Hubbe)  in_error=buf;
c857761999-03-16Fredrik Hübinette (Hubbe) 
81299f1999-03-19Fredrik Hübinette (Hubbe)  ERROR_STRUCT(generic,o)->desc=make_shared_string(buf); f_backtrace(0); if(func) { push_int(0); push_int(0); push_text(func);
e88b9e1999-04-02Fredrik Hübinette (Hubbe)  for (i=0;i<args;i++)
81299f1999-03-19Fredrik Hübinette (Hubbe)  push_svalue(base_sp + i); f_aggregate(args + 3); f_aggregate(1); f_add(2); }
c857761999-03-16Fredrik Hübinette (Hubbe) 
81299f1999-03-19Fredrik Hübinette (Hubbe)  if(sp[-1].type!=T_ARRAY) fatal("Error failed to generate a backtrace!\n"); ERROR_STRUCT(generic,o)->backtrace=sp[-1].u.array; sp--; free_svalue(& throw_value); throw_value.type=T_OBJECT; throw_value.u.object=o;
c857761999-03-16Fredrik Hübinette (Hubbe)  in_error=0; pike_throw(); /* Hope someone is catching, or we will be out of balls. */ }
81299f1999-03-19Fredrik Hübinette (Hubbe) void generic_error( char *func, struct svalue *base_sp, int args, char *desc, ...) ATTRIBUTE((noreturn,format (printf, 4, 5)))
c857761999-03-16Fredrik Hübinette (Hubbe) {
81299f1999-03-19Fredrik Hübinette (Hubbe)  INIT_ERROR(generic); ERROR_DONE(generic);
c857761999-03-16Fredrik Hübinette (Hubbe) }
81299f1999-03-19Fredrik Hübinette (Hubbe) void index_error( char *func, struct svalue *base_sp, int args, struct svalue *val, struct svalue *ind, char *desc, ...) ATTRIBUTE((noreturn,format (printf, 6, 7))) { INIT_ERROR(index); ERROR_COPY_SVALUE(index, val); ERROR_COPY_SVALUE(index, ind); ERROR_DONE(generic); }
c857761999-03-16Fredrik Hübinette (Hubbe) 
81299f1999-03-19Fredrik Hübinette (Hubbe) void 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)))
c857761999-03-16Fredrik Hübinette (Hubbe) {
81299f1999-03-19Fredrik Hübinette (Hubbe)  INIT_ERROR(bad_arg); ERROR_COPY(bad_arg, which_arg); ERROR_STRUCT(bad_arg,o)->expected_type=make_shared_string(expected_type); if(got) { ERROR_COPY_SVALUE(bad_arg, got); }else{ ERROR_STRUCT(bad_arg,o)->got.type=T_INT; ERROR_STRUCT(bad_arg,o)->got.subtype=NUMBER_UNDEFINED; ERROR_STRUCT(bad_arg,o)->got.u.integer=0; } ERROR_DONE(generic); }
c857761999-03-16Fredrik Hübinette (Hubbe) 
d0ed261999-03-20Fredrik Hübinette (Hubbe) void math_error( char *func, struct svalue *base_sp, int args,
28af0c1999-03-23Fredrik Hübinette (Hubbe)  struct svalue *number,
b9f8361999-03-23Fredrik Hübinette (Hubbe)  char *desc, ...) ATTRIBUTE((noreturn,format (printf, 5, 6)))
d0ed261999-03-20Fredrik Hübinette (Hubbe) { INIT_ERROR(math);
28af0c1999-03-23Fredrik Hübinette (Hubbe)  if(number) {
c023d51999-03-23Fredrik Hübinette (Hubbe)  ERROR_COPY_SVALUE(math, number);
28af0c1999-03-23Fredrik Hübinette (Hubbe)  }else{
c023d51999-03-23Fredrik Hübinette (Hubbe)  ERROR_STRUCT(math,o)->number.type=T_INT; ERROR_STRUCT(math,o)->number.subtype=NUMBER_UNDEFINED; ERROR_STRUCT(math,o)->number.u.integer=0;
28af0c1999-03-23Fredrik Hübinette (Hubbe)  }
d0ed261999-03-20Fredrik Hübinette (Hubbe)  ERROR_DONE(generic); } void resource_error( char *func, struct svalue *base_sp, int args, char *resource_type, long howmuch, char *desc, ...) ATTRIBUTE((noreturn,format (printf, 6, 7))) { INIT_ERROR(resource); ERROR_COPY(resource,howmuch); ERROR_STRUCT(resource,o)->resource_type=make_shared_string(resource_type); ERROR_DONE(generic); }
c857761999-03-16Fredrik Hübinette (Hubbe) 
64dc4c1999-04-17Henrik Grubbström (Grubba) void permission_error( char *func, struct svalue *base_sp, int args, char *permission_type, char *desc, ...) ATTRIBUTE((noreturn, format(printf, 2, 3))) { INIT_ERROR(permission); ERROR_STRUCT(permission,o)->permission_type= make_shared_string(permission_type); ERROR_DONE(generic); }
81299f1999-03-19Fredrik Hübinette (Hubbe) void init_error(void) { #define ERR_SETUP #include "errors.h" }
c857761999-03-16Fredrik Hübinette (Hubbe) 
81299f1999-03-19Fredrik Hübinette (Hubbe) void cleanup_error(void) { #define ERR_CLEANUP #include "errors.h"
c857761999-03-16Fredrik Hübinette (Hubbe) } #endif