Re: Structured Exception Handling (was: Try Finally...)
From: VBDis (vbdis_at_aol.com)
Date: 11/01/04
- Next message: VBDis: "Re: Structured Exception Handling (was: Try Finally...)"
- Previous message: VBDis: "Re: Function var in object; instance reference problem"
- Maybe in reply to: Rob Kennedy: "Re: Structured Exception Handling (was: Try Finally...)"
- Next in thread: VBDis: "Re: Structured Exception Handling (was: Try Finally...)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 01 Nov 2004 01:32:32 GMT
Im Artikel <4184d94b$0$37789$e4fe514c@news.xs4all.nl>, "Maarten Wiltink"
<maarten@kittensandcats.net> schreibt:
>If an exception is raised during execution of statementList1, control
>is [immediately] transferred to statementList2; [only] once
>statementList2 finishes executing, the exception is re-raised."
Okay, a hard nut ;-)
>The parts in square brackets are my additions to disambiguate how I
>read this. To me, it promises that nested try-except and try-finally
>statements will be traversed outwards exactly once, executing each
>in accordance with its semantics, in nesting order.
This is the easy part. What really bite me is the re-raise of the exception
(see below).
The weak point in your interpretation is the assumed "immediate" transfer to
statementList2. We certainly agree that some code has to execute after an
exception is thrown, i.e. that code that forces the exit from statementList1
and the continuation in statementList2. According to my observations that code
includes the first (arbitration) pass of the SEH, so that the continuation
effectively occurs in the second (unwinding) pass.
Short proof:
All but the _HandleFinally subroutines start with code like this (here: D4):
MOV EAX,[ESP+4]
TEST [EAX].TExceptionRecord.ExceptionFlags,cUnwindInProgress
JNE @@exit
This means that during unwinding the code immediately returns, without any
further actions. In _HandleFinally instead the opposite behaviour is encoded,
here nothing happens unless one of the unwind flags (cUnwinding or
cUnwindingForExit) is set.
The ExceptionFlags are updated once, before the RtlUnwind call, to the
unwinding state. Consequently no exception filter nor exception handler code
can execute during the unwinding of the stack - this is possible only in the
first pass.
--- Without appropriate debugging techniques one may miss the invocation of all the _Handle... procedures during the arbitration pass, because at that time no user code ever executes. The selected exception handler runs after the stack is unwound and all Finally blocks have been executed, as indicated in the arguments of the RtlUnwind call. This effectively is the point where exception handling stops and the "normal" execution of the program begins. >To me, it promises that nested try-except and try-finally >statements will be traversed outwards exactly once This certainly is true for the user code in the Except and Finally blocks. Nonetheless I hope to have proven that the hidden preambles of that code, the _Handle... procedures, are called moreoften, during the arbitration pass. It's the code in these procedures that guarantees that the according /user/ code is executed exactly once. Now for the hard nut: Similar (non-debugging!) techniques are required to determine whether "once statementList2 finishes executing, the exception is re-raised." is correct. >From an inspection of the NotifyExceptFinally code I conclude that a re-raise only occurs when debugging, otherwise the stack is unwound without interruption. The re-raise effectively may be required to re-activate the debugger, which otherwise has no chance to trace the user code in the following Finally blocks. I admit that here I'm on thin ice :-( But - have you ever seen the debugger reporting another exception, resulting from a re-raise when exiting from a Finally block? Some more arguments for non-believers: When the Delphi code (in a DLL...) is called from some non-Delphi code, then an exception filter in that external code has the right to specify the location, where program operation shall be resumed: >> void RtlUnwind( PVOID TargetFrame, PVOID TargetIp, PEXCEPTION_RECORD ExceptionRecord, PVOID ReturnValue ); Parameters: TargetFrame [in, optional] Pointer to the call frame that is the target of the unwind. If this parameter is NULL, the function performs an exit unwind. TargetIp [in, optional] Continuation address of the unwind. This parameter is ignored if TargetFrame is NULL. ... << Since it's unknown where the normal program flow shall continue, until an exception filter has indicated that location by calling RtlUnwind, the chain of guard blocks has to be traversed, in a first pass, until an exception filter signals to stop the search. During this pass none but the exception filters are allowed to do something, in detail no Finally code can become active then. I'll split my comments to your contribution here, to separate different topics. DoDi
- Next message: VBDis: "Re: Structured Exception Handling (was: Try Finally...)"
- Previous message: VBDis: "Re: Function var in object; instance reference problem"
- Maybe in reply to: Rob Kennedy: "Re: Structured Exception Handling (was: Try Finally...)"
- Next in thread: VBDis: "Re: Structured Exception Handling (was: Try Finally...)"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|