Asynchronous Exceptions

published: Mon, 21-Mar-2005   |   updated: Thu, 27-Oct-2005

This article is an interesting email that was sent out to the CLR team at Microsoft about asynchronous exceptions. The email is, shall we say, information-dense. It’s targeted at the Framework developers, but there are some ideas we can take from this as application developers.

1. Don’t write code like this:

try {
  // blah
catch (Exception ex) {
  // do something with ex, such as log it

since you may catch something you really can’t do anything with. For example, even the logging code may fail in interesting ways in the face of some exceptions.

So always catch specific exceptions, such as SQLException instances. This link shows the exceptions thrown from the Framework (although I think the information shown here is for Whidbey — Visual Studio 2005 — only).

And if you remove the throw statement from the catch block (thereby swallowing the exception) you may leave the application as a whole in an unstable state.

2. A corollary: never throw instances of Exception. Always use a user-defined exception class.

3. Try not to throw exceptions from a constructor, especially if you’ve allocated non-memory resources prior to the throw. The finalizer (and if you are allocating non-memory resources, you should have a finalizer as well as implementing IDisposable) will run at some indeterminate time later.

4. Use the using syntax to create objects that implement IDisposable. It’s very likely that the compiler code generation or the JITter will be enhanced in this instance to ensure that objects are properly (deterministically) disposed even in the face of asynchronous exceptions.

The problem here is that if you have code like this:

using (Foo foo = new Foo()) {
  // blah

an asynchronous exception may be thrown in between the constructor completing (and therefore the object being created and alive) and the assignment to foo. If the assignment didn't take place, the using statement is not entered and the newly-created object becomes unreferenced, to be collected at some indeterminate time later. And presumably because IDisposable is being implemented, there's a finalizer in there somewhere, and this will only get called, much much later.

Now, there is nothing we can do about this at the moment, so just ignore it. But, if those awfully nice people in the C# team (or maybe in the Framework team) do their stuff, they may fix this issue with using.

5. The JITter does some heroic funky stuff to ensure that a monitor allocated with a lock statement is released no matter what.

6. Code is guaranteed not to be interrupted by an asynchronous exception in a finally or a catch block. Interesting (as in, I didn’t know this), but we shouldn’t take advantage of it in our code.

(via Brad Abrams)