home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / winxfltr.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  14KB  |  452 lines

  1. /***
  2. *winxfltr.c - startup exception filter
  3. *
  4. *       Copyright (c) 1990-1997, Microsoft Corporation. All rights reserved
  5. *
  6. *Purpose:
  7. *       Defines _XcptFilter(), the function called by the exception filter
  8. *       expression in the startup code.
  9. *
  10. *******************************************************************************/
  11.  
  12.  
  13. #include <cruntime.h>
  14. #include <float.h>
  15. #include <mtdll.h>
  16. #include <oscalls.h>
  17. #include <signal.h>
  18. #include <stddef.h>
  19.  
  20.  
  21. /*
  22.  * special code denoting no signal.
  23.  */
  24. #define NOSIG   -1
  25.  
  26.  
  27. struct _XCPT_ACTION _XcptActTab[] = {
  28.  
  29. /*
  30.  * Exceptions corresponding to the same signal (e.g., SIGFPE) must be grouped
  31.  * together.
  32.  *
  33.  *        XcptNum                                        SigNum    XcptAction
  34.  *        -------------------------------------------------------------------
  35.  */
  36.         { (unsigned long)STATUS_ACCESS_VIOLATION,         SIGSEGV, SIG_DFL },
  37.  
  38.         { (unsigned long)STATUS_ILLEGAL_INSTRUCTION,      SIGILL,  SIG_DFL },
  39.  
  40.         { (unsigned long)STATUS_PRIVILEGED_INSTRUCTION,   SIGILL,  SIG_DFL },
  41.  
  42. /*      { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, NOSIG,   SIG_DIE },
  43.  */
  44. /*      { (unsigned long)STATUS_INVALID_DISPOSITION,      NOSIG,   SIG_DIE },
  45.  */
  46.         { (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND,   SIGFPE,  SIG_DFL },
  47.  
  48.         { (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO,     SIGFPE,  SIG_DFL },
  49.  
  50.         { (unsigned long)STATUS_FLOAT_INEXACT_RESULT,     SIGFPE,  SIG_DFL },
  51.  
  52.         { (unsigned long)STATUS_FLOAT_INVALID_OPERATION,  SIGFPE,  SIG_DFL },
  53.  
  54.         { (unsigned long)STATUS_FLOAT_OVERFLOW,           SIGFPE,  SIG_DFL },
  55.  
  56.         { (unsigned long)STATUS_FLOAT_STACK_CHECK,        SIGFPE,  SIG_DFL },
  57.  
  58.         { (unsigned long)STATUS_FLOAT_UNDERFLOW,          SIGFPE,  SIG_DFL },
  59.  
  60. /*      { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO,   NOSIG,   SIG_DIE },
  61.  */
  62. /*      { (unsigned long)STATUS_STACK_OVERFLOW,           NOSIG,   SIG_DIE }
  63.  */
  64. };
  65.  
  66. /*
  67.  * WARNING!!!! The definition below amounts to defining that:
  68.  *
  69.  *                  XcptActTab[ _First_FPE_Indx ]
  70.  *
  71.  * is the very FIRST entry in the table corresponding to a floating point
  72.  * exception. Whenever the definition of the XcptActTab[] table is changed,
  73.  * this #define must be review to ensure correctness.
  74.  */
  75. int _First_FPE_Indx = 3;
  76.  
  77. /*
  78.  * There are _Num_FPE (currently, 7) entries in XcptActTab corresponding to
  79.  * floating point exceptions.
  80.  */
  81. int _Num_FPE = 7;
  82.  
  83. #ifdef _MT
  84.  
  85. /*
  86.  * size of the exception-action table (in bytes)
  87.  */
  88. int _XcptActTabSize = sizeof _XcptActTab;
  89.  
  90. #endif  /* _MT */
  91.  
  92. /*
  93.  * number of entries in the exception-action table
  94.  */
  95. int _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]);
  96.  
  97.  
  98. #ifdef _MT
  99.  
  100. /*
  101.  * the FPECODE and PXCPTINFOPTRS macros are intended to simplify some of
  102.  * single vs multi-thread code in the filter function. basically, each macro
  103.  * is conditionally defined to be a global variable or the corresponding
  104.  * field in the per-thread data structure. NOTE THE ASSUMPTION THAT THE
  105.  * _ptiddata VARIABLE IS ALWAYS NAMED ptd!!!!
  106.  */
  107.  
  108. #define FPECODE         ptd->_tfpecode
  109.  
  110. #define PXCPTINFOPTRS   ptd->_tpxcptinfoptrs
  111.  
  112. #else  /* _MT */
  113.  
  114. /*
  115.  * global variable containing the floating point exception code
  116.  */
  117. int _fpecode = _FPE_EXPLICITGEN;
  118.  
  119. #define FPECODE         _fpecode
  120.  
  121. /*
  122.  * global variable holding _PEXCEPTION_INFO_PTRS value
  123.  */
  124. void * _pxcptinfoptrs = NULL;
  125.  
  126. #define PXCPTINFOPTRS   _pxcptinfoptrs
  127.  
  128. #endif  /* _MT */
  129.  
  130. /*
  131.  * function to look up the exception action table (_XcptActTab[]) corresponding
  132.  * to the given exception
  133.  */
  134.  
  135. #ifdef _MT
  136.  
  137. static struct _XCPT_ACTION * __cdecl xcptlookup(
  138.         unsigned long,
  139.         struct _XCPT_ACTION *
  140.         );
  141.  
  142. #else  /* _MT */
  143.  
  144. static struct _XCPT_ACTION * __cdecl xcptlookup(
  145.         unsigned long
  146.         );
  147.  
  148. #endif  /* _MT */
  149.  
  150.  
  151. /***
  152. *int _XcptFilter(xcptnum, pxcptptrs) - Identify exception and the action to
  153. *       be taken with it
  154. *
  155. *Purpose:
  156. *       _XcptFilter() is called by the exception filter expression of the
  157. *       _try - _except statement, in the startup code, which guards the call
  158. *       to the user's main(). _XcptFilter() consults the _XcptActTab[] table
  159. *       to identify the exception and determine its disposition. The
  160. *       is disposition of an exception corresponding to a C signal may be
  161. *       modified by a call to signal(). There are three broad cases:
  162. *
  163. *       (1) Unrecognized exceptions and exceptions for which the XcptAction
  164. *           value is SIG_DFL.
  165. *
  166. *           In both of these cases, UnhandledExceptionFilter() is called and
  167. *           its return value is returned.
  168. *
  169. *       (2) Exceptions corresponding to C signals with an XcptAction value
  170. *           NOT equal to SIG_DFL.
  171. *
  172. *           These are the C signals whose disposition has been affected by a
  173. *           call to signal() or whose default semantics differ slightly from
  174. *           from the corresponding OS exception. In all cases, the appropriate
  175. *           disposition of the C signal is made by the function (e.g., calling
  176. *           a user-specified signal handler). Then, EXCEPTION_CONTINUE_EXECU-
  177. *           TION is returned to cause the OS exception dispatcher to dismiss
  178. *           the exception and resume execution at the point where the
  179. *           exception occurred.
  180. *
  181. *       (3) Exceptions for which the XcptAction value is SIG_DIE.
  182. *
  183. *           These are the exceptions corresponding to fatal C runtime errors.
  184. *           _XCPT_HANDLE is returned to cause control to pass into the
  185. *           _except-block of the _try - _except statement. There, the runtime
  186. *           error is identified, an appropriate error message is printed out
  187. *           and the program is terminated.
  188. *
  189. *Entry:
  190. *
  191. *Exit:
  192. *
  193. *Exceptions:
  194. *       That's what it's all about!
  195. *
  196. *******************************************************************************/
  197.  
  198. int __cdecl _XcptFilter (
  199.         unsigned long xcptnum,
  200.         PEXCEPTION_POINTERS pxcptinfoptrs
  201.         )
  202. {
  203.         struct _XCPT_ACTION * pxcptact;
  204.         _PHNDLR phandler;
  205.         void *oldpxcptinfoptrs;
  206.         int oldfpecode;
  207.         int indx;
  208.  
  209. #ifdef _MT
  210.         _ptiddata ptd = _getptd();
  211. #endif  /* _MT */
  212.  
  213.         /*
  214.          * first, take care of all unrecognized exceptions and exceptions with
  215.          * XcptAction values of SIG_DFL.
  216.          */
  217. #ifdef _MT
  218.         if ( ((pxcptact = xcptlookup(xcptnum, ptd->_pxcptacttab)) == NULL)
  219.             || (pxcptact->XcptAction == SIG_DFL) )
  220. #else  /* _MT */
  221.         if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) ||
  222.             (pxcptact->XcptAction == SIG_DFL) )
  223. #endif  /* _MT */
  224.  
  225.                 /*
  226.                  * pass the buck to the UnhandledExceptionFilter
  227.                  */
  228.                 return( UnhandledExceptionFilter(pxcptinfoptrs) );
  229.  
  230.  
  231.         /*
  232.          * next, weed out all of the exceptions that need to be handled by
  233.          * dying, perhaps with a runtime error message
  234.          */
  235.         if ( pxcptact->XcptAction == SIG_DIE ) {
  236.                 /*
  237.                  * reset XcptAction (in case of recursion) and drop into the
  238.                  * except-clause.
  239.                  */
  240.                 pxcptact->XcptAction = SIG_DFL;
  241.                 return(EXCEPTION_EXECUTE_HANDLER);
  242.         }
  243.  
  244.         /*
  245.          * next, weed out all of the exceptions that are simply ignored
  246.          */
  247.         if ( pxcptact->XcptAction == SIG_IGN )
  248.                 /*
  249.                  * resume execution
  250.                  */
  251.                 return(EXCEPTION_CONTINUE_EXECUTION);
  252.  
  253.         /*
  254.          * the remaining exceptions all correspond to C signals which have
  255.          * signal handlers associated with them. for some, special setup
  256.          * is required before the signal handler is called. in all cases,
  257.          * if the signal handler returns, -1 is returned by this function
  258.          * to resume execution at the point where the exception occurred.
  259.          */
  260.         phandler = pxcptact->XcptAction;
  261.  
  262.         /*
  263.          * save the old value of _pxcptinfoptrs (in case this is a nested
  264.          * exception/signal) and store the current one.
  265.          */
  266.         oldpxcptinfoptrs = PXCPTINFOPTRS;
  267.         PXCPTINFOPTRS = pxcptinfoptrs;
  268.  
  269.         /*
  270.          * call the user-supplied signal handler
  271.          *
  272.          * floating point exceptions must be handled specially since, from
  273.          * the C point-of-view, there is only one signal. the exact identity
  274.          * of the exception is passed in the global variable _fpecode.
  275.          */
  276.         if ( pxcptact->SigNum == SIGFPE ) {
  277.  
  278.                 /*
  279.                  * reset the XcptAction field to the default for all entries
  280.                  * corresponding to SIGFPE.
  281.                  */
  282.                 for ( indx = _First_FPE_Indx ;
  283.                       indx < _First_FPE_Indx + _Num_FPE ;
  284.                       indx++ )
  285.                 {
  286. #ifdef _MT
  287.                         ( (struct _XCPT_ACTION *)(ptd->_pxcptacttab) +
  288.                           indx )->XcptAction = SIG_DFL;
  289. #else  /* _MT */
  290.                         _XcptActTab[indx].XcptAction = SIG_DFL;
  291. #endif  /* _MT */
  292.                 }
  293.  
  294.                 /*
  295.                  * Save the current _fpecode in case it is a nested floating
  296.                  * point exception (not clear that we need to support this,
  297.                  * but it's easy).
  298.                  */
  299.                 oldfpecode = FPECODE;
  300.  
  301.                 /*
  302.                  * there are no exceptions corresponding to
  303.                  * following _FPE_xxx codes:
  304.                  *
  305.                  *      _FPE_UNEMULATED
  306.                  *      _FPE_SQRTNEG
  307.                  *
  308.                  * futhermore, STATUS_FLOATING_STACK_CHECK is
  309.                  * raised for both floating point stack under-
  310.                  * flow and overflow. thus, the exception does
  311.                  * not distinguish between _FPE_STACKOVERLOW
  312.                  * and _FPE_STACKUNDERFLOW. arbitrarily, _fpecode
  313.                  * is set to the former value.
  314.                  *
  315.                  * the following should be a switch statement but, alas, the
  316.                  * compiler doesn't like switching on unsigned longs...
  317.                  */
  318.                 if ( pxcptact->XcptNum == STATUS_FLOAT_DIVIDE_BY_ZERO )
  319.  
  320.                         FPECODE = _FPE_ZERODIVIDE;
  321.  
  322.                 else if ( pxcptact->XcptNum == STATUS_FLOAT_INVALID_OPERATION )
  323.  
  324.                         FPECODE = _FPE_INVALID;
  325.  
  326.                 else if ( pxcptact->XcptNum == STATUS_FLOAT_OVERFLOW )
  327.  
  328.                         FPECODE = _FPE_OVERFLOW;
  329.  
  330.                 else if ( pxcptact->XcptNum == STATUS_FLOAT_UNDERFLOW )
  331.  
  332.                         FPECODE = _FPE_UNDERFLOW;
  333.  
  334.                 else if ( pxcptact->XcptNum == STATUS_FLOAT_DENORMAL_OPERAND )
  335.  
  336.                         FPECODE = _FPE_DENORMAL;
  337.  
  338.                 else if ( pxcptact->XcptNum == STATUS_FLOAT_INEXACT_RESULT )
  339.  
  340.                         FPECODE = _FPE_INEXACT;
  341.  
  342.                 else if ( pxcptact->XcptNum == STATUS_FLOAT_STACK_CHECK )
  343.  
  344.                         FPECODE = _FPE_STACKOVERFLOW;
  345.  
  346.                 /*
  347.                  * call the SIGFPE handler. note the special code to support
  348.                  * old MS-C programs whose SIGFPE handlers expect two args.
  349.                  *
  350.                  * NOTE: THE CAST AND CALL BELOW DEPEND ON __cdecl BEING
  351.                  * CALLER CLEANUP!
  352.                  */
  353.                 (*(void (__cdecl *)(int, int))phandler)(SIGFPE, FPECODE);
  354.  
  355.                 /*
  356.                  * restore the old value of _fpecode
  357.                  */
  358.                 FPECODE = oldfpecode;
  359.         }
  360.         else {
  361.                 /*
  362.                  * reset the XcptAction field to the default, then call the
  363.                  * user-supplied handler
  364.                  */
  365.                 pxcptact->XcptAction = SIG_DFL;
  366.                 (*phandler)(pxcptact->SigNum);
  367.         }
  368.  
  369.         /*
  370.          * restore the old value of _pxcptinfoptrs
  371.          */
  372.         PXCPTINFOPTRS = oldpxcptinfoptrs;
  373.  
  374.         return(EXCEPTION_CONTINUE_EXECUTION);
  375.  
  376. }
  377.  
  378.  
  379. /***
  380. *struct _XCPT_ACTION * xcptlookup(xcptnum, pxcptrec) - look up exception-action
  381. *       table entry for xcptnum
  382. *
  383. *Purpose:
  384. *       Find the in _XcptActTab[] whose Xcptnum field is xcptnum.
  385. *
  386. *Entry:
  387. *       unsigned long xcptnum            - exception type
  388. *
  389. *       _PEXCEPTIONREPORTRECORD pxcptrec - pointer to exception report record
  390. *       (used only to distinguish different types of XCPT_SIGNAL)
  391. *
  392. *Exit:
  393. *       If successful, pointer to the table entry. If no such entry, NULL is
  394. *       returned.
  395. *
  396. *Exceptions:
  397. *
  398. *******************************************************************************/
  399.  
  400. #ifdef _MT
  401.  
  402. static struct _XCPT_ACTION * __cdecl xcptlookup (
  403.         unsigned long xcptnum,
  404.         struct _XCPT_ACTION * pxcptacttab
  405.         )
  406.  
  407. #else  /* _MT */
  408.  
  409. static struct _XCPT_ACTION * __cdecl xcptlookup (
  410.         unsigned long xcptnum
  411.         )
  412.  
  413. #endif  /* _MT */
  414.  
  415. {
  416. #ifdef _MT
  417.         struct _XCPT_ACTION *pxcptact = pxcptacttab;
  418. #else  /* _MT */
  419.         struct _XCPT_ACTION *pxcptact = _XcptActTab;
  420. #endif  /* _MT */
  421.  
  422.         /*
  423.          * walk thru the _xcptactab table looking for the proper entry
  424.          */
  425. #ifdef _MT
  426.  
  427.         while ( (pxcptact->XcptNum != xcptnum) &&
  428.                 (++pxcptact < pxcptacttab + _XcptActTabCount) ) ;
  429.  
  430. #else  /* _MT */
  431.  
  432.         while ( (pxcptact->XcptNum != xcptnum) &&
  433.                 (++pxcptact < _XcptActTab + _XcptActTabCount) ) ;
  434.  
  435. #endif  /* _MT */
  436.  
  437.         /*
  438.          * if no table entry was found corresponding to xcptnum, return NULL
  439.          */
  440. #ifdef _MT
  441.         if ( (pxcptact >= pxcptacttab + _XcptActTabCount) ||
  442. #else  /* _MT */
  443.         if ( (pxcptact >= _XcptActTab + _XcptActTabCount) ||
  444. #endif  /* _MT */
  445.              (pxcptact->XcptNum != xcptnum) )
  446.                 return(NULL);
  447.  
  448.         return(pxcptact);
  449. }
  450.  
  451.  
  452.