Catch, Rethrow and Filters - Why you should care?

A very common pattern in the usage of managed exception handling is that of catching an exception, inspecting it's type and rethrowing it once you realize it was not the exception you wanted to handle. Below is such an example (and should be avoided in preference to another approach described further below in the writeup) that uses CustomBaseException as the base type of an exception hierarchy and CustomDontWantToCatchException as a type that derives from the base class that you wouldn’t want to catch:

1.In the first pass, the CLR looks for a handler for the thrown exception. When one is found, it begins the second pass.

2.In the second pass, also known as the unwind pass, it invokes all the termination handlers (e.g. managed finally/fault blocks, along with the native counterparts like __finally, destructors of stack allocated objects) that lie between the handler of the exception and the point at which the exception was thrown.

Thus, if you use a pattern like the one above, only to rethrow an exception since it was decided not to deal with it, prior to your [catch] handler being invoked, the termination handlers will be invoked. These handlers would end up doing the cleanup (like reset program state) before control is returned to the handler that agreed to handle the exception. Hence, by the time you enter the catch block, like in the example above, program state would have been modified since the finally in Foo would have been invoked. Thus, type handlers (like a catch clause) are invoked after the second pass has successfully been completed even though they are located in the first pass.

Assuming the exception was CustomDontWantToCatchException, the catch block proceeds to rethrow it, expecting it to go unhandled. When exceptions go unhandled, it is a good thing - and that is because we get the actual program state at the time when the exception was thrown. However, when pattern like the one above is used to rethrow conditionally, the program state gets modified and when the rethrown exception becomes unhandled, you will see actual program state from the point of rethrow and not the original throw.

So, how do we address such conditional exception processing without affecting program state for better diagnostics (in case the exception goes unhandled)?

Filters! Not really well known and not used a lot, managed filters are invoked by the CLR in the first pass when it is looking for a handler for an exception. Whilea type handler is associated with a concrete type based upon which the CLR will decide whether the handler is capable of handling the exception or not, a filter can have custom logic to determine whether it wants to handle the exception or not.

When a filter is found in the first pass, the CLR will pass it the exception object corresponding to the thrown exception. The filter can then decide whether it wants to handle the exception or not, by accessing the state on the exception object (Note: accessing global program state from within a filter may lead to unexpected results. Thus, any such accesses should be avoided from within a filter). Once it has decided, a boolean is returned back to the CLR indicate its decision. If it agrees to handle the exception, the CLR will proceed to trigger the second (or unwind) pass. But if it decides not to handle the exception, the CLR will continue look further on the stack for any handler that may want to handle the exception. If none are found, the exception becomes unhandled and CLR's unhandled exception processing kicks in.

Hence, instead of catching all exceptions as shown in the example above (or using base type of a given exception hierarchy) and then rethrowing the caught exception because you didn’t want to handle it, write a filter that will enable you to do just that without triggering the second pass and modifying program state in the process.

And how does one write a managed filter?

While the CLR support filters, not all managed languages support it - IL and VB, for instance, do support it but C# does not! Rewriting the Main method above in VB , we can see how easy it can be to inspect an exception on the fly without affecting the program state and conditionally deciding whether, or not, to handle the exception:

You can see that, towards the end of the disassembly, we have the IL regions (bold and highlighted in yellow, between IL offset 3B and 3C) defining what constitutes the try block, the filter and if the exception is going to be handled, the filter-handler as well. Depending upon what the filter returns, after invoking ShouldCatch (which, in this example, decides whether the exception should be handled based upon its type), the CLR will eitherexecute the filter-handler or continue to go up the stack looking for exception handlers.

To conclude, for such exception inspection patterns that need to handle exception conditionally, use filters as they enable you to do the same as catching and rethrowing pattern without affecting the program state. It’d be great if they were in C#, but they’re not, so really consider using IL filters or VB where you need this functionality.

BTW: beside filters, the CLR also supports another construct called fault which can also be useful sometimes. A wrapping method that captures all the features of exception handling could be written in IL for that purpose.

sich

6 Feb 2009 3:38 AM

Great information! But guys, I often see that MS uses the pattern shown at the beginning to filter, for example, critical exceptions or something similar to this. This code catches an Exception, passes it to a method like IsCricicalException, and then decides to rethrow it, or to handle. Is that an indended usage? Is the BCL team aware of issues you described above?

Thanks for the post, it's really interesting! About the filtering pattern described: isn't this similar in function to the normal try/catch(child)/catch(base) pattern?

Meaning, suppose Foo can throw CustomBaseExceptions, some of which may be CustomDontWantToCatchExceptions; instead of allowing Foo to throw CustomBaseException, it could throw FooExceptions (maybe wrapping the group we want to catch), also derived from CustomBaseException, and then use

try / catch(FooException e)

That would also totally ignore CustomDontWantToCatchExceptions. What is the advantage of a filter over this?

@Carlo Kok: It's good to see that Delphi Prism supports filters. I haven't used Delphi myself, but I think it's nice to see languages support a rich variety of EH constructs. It's a testament to the richness of the .NET platform that a diverse set of languages can be expressed on the .NET runtime without runtime changes. I'm curious to know if Delphi supported filters or whether this is a Prism extension to the language syntax.

@Omer Mor: Junfeng's blog shows a nice pattern. If you read it, make sure to read the comments--he makes some good points in there as well ("catch and rethrow is a bad pattern"). Faults are an interesting construct as well, but consider that having both filters and faults is a bit redundant :)

@DotNetKicks: Ouch!

@Ken Boogaart: The CLR team doesn't own the languages implemented on top of the CLR. While we work closely with the C# team, we don't affect their language design. I haven't heard anything about filters in C# 4 but you should check with them. Eric Lippert has a good blog if you want to ask there about C# plans (http://blogs.msdn.com/ericlippert/).

@Karl Agius: One difference between filters and the pattern you describe is that filters allow arbitrary code execution whereas your pattern only discriminates on exception type. While Gaurav's ShouldCatch function just checks the type of the exception, it could have done anything--check the status of the left mouse button, for example--and decided to whether to catch the exception. Filters are a very powerful mechanism.

Gaurav Khanna [CLR Dev]

8 Feb 2009 2:42 PM

Hi Karl Agius,

In the approach you describe:

1) You describe deriving a new exception type to catch the exceptions you intend to catch. If catching specific exceptions is what you want to do, you dont need to define a new type but filters can help examine the type as the exception passes by.

2) You mention creating FooException that would group the exceptions you wish to catch. Again, not only you define a new type, but either:

=> everytime you throw from within (or callees of) Foo, you will need to throw the actual exception as the inner of FooException, OR

=> if the original exception was thrown by the callee of Foo, Foo will need to catch the specific types and let others pass by (which brings you back to what this post describes). Catching the original exception within Foo and then throwing the wrapped exception will destroy the native stack pertaining to the original point of throw (and the program state as well) which will affect debugging.

Filters help you ascertain the exception type in an easy fashion, without triggering unwinds or affecting program state. This is specially useful when you have multiple exception types and you want to conditionally catch them without writing explicit catch clause for each of them or writing a catch for base and rethrowing conditionally. If you are sure you want to catch just one type of exception, then writing an explicit catch for that type is good enough.

@Andrew Pardoe [CLR PM]:"Faults are an interesting construct as well, but consider that having both filters and faults is a bit redundant :)"

It was my understanding that faults are like finally in that they are executed during the 2nd pass, and that the exception processing doesn't stop at them, but with the additional restriction that they are only executed if there was an exception.

I don't see how catch/filters can archive that?

If you put code into the filter, it's already executed during pass 1. If you want your code to be executed in pass 2 you have to actually catch the exception and re-throw it. Resulting in exactly the problems described in the original post.

A fault block on the other hand should only execute at all (and during the 2nd pass) if the 1st pass found a valid catch block further up the callstack.

So it looks to me that there is no way how filters for catch do make faults redundant?

@Thorsten Engler: Good catch! I meant that finally and fault blocks are redundant.

If I wanted to simulate fault blocks with a filter, though, I'd set a global boolean in my filter expression, not handle the exception, and use the global variable state to conditionally execute my fault block. Using Gaurav's example, I'd have ShouldCatch set GlobalFlag=true and return false. Then my "fault block" would be If GlobalFlag is true Then ...

This is a horrible hack, though, only meant for entertainment value. You can write all kinds of fun, horrible code by abusing EH.

@sich: Sorry, I missed responding to your post last time. I'm not in favor of functions "filtering" exceptions and rethrowing ones they don't want to catch. The BCL team is certainly aware of this advice.

There was a suggestion on Connect to add filters to C# recently, but Mads on the C# team responded that he considered it an anti-pattern and had no interest in adding it to the language. It always surprises me how different language design teams can look at features so differently.

@Andrew

I don't see how finally and fault blocks are redundant. Sure, there is a pattern you can use to implement something similar to fault in finally, but it is not 100% effective in the face of ThreadAbortException. And besides, why rely on a pattern, which makes the code more difficult to read and understand, when it would fit so nicely as a language feature into the existing exception handling mechanism?

Boo also supports Filter catch blocks. Additionally, Boo also has support for Fault handlers, which are similar to Finally blocks, but execute only when an unhandled exception leaves their protected try block. Useful for logging and those instances where you are just performing an operation and rethrowing otherwise.