[Mono-list] Re: Seeing Values of Unwound Stack variables at Exception Handler

Jonathan Pryor jonpryor@vt.edu
Fri, 24 Dec 2004 09:25:52 -0500


On Fri, 2004-12-24 at 00:53 -0500, Jonathan Gilbert wrote:
> I'm not sure about "custom stack unwinder notification", but it seems to
> me, the pattern you've written there, that is:
> 
> bool finished = false;
> try
> {
>   ...
>   finished = true;
> }
> finally
> {
>   if (!finished)
>   {
>     ...
>   }
> }
> 
> ..is equivalent to this:
> 
> try
> {
>   ...
> }
> catch
> {
>   ...
>   throw;
> }
> 
> Don't know if this helps at all, but it is the behaviour you described with
> the try/finally. The 'finally' clause always runs when code flow exits the
> scope; this is why the flag is required. The flag ensures that the code
> runs only when code flow did not leave the 'try' block "normally" -- that
> is, when an exception occurred. This is the situation that the 'catch'
> block runs under. Also note, rethrowing the exception will not interfere
> with the stack trace; that is generated when the exception is constructed
> ("new Exception(...)"), and not when it is 'throw'n.

This is correct, but a bare `throw;' is not without penalty.  Sure, you
don't lose any of the stack trace information, but you instead lose the
help of the Visual Studio Debugger, which will normally break on the
original `throw' statement, as long as that throw statement doesn't have
a matching `catch'.

Since there is a `catch', when debugging under Visual Studio the
exception will be thrown, then caught, and the stack is unwound to the
catch site -- so you lose the ability to view/debug the stack of the
original throw site.

This is why 

	try {/* ... */ 
		finished = true;
	}
	finally {
		if (!finished) /*...*/
	}

is the preferred idiom, to have a better debugging experience.

I believe I first saw this on Eric Gunnerson's C# blog, but (1) I'm not
sure, and (2) I'm too lazy to look it up.

Apparently IL has a language construct equivalent to "call me only if an
exception was thrown" (the equivalent of a !finally block), but no other
languages make this functionality available.

 - Jon