Structured Exception Handling (was: Try Finally...)
From: VBDis (vbdis_at_aol.com)
Date: 10/26/04
- Next message: Bjørge Sæther: "Re: Try Finally..."
- Previous message: VBDis: "Re: Try Finally..."
- In reply to:(deleted message) L D Blake: "Re: Try Finally..."
- Next in thread: Maarten Wiltink: "Re: Structured Exception Handling (was: Try Finally...)"
- Reply: Maarten Wiltink: "Re: Structured Exception Handling (was: Try Finally...)"
- Reply: Maarten Wiltink: "Re: Structured Exception Handling (was: Try Finally...)"
- Reply: J French: "Re: Structured Exception Handling (was: Try Finally...)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 26 Oct 2004 21:27:49 GMT
This thread shall help in separating facts from opinions about SEH. In the
first part I'll present some facts about the Windows SEH, as found in the MSDN.
In following parts we should try to describe the Delphi handling of exceptions,
and bring it together with the API procedures.
[MSDN: Structured Exception Handling]
An exception is an event that occurs during the execution of a program, and
requires the execution of code outside the normal flow of control...
Structured exception handling is a mechanism for handling both hardware and
software exceptions. Therefore, your code will handle hardware and software
exceptions identically. Structured exception handling enables you to have
complete control over the handling of exceptions, provides support for
debuggers, and is usable across all programming languages and machines.
The system also supports termination handling, which enables you to ensure that
whenever a guarded body of code is executed, a specified block of termination
code is also executed. The termination code is executed regardless of how the
flow of control leaves the guarded body. For example, a termination handler can
guarantee that clean-up tasks are performed even if an exception or some other
error occurs while the guarded body of code is being executed.
[DoDi: Delphi Relationship]
In Delphi the exeption handling is described in Try/Except blocks, and
termination handling in Try/Finally blocks.
[MSDN: Exception Handling]
...
An exception can be continuable or noncontinuable. A noncontinuable exception
arises when the event is not continuable in the hardware, or if continuation
makes no sense. A noncontinuable exception does not terminate the application.
Therefore, an application may be able to catch the exception and run. However,
a noncontinuable exception typically arises as a result of a corrupted stack or
other serious problem, making it difficult to recover from the exception.
[DoDi]
I'm not sure of the meaning of "continuable". Absolutely noncontinuable should
only be situations where the stack cannot be unwound. I doubt that the system
can determine whether vital information was overwritten in general.
[MSDN: Exception Dispatching]
When a hardware or software exception occurs, the processor stops execution at
the point at which the exception occurred and transfers control to the system.
First, the system saves both the machine state of the current thread and
information that describes the exception. The system then attempts to find an
exception handler to handle the exception.
...
The exception record includes the following information:
- An exception code that identifies the type of exception.
- Flags indicating whether the exception is continuable. Any attempt to
continue execution after a noncontinuable exception generates another
exception.
- A pointer to another exception record. This facilitates creation of a linked
list of exceptions if nested exceptions occur.
- The address at which the exception occurred.
- An array of arguments that provide additional information about the
exception.
When an exception occurs in user-mode code, the system uses the following
search order to find an exception handler:
- If the process is being debugged, the system notifies the debugger.
- If the process is not being debugged, or if the associated debugger does not
handle the exception, the system attempts to locate a frame-based exception
handler by searching the stack frames of the thread in which the exception
occurred. The system searches the current stack frame first, then searches
through preceding stack frames in reverse order.
- If no frame-based handler can be found, or no frame-based handler handles the
exception, but the process is being debugged, the system notifies the debugger
a second time.
- If the process is not being debugged, or if the associated debugger does not
handle the exception, the system provides default handling based on the
exception type. For most exceptions, the default action is to call the
ExitProcess function.
[DoDi: stack frame?]
It's unclear what "searching stack frames" means. IMO it means searching the
list of Try blocks, in Delphi terms, because searching call stack frames
doesn't provide information related to exception handling. Aren't the SEH
(guard) blocks linked via the FS register?
[MSDN: Frame-based Exception Handling]
A frame-based exception handler allows you to deal with the possibility that an
exception may occur in a certain sequence of code. A frame-based exception
handler consists of the following elements.
- A guarded body of code
- A filter expression
- An exception-handler block
Frame-based exception handlers are declared in language-specific
syntax...[Delphi: Try/Except]
The guarded body of code is a set of one or more statements for which the
filter expression and the exception-handler block provide exception-handling
protection.
The filter expression of a frame-based exception handler is an expression that
is evaluated by the system when an exception occurs within the guarded body.
This evaluation results in one of the following actions by the system:
- The system stops its search for an exception handler, restores the machine
state, and continues thread execution at the point at which the exception
occurred.
- The system continues its search for an exception handler.
- The system transfers control to the exception handler, and thread execution
continues sequentially in the stack frame in which the exception handler is
found. If the handler is not in the stack frame in which 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 an exception handler is executed, termination handlers are executed for
any guarded bodies of code that terminated as a result of the transfer of
control to the exception handler.
The filter expression can be a simple expression, or it can invoke a filter
function that attempts to handle the exception....
These functions cannot be called from within a filter function, but their
return values can be passed as parameters to a filter function.
GetExceptionCode can be used within the exception-handler block, but
GetExceptionInformation cannot because the information it points to is
typically on the stack and is destroyed when control is transferred to an
exception handler. However, an application can copy the information to safe
storage to make it available to the exception handler.
The advantage of a filter function is that it can handle an exception and
return a value that causes the system to continue execution from the point at
which the exception occurred. With an exception-handler block, in contrast,
execution continues sequentially from the exception handler rather than from
the point of the exception.
[DoDi: Delphi...]
Delphi doesn't allow to continue at the point at which the exception occured.
However we might discuss such a feature, and how it could be added without
modifications to the compiler.
The note on GetExceptionInformation suggests that Delphi (the RTL code) has to
copy the exception information, prior to invoking the Except code.
[MSDN: Termination Handling]
A termination handler ensures that a specific block of code is executed
whenever flow of control leaves a particular guarded body of code. A
termination handler consists of the following elements:
- A guarded body of code
- A block of termination code to be executed when the flow of control leaves
the guarded body
Termination handlers are declared in language-specific syntax...[Delphi:
Try/Finally]
Whenever the guarded body is executed, the block of termination code will be
executed. The only exception to this is when the thread terminates during
execution of the guarded body (for example, if the ExitThread or ExitProcess
function is called from within the guarded body).
[DoDi: Delphi?]
Bypassing Try/Finally when a thread is terminated doesn't seem to make sense.
At least the local dynamic variables (AnsiString...) of the active subroutines
in the thread must be finalized. This might be a point why the API handling of
termination handlers is inappropriate for Delphi code?
[MSDN continued]
The termination block is executed when the flow of control leaves the guarded
body, regardless of whether the guarded body terminated normally or abnormally.
The guarded body is considered to have terminated normally when the last
statement in the block is executed and control proceeds sequentially into the
termination block. Abnormal termination occurs when the flow of control leaves
the guarded body due to an exception, or due to a control statement such as
return, goto, break, or continue. The AbnormalTermination function can be
called from within the termination block to determine whether the guarded body
terminated normally.
[MSDN: Vectored Exception Handling]
Vectored exception handlers are not frame-based handlers. Therefore, you can
add a handler and ensure that it gets called regardless of where you are in a
call frame. The handlers are called in the order that they were added, after
the debugger gets a first chance notification, but before frame-based
dispatching occurs.
To add a handler, use the AddVectoredExceptionHandler function. The handler is
called for all future exceptions for the process. To remove a handler, use the
RemoveVectoredExceptionHandler function.
[DoDi]
The preceding section was added for completeness only, perhaps it's how Delphi
exception handling is linked in, or could be linked into the API exception
handling.
I've already tried to indicate the Delphi equivalences and implications.
Perhaps Laura can add how Delphi actually links into the API exception
handling?
DoDi
- Next message: Bjørge Sæther: "Re: Try Finally..."
- Previous message: VBDis: "Re: Try Finally..."
- In reply to:(deleted message) L D Blake: "Re: Try Finally..."
- Next in thread: Maarten Wiltink: "Re: Structured Exception Handling (was: Try Finally...)"
- Reply: Maarten Wiltink: "Re: Structured Exception Handling (was: Try Finally...)"
- Reply: Maarten Wiltink: "Re: Structured Exception Handling (was: Try Finally...)"
- Reply: J French: "Re: Structured Exception Handling (was: Try Finally...)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|