Friday, December 4, 2009

Example: Using a Filter Function









Example: Using a Filter Function


Program 4-3 is a skeleton program that illustrates exception and termination handling with a filter function. This example prompts the user to specify the exception type and then proceeds to generate an exception. The filter function disposes of the different exception types in various ways; the selections here are arbitrary and are intended simply to illustrate the possibilities. In particular, the program diagnoses memory access violations, giving the virtual address of the reference.


The __finally block restores the state of the floating-point mask. Restoring state, as done here, is clearly not important when the process is about to terminate, but it is important later when a thread is terminated. In general, a process should still restore system resources by, for example, deleting temporary files and releasing synchronization resources (Chapter 8) and file locks (Chapters 3 and 6). The filter function is shown in Program 4-4.


This example does not illustrate memory allocation exceptions; they will be used extensively starting in Chapter 5.


Program 4-3. Excption: Processing Exceptions and Termination



#include "EvryThng.h"
#include <float.h>

DWORD Filter (LPEXCEPTION_POINTERS, LPDWORD);
double x = 1.0, y = 0.0;

int _tmain (int argc, LPTSTR argv [])
{
DWORD ECatgry, i = 0, ix, iy = 0;
LPDWORD pNull = NULL;
BOOL Done = FALSE;
DWORD FPOld, FPNew;
FPOld = _controlfp (0, 0); /* Save old control mask. */
/* Enable floating-point exceptions. */
FPNew = FPOld & ~(EM_OVERFLOW | EM_UNDERFLOW | EM_INEXACT
| EM_ZERODIVIDE | EM_DENORMAL | EM_INVALID);
_controlfp (FPNew, MCW_EM);

while (!Done) _try { /* Try-finally. */
_tprintf (_T ("Enter exception type: "));
_tprintf (_T
(" 1: Mem, 2: Int, 3: Flt 4: User 5: __leave "));
_tscanf (_T ("%d"), &i);
__try { /* Try-except block. */
switch (i) {
case 1: /* Memory reference. */
ix = *pNull; *pNull = 5; break;
case 2: /* Integer arithmetic. */
ix = ix / iy; break;
case 3: /* Floating-point exception. */
x = x / y;
_tprintf (_T ("x = %20e\n"), x); break;
case 4: /* User-generated exception. */
ReportException (_T ("User exception"), 1); break;
case 5: /* Use the _leave statement to terminate. */
__leave;
default: Done = TRUE;
}
} /* End of inner __try. */

__except (Filter (GetExceptionInformation (), &ECatgry))
{
switch (ECatgry) {
case 0:
_tprintf (_T ("Unknown Exception\n")); break;
case 1:
_tprintf (_T ("Memory Ref Exception\n")); continue;
case 2:
_tprintf (_T ("Integer Exception\n")); break;
case 3:
_tprintf (_T ("Floating-Point Exception\n"));
_clearfp (); break;
case 10:
_tprintf (_T ("User Exception\n")); break;
default:
_tprintf ( _T ("Unknown Exception\n")); break;
} /* End of switch statement. */

_tprintf (_T ("End of handler\n"));
} /* End of try-except block. */
} /* End of While loop -- the termination handler is below. */

__finally { /* This is part of the while loop. */
_tprintf (_T ("Abnormal Termination?: %d\n"),
AbnormalTermination ());
}
_controlfp (FPOld, 0xFFFFFFFF); /* Restore old FP mask.*/
return 0;
}



Program 4-4 shows the filter function used in Program 4-3. This function simply checks and categorizes the various possible exception code values. The code on the book's Web site checks every possible value; here the function tests only for a few that are relevant to the test program.


Program 4-4. The Filter Function



static DWORD Filter (LPEXCEPTION_POINTERS pExP, LPDWORD ECatgry)
/* Categorize the exception and decide action. */
{
DWORD ExCode, ReadWrite, VirtAddr;
ExCode = pExP->ExceptionRecord->ExceptionCode;
_tprintf (_T ("Filter. ExCode: %x\n"), ExCode);
if ((0x20000000 & ExCode) != 0) { /* User exception. */
*ECatgry = 10;
return EXCEPTION_EXECUTE_HANDLER;
}

switch (ExCode) {
case EXCEPTION_ACCESS_VIOLATION:
ReadWrite = /* Was it a read or a write? */
pExP->ExceptionRecord->ExceptionInformation [0];
VirtAddr = /* Virtual address of the violation. */
pExP->ExceptionRecord->ExceptionInformation [1];
_tprintf (
_T ("Access Violation. Read/Write: %d. Address: %x\n"),
ReadWrite, VirtAddr);
*ECatgry = 1;
return EXCEPTION_EXECUTE_HANDLER;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_OVERFLOW:
*ECatgry = 2;
return EXCEPTION_EXECUTE_HANDLER;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:

case EXCEPTION_FLT_OVERFLOW:
_tprintf (_T ("Flt Exception - large result.\n"));
*ECatgry = 3;
_clearfp ();
return (DWORD) EXCEPTION_EXECUTE_HANDLER;

default:
*ECatgry = 0;
return EXCEPTION_CONTINUE_SEARCH;
}
}










    No comments: