Ayende @ Rahien

It's a girl

I am being stalked by CLR bugs

imageI just spent several hours tracking down a crashing but in my current project.

The  issue was, quite clearly, a problem with releasing unmanaged resources. So I tightened my control over resources and made absolutely sure that I am releasing everything properly.

I simply could not believe what was going on. I knew what they code is doing, and I knew that what I was getting was flat out impossible.

Yes, I know that we keep saying that, but this bug really is not possible!

The situation is quite clear, during the shutdown process of the application, an unmanaged resource’s finalizer would throw an exception because it wasn’t properly disposed.

The problem? It is most assuredly should be disposed. When debugging through the problem, I found out something extremely strange and worrying. The managed object’s finalizer was running while there were strong references to the object.

You can see that in the attached screenshot (click the image see it in full size).

That is, by the way, when you have the root in a static field, so it cannot be that the whole graph is free.

This is somehow related to threading, because debugging this would often change the way this works, but running without a debugger consistently fails.

The CLR semantics for finalizers clearly state that they can only be run after there are no more strong references to the instance. Cleary, this is not what is going on here.

The only thing that I can think of that can affect this is that there is something really strange going on with app domain unloads.

Now, I can’t figure if this is me being extremely stupid or if this is a real problem. I did manage to create a reproduction of the issue, however, which you can download here.

This is on VMWare Fusion, running Windows 2008 x64, with .Net 3.5 SP1.

To reproduce, start the application in WebDev.WebServer, wait for the page to load, and the close the WebDev.WebServer. If it crashes, you have successfully reproduced the problem.

Update – This is really interesting. both stack traces are operating on the same object, by the way.

image

Adding locking around the finalizer and dispose seems to have made the problem go away.

Comments

Kevin Dente
01/21/2009 06:23 PM by
Kevin Dente

There's an old post by Chris Brumme that seems to confirm that this is expected behavior.

blogs.msdn.com/.../77460.aspx

"Astute readers will have noticed that during process shutdown and AppDomain unloading we actually finalize objects in the RegisteredForFinalization queue. Such objects are still reachable and would not normally be subject to finalization."

I assume this is because they don't want to risk leaving resources like database connections orphaned during process shutdown.

Howard Pinsley
01/21/2009 08:40 PM by
Howard Pinsley

I won't presume to know more about this stuff than you, but I was wondering something. If a managed class -- say PersistentHashTable -- which implements IDisposable and contains no references to unmanaged objects and only references to managed objects that also implement IDisposable, then there is no need to implement a finalizer. However, if the object that it references -- a Microsoft.Isam.Esent.Interop.Instance -- holds onto an unmanaged resource but fails to properly implement a finalizer (in case Dispose() is not called), isn't that object ill-behaved? I wonder if implementing a finalizer on PersistentHashTable which calls Instance.Dispose() makes any sense? I would imagine you'd have to wrap that in a try/catch as finalizer ordering is not guaranteed.

On a side note, does this have anything to due with the problems with Castle Windsor and object lifetime (issues that have apparently just recently been addressed in the trunk)?

configurator
01/21/2009 09:03 PM by
configurator

As far as I know, when Unloading AppDomains and shutting down processes, all objects are finalized even when they are reachable. Isn't that consistent with the spec?

Ayende Rahien
01/21/2009 09:33 PM by
Ayende Rahien

The problem is that in this case, the shutdown process occurs concurrently with the cleanup code.

Alois Kraus
01/21/2009 11:04 PM by
Alois Kraus

Hi Ayende,

perhaps this link can shed some light onto your problem:

www.codeproject.com/.../...ApplicationShutdow.aspx

The golden rules of finalization are:

Do not rely on it, do not take any locks inside a finalizer.

Do not call to other objects which are also finalizable or do contain finalizable objects because the might be also finalized at this very moment if you have server GC enabled which means that you have several finalizer threads running.

It seems you have cornered yourself with a design which relies on finalization order. You could mitigate it a bit if you use a CriticalFinalizer to get at least some ordering.

geekswithblogs.net/akraus1/articles/81629.aspx

Yours,

Alois Kraus

Dave
01/22/2009 08:00 AM by
Dave

I'm aware of this issue and I think that i know why. As you know you can set the modifier of the constructor, but you can't set the modifier of the deconstructor and I believe that there lies the problem.

When you make a constructor static and assign an unmanaged resource to a static field than there's no deconstructor which can free the unmanaged resource. When you mark a class static you get even a compile error when you tryu to create a deconstructor. So my question is: Why can I create a constructor, but not a deconstructor. It seems to me that a static class isn't a whole different from a 'normal' class. The scope of a static class is the application domain and when the appdomain is disposed, the CLR should call the deconstructors on the static class used.

So currently I try to avoid unmanaged resources stored in static fields.

Josh
01/23/2009 01:11 AM by
Josh

Should you have titled this post "... CLR bugs" when you have not even identified a bug?

Ayende Rahien
01/23/2009 01:30 AM by
Ayende Rahien

Josh,

There is a bug.

It is in the parallel execution of the Application_End and the AppDomain.Unload

Comments have been closed on this topic.