Retro video games delivered to your door every month!
Click above to get retro games delivered to your door ever month!
X-Hacker.org- Watcom C/C++ User's Guide - where things really get interesting is in the interaction between<b></b> http://www.X-Hacker.org [<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
Where things really get interesting is in the interaction between
try/finally blocks and try/except blocks.  These blocks can be nested within
each other.  In an earlier part of the discussion, we talked about global
unwinds and how they can be caused by exceptions being generated in nested
function calls.  All of this should become clear after studying the
following example.

Example:

     #include <stdio.h>
     #include <stdlib.h>
     #include <excpt.h>

     func_level4()
     {
       char *nullp = NULL;

       printf( "Attempting illegal memory reference\n" );
       _try {
         *nullp = '\1';
       }
       _finally {
         if( AbnormalTermination() )
           printf( "Unwind in func_level4\n" );
       }
       printf( "Normal return from func_level4\n" );
     }

     func_level3()
     {
       _try {
         func_level4();
       }
       _finally {
         if( AbnormalTermination() )
           printf( "Unwind in func_level3\n" );
       }
       printf( "Normal return from func_level3\n" );
     }

     func_level2()
     {
       _try {
         _try {
           func_level3();
         }
         _except (EXCEPTION_CONTINUE_SEARCH) {
           printf( "Exception never handled in func_level2\n" );
         }
       }
       _finally {
         if( AbnormalTermination() )
           printf( "Unwind in func_level2\n" );
       }
       printf( "Normal return from func_level2\n" );
     }

     func_level1()
     {
       _try {
         func_level2();
       }
       _finally {
         if( AbnormalTermination() )
           printf( "Unwind in func_level1\n" );
       }
       printf( "Normal return from func_level1\n" );
     }

     func_level0()
     {
       _try {
         _try {
           func_level1();
         }
         _except (EXCEPTION_EXECUTE_HANDLER) {
           printf( "Exception handled in func_level0\n" );
         }
       }
       _finally {
         if( AbnormalTermination() )
           printf( "Unwind in func_level0\n" );
       }
       printf( "Normal return from func_level0\n" );
     }

     void main( int argc, char **argv )
     {
       _try {
         _try {
           func_level0();
         }
         _except (EXCEPTION_EXECUTE_HANDLER) {
           printf( "Exception handled in main\n" );
         }
       }
       _finally {
         if( AbnormalTermination() )
           printf( "Unwind in main\n" );
       }
       printf( "Normal return from main\n" );
     }

In this example,

 1. main calls func_level0

 2. func_level0 calls func_level1

 3. func_level1 calls func_level2

 4. func_level2 calls func_level3

 5. func_level3 calls func_level4

It is in func_level4 where the exception occurs.  The run-time system traps
the exception and performs a search of the active try blocks looking for one
that is paired up with an except block.

When it finds one, the filter is executed and, if the result is
EXCEPTION_EXECUTE_HANDLER, then the except block is executed after
performing a global unwind.

If the result is EXCEPTION_CONTINUE_EXECUTION, the run-time system resumes
execution at the instruction that caused the exception.

If the result is EXCEPTION_CONTINUE_SEARCH, the run-time system continues
its search for an except block with a filter that returns one of the other
possible values.  If it does not find any exception handler that is prepared
to handle the exception, the application will be terminated with the
appropriate exception notification.

Let us look at the result of executing the example program.  The following
messages are printed.


     Attempting illegal memory reference
     Unwind in func_level4
     Unwind in func_level3
     Unwind in func_level2
     Unwind in func_level1
     Exception handled in func_level0
     Normal return from func_level0
     Normal return from main

The run-time system searched down the try/except chain until it got to
func_level0 which had an except filter that evaluated to
EXCEPTION_EXECUTE_HANDLER.  It then performed a global unwind in which the
try/finally blocks of func_level4, func_level3, func_level2, and func_level1
were executed.  After this, the exception handler in func_level0 did its
thing and execution resumed in func_level0 which returned back to main which
returned to the run-time system for normal program termination.  Note the
use of the built-in AbnormalTermination function in the finally blocks of
each function.

This sequence of events permits each function to do any cleaning up that it
deems necessary before it is wiped off the execution stack.

Online resources provided by: http://www.X-Hacker.org --- NG 2 HTML conversion by Dave Pearson