home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Programming / sofa / archive / SmallEiffel.lha / SmallEiffel / sys / runtime / exceptions.c < prev    next >
C/C++ Source or Header  |  1999-06-05  |  16KB  |  556 lines

  1. /*
  2. -- This file is  free  software, which  comes  along  with  SmallEiffel. This
  3. -- software  is  distributed  in the hope that it will be useful, but WITHOUT 
  4. -- ANY  WARRANTY;  without  even  the  implied warranty of MERCHANTABILITY or
  5. -- FITNESS  FOR A PARTICULAR PURPOSE. You can modify it as you want, provided
  6. -- this header is kept unaltered, and a notification of the changes is added.
  7. -- You  are  allowed  to  redistribute  it and sell it, alone or as a part of 
  8. -- another product.
  9. --          Copyright (C) 1994-98 LORIA - UHP - CRIN - INRIA - FRANCE
  10. --            Dominique COLNET and Suzanne COLLIN - colnet@loria.fr 
  11. --                       http://www.loria.fr/SmallEiffel
  12. --
  13. */
  14. /*
  15.   This file (exception.c) is automatically included when exception handling
  16.   is used somewhere in the live code.
  17. */
  18.  
  19. /*
  20.   Miscellaneous Notes:
  21.   We are currently using the old signal() system call instead of 
  22.   the prefered sigaction() call.  
  23.   
  24.   On Linux systems at least, signal() is implemented by sigaction() 
  25.   so it doesn't really matter.  Need to investigate this on other
  26.   Unix systems.
  27.  
  28.   James Graves (ansible@xnet.com)
  29. */
  30.  
  31. /* 
  32.    Top of the rescue context stack (or NULL if there is no current
  33.    context) :
  34. */
  35. struct rescue_context *rescue_context_top = NULL;
  36.  
  37. /* 
  38.    Set to nonzero if the exception was internally generated, as with an
  39.    assertion violation.  It is Os_signal (11) for an OS signal.
  40. */
  41. int internal_exception_number;
  42. int original_internal_exception_number;
  43.  
  44. /* 
  45.    Set to nonzero if the exception was a signal (external).  It is 0
  46.    for an internal exception.
  47. */
  48. int signal_exception_number;
  49.  
  50. /*
  51.    Used by some internal exceptions to print additional debugging
  52.    information when the exception is not handled and a dump is done.
  53. */
  54. char *additional_error_message;
  55.  
  56. static void critical_error_exit(void) {
  57. /* This is called whenever a critical error in the SmallEiffel
  58.    is encountered.  This kind of error cannot be handled by the
  59.    exception handler.
  60.    
  61.    For instance, this routine is called if there is an error in the
  62.    operation of the exception handler routines themselves.
  63. */
  64.   fprintf(stderr, "There was a critical error in the SmallEiffel runtime.\n");
  65.   exit(2);
  66. }
  67.  
  68. void setup_signal_handler() {
  69. /*
  70.   Sets up the reception of signals.  If exception handling is enabled
  71.   (by the existance of a rescue clause somewhere), then all OS signals
  72.   now go to exception_handler instead of se_print_run_time_stack().
  73. */
  74. #ifdef SIG_ERR
  75. /* Check signal() call for errors.  Posix compliant systems should
  76.    define SIG_ERR which is returned by signal() on an error. All Unix 
  77.    signals are included except * for SIGKILL and SIGSTOP.  
  78.    
  79.    The other signals SmallEiffel traps for
  80.    other OSs (like SIGBREAK) are not included here, but are below
  81.    in the #else part, for non-Posix systems.
  82. */
  83.  
  84. # ifdef SIGHUP
  85.    if ( SIG_ERR == signal( SIGHUP, signal_exception_handler ) ) 
  86.       {
  87.       fprintf(stderr, "Error setting up signal handler for SIGHUP.\n");
  88.       critical_error_exit();
  89.       }
  90. # endif
  91.        
  92. # ifdef SIGINT
  93.    if ( SIG_ERR == signal( SIGINT, signal_exception_handler ) ) {
  94.       fprintf(stderr, "Error setting up signal handler for SIGINT.\n");
  95.       critical_error_exit();
  96.       }
  97. # endif
  98.        
  99. # ifdef SIGQUIT
  100.    if ( SIG_ERR == signal( SIGQUIT, signal_exception_handler ) ) {
  101.       fprintf(stderr, "Error setting up signal handler for SIGQUIT.\n");
  102.       critical_error_exit();
  103.       }
  104. # endif
  105.        
  106. # ifdef SIGILL
  107.    if ( SIG_ERR == signal( SIGILL, signal_exception_handler ) ) {
  108.       fprintf(stderr, "Error setting up signal handler for SIGILL.\n");
  109.       critical_error_exit();
  110.       }
  111. # endif
  112.        
  113. # ifdef SIGTRAP
  114.    if ( SIG_ERR == signal( SIGTRAP, signal_exception_handler ) ) {
  115.       fprintf(stderr, "Error setting up signal handler for SIGTRAP.\n");
  116.       critical_error_exit();
  117.       }
  118. # endif
  119.        
  120. # ifdef SIGIOT
  121.    if ( SIG_ERR == signal( SIGIOT, signal_exception_handler ) ) {
  122.       fprintf(stderr, "Error setting up signal handler for SIGIOT.\n");
  123.       critical_error_exit();
  124.       }
  125. # endif
  126.        
  127. # ifdef SIGBUS
  128.    if ( SIG_ERR == signal( SIGBUS, signal_exception_handler ) ) {
  129.       fprintf(stderr, "Error setting up signal handler for SIGBUS.\n");
  130.       critical_error_exit();
  131.       }
  132. # endif
  133.        
  134. # ifdef SIGFPE
  135.    if ( SIG_ERR == signal( SIGFPE, signal_exception_handler ) ) {
  136.       fprintf(stderr, "Error setting up signal handler for SIGFPE.\n");
  137.       critical_error_exit();
  138.       }
  139. # endif
  140.        
  141. # ifdef SIGUSR1
  142.    if ( SIG_ERR == signal( SIGUSR1, signal_exception_handler ) ) {
  143.       fprintf(stderr, "Error setting up signal handler for SIGUSR1.\n");
  144.       critical_error_exit();
  145.       }
  146. # endif
  147.        
  148. # ifdef SIGSEGV
  149.    if ( SIG_ERR == signal( SIGSEGV, signal_exception_handler ) ) {
  150.       fprintf(stderr, "Error setting up signal handler for SIGSEGV.\n");
  151.       critical_error_exit();
  152.       }
  153. # endif
  154.        
  155. # ifdef SIGUSR2
  156.    if ( SIG_ERR == signal( SIGUSR2, signal_exception_handler ) ) {
  157.       fprintf(stderr, "Error setting up signal handler for SIGUSR2.\n");
  158.       critical_error_exit();
  159.       }
  160. # endif
  161.        
  162. # ifdef SIGPIPE
  163.    if ( SIG_ERR == signal( SIGPIPE, signal_exception_handler ) ) {
  164.       fprintf(stderr, "Error setting up signal handler for SIGPIPE.\n");
  165.       critical_error_exit();
  166.       }
  167. # endif
  168.        
  169. # ifdef SIGALRM
  170.    if ( SIG_ERR == signal( SIGALRM, signal_exception_handler ) ) {
  171.       fprintf(stderr, "Error setting up signal handler for SIGALRM.\n");
  172.       critical_error_exit();
  173.       }
  174. # endif
  175.        
  176. # ifdef SIGTERM
  177.    if ( SIG_ERR == signal( SIGTERM, signal_exception_handler ) ) {
  178.       fprintf(stderr, "Error setting up signal handler for SIGTERM.\n");
  179.       critical_error_exit();
  180.       }
  181. # endif
  182.        
  183. # ifdef SIGCHLD
  184.    if ( SIG_ERR == signal( SIGCHLD, signal_exception_handler ) ) {
  185.       fprintf(stderr, "Error setting up signal handler for SIGCHLD.\n");
  186.       critical_error_exit();
  187.       }
  188. # endif
  189.        
  190. # ifdef SIGCONT
  191.    if ( SIG_ERR == signal( SIGCONT, signal_exception_handler ) ) {
  192.       fprintf(stderr, "Error setting up signal handler for SIGCONT.\n");
  193.       critical_error_exit();
  194.       }
  195. # endif
  196.        
  197. # ifdef SIGTSTP
  198.    if ( SIG_ERR == signal( SIGTSTP, signal_exception_handler ) ) {
  199.       fprintf(stderr, "Error setting up signal handler for SIGTSTP.\n");
  200.       critical_error_exit();
  201.       }
  202. # endif
  203.        
  204. # ifdef SIGTTIN
  205.    if ( SIG_ERR == signal( SIGTTIN, signal_exception_handler ) ) {
  206.       fprintf(stderr, "Error setting up signal handler for SIGTTIN.\n");
  207.       critical_error_exit();
  208.       }
  209. # endif
  210.        
  211. # ifdef SIGTTOU
  212.    if ( SIG_ERR == signal( SIGTTOU, signal_exception_handler ) ) {
  213.       fprintf(stderr, "Error setting up signal handler for SIGTTOU.\n");
  214.       critical_error_exit();
  215.       }
  216. # endif
  217.        
  218. # ifdef SIGURG
  219.    if ( SIG_ERR == signal( SIGURG, signal_exception_handler ) ) {
  220.       fprintf(stderr, "Error setting up signal handler for SIGURG.\n");
  221.       critical_error_exit();
  222.       }
  223. # endif
  224.        
  225. # ifdef SIGXCPU
  226.    if ( SIG_ERR == signal( SIGXCPU, signal_exception_handler ) ) {
  227.       fprintf(stderr, "Error setting up signal handler for SIGXCPU.\n");
  228.       critical_error_exit();
  229.       }
  230. # endif
  231.        
  232. # ifdef SIGXFSZ
  233.    if ( SIG_ERR == signal( SIGXFSZ, signal_exception_handler ) ) {
  234.       fprintf(stderr, "Error setting up signal handler for SIGXFSZ.\n");
  235.       critical_error_exit();
  236.       }
  237. # endif
  238.        
  239. # ifdef SIGVTALRM
  240.    if ( SIG_ERR == signal( SIGVTALRM, signal_exception_handler ) ) {
  241.       fprintf(stderr, "Error setting up signal handler for SIGVTALRM.\n");
  242.       critical_error_exit();
  243.       }
  244. # endif
  245.        
  246. # ifdef SIGPROF
  247.    if ( SIG_ERR == signal( SIGPROF, signal_exception_handler ) ) {
  248.       fprintf(stderr, "Error setting up signal handler for SIGPROF.\n");
  249.       critical_error_exit();
  250.       }
  251. # endif
  252.        
  253. # ifdef SIGWINCH
  254.    if ( SIG_ERR == signal( SIGWINCH, signal_exception_handler ) ) {
  255.       fprintf(stderr, "Error setting up signal handler for SIGWINCH.\n");
  256.       critical_error_exit();
  257.       }
  258. # endif
  259.        
  260. # ifdef SIGIO
  261.    if ( SIG_ERR == signal( SIGIO, signal_exception_handler ) ) {
  262.       fprintf(stderr, "Error setting up signal handler for SIGIO.\n");
  263.       critical_error_exit();
  264.       }
  265. # endif
  266.        
  267. # ifdef SIGPWR
  268.    if ( SIG_ERR == signal( SIGPWR, signal_exception_handler ) ) {
  269.       fprintf(stderr, "Error setting up signal handler for SIGPWR.\n");
  270.       critical_error_exit();
  271.       }
  272. # endif
  273.        
  274. #else   /* SIG_ERR not defined, non-Posix system? */
  275.  
  276. /* These don't check return code for the signal() OS call.  Bad practice,
  277.    but what can be done?  */
  278.  
  279. # ifdef SIGBREAK
  280.    /* This signal does not exist on Unix systems. */
  281.    signal( SIGBREAK, signal_exception_handler );
  282. # endif
  283.  
  284. # ifdef SIGHUP
  285.    signal( SIGHUP, signal_exception_handler );
  286. # endif
  287.  
  288. # ifdef SIGINT
  289.    signal( SIGINT, signal_exception_handler );
  290. # endif
  291.  
  292. # ifdef SIGQUIT
  293.    signal( SIGQUIT, signal_exception_handler );
  294. # endif
  295.  
  296. # ifdef SIGILL
  297.    signal( SIGILL, signal_exception_handler );
  298. # endif
  299.  
  300. # ifdef SIGTRAP
  301.    signal( SIGTRAP, signal_exception_handler );
  302. # endif
  303.  
  304. # ifdef SIGIOT
  305.    signal( SIGIOT, signal_exception_handler );
  306. # endif
  307.  
  308. # ifdef SIGBUS
  309.    signal( SIGBUS, signal_exception_handler );
  310. # endif
  311.  
  312. # ifdef SIGFPE
  313.    signal( SIGFPE, signal_exception_handler );
  314. # endif
  315.  
  316. # ifdef SIGKILL
  317.    /* This should silently fail on Unix systems, but is reported to work
  318.       on other non-Unix systems.  You have been warned. */
  319.    signal( SIGKILL, signal_exception_handler );
  320. # endif
  321.  
  322. # ifdef SIGUSR1
  323.    signal( SIGUSR1, signal_exception_handler );
  324. # endif
  325.  
  326. # ifdef SIGSEGV
  327.    signal( SIGSEGV, signal_exception_handler );
  328. # endif
  329.  
  330. # ifdef SIGUSR2
  331.    signal( SIGUSR2, signal_exception_handler );
  332. # endif
  333.  
  334. # ifdef SIGPIPE
  335.    signal( SIGPIPE, signal_exception_handler );
  336. # endif
  337.  
  338. # ifdef SIGALRM
  339.    signal( SIGALRM, signal_exception_handler );
  340. # endif
  341.  
  342. # ifdef SIGTERM
  343.    signal( SIGTERM, signal_exception_handler );
  344. # endif
  345.  
  346. # ifdef SIGCHLD
  347.    signal( SIGCHLD, signal_exception_handler );
  348. # endif
  349.  
  350. # ifdef SIGCONT
  351.    signal( SIGCONT, signal_exception_handler );
  352. # endif
  353.  
  354. # ifdef SIGSTOP
  355.    /* This should also silently fail on all Unix systems, but it may
  356.       be effective on other OSs. */
  357.    signal( SIGSTOP, signal_exception_handler );
  358. # endif
  359.  
  360. # ifdef SIGTSTP
  361.    signal( SIGTSTP, signal_exception_handler );
  362. # endif
  363.  
  364. # ifdef SIGTTIN
  365.    signal( SIGTTIN, signal_exception_handler );
  366. # endif
  367.  
  368. # ifdef SIGTTOU
  369.    signal( SIGTTOU, signal_exception_handler );
  370. # endif
  371.  
  372. # ifdef SIGURG
  373.    signal( SIGURG, signal_exception_handler );
  374. # endif
  375.  
  376. # ifdef SIGXCPU
  377.    signal( SIGXCPU, signal_exception_handler );
  378. # endif
  379.  
  380. # ifdef SIGXFSZ
  381.    signal( SIGXFSZ, signal_exception_handler );
  382. # endif
  383.  
  384. # ifdef SIGTALRM
  385.    signal( SIGTALRM, signal_exception_handler );
  386. # endif
  387.  
  388. # ifdef SIGPROF
  389.    signal( SIGPROF, signal_exception_handler );
  390. # endif
  391.  
  392. # ifdef SIGWINCH
  393.    signal( SIGWINCH, signal_exception_handler );
  394. # endif
  395.  
  396. # ifdef SIGIO
  397.    signal( SIGIO, signal_exception_handler );
  398. # endif
  399.  
  400. # ifdef SIGPWR
  401.    signal( SIGPWR, signal_exception_handler );
  402. # endif
  403.  
  404. #endif  /* ifdef SIG_ERR */
  405.  
  406. }
  407.  
  408. void signal_exception_handler(int signal_number) {
  409.   /* Set up to be called whenever an OS signal has been received.
  410.      Checks to see if there is a rescue clause active (somewhere on the
  411.      call stack), and if so, transfer control to that.
  412.   */
  413.   struct rescue_context *current_context;
  414.  
  415. #ifdef SIG_ERR
  416.   /* some OS implementations automatically block a signal while
  417.    * executing the signal handler, but some do not. */
  418.   if ( SIG_ERR == signal( signal_number, SIG_IGN ) ) {
  419.     fprintf(stderr, "In signal_exception_handler: ");
  420.     fprintf(stderr, "Error turning off signal %d.\n", signal_number );
  421.     critical_error_exit();
  422.   }
  423. #else
  424.   signal( signal_number, SIG_IGN );
  425. #endif
  426.  
  427.   internal_exception_number = Os_signal;
  428.   original_internal_exception_number = 0;
  429.   signal_exception_number = signal_number;
  430.        
  431.   if ( rescue_context_top != NULL ) {
  432.     current_context = rescue_context_top;
  433.     rescue_context_top = rescue_context_top->next;
  434.  
  435.     /* now re-enable that signal */
  436. #ifdef SIG_ERR
  437.     if ( SIG_ERR == signal( signal_number, signal_exception_handler ) ) {
  438.       fprintf(stderr, "In signal_exception_handler: ");
  439.       fprintf(stderr, "Error turning on signal %d.\n", signal_number );
  440.       critical_error_exit();
  441.     }
  442. #else
  443.     signal( signal_number, signal_exception_handler );
  444. #endif
  445.     
  446.     LONGJMP( current_context->jb, internal_exception_number );
  447.   }
  448.  
  449.   /* No current rescue clause, exit with a dump : */
  450.   print_exception();
  451.   se_print_run_time_stack();
  452.   exit(1);
  453. }
  454.  
  455. void internal_exception_handler(int exception_number) {
  456.   /* Called whenever an internal (to SmallEiffel) exception is to
  457.      be raised (`raise' feature, assertion violation, etc.).  
  458.  
  459.      Checks to see if there is a current rescue clause (somewhere 
  460.      in the call stack), and transfers control to it.
  461.      Else exit with a stack trace (if enabled).
  462.   */
  463.   struct rescue_context *current_context;
  464.  
  465.   /* If this is not a routine failure, clear out old exception
  466.    * information. */
  467.   if ( exception_number != Routine_failure ) {
  468.     internal_exception_number = exception_number;
  469.     original_internal_exception_number = 0;
  470.     signal_exception_number = 0;
  471.   }
  472.   else {
  473.     original_internal_exception_number = internal_exception_number;
  474.   }
  475.  
  476.   if ( rescue_context_top != NULL ) {
  477.     current_context = rescue_context_top;
  478.     rescue_context_top = rescue_context_top->next;
  479.     LONGJMP( current_context->jb, exception_number );
  480.   }
  481.   
  482.   /* No current rescue clause, exit with a dump : */
  483.   print_exception();
  484.   se_print_run_time_stack();
  485.   exit(1);
  486. }
  487.  
  488. #ifdef SE_NO_CHECK
  489. static void print_exception_case( int ex_num ) {
  490.   switch( ex_num ) {
  491.   case Check_instruction:
  492.     fprintf(SE_ERR, "Check instruction failed.\n");
  493.     break;
  494.   case Class_invariant:
  495.     fprintf(SE_ERR, "Class invariant not maintained.\n");
  496.     break;
  497.   case Developer_exception:
  498.     fprintf(SE_ERR, "Developer exception:\n");
  499.     break;
  500.   case Incorrect_inspect_value:
  501.     fprintf(SE_ERR, "Incorrect inspect value.\n");
  502.     break;
  503.   case Loop_invariant:
  504.     fprintf(SE_ERR, "Loop invariant failed.\n");
  505.     break;
  506.   case Loop_variant:
  507.     fprintf(SE_ERR, "Loop variant failed to decrease.\n");
  508.     break;
  509.   case No_more_memory:
  510.     fprintf(SE_ERR, "Failed to allocate additional memory.\n");
  511.     break;
  512.   case Postcondition:
  513.     fprintf(SE_ERR, "Postcondition (ensure clause) failed.\n");
  514.     break;
  515.   case Precondition:
  516.     fprintf(SE_ERR, "Precondition (require clause) failed.\n");
  517.     break;
  518.   case Routine_failure:
  519.     fprintf(SE_ERR, "Routine failure.\n");
  520.     break;
  521.   case Os_signal:
  522.     fprintf(SE_ERR, "OS Signal (%d) received.\n", 
  523.         signal_exception_number );
  524.     break;
  525.   case Void_attached_to_expanded:
  526.     fprintf(SE_ERR, "A Void became attached to an expanded object.\n");
  527.     fprintf(SE_ERR, "Please report this problem to the SmallEiffel team.\n");
  528.     break;
  529.   case Void_call_target:
  530.     fprintf(SE_ERR, "Feature call attempted on a Void reference.\n");
  531.     break;
  532.   default:
  533.     fprintf(SE_ERR, "There was an unknown exception.\n");
  534.     fprintf(SE_ERR, "Please report this problem to the SmallEiffel team.\n");
  535.   }
  536. }
  537. #endif
  538.  
  539. void print_exception(void) {
  540.   /* Display some information about last not handled exception. */
  541. #ifdef SE_NO_CHECK
  542.   fprintf(SE_ERR,"Exception number %d not handled.\n",internal_exception_number);
  543.   if ( internal_exception_number == Routine_failure ) {
  544.     fprintf(SE_ERR, "Routine failure.  Original exception: \n");
  545.     print_exception_case( original_internal_exception_number );
  546.   }
  547.   else {
  548.     print_exception_case( internal_exception_number );
  549.   }
  550.   if ( additional_error_message != NULL ) {
  551.     fprintf(SE_ERR, "%s\n", additional_error_message );
  552.   }
  553. #endif
  554. }
  555.  
  556.