ASP.NET 2.0 - Investigating .NET Exceptions with WinDbg (Compilation and Load Exceptions)
I have talked in earlier posts about how to log and debug .net exceptions with WinDBG.
All .NET exceptions derive from System.Exception and with the following member variables.
- Data
- HelpLink
- InnerException
- Message
- Source
- StackTrace
- TargetSite
Apart from this basic information exceptions deriving from System.Exception usually add a few member variables where they store information specific to that type of exception. This time I wanted to talk a little about some special exceptions that we can dig into to get way more information than they appear to contain at first glance…
More specifically I will talk about the following compilation or loading exceptions:
- System.Web.HttpCompileException
- System.Web.HttpParseException
- System.IO.FileNotFoundException
The assumption here is that you have gathered a memory dump with adplus and you find one of the above exceptions on the heap when you run !dumpheap -type Exception
.
System.Web.HttpCompileException
Sample error message
CS0246: The type or namespace name '<namespace>' could not be found (are you missing a using directive or an assembly reference?)
When you look at this exception by running !PrintException [address of HttpCompileException object]
in 2.0 or !dumpobj
in 1.1 you will see something like this:
0:005> !PrintException 02d030cc
Exception object: 02d030cc
Exception type: System.Web.HttpCompileException
Message: External component has thrown an exception.
InnerException: <none>
StackTrace (generated):
SP IP Function
0F6FF25C 689B1B01 System.Web.Compilation.AssemblyBuilder.Compile()
0F6FF2A4 686DB64A System.Web.Compilation.WebDirectoryBatchCompiler.CompileAssemblyBuilder(System.Web.Compilation.AssemblyBuilder)
0F6FF2D4 68675054 System.Web.Compilation.WebDirectoryBatchCompiler.CompileNonDependentBuildProviders(System.Collections.ICollection)
0F6FF334 686706A2 System.Web.Compilation.WebDirectoryBatchCompiler.Process()
0F6FF35C 6867027E System.Web.Compilation.BuildManager.BatchCompileWebDirectoryInternal(System.Web.Hosting.VirtualDirectory, Boolean)
StackTraceString: <none>
HResult: 80004005
The current thread is unmanaged
I don’t know about you, but this information doesn’t really tell me very much about what went on. The reason for this is that the exception was thrown by an external component (i.e. the compiler vbc.exe, csc.exe etc.)
Compare this to the information that we would get in a browser for the same exception:
Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.
Compiler Error Message: CS0246: The type or namespace name 'BusinessStuff' could not be found (are you missing a using directive or an assembly reference?)
Source Error:
Line 9: using System.Web.UI.WebControls.WebParts;
Line 10: using System.Web.UI.HtmlControls;
Line 11: using BusinessStuff;
Line 12:
Line 13: public partial class Default4 : System.Web.UI.Page
If we had that type of information in the dump getting rid of the exception would probably have been a piece of cake. So how can we get this information from the exception in the dump?
If we look at the definition for HttpCompileException in msdn we find that apart from the standard Exception member variables, the HttpCompileException has two extra member variables called Results and SourceCode. Results is populated with the actual compilation errors and SourceCode contains the source code for the file that failed to compile.
0:005> !do 02d030cc
Name: System.Web.HttpCompileException
MethodTable: 68a5f4b4
EEClass: 68a5f434
Size: 100(0x64) bytes
(C:\WINDOWS\assembly\GAC_32\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll)
Fields:
MT Field Offset Type VT Attr Value Name
...
790fed1c 4000f97 48 System.Int32 0 instance 0 _httpCode
68a5c4d8 4000f98 44 ...eb.ErrorFormatter 0 instance 02d164c8 _errorFormatter
790fed1c 4000f99 4c System.Int32 0 instance 0 _webEventCode
7a754b50 4000f9b 50 ...r.CompilerResults 0 instance 02cd8520 _results
790fa3e0 4000f9c 54 System.String 0 instance 02d0e424 _sourceCode
...
In the _results we can find the error number (CS0246), message (The type or namespace name ‘BusinessStuff’ could not be found (are you missing a using directive or an assembly reference?)), source file (default4.aspx.cs) and the line number (11) like this:
0:005> !do 02cd8520
Name: System.CodeDom.Compiler.CompilerResults
MethodTable: 7a754b50
EEClass: 7a754ae0
Size: 36(0x24) bytes
(C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)
Fields:
MT Field Offset Type VT Attr Value Name
7a754bd4 4000f55 4 ...erErrorCollection 0 instance 02cd8544 errors
7a74847c 4000f56 8 ....StringCollection 0 instance 02cd8568 output
...
0:005> !do 02cd8544
Name: System.CodeDom.Compiler.CompilerErrorCollection
MethodTable: 7a754bd4
EEClass: 7a7b07c4
Size: 12(0xc) bytes
(C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)
Fields:
MT Field Offset Type VT Attr Value Name
791036b0 40008f1 4 ...ections.ArrayList 0 instance 02cd8550 list
0:005> !do 02cd8550
Name: System.Collections.ArrayList
MethodTable: 791036b0
EEClass: 79103604
Size: 24(0x18) bytes
(C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
MT Field Offset Type VT Attr Value Name
79124228 40008c0 4 System.Object[] 0 instance 02d02b68 _items
790fed1c 40008c1 c System.Int32 0 instance 1 _size
...
0:005> dc 02d02b68
02d02b68 79124228 00000004 790f9c18 02d0281c (B.y.......y.(..
02d02b78 00000000 00000000 00000000 00000000 ................
...
0:005> !do 02d0281c
Name: System.CodeDom.Compiler.CompilerError
MethodTable: 7a7650e4
EEClass: 7a7b79f0
Size: 32(0x20) bytes
(C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll)
Fields:
MT Field Offset Type VT Attr Value Name
790fed1c 4000f38 10 System.Int32 0 instance 11 line
790fed1c 4000f39 14 System.Int32 0 instance 7 column
790fa3e0 4000f3a 4 System.String 0 instance 02d02a40 errorNumber
79104f64 4000f3b 18 System.Boolean 0 instance 0 warning
790fa3e0 4000f3c 8 System.String 0 instance 02d02a60 errorText
790fa3e0 4000f3d c System.String 0 instance 02d02980 fileName
0:005> !do 02d02a40
String: CS0246
0:005> !do 02d02a60
String: The type or namespace name 'BusinessStuff' could not be found (are you missing a using directive or an assembly reference?)
0:005> !do 02d02980
String: c:\Inetpub\wwwroot\DebuggerSamples\Default4.aspx.cs
And this together with the source code will give us all the information that we normally see in the browser.
System.Web.HttpParseException
Sample error message:
Parser Error: Could not load type '<namespace>.<type>'.
This type of exception typically occurs when you deploy a web application and either the code behind for a page is not compiled or you have a reference set to an assembly but the version of that assembly is different on the dev machine and on the client such that the type you are trying to access is not defined in the version on the server.
Alternatively it might be that the files containing the type definition are locked by an external process such as a virus scanner, indexing service or backup software. The best way to troubleshoot these is to look at the type and the dll it would be defined in, and verify that the dll exists on the server. If it does you can run NTFilemon to see why it can’t load the dll.
If you dump this out with !dumpobj (!do)
you will see something like this:
0:000> !do 0x184aee84
Name: System.Web.HttpParseException
...
0x79b96824 0x4000020 0x10 CLASS instance 0x184aeed4 _message
0x79b96824 0x4000021 0x14 CLASS instance 0x184aed34 _innerException
0x79b96824 0x4000022 0x18 CLASS instance 0x00000000 _helpURL
0x79b96824 0x4000023 0x1c CLASS instance 0x184aef88 _stackTrace
0x79b96824 0x4000024 0x20 CLASS instance 0x00000000 _stackTraceString
0x79b96824 0x4000025 0x24 CLASS instance 0x00000000 _remoteStackTraceString
0x79b96824 0x4000026 0x2c System.Int32 instance 0 _remoteStackIndex
0x79b96824 0x4000027 0x30 System.Int32 instance -2147467259 _HResult
0x79b96824 0x4000028 0x28 CLASS instance 0x00000000 _source
0x79b96824 0x4000029 0x34 System.Int32 instance 0 _xptrs
0x79b96824 0x400002a 0x38 System.Int32 instance -532459699 _xcode
0x020784fc 0x4000604 0x40 System.Int32 instance 0 _httpCode
0x020784fc 0x4000605 0x3c CLASS instance 0x184aef6c _errorFormatter
0x04392114 0x4000608 0x44 CLASS instance 0x1053b41c _fileName
0x04392114 0x4000609 0x48 System.Int32 instance 1 _line
-----------------
Exception 0x184aee84 in MT 0x04392114: System.Web.HttpParseException
_message: Parser Error: Could not load type 'DebuggerSamples.MyPage'
...
And from here we can take a look at the filename to see which file we failed in:
0:000> !do 0x1053b41c
String: C:\InetPub\wwwroot\DebuggerSamples\MyPage.aspx
And also at the _errorFormatter to get the source code
0:000> !do 0x184aef6c
Name: System.Web.ParseErrorFormatter
...
MT Field Offset Type Attr Value Name
0x052f2fec 0x4000460 0x4 CLASS instance 0x1053b41c _fileName
0x052f2fec 0x4000461 0x8 CLASS instance 0x184ae51c _sourceCode
0x052f2fec 0x4000462 0xc System.Int32 instance 1 _line
0x052f3274 0x4000467 0x10 CLASS instance 0x184aed7c _message
0x052f3274 0x4000468 0x14 CLASS instance 0x184aee84 _excep
0:000> !do 0x184ae51c
String: <%@ Page Language="vb" AutoEventWireup="false" Codebehind="MyPage.aspx.vb" Inherits="DebuggerSamples.MyPage"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>MyPage</title>
<meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" content="Visual Basic .NET 7.1">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:Button id="MyButton" runat=server />
</form>
</body>
</HTML>
Finally, putting it all together, we can see from the ErrorFormatter that we failed with a
Parser Error: Could not load type 'DebuggerSamples.MyPage' on line 1 of C:\InetPub\wwwroot\DebuggerSamples\MyPage.aspx
and line 1 was <%@ Page Language="vb" AutoEventWireup="false" Codebehind="MyPage.aspx.vb" Inherits="DebuggerSamples.MyPage"%>
System.IO.FileNotFoundException
Sample error message:
File or assembly name <assembly name>, or one of its dependencies, was not found
You will normally see this exception if one of the dlls loaded in the process refers to a dll or a version of a dll that is not present on the system. It doesn’t necessarily have any decremental effect if for example you are loading controls in your process that uses functions in Microsoft.VisualStudio.dll or stdole.dll for design time purposes but does not use them for runtime purposes.
This is an example of how this exception looks in the debugger if you dump it out with !dumpobj
0:000> !do 0x1031b1fc
Name: System.IO.FileNotFoundException
MethodTable 0x79bfbdcc
EEClass 0x79bfbe5c
Size 72(0x48) bytes
GC Generation: 2
mdToken: 0x02000345 (c:\windows\microsoft.net\framework\v1.1.4322\mscorlib.dll)
FieldDesc*: 0x79bfbec0
MT Field Offset Type Attr Value Name
0x79b96824 0x400001d 0x4 CLASS instance 0x00000000 _className
0x79b96824 0x400001e 0x8 CLASS instance 0x00000000 _exceptionMethod
0x79b96824 0x400001f 0xc CLASS instance 0x00000000 _exceptionMethodString
0x79b96824 0x4000020 0x10 CLASS instance 0x1031b244 _message
0x79b96824 0x4000021 0x14 CLASS instance 0x00000000 _innerException
0x79b96824 0x4000022 0x18 CLASS instance 0x00000000 _helpURL
0x79b96824 0x4000023 0x1c CLASS instance 0x00000000 _stackTrace
0x79b96824 0x4000024 0x20 CLASS instance 0x00000000 _stackTraceString
0x79b96824 0x4000025 0x24 CLASS instance 0x00000000 _remoteStackTraceString
0x79b96824 0x4000026 0x2c System.Int32 instance 0 _remoteStackIndex
0x79b96824 0x4000027 0x30 System.Int32 instance -2147024894 _HResult
0x79b96824 0x4000028 0x28 CLASS instance 0x00000000 _source
0x79b96824 0x4000029 0x34 System.Int32 instance 0 _xptrs
0x79b96824 0x400002a 0x38 System.Int32 instance -532459699 _xcode
0x79bfbdcc 0x4000f23 0x3c CLASS instance 0x14358078 _fileName
0x79bfbdcc 0x4000f24 0x40 CLASS instance 0x1031a570 _fusionLog
-----------------
Exception 0x1031b1fc in MT 0x79bfbdcc: System.IO.FileNotFoundException
_message: File or assembly name stdole, or one of its dependencies, was not found.
The interesting part of this exception is the _fusionLog which tells us exactly where it is looking for the dll and also what specific version it is looking for along with the reason it can not find it.
0:000> !do 0x1031a570
String: === Pre-bind state information ===
LOG: DisplayName = stdole, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
(Fully-specified)
LOG: Appbase = file:///c:/inetpub/wwwroot/DebuggerSamples
LOG: Initial PrivatePath = bin
Calling assembly : (Unknown).
===
LOG: Publisher policy file is not found.
LOG: No redirect found in host configuration file (C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet.config).
LOG: Using machine configuration file from C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\config\machine.config.
LOG: Post-policy reference: stdole, Version=7.0.3300.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/DebuggerSamples/e2b59b51/5bf1057f/stdole.DLL.
LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/DebuggerSamples/e2b59b51/5bf1057f/stdole/stdole.DLL.
LOG: Attempting download of new URL file:///c:/inetpub/wwwroot/DebuggerSamples/bin/stdole.DLL.
LOG: Attempting download of new URL file:///c:/inetpub/wwwroot/DebuggerSamples/bin/stdole/stdole.DLL.
LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/DebuggerSamples/e2b59b51/5bf1057f/stdole.EXE.
LOG: Attempting download of new URL file:///C:/WINDOWS/Microsoft.NET/Framework/v1.1.4322/Temporary ASP.NET Files/DebuggerSamples/e2b59b51/5bf1057f/stdole/stdole.EXE.
LOG: Attempting download of new URL file:///c:/inetpub/wwwroot/DebuggerSamples/bin/stdole.EXE.
LOG: Attempting download of new URL file:///c:/inetpub/wwwroot/DebuggerSamples/bin/stdole/stdole.EXE.
Publishers policy file is not found usually means that we can’t find the requested dll in any of the applications “paths”.
Conclusion
Even though this post talks about some specific exceptions, hopefully you can use it to help you dig into other exceptions as well to get the additional data that those exceptions provide.
Keep debugging!
Laters