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 >
Wrap
C/C++ Source or Header
|
1998-06-17
|
14KB
|
452 lines
/***
*winxfltr.c - startup exception filter
*
* Copyright (c) 1990-1997, Microsoft Corporation. All rights reserved
*
*Purpose:
* Defines _XcptFilter(), the function called by the exception filter
* expression in the startup code.
*
*******************************************************************************/
#include <cruntime.h>
#include <float.h>
#include <mtdll.h>
#include <oscalls.h>
#include <signal.h>
#include <stddef.h>
/*
* special code denoting no signal.
*/
#define NOSIG -1
struct _XCPT_ACTION _XcptActTab[] = {
/*
* Exceptions corresponding to the same signal (e.g., SIGFPE) must be grouped
* together.
*
* XcptNum SigNum XcptAction
* -------------------------------------------------------------------
*/
{ (unsigned long)STATUS_ACCESS_VIOLATION, SIGSEGV, SIG_DFL },
{ (unsigned long)STATUS_ILLEGAL_INSTRUCTION, SIGILL, SIG_DFL },
{ (unsigned long)STATUS_PRIVILEGED_INSTRUCTION, SIGILL, SIG_DFL },
/* { (unsigned long)STATUS_NONCONTINUABLE_EXCEPTION, NOSIG, SIG_DIE },
*/
/* { (unsigned long)STATUS_INVALID_DISPOSITION, NOSIG, SIG_DIE },
*/
{ (unsigned long)STATUS_FLOAT_DENORMAL_OPERAND, SIGFPE, SIG_DFL },
{ (unsigned long)STATUS_FLOAT_DIVIDE_BY_ZERO, SIGFPE, SIG_DFL },
{ (unsigned long)STATUS_FLOAT_INEXACT_RESULT, SIGFPE, SIG_DFL },
{ (unsigned long)STATUS_FLOAT_INVALID_OPERATION, SIGFPE, SIG_DFL },
{ (unsigned long)STATUS_FLOAT_OVERFLOW, SIGFPE, SIG_DFL },
{ (unsigned long)STATUS_FLOAT_STACK_CHECK, SIGFPE, SIG_DFL },
{ (unsigned long)STATUS_FLOAT_UNDERFLOW, SIGFPE, SIG_DFL },
/* { (unsigned long)STATUS_INTEGER_DIVIDE_BY_ZERO, NOSIG, SIG_DIE },
*/
/* { (unsigned long)STATUS_STACK_OVERFLOW, NOSIG, SIG_DIE }
*/
};
/*
* WARNING!!!! The definition below amounts to defining that:
*
* XcptActTab[ _First_FPE_Indx ]
*
* is the very FIRST entry in the table corresponding to a floating point
* exception. Whenever the definition of the XcptActTab[] table is changed,
* this #define must be review to ensure correctness.
*/
int _First_FPE_Indx = 3;
/*
* There are _Num_FPE (currently, 7) entries in XcptActTab corresponding to
* floating point exceptions.
*/
int _Num_FPE = 7;
#ifdef _MT
/*
* size of the exception-action table (in bytes)
*/
int _XcptActTabSize = sizeof _XcptActTab;
#endif /* _MT */
/*
* number of entries in the exception-action table
*/
int _XcptActTabCount = (sizeof _XcptActTab)/sizeof(_XcptActTab[0]);
#ifdef _MT
/*
* the FPECODE and PXCPTINFOPTRS macros are intended to simplify some of
* single vs multi-thread code in the filter function. basically, each macro
* is conditionally defined to be a global variable or the corresponding
* field in the per-thread data structure. NOTE THE ASSUMPTION THAT THE
* _ptiddata VARIABLE IS ALWAYS NAMED ptd!!!!
*/
#define FPECODE ptd->_tfpecode
#define PXCPTINFOPTRS ptd->_tpxcptinfoptrs
#else /* _MT */
/*
* global variable containing the floating point exception code
*/
int _fpecode = _FPE_EXPLICITGEN;
#define FPECODE _fpecode
/*
* global variable holding _PEXCEPTION_INFO_PTRS value
*/
void * _pxcptinfoptrs = NULL;
#define PXCPTINFOPTRS _pxcptinfoptrs
#endif /* _MT */
/*
* function to look up the exception action table (_XcptActTab[]) corresponding
* to the given exception
*/
#ifdef _MT
static struct _XCPT_ACTION * __cdecl xcptlookup(
unsigned long,
struct _XCPT_ACTION *
);
#else /* _MT */
static struct _XCPT_ACTION * __cdecl xcptlookup(
unsigned long
);
#endif /* _MT */
/***
*int _XcptFilter(xcptnum, pxcptptrs) - Identify exception and the action to
* be taken with it
*
*Purpose:
* _XcptFilter() is called by the exception filter expression of the
* _try - _except statement, in the startup code, which guards the call
* to the user's main(). _XcptFilter() consults the _XcptActTab[] table
* to identify the exception and determine its disposition. The
* is disposition of an exception corresponding to a C signal may be
* modified by a call to signal(). There are three broad cases:
*
* (1) Unrecognized exceptions and exceptions for which the XcptAction
* value is SIG_DFL.
*
* In both of these cases, UnhandledExceptionFilter() is called and
* its return value is returned.
*
* (2) Exceptions corresponding to C signals with an XcptAction value
* NOT equal to SIG_DFL.
*
* These are the C signals whose disposition has been affected by a
* call to signal() or whose default semantics differ slightly from
* from the corresponding OS exception. In all cases, the appropriate
* disposition of the C signal is made by the function (e.g., calling
* a user-specified signal handler). Then, EXCEPTION_CONTINUE_EXECU-
* TION is returned to cause the OS exception dispatcher to dismiss
* the exception and resume execution at the point where the
* exception occurred.
*
* (3) Exceptions for which the XcptAction value is SIG_DIE.
*
* These are the exceptions corresponding to fatal C runtime errors.
* _XCPT_HANDLE is returned to cause control to pass into the
* _except-block of the _try - _except statement. There, the runtime
* error is identified, an appropriate error message is printed out
* and the program is terminated.
*
*Entry:
*
*Exit:
*
*Exceptions:
* That's what it's all about!
*
*******************************************************************************/
int __cdecl _XcptFilter (
unsigned long xcptnum,
PEXCEPTION_POINTERS pxcptinfoptrs
)
{
struct _XCPT_ACTION * pxcptact;
_PHNDLR phandler;
void *oldpxcptinfoptrs;
int oldfpecode;
int indx;
#ifdef _MT
_ptiddata ptd = _getptd();
#endif /* _MT */
/*
* first, take care of all unrecognized exceptions and exceptions with
* XcptAction values of SIG_DFL.
*/
#ifdef _MT
if ( ((pxcptact = xcptlookup(xcptnum, ptd->_pxcptacttab)) == NULL)
|| (pxcptact->XcptAction == SIG_DFL) )
#else /* _MT */
if ( ((pxcptact = xcptlookup(xcptnum)) == NULL) ||
(pxcptact->XcptAction == SIG_DFL) )
#endif /* _MT */
/*
* pass the buck to the UnhandledExceptionFilter
*/
return( UnhandledExceptionFilter(pxcptinfoptrs) );
/*
* next, weed out all of the exceptions that need to be handled by
* dying, perhaps with a runtime error message
*/
if ( pxcptact->XcptAction == SIG_DIE ) {
/*
* reset XcptAction (in case of recursion) and drop into the
* except-clause.
*/
pxcptact->XcptAction = SIG_DFL;
return(EXCEPTION_EXECUTE_HANDLER);
}
/*
* next, weed out all of the exceptions that are simply ignored
*/
if ( pxcptact->XcptAction == SIG_IGN )
/*
* resume execution
*/
return(EXCEPTION_CONTINUE_EXECUTION);
/*
* the remaining exceptions all correspond to C signals which have
* signal handlers associated with them. for some, special setup
* is required before the signal handler is called. in all cases,
* if the signal handler returns, -1 is returned by this function
* to resume execution at the point where the exception occurred.
*/
phandler = pxcptact->XcptAction;
/*
* save the old value of _pxcptinfoptrs (in case this is a nested
* exception/signal) and store the current one.
*/
oldpxcptinfoptrs = PXCPTINFOPTRS;
PXCPTINFOPTRS = pxcptinfoptrs;
/*
* call the user-supplied signal handler
*
* floating point exceptions must be handled specially since, from
* the C point-of-view, there is only one signal. the exact identity
* of the exception is passed in the global variable _fpecode.
*/
if ( pxcptact->SigNum == SIGFPE ) {
/*
* reset the XcptAction field to the default for all entries
* corresponding to SIGFPE.
*/
for ( indx = _First_FPE_Indx ;
indx < _First_FPE_Indx + _Num_FPE ;
indx++ )
{
#ifdef _MT
( (struct _XCPT_ACTION *)(ptd->_pxcptacttab) +
indx )->XcptAction = SIG_DFL;
#else /* _MT */
_XcptActTab[indx].XcptAction = SIG_DFL;
#endif /* _MT */
}
/*
* Save the current _fpecode in case it is a nested floating
* point exception (not clear that we need to support this,
* but it's easy).
*/
oldfpecode = FPECODE;
/*
* there are no exceptions corresponding to
* following _FPE_xxx codes:
*
* _FPE_UNEMULATED
* _FPE_SQRTNEG
*
* futhermore, STATUS_FLOATING_STACK_CHECK is
* raised for both floating point stack under-
* flow and overflow. thus, the exception does
* not distinguish between _FPE_STACKOVERLOW
* and _FPE_STACKUNDERFLOW. arbitrarily, _fpecode
* is set to the former value.
*
* the following should be a switch statement but, alas, the
* compiler doesn't like switching on unsigned longs...
*/
if ( pxcptact->XcptNum == STATUS_FLOAT_DIVIDE_BY_ZERO )
FPECODE = _FPE_ZERODIVIDE;
else if ( pxcptact->XcptNum == STATUS_FLOAT_INVALID_OPERATION )
FPECODE = _FPE_INVALID;
else if ( pxcptact->XcptNum == STATUS_FLOAT_OVERFLOW )
FPECODE = _FPE_OVERFLOW;
else if ( pxcptact->XcptNum == STATUS_FLOAT_UNDERFLOW )
FPECODE = _FPE_UNDERFLOW;
else if ( pxcptact->XcptNum == STATUS_FLOAT_DENORMAL_OPERAND )
FPECODE = _FPE_DENORMAL;
else if ( pxcptact->XcptNum == STATUS_FLOAT_INEXACT_RESULT )
FPECODE = _FPE_INEXACT;
else if ( pxcptact->XcptNum == STATUS_FLOAT_STACK_CHECK )
FPECODE = _FPE_STACKOVERFLOW;
/*
* call the SIGFPE handler. note the special code to support
* old MS-C programs whose SIGFPE handlers expect two args.
*
* NOTE: THE CAST AND CALL BELOW DEPEND ON __cdecl BEING
* CALLER CLEANUP!
*/
(*(void (__cdecl *)(int, int))phandler)(SIGFPE, FPECODE);
/*
* restore the old value of _fpecode
*/
FPECODE = oldfpecode;
}
else {
/*
* reset the XcptAction field to the default, then call the
* user-supplied handler
*/
pxcptact->XcptAction = SIG_DFL;
(*phandler)(pxcptact->SigNum);
}
/*
* restore the old value of _pxcptinfoptrs
*/
PXCPTINFOPTRS = oldpxcptinfoptrs;
return(EXCEPTION_CONTINUE_EXECUTION);
}
/***
*struct _XCPT_ACTION * xcptlookup(xcptnum, pxcptrec) - look up exception-action
* table entry for xcptnum
*
*Purpose:
* Find the in _XcptActTab[] whose Xcptnum field is xcptnum.
*
*Entry:
* unsigned long xcptnum - exception type
*
* _PEXCEPTIONREPORTRECORD pxcptrec - pointer to exception report record
* (used only to distinguish different types of XCPT_SIGNAL)
*
*Exit:
* If successful, pointer to the table entry. If no such entry, NULL is
* returned.
*
*Exceptions:
*
*******************************************************************************/
#ifdef _MT
static struct _XCPT_ACTION * __cdecl xcptlookup (
unsigned long xcptnum,
struct _XCPT_ACTION * pxcptacttab
)
#else /* _MT */
static struct _XCPT_ACTION * __cdecl xcptlookup (
unsigned long xcptnum
)
#endif /* _MT */
{
#ifdef _MT
struct _XCPT_ACTION *pxcptact = pxcptacttab;
#else /* _MT */
struct _XCPT_ACTION *pxcptact = _XcptActTab;
#endif /* _MT */
/*
* walk thru the _xcptactab table looking for the proper entry
*/
#ifdef _MT
while ( (pxcptact->XcptNum != xcptnum) &&
(++pxcptact < pxcptacttab + _XcptActTabCount) ) ;
#else /* _MT */
while ( (pxcptact->XcptNum != xcptnum) &&
(++pxcptact < _XcptActTab + _XcptActTabCount) ) ;
#endif /* _MT */
/*
* if no table entry was found corresponding to xcptnum, return NULL
*/
#ifdef _MT
if ( (pxcptact >= pxcptacttab + _XcptActTabCount) ||
#else /* _MT */
if ( (pxcptact >= _XcptActTab + _XcptActTabCount) ||
#endif /* _MT */
(pxcptact->XcptNum != xcptnum) )
return(NULL);
return(pxcptact);
}