Debugging the White Screen of Darn
White Screen Of Darn (WSOD for short) is a feature designed to give Visual Studio
developers information about designer errors. For each exception that the Visual
Studio designer encounters, the WSOD displays the exception stack trace. This is
a very useful tool. For instance, if a third party developer notices that the stack
trace contains some stack frames which are his/hers own code, then the developer
can inspect these stack frames for possible problems.
However, sometimes the customer needs more information than just the stack trace.
In this paper I will describe how PSS engineers can debug WSOD. I will also give
an example how to solve a WSOD issue which was reported several times. This paper
is based on a set of emails that I sent to one of our PSS engineers. She had success
using these instructions so I thought others would benefit from these instructions
as well.
Debugging Devenv.exe
Since WSOD happens at design time, debugging WSOD requires in fact debugging the
Devenv.exe. Here is a list of steps on how to setup Vs.Net to debug Vs.Net. In order
to debug Vs.Net we need to create a solution file that contains the symbol path
for Devenv.exe. We also need to disable just in time debugger, set the debugger
type as managed only, and set the debugger to break on any exception.
Create a VS.Net solution to debug Devenv.exe.
- Start Vs.Net.
- Click File -> Open Project menu.
- In the Open File Dialog, navigate to Devenv.exe directory and select Devenv.exe
- Open Devenv.exe. This will create a new solution file: devenv.sln. Save devenv.sln
Set the symbol path.
Jessica Fosler has a great blog entry on how to debug managed code and how to set
symbols for the external customers. Please see
http://blogs.msdn.com/jfoscoding/archive/2005/09/05/461096.aspx for details
on configure your computer to use the Microsoft Symbol Server.
Disable Just in Time Debugger, set debugging type as managed only, and set the debugger
to break on any exception
Disabling just in time debugging can be done in the following way:
- Click on "Tools" menu.
- Click on "Options" menu item.
- In the "Options" dialog, under the "Debugging" node locate and click on the "Just-In-Time"
node.
- In the "Enable "Just-In-Time debugging for these types of code:" list view un-check
all types of code: "Managed" code, "Native" code and "Script" code.
To set the debugging type as managed only:
- Right click on the "devenv.exe" in the Solution Explorer.
- On the context menu, click on "Properties"
- On the "devenv Property Pages" dialog, locate and click on the "Debugging" node.
- Locate the "Debugger Type" item in the list view located in the right hand side
of the dialog. The "Debugger Type" should be set to "Auto".
- Change the "Debugger Type" to "Managed Only"
And here is how to break on any exception:
- Click on the "Debug" menu.
- Click on the "Exceptions" menu item.
- In the "Exceptions" dialog, locate the "Common Language Runtime Exceptions" item.
- Locate and check the check box corresponding to "Common Language Runtime Exceptions"
item and the "Thrown" column" column.
Debugging a WSOD issue
Now let's debug a WSOD issue. I will choose to debug a WSOD caused by the ResourceManager.
This issue was hit several times.
For starters, here is the WSOD that we get with this issue:
We can tell that an error happens when the StronglyTypedResourceBuilder fetches
a resource.
In order to debug this WSOD issue we will use the "devenv.sln" that we created previously;
let's open it up in Vs.Net.
After "devenv.sln" was loaded in Vs.Net, hit F5 – this will start the debugged instance
of Vs.Net.
In the debugged Vs.Net load the project that caused this error then open the form
that causes problems – this is DerivedForm.vb.
Because we set the debugger to break on any exceptions, the debugger will break
on some exceptions that are not related to this scenario. For instance, Vs TypeResolutionService
throws some exceptions when it can't find a type. In most cases, these exceptions
are not related to the WSOD that we want to debug. So check the "Call Stack" window
and if you see that the Vs TypeResolutionService is on the stack keep going (i.e.,
hit F5):
After getting 2 or 3 exceptions from the VS TypeResolutionService, we finally get
the exception that caused the WSOD. We know it is the exception that causes the
WSOD because it has the same stack trace as the picture we got at the beginning
of the investigation:
We look in the local variable window and find out that "docValue" variable is null.
Accessing "docValue"'s Length property causes the "Object reference not set to an
instance of an object" exception. So, it looks like we have a resource of type string
that contains a null value.
At this point it looks like this is a bug in the StronglyTypedResourceBuilder: the
StronglyTypedResourceBuilder does not deal w/ string resources which have a null
value. We could assign the bug to the Base Class Libraries team and be done with
the investigation.
However, we want to find out which file contains the resource in question. This
way, we can maybe fix the file and not wait for the Base Class Libraries to fix
the bug.
First we look at the resource name that causes the "Object reference not set to
an instance of an object" exception. The "resourceName" variable is "PermissionEventArgs.Error."
So, we conclude that the StronglyTypedResourceBuilder failed when it tried to load
the "PermissionEventArgs.Error" resource.
In order to find the file that contains the "PermissionEventArgs.Error" resource,
we look at the stack trace again to find out which component called into the StronglyTypedResourceBuilder:
We see that the ResXGlobalObject component that called into the StronglyTypedResourceBuilder.
We double click on the stack frame that corresponds to the StronglyTypedResourceBuilder:
We now go looking around for more information about the ResXGlobalObject and we
expand the "this" pointer that we find at that stack frame:
We see that the filename that contains the resource with a null value is "c:\bugs\580465\Test\Test\Strings.resx"
With this information and with the resource name we found earlier we can go ahead
and fix the resource file so it does not cause the "Object references not set to
an instance of an object" error when we open "DerivedForm.vb" in the designer again.
Further developments
Filtering on which exception to break on
As you can see, if we enable break on any exception then it is possible that the
debugger will break on several exceptions before it actually hits the exception
that causes the WSOD. We can mitigate that and reduce the number of exceptions the
debugger breaks on before hitting the WSOD exception.
We can use the same issue as an example. If we go back to the WSOD screen, we see
that the actual exception that caused the WSOD is "Object reference not set to an
instance of an object" exception. This means that if we want to break on just the
exception that caused the WSOD, then we need to break only on exceptions of type
"System.NullReferenceException." To do that, let's go back to the "Exceptions" dialog.
Last time we edited the "Exceptions" dialog we enabled breaking on any managed exception.
In order to break only on exceptions of type "System.NullReferenceException" we
need to know that the NullReferenceException is declared in the System namespace.
First, we expand the "Common Language Runtime Exceptions" node, and then we expand
the "System" node as below:
Under the "System" node we locate the NullReferenceException node. Then we check
the check box that corresponds to the "System.NullReferenceException" item and the
"Thrown" column, as below:
Now we hit F5 – this will start the debugged instance of Vs.Net and open the project
that caused the WSOD. When we open "DerivedForm.vb" the debugger will not longer
break on the exceptions thrown by the Vs TypeResolutionService and instead will
break when the StronglyTypedResourceBuilder accesses the "Length" property for the
null "docValue" variable.