Welcome to MSDN Blogs Sign in | Join | Help

DoStackSnapshot Tidbit #1: Exception Filters

Believe it or not, my last (rather large) post on stack walking actually left out several miscellaneous details about using DoStackSnapshot.  I'll be posting those details separately.  We'll start off with some light reading on exception filters.  No deadlocks this time, I promise.

For those of you diehard C# fans, you might be unaware of the existence of exception filters in managed code. While VB.NET makes them explicitly available to the programmer, C# does not. Filters are important to understand when you call DoStackSnapshot, as your results might look a little weird if you don't know how to interpret them.

First, a little background. For the full deal, check out the MSDN Library topic on VB.NET's try/catch/finally statements. But here's an appetizer. In VB.NET you can do this:


Function Negative() As Boolean
    Return False
End Function

Function Positive() As Boolean
    Return True
End Function

Sub Thrower
    Throw New Exception
End Sub

Sub Main()
    Try
        Thrower()
    Catch ex As Exception When Negative()
        MsgBox("Negative")
    Catch ex As Exception When Positive()
        MsgBox("Positive")
    End Try
End Sub


The filters are the things that come after "When". We all know that, when an exception is thrown, its type must match the type specified in a Catch clause in order for that Catch clause to be executed. "When" is a way to further restrict whether a Catch clause will be executed. Now, not only must the exception's type match, but also the When clause must evaluate to True for that Catch clause to be chosen. In the example above, when we run, we'll skip the first Catch clause (because its filter returned False), and execute the second, thus showing a message box with "Positive" in it.

The thing you need to realize about DoStackSnapshot's behavior (indeed, CLR in general) is that the execution of a When clause is really a separate function call. In the above example, imagine we take a stack snapshot while inside Positive(). Our managed-only stack trace, as reported by DoStackSnapshot, would then look like this (stack grows up):

Positive
Main
Thrower

Main

It's that highlighted Main that seems odd at first. While the exception is thrown inside Thrower(), the CLR needs to execute the filter clauses to figure out which Catch wins.  These filter executions are actually function calls.  Since filter clauses don't have their own names, we just use the name of the function containing the filter clause for stack reporting purposes.  Thus, the highlighted Main above is the execution of a filter clause located inside Main (in this case, "When Positive()").  When each filter clause completes, we "return" back to Thrower() to continue our search for the filter that returns True.  Since this is how the call stack is built up, that's what DoStackSnapshot will report.
Published Monday, October 10, 2005 1:25 PM by davbr

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: DoStackSnapshot Tidbit #1: Exception Filters

Thursday, October 13, 2005 11:46 AM by BlackTigerX
"For those of you diehard C# fans, you might be unaware of the existence of exception filters in managed code. While VB.NET makes them explicitly available to the programmer, C# does not"

so are they available at all in C#?

# re: DoStackSnapshot Tidbit #1: Exception Filters

Thursday, October 13, 2005 12:27 PM by davbr
Nope. One who enjoys being gross and hacky can kind of simulate them to a small extent by having lots of different exception types. Imagine your original throw can throw one of the types based on a condition. Your catch clauses can catch each type, and even rethrow based on a condition in that scope, etc. But this can get expensive and difficult to read, so I wouldn't recommend it.

# re: DoStackSnapshot Tidbit #1: Exception Filters

Monday, October 17, 2005 3:37 PM by davbr
Chris Brumme's incredibly detailed blog contains a post that theorizes about another way to achieve this using anonymous methods (which are introduced here: http://msdn.microsoft.com/msdnmag/issues/04/05/C20/). Go to Chris's post at http://blogs.msdn.com/cbrumme/archive/2003/10/01/51524.aspx and search in your browser for "DoTryCatch". I don't know if anyone's actually tried this yet, but you might enjoy exploring it.

# re: DoStackSnapshot Tidbit #1: Exception Filters

Wednesday, November 29, 2006 4:02 AM by Andrei Faber

Reading this article, I arrived at an idea. Is it possible to modify stack, for example substitute return point, or even add a faked-up stack frame? Such methods are used in native apps sometimes, but I'm not sure if this is possible under CLR.

# Doctoring the stack frame

Wednesday, November 29, 2006 12:43 PM by davbr

Hi, Andrei, sounds like a fun idea, but modifying the stack frame, such as substituting in your own return addresses, is not advised with managed apps.  Various parts of the runtime need to walk the stack explicitly (to support garbage collection, security checks, exception handling, debugging, etc.).  If you change the stack, these subsystems will get confused, and the app will fail in all sorts of ways.  If your goal is to get your own custom profiler code to run I recommend either using the enter/leave/tailcall hooks, or IL rewriting to get your own code in there.  Modifying the stack will not work.

# re: DoStackSnapshot Tidbit #1: Exception Filters

Thursday, November 30, 2006 3:08 AM by Andrei Faber

Hello David; I think this is a good idea. BTW, what will be result of rewriting code, when application is under debug, and/or rewrite occured in the method which is currently executing?

# re: DoStackSnapshot Tidbit #1: Exception Filters

Thursday, November 30, 2006 3:46 PM by davbr

If your profiler rewrites IL via SetILFunctionBody(), a debugger should work fine, but you'll need to call SetILInstrumentedCodeMap() to inform the CLR how your rewritten IL maps to the original IL.  That's the only extra piece of information the debugger needs to be able to go from native code offset (of the JITted, rewritten IL) to the original language source code (C#, VB.NET, etc.).

Note that if your rewritten IL is so drastically different from the original IL that a simple mapping is impossible, then of course the debugging experience will be confusing.

Also note that there's a general limitation in that, if profiling is on, then a debugger is unable to use the Edit and Continue feature, regardless of whether you're rewriting IL or not.

Finally, note that it is impossible to rewrite IL of a function currently executing, because the profiling API only allows you to change the IL at JIT time (specifically, call SetILFunctionBody() from within your JITCompilationStarted() callback).  So the IL is always rewritten before the first managed thread gets to execute it.

# re: DoStackSnapshot Tidbit #1: Exception Filters

Friday, December 01, 2006 8:48 AM by Andrei Faber

Thanks, David. And another question - is it possible to rewrite method several times by using SetFunctionReJIT method?

# re: DoStackSnapshot Tidbit #1: Exception Filters

Monday, December 04, 2006 12:31 PM by davbr

SetFunctionReJIT has been deprecated in 2.0.  The only way to rewrite IL in 2.0 is to do so before the function is JITted, which gives you only one opportunity per function.

# David Broman s CLR Profiling API Blog DoStackSnapshot Tidbit 1 | pool toys

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker