home *** CD-ROM | disk | FTP | other *** search
/ Power GUI Programming with VisualAge C++ / powergui.iso / trialva / ibmcppw / samples / compiler / seh / seh.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-20  |  17.6 KB  |  494 lines

  1. /*+--------------------------------------------------------------------------+*/
  2. /*|                                                                          |*/
  3. /*| PROGRAM NAME: SEH                                                        |*/
  4. /*| -------------                                                            |*/
  5. /*|  A Structured Exception Handling Sample program                          |*/
  6. /*|                                                                          |*/
  7. /*| COPYRIGHT:                                                               |*/
  8. /*| ----------                                                               |*/
  9. /*|  Copyright (C) International Business Machines Corp.,                    |*/
  10. /*|  1991,1992,1993,1994,1995,1996.                                          |*/
  11. /*|                                                                          |*/
  12. /*| DISCLAIMER OF WARRANTIES:                                                |*/
  13. /*| -------------------------                                                |*/
  14. /*| The following [enclosed] code is sample code created by IBM              |*/
  15. /*| Corporation.  This sample code is not part of any standard IBM product   |*/
  16. /*| and is provided to you solely for the purpose of assisting you in the    |*/
  17. /*| development of your applications.  The code is provided "AS IS",         |*/
  18. /*| without warranty of any kind.  IBM shall not be liable for any damages   |*/
  19. /*| arising out of your use of the sample code, even if they have been       |*/
  20. /*| advised of the possibility of such damages.                              |*/
  21. /*|                                                                          |*/
  22. /*| REVISION LEVEL: 1.0                                                      |*/
  23. /*| ---------------                                                          |*/
  24. /*|                                                                          |*/
  25. /*| WHAT THIS PROGRAM DOES:                                                  |*/
  26. /*| -----------------------                                                  |*/
  27. /*|  This program is a demonstration of the use of Structured Exception      |*/
  28. /*|  Handling. It will show both Termination Handling and Exception Hanlding.|*/
  29. /*|  Some concepts adapted from Advanced Windows NT by Jeffrey Richter.      |*/
  30. /*|                                                                          |*/
  31. /*| WHAT THIS PROGRAM DEMONSTRATES:                                          |*/
  32. /*| -------------------------------                                          |*/
  33. /*|  This program demonstrates the following in Structured Exceptions:         |*/
  34. /*|  TRY-FINALLY Block                                                       |*/
  35. /*|  TRY-EXCEPT Block                                                        |*/
  36. /*|   Global Unwind                                                          |*/
  37. /*|   AbnormalTermination                                                    |*/
  38. /*|   GetExceptionCode                                                       |*/
  39. /*|   GetExceptionInformation                                                |*/
  40. /*|  REQUIRED FILES:                                                         |*/
  41. /*|  ---------------                                                         |*/
  42. /*|                                                                          |*/
  43. /*|    SEH.C         - Source code                                           |*/
  44. /*|                                                                          |*/
  45. /*|  REQUIRED PROGRAMS:                                                      |*/
  46. /*|  ------------------                                                      |*/
  47. /*|                                                                          |*/
  48. /*|    IBM C Set++ Compiler                                                  |*/
  49. /*|    IBM Linker                                                            |*/
  50. /*|                                                                          |*/
  51. /*|                                                                          |*/
  52. /*+--------------------------------------------------------------------------+*/
  53.  
  54. #include <windows.h>
  55. #include <stdio.h>      
  56. #include <stdlib.h> 
  57. #include <excpt.h>
  58.  
  59. #define FILENAME        "seh.txt"    /* File for reading */
  60. #define FILEMODE        "r"        /* open file for read */
  61. #define NUMOBJECTS         (50)    /* Make it 50 objects */
  62. #define NUMATTEMPTS        (100)    /* Make 100 attempts at accessing these objects */
  63.  
  64. void openFile(void);
  65. int MakeArrayFilter (LPEXCEPTION_POINTERS, LPBYTE, LONG);
  66.  
  67. /* Useful macro for creating our own software exception codes.
  68.    This is a 32 bit value laid out as follows:
  69.    Bit 31-30    Sev        00     Success
  70.                           01     Informational
  71.                           10     Warning
  72.                           11     Error
  73.    Bit 29        Cus/MS    0     MS reserved
  74.                           1    Customer code
  75.    Bit 28        Reserved bit (always 0)
  76.    Bit 27-16    Facility Code
  77.    Bit 15-0        Facility's status code
  78. */
  79. #define MAKEUSEREXCEPTION(Severity, Facility, Exception) \
  80.    ((DWORD) ( \
  81.    /* Severity code */     (Severity  << 30) |     \
  82.    /* MS(0) or Cust(1) */  (1         << 29) |     \
  83.    /* Reserved(0) */       (0         << 28) |     \
  84.    /* Facility code */     (Facility  << 16) |     \
  85.    /* Exception code */    (Exception <<  0)))
  86.  
  87. /* Our very own software exception. This exception is raised
  88.    when an object of the array needs to be initialized
  89.    to all zeroes.
  90. */
  91. #define SE_ZERO_OBJECT   MAKEUSEREXCEPTION(3, 0, 1)
  92.  
  93. /* Declare each array object to be 1K bytes. */
  94. typedef struct {
  95.    BYTE OneK[1024];
  96. } OBJECT, *LPOBJECT;
  97.  
  98. int openFileFilter(DWORD dwExceptionCode) {
  99.     #if !NDEBUG
  100.         printf("   ExceptionCode is:%x\n",dwExceptionCode);
  101.     #endif
  102.     switch (dwExceptionCode){
  103.         case EXCEPTION_ACCESS_VIOLATION:
  104.             return EXCEPTION_EXECUTE_HANDLER;
  105.         default:
  106.             return EXCEPTION_CONTINUE_SEARCH;
  107.     }
  108. }
  109.  
  110. void openFile() {
  111.     FILE *hFile;
  112.        
  113.     __try {
  114.         /* Clear the "Execution log" list box. */
  115.         printf("Starting execution for Termination Handler sample\n");
  116.  
  117.           /* Open the file. */
  118.  
  119.           /* This line could cause an exception */
  120.           hFile = fopen(FILENAME,FILEMODE);
  121.  
  122.         if (hFile != NULL)
  123.             printf("   File open: OK\n");
  124.         else {
  125.             printf("   File open: FAIL\n");
  126.                 __leave; 
  127.         }
  128.  
  129.         /* Now do some processing that will cause an exception 
  130.            We will just raise a dummy exception to cause a Global Unwind */
  131.         RaiseException(EXCEPTION_ACCESS_VIOLATION, 
  132.             0, /*ontinuable exception, */
  133.             0, NULL); /* No arguments */
  134.         
  135.        }   /* try */
  136.     __finally {
  137.            /*Display a notification that we are cleaning up. */
  138.           printf("   Cleaning up\n");
  139.  
  140.           /* Guarantee that the file is closed. */
  141.           if (!AbnormalTermination()) {
  142.             /* Normal Exit of Try block involves:
  143.                1. Execution to the closing brace
  144.                2. exit through __leave
  145.                  No errors occurred in the try block, so just close the file */
  146.             if (hFile) {
  147.                 printf("   Normal Exit: Closing file\n");
  148.                 fclose(hFile);
  149.             } else
  150.                 printf("   Exit through __leave: nothing to close\n");
  151.  
  152.           }    else {
  153.               /* Abnormal exit of TRY block. Possibly due to:
  154.                  1. an exception causing a Global Unwind
  155.                  2. Local Unwind
  156.                  Option 2 is impossible as there are no goto/return/break/continue/longjmp
  157.                  in TRY block. So it must be a Global Unwind. */
  158.             if (hFile) {
  159.                 printf("   Abnormal Exit: Closing file\n");
  160.                 fclose(hFile);
  161.             }
  162.         }
  163.     } /*finally*/
  164. }
  165.  
  166. void SetVirtualMem(LPEXCEPTION_POINTERS lpEP, LPBYTE lpAccessMemAddr) {
  167.  
  168.        BOOL fWriteToMem;
  169.   
  170.      /* Find out whether a memory read or write was tried. */
  171.        fWriteToMem = (BOOL)lpEP->ExceptionRecord->ExceptionInformation[0];
  172.  
  173.        /* Add an entry to the "Execution log" list box. */
  174.        printf("---> Committing memory (%s attempted)\n",fWriteToMem ? "write" : "read");
  175.   
  176.        /* The attempted memory access did occur while the 
  177.           program was accessing an object in our array.
  178.           Let's try to commit memory to an individual object of
  179.           the reserved array's address space. */
  180.  
  181.        VirtualAlloc (lpAccessMemAddr, sizeof(OBJECT), MEM_COMMIT, PAGE_READWRITE);
  182.  
  183.        if (!fWriteToMem) {
  184.         /* The program is trying to read an array OBJECT
  185.              that has never been created. We'll raise our very
  186.              own software exception so that this array object
  187.              will be zeroed before it is accessed. */
  188.           RaiseException(SE_ZERO_OBJECT, 0, 1,(LPDWORD) &lpAccessMemAddr);
  189.        }
  190. }
  191.  
  192. int MakeArrayFilter (LPEXCEPTION_POINTERS lpEP, LPBYTE lpArrayOfObject, LONG lNumBytesinArrayofObject) {
  193.  
  194.        /* Get the exception code explaining
  195.           why the filter is executing. */
  196.        DWORD  dwExceptionCode =lpEP->ExceptionRecord->ExceptionCode;
  197.        /* Assume that this filter will NOT handle the exception
  198.           and will let the system continue scanning
  199.           for other filters. */
  200.        int    nFilterAction = EXCEPTION_CONTINUE_SEARCH;
  201.  
  202.        LPBYTE lpAccessMemAddr;
  203.     #if !NDEBUG
  204.            printf("Filter:dwExceptionCode=%x\n",dwExceptionCode);
  205.     #endif
  206.     __try {
  207.           /* Declare an EXCEPTION_RECORD structure that is local 
  208.              to this __try frame. This variable is used in the 
  209.              __except block below. */
  210.           EXCEPTION_RECORD ArrayExceptRec;
  211.  
  212.           /* We must first determine if the exception is
  213.              occurring because of a memory access to zero the
  214.              array of elements. This filter and handler does not
  215.              process any other types of exceptions. */
  216.  
  217.           if (dwExceptionCode != EXCEPTION_ACCESS_VIOLATION) {
  218.             /* If the exception is not a memory access violation,
  219.                 the exception is not due to an array object
  220.                 access. The system should continue its search for
  221.                 another exception filter. */
  222.              nFilterAction = EXCEPTION_CONTINUE_SEARCH;
  223.              __leave;
  224.           }
  225.  
  226.           if (lpArrayOfObject == NULL) {
  227.              /* The exception occurred either before attempting to
  228.                 reserve the address space or, the array's address
  229.                 space was unsuccessfully reserved. */
  230.              nFilterAction = EXCEPTION_CONTINUE_SEARCH;
  231.              __leave; 
  232.           }
  233.  
  234.           /* Get the address of the attempted memory access. */
  235.           lpAccessMemAddr = (LPBYTE)lpEP->ExceptionRecord->ExceptionInformation[1];
  236.           
  237.           if ((lpAccessMemAddr < lpArrayOfObject) ||((lpArrayOfObject + lNumBytesinArrayofObject) < lpAccessMemAddr)) {
  238.             /* Address attempted is BELOW the beginning of the
  239.                  array's reserved space or is ABOVE the end of the
  240.                  array's reserved space. We'll let some other
  241.                filter handle this exception. */
  242.              nFilterAction = EXCEPTION_CONTINUE_SEARCH;
  243.              __leave; 
  244.           }
  245.  
  246.  
  247.           __try {
  248.              /* Call the function that commits memory to the
  249.                 accessed array object. This function will raise
  250.                 a software exception if read-access was attempted.
  251.                 In this case, we want to zero the contents of the
  252.                 array object before the read continues. */
  253.         
  254.             SetVirtualMem(lpEP, lpAccessMemAddr);
  255.           }
  256.  
  257.           /* We only want to handle the exception if it is our
  258.              very own software exception telling us to zero the
  259.              contents of the array object. If this happens, we
  260.              need to save the additional information given to us
  261.              with the SE_ZERO_OBJECT exception code so that the
  262.              handler knows which array object to zero. */
  263.           __except ((GetExceptionCode() == SE_ZERO_OBJECT) ?
  264.              (ArrayExceptRec = 
  265.             *((GetExceptionInformation())->ExceptionRecord),
  266.             EXCEPTION_EXECUTE_HANDLER) : EXCEPTION_CONTINUE_SEARCH) {
  267.              /* Get the address of the array object to zero. */
  268.              LPOBJECT lpArrayObjectToZero = (LPOBJECT)
  269.                 ArrayExceptRec.ExceptionInformation[0];
  270.  
  271.              /* Zero the array object before reading from it. */
  272.              memset((LPVOID) lpArrayObjectToZero, 0, sizeof(OBJECT));
  273.  
  274.              printf("---> Zeroed array object\n");
  275.           }
  276.  
  277.           /* Memory is committed now, let's restart the
  278.              instruction that caused the exception in the first
  279.              place. This time, it will succeed and not cause
  280.              another exception. */
  281.           nFilterAction = EXCEPTION_CONTINUE_EXECUTION;
  282.        }
  283.  
  284.        __finally {
  285.         /* There is nothing to do here, except to show that
  286.            one can have a Termination Handler inside an
  287.             Exception Handler.
  288.            You could use this to show status. */
  289.        }
  290.  
  291.        /* Now that memory is committed, we can continue execution
  292.           on the instruction that generated the exception in
  293.           the first place. */
  294.        return(nFilterAction);
  295. }
  296.  
  297. void makeArray(int nNumAttempts) {
  298.     LPOBJECT lpArrayOfObject;
  299.        OBJECT Object;
  300.        int nObjectNum;
  301.        const LONG lNumBytesinArrayofObject = sizeof(OBJECT) * NUMOBJECTS;
  302.  
  303.        __try {
  304.            /* Clear the "Execution log" list box. */
  305.            printf("Starting Execution on Exception Handler sample\n");
  306.  
  307.           /* Reserve an address space large enough to
  308.              hold NUMOBJECTS number of ELEMENTs. */
  309.           lpArrayOfObject=VirtualAlloc(NULL,lNumBytesinArrayofObject,MEM_RESERVE, PAGE_NOACCESS);
  310.  
  311.         while (nNumAttempts--) {
  312.             #if !NDEBUG
  313.                 printf("NumAccesses=%d\n",nNumAttempts);
  314.             #endif
  315.              /* Get the index of a random object to access. */
  316.              nObjectNum = rand() % NUMOBJECTS;
  317.  
  318.              /* Give us a 50% chance of reading and a
  319.                 50% chance of writing. */
  320.              if ((rand() % 2) == 0) {
  321.                 /* Attempt a read access. */
  322.                 printf("Reading index: %d\n",nObjectNum);
  323.  
  324.                 /* The exception will occur on this line. */
  325.                 Object = lpArrayOfObject[nObjectNum];
  326.  
  327.              } else {
  328.                 /* Attempt a write access. */
  329.                 printf("Writing index: %d\n",nObjectNum);
  330.  
  331.                 /* The exception will occur on this line. */
  332.                 lpArrayOfObject[nObjectNum] = Object;
  333.              }
  334.  
  335.           }  /* while */
  336.  
  337.           /* We are done with the execution. */
  338.           printf("Execution ended\n");
  339.  
  340.           /* Decommit and free the array of ELEMENTs. */
  341.           VirtualFree(lpArrayOfObject,0, MEM_RELEASE);
  342.        }  /* __try */
  343.  
  344.        __except (
  345.         MakeArrayFilter(GetExceptionInformation(), (LPBYTE) lpArrayOfObject,
  346.         lNumBytesinArrayofObject)) {
  347.  
  348.           /* Since the filter never returns
  349.              EXCEPTION_EXECUTE_HANDLER, there is nothing
  350.              to do here. */
  351.  
  352.        }  /* __except */
  353. }
  354.            
  355. void main()     {
  356. /* Part 1: demonstrate Termination Handling */
  357. /* This will attempt to open a non-existant file, and will
  358.    clean itself up through the finally body */
  359.     __try {
  360.         openFile();
  361.     }
  362.     __except (openFileFilter(GetExceptionCode())) {
  363.             printf("   Open File: Caught Exception Access Violation\n");
  364.     } /* except */
  365. /* Part 2: demonstrate Exception Handling */
  366.     makeArray(NUMATTEMPTS);
  367. }      
  368. /* ouput should be something like:
  369.  
  370. Starting execution for Termination Handler sample
  371.    File open: FAIL
  372.    Cleaning up
  373.    Exit through __leave: nothing to close
  374. Starting Execution on Exception Handler sample
  375. Reading index: 38
  376. ---> Committing memory (read attempted)
  377. ---> Zeroed array object
  378. Writing index: 13
  379. ---> Committing memory (write attempted)
  380. Writing index: 1
  381. ---> Committing memory (write attempted)
  382. Writing index: 10
  383. ---> Committing memory (write attempted)
  384. Reading index: 12
  385. Writing index: 49
  386. ---> Committing memory (write attempted)
  387. Reading index: 34
  388. ---> Committing memory (read attempted)
  389. ---> Zeroed array object
  390. Writing index: 25
  391. ---> Committing memory (write attempted)
  392. Writing index: 39
  393. Reading index: 37
  394. Reading index: 16
  395. ---> Committing memory (read attempted)
  396. ---> Zeroed array object
  397. Writing index: 45
  398. ---> Committing memory (write attempted)
  399. Reading index: 17
  400. Writing index: 31
  401. ---> Committing memory (write attempted)
  402. Reading index: 32
  403. Writing index: 24
  404. Reading index: 44
  405. Writing index: 1
  406. Writing index: 4
  407. ---> Committing memory (write attempted)
  408. Reading index: 11
  409. Reading index: 28
  410. Writing index: 35
  411. Reading index: 17
  412. Writing index: 15
  413. Reading index: 12
  414. Reading index: 3
  415. Writing index: 44
  416. Reading index: 12
  417. Writing index: 22
  418. ---> Committing memory (write attempted)
  419. Writing index: 7
  420. Writing index: 29
  421. Reading index: 1
  422. Writing index: 20
  423. Writing index: 48
  424. Reading index: 29
  425. Reading index: 6
  426. Reading index: 38
  427. Reading index: 14
  428. Writing index: 16
  429. Reading index: 31
  430. Reading index: 43
  431. ---> Committing memory (read attempted)
  432. ---> Zeroed array object
  433. Reading index: 33
  434. Writing index: 10
  435. Writing index: 21
  436. Writing index: 36
  437. Writing index: 10
  438. Reading index: 29
  439. Writing index: 25
  440. Writing index: 14
  441. Writing index: 38
  442. Writing index: 2
  443. Writing index: 34
  444. Writing index: 32
  445. Writing index: 36
  446. Reading index: 6
  447. Reading index: 1
  448. Reading index: 23
  449. Reading index: 43
  450. Reading index: 48
  451. Writing index: 20
  452. Reading index: 6
  453. Writing index: 16
  454. Reading index: 43
  455. Writing index: 41
  456. Writing index: 26
  457. Reading index: 35
  458. Reading index: 10
  459. Writing index: 2
  460. Reading index: 20
  461. Reading index: 39
  462. Writing index: 35
  463. Writing index: 25
  464. Writing index: 14
  465. Writing index: 26
  466. Writing index: 43
  467. Writing index: 19
  468. Writing index: 23
  469. Reading index: 15
  470. Writing index: 23
  471. Writing index: 13
  472. Writing index: 49
  473. Reading index: 13
  474. Writing index: 26
  475. Reading index: 46
  476. Reading index: 36
  477. Reading index: 28
  478. Writing index: 23
  479. Writing index: 21
  480. Reading index: 2
  481. Writing index: 41
  482. Reading index: 22
  483. Writing index: 28
  484. Writing index: 13
  485. Reading index: 41
  486. Reading index: 25
  487. Writing index: 13
  488. Writing index: 44
  489. Writing index: 13
  490. Reading index: 11
  491. Reading index: 45
  492. Execution ended
  493. */
  494.