The information in this article applies to:
SUMMARYWhen you use the try/finally exception handling, it helps to provide a robust application. If you use it incorrectly, however, it can cause unnecessary overhead. Any flow of control out of the try/finally block is considered an abnormal termination that can cause hundreds of instructions to be executed on an Intel x86 system, and thousands on RISC machines. This occurs even if the control leaves via a control statement on the very last statement of the try body or finally clause. MORE INFORMATION
Any flow of control out of the try/finally block using the following
statements causes abnormal termination: return, goto, continue, or break.
Notice that these statements only cause abnormal termination if they cause
control to leave the try block or finally clause. Using a break statement
in a loop inside the try block or finally clause only causes control to
exit the loop, not the try/finally block. This is perfectly acceptable. On
the other hand, use of a break statement that causes control to leave the
try block or finally block results in abnormal termination and inefficient
execution.
In the example above, abnormal termination of the try body occurs when the
return statement in the middle of the try body is executed. On the other
hand, if the result of the condition is false, then the return statement is
avoided and efficient execution of the finally clause occurs because this
is not an abnormal termination. Abnormal termination also occurs if the
return statement is executed in the finally clause.
The abnormal termination can be avoided in the above example a couple of ways. First, the return statement in the try body can be replaced with a __leave statement. Check your compiler documentation to determine if this statement is recognized by your compiler. If your compiler doesn't support such a statement, then you can use the second method. The second method avoids abnormal termination in both the try block and the finally clause by note executing a return statement at all. The solution is to move the return statement AFTER the end of the finally clause. This causes execution to fall through the try body normally. NOTE: If your compiler does not support the __leave directive, or if you are using C++ exception handling, you may also use the goto statement to simulate a "leave". To do this effeciently, create a label as the last line before the terminating brace of the try block and goto the label. It is important, however, NOT to goto a label outside of the try block. For example, then following code works properly:
When abnormal termination occurs, hundreds to thousands of instructions are
executed. A stack unwind must occur that causes a backward search through
frames to determine if there are any termination handlers to be called. On
an Intel x86 system, this executes the C runtime handlers and examines the
handler list. On a RISC machine, this also causes the function table to be
searched and the prologue of each intervening function to be executed
backwards interpretively.
Structured Exception Handling DetailsStructured exception handling has two stages. First, the system searches through the exception stack executing each exception filter. Evaluation of the exception filter results in one of the following: the machine state is restored and execution continues at the point of the exception, or the system continues searching for an exception handler repeating this stage, or the system transfers control to the exception handler (stage 2). In stage 2, thread execution continues in the stack frame where the exception handler is found. If the handler is not in the stack frame where the exception occurred, the system unwinds the stack, leaving the current stack frame and any other stack frames until it is back to the exception handler's stack frame. Before the exception handler's frame is reached during this unwind, each finally clause is executed for each try block that terminated as a result of the transfer of control to the exception handler.An abnormal termination in the finally clause aborts this second stage. Instead of returning to the system unwinder, the finally block returns to the enclosing function's caller (for instance, Foo()'s parent). The filter function may have set some status or performed an allocation in anticipation of the exception handler being entered. In this case, the intervening finally clause with the return stops the unwind, and the exception handler is never entered. This behavior is by design. It makes it possible for a finally clause to stop an unwind and return a status. This is what is referred to as a "collided unwind." Normally this behavior is transparent to any higher-level exception handling code. However, if a filter function stores information that it expects to process in an exception handler (as a side effect), then it may or may not be transparent. You should avoid storing such information in a filter function because it is always possible that the exception handler will not be executed because the unwind is preempted. In the absence of storing such information, it is transparent that an exception occurred and a collided unwind occurred if one of the descendant functions has a try/finally block with a finally clause that preempts the unwind. Additional query words: SEH scope
Keywords : kbprg kbKernBase kbNTOS350 kbNTOS351 kbNTOS400 kbWinOS2000 kbExceptHandSEH kbWinOS95 kbDSupport kbGrpKernBase |
Last Reviewed: January 11, 2000 © 2000 Microsoft Corporation. All rights reserved. Terms of Use. |