SharePoint : Faulting application w3wp.exe

Faulting application w3wp.exe, version 6.0.3790.1830, stamp 42435be1, faulting module stswel.dll, version 11.0.6568.0, stamp 42e17544, debug? 0, fault address 0x0009310c.

This is something I fell victim about 18 months ago, pre-SP1 for Windows SharePoint Services, and I'd forgotten about until the recent release of SP2 for both WSS and SPS. By the time I had resolved the problem and discussed it with the Microsoft Escalation Engineer we had standing by, SP1 was already in testing. It was said that a "fix" may not make that service pack. So, it was worked around and was duly forgotten until now -- the release of SP2 -- and so I decided to see if it had been "fixed."

Now, I put "fix" and "fixed" in quotes because to be fair to Microsoft, the issue at hand is not quite so straightforward to repair per-se. It all stems from a particular quirk of using the IDisposable pattern: if you're given an object that implements IDisposable via a closed-source API (like SharePoint's), how do you really know for sure if you can safely Dispose() of it when you're done?

It all started when I was in the middle of a very critical global rollout (think screaming IT directors, managers sweating, staff afraid to go for toilet breaks critical) for a large multinational when I started getting directed to the webpart maintenance page on the occasional page, in a seemingly random manner. When I enabled stacktracing in the web.config file, I saw:


[WebPartPageUserException: Exception occurred.]
Microsoft.SharePoint.SPWebPartCollection.a(WebPart A_0, Boolean A_1) +423
Microsoft.SharePoint.SPWebPartCollection.a(WebPart A_0) +7
Microsoft.SharePoint.SPWebPartCollection.f(WebPart A_0) +39
Microsoft.SharePoint.SPWebPartCollection.b(WebPart A_0) +333
Microsoft.SharePoint.WebPartPages.WebPart.g() +88
Microsoft.SharePoint.WebPartPages.WebPart.bl() +266
Microsoft.SharePoint.WebPartPages.WebPart.OnUnload(EventArgs e) +92
System.Web.UI.Control.UnloadRecursive(Boolean dispose) +121
System.Web.UI.Control.UnloadRecursive(Boolean dispose) +74
System.Web.UI.Control.UnloadRecursive(Boolean dispose) +74
System.Web.UI.Control.UnloadRecursive(Boolean dispose) +74
System.Web.UI.Page.ProcessRequestCleanup() +24
System.Web.UI.Page.ProcessRequest() +218
System.Web.UI.Page.ProcessRequest(HttpContext context) +18
Microsoft.SharePoint.ApplicationRuntime.SharePointHandler.SPProcessRequest(HttpContext context) +415

[ApplicationException: Exception of type System.ApplicationException was thrown.]
Microsoft.SharePoint.ApplicationRuntime.SharePointHandler.SPProcessRequest(HttpContext context) +1073
Microsoft.SharePoint.ApplicationRuntime.SharePointHandler.SPProcessRequest(HttpContext context) +0
Microsoft.SharePoint.ApplicationRuntime.SharePointHandler.ProcessRequest(HttpContext context) +21
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication+IExecutionStep.Execute() +179
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +87


Prior to this event, I'd gone a mad optimization run: checking all objects for IDisposable (SPWeb, SPSite etc) and making sure that I was either calling Dispose in a finally clause, or wrapping the block in a using statement; avoiding dodgy concatenations; unneccesary boxing/unboxing; checking all DLLs were Release build, etc etc. The reasons for this was because our application was running slower than expected and was doing quite a lot of swapping of virtual memory. Later in the project we discovered the real problem to be a badly written navigation control that was building an in-memory XML file using the Xml DOM classes: these things are serious memory hogs -- stick to StringBuilders if you can. Back to the problem: we had three different webparts in different permutations on various pages, and eventually I narrowed it to a certain combination of webparts. This took a long, long time to isolate the code in question; here is the heart of it:

WebPart A:

using (SPWeb thisWeb = SPControl.GetContextWeb(HttpContext.Current)) {
    // do something with thisWeb object, read site name, etc...
}


WebPart B:


[WebPartStorage(Storage.Personal)]
public int Size {
    get { ... }
    set { ... }
}

public void MyMethod() {
    this.Size = 5;
    this.SaveProperties = true;
}


So, the crux of it was that if any webpart on the page calls Dispose on the context SPWeb, and another webpart (or the same one) wants to SaveProperties, we're screwed. When the page unloads and the SharePoint framework tries to serialize any changed Properties to the content database, it fails because an essential COM object has been released in the disposal process that facilitates the property serialization process. You can reproduce the crash in RTM, SP1 and SP2 of both SPS and WSS with the following:

Repro code:

protected override void RenderWebPart(HtmlTextWriter output) {
    Text = "crash";
    using (SPWeb web = SPControl.GetContextWeb(HttpContext.Current)) {
        output.Write(SPEncode.HtmlEncode(Text)));
    }
    this.SaveProperties = true;
}


What's the answer? You can dispose any SPWeb objects obtained from a GetSubWebsForCurrentUser call for example, but don't dispose of the SPWeb associated with the current Web or you'll be in a whole world of trouble.

UPDATE: I just discovered that http://support.microsoft.com/default.aspx?scid=901259 was created sometime in the last few months in response to my original findings.
blog comments powered by Disqus

About the author

Irish, PowerShell MVP, .NET/ASP.NET/SharePoint Developer, Budding Architect. Developer. Montrealer. Opinionated. Montreal, Quebec.

Month List

Page List