Jaa


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 fun NTFilemon from https://www.sysinternals.com to see why it can not 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 error formatter 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="https://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,

 

 

Comments

  • Anonymous
    October 13, 2006
    Now, that is an extremely interesting post! Thanks Tess, and keep up the good work of opening the internals of .net to us...

  • Anonymous
    October 13, 2006
    Hi Tess, I am kind of confuse about HttpCompileException. I thought we need to be able to compile *.aspx cleanly to MSIL before it could run? How can you get HttpCompileException @ run time ? Thanks

  • Anonymous
    October 13, 2006
    In your System.Web.HttpCompileException,

  1. You used !dc 02d02b68 to dump array class
  2. You used the 4th dword to dump the element info. My questions:
  3. Is there a doc for the array class ? How about other system class ?
  4. If I have a user-defined class, How do I do that ? Thanks
  • Anonymous
    October 15, 2006
    The comment has been removed

  • Anonymous
    October 15, 2006
    nativecpp: I used dc to dump the array class.  It is slightly different from !dc.   dc is a built in command in windbg which displays the contents of memory at the address given (addresses and ascii characters). !dc is short for !dumpcollection  (a command in some versions of sos.dll) But anyways, that is a little besides the point.   Here is how it works: From dumping out the array list I know that the array list has a number of items stored in an object array.  Specifically this one has 1 item (per the _size membervariable) 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 ... When you dump out an object array you get the following: 0:005> dc 02d02b68 02d02b68 79124228 00000004 790f9c18 02d0281c (B.y.......y.(.. 02d02b78 00000000 00000000 00000000 00000000 ................ The first column is the address that we are dumping at and then on each row this is followed by 4 columns with data, and one column that contains the ascii representation of this data. If we take a look at the first column we have the dwords: 79124228 00000004 790f9c18 02d0281c In an object array and really in any .net object, the first dword if you dump out the raw data is a method table.   79124228  is the method table for Object[] Then, specifically in an object array, the following two dwords are size in bytes (00000004) and method table of objects in the array (790f9c18 = MT for object). Finally, after this 3 dword prologue the actuall addresses of the objects start, so object addresses are located on 4 dword and forward  (in this particular case only one item but could have been more).   Long story short:) This is why i picked the 4th dword. In 1.1 you can also run !do -v <address> (!dumpobject verbose)  in some versions of sos.dll to get the data printed out. But the way I have shown above works in all versions. For system classes and user defined classes just use !dumpobj, this will dump out the contents of your class (like in the HttpCompileException class above).   And if you have a member variable that is an array of some sort, you can dump it like i described. Technically, !dumpobj is only a nicer representation of running dc or dd on an object.  If you dump an object with !do and then dc and compare the data at different offsets with the !do output you will see what I mean.

  • Anonymous
    October 16, 2006
    Thanks for the clarification. That showed you I am NOT an aspx guru :-(

  • Anonymous
    October 17, 2006
    The comment has been removed

  • Anonymous
    October 17, 2006
    I nativeCpp.  Since it is an object array you do dc 013e3728 And then do !do on the 4th dword to dump out the first (and in this case only) string The relationship between windbg and sos goes like this. Windbg is the debugger.  It only knows native code so the commands such as dc etc. are done on raw memory.   Managed structures are in the end still raw memory, but to make them more readable you load sos.dll which is a debugger extension (a set of functions that display the raw memory in a more readable way using information about the object such as method table etc.) So whenever you debug .net code you use both native commands and sos commands in conjunction.  dc is used here because there is no method in sos.dll to dump out an array of objects    (except for some versions of sos.dll which contain the function !do -v)  

  • Anonymous
    October 18, 2006
    The comment has been removed

  • Anonymous
    October 18, 2006
    Hi Tess, Another related question to my earlier post. If I have an array of user-defined class and because SOS does NOT have a command to dump elements of it, I have to resort to Windbg dc command. However, as you indicated, 4th dword is only for string. how do I do that for other classes ? Sorry for asking so many questions :-( Thanks

  • Anonymous
    October 18, 2006
    Hi NativeCpp, My mistake, I thought you were using it in windbg.  In Visual Studio you can not run dc, so you can't dump arrays with sos (2.0),  if you are still on the stack where the problem occurred you should be able to see them in your watch window, but if not you would have to create a dump and open it in windbg. In regards to collections of user defined objects, it works the same way, the 4th element and forward (of an array) is a pointer to the user defined class in that case and you should be able to do !do on that. It is not specific to strings...  In fact the 3rd dword will contain the mt of the userdefined class in that case. There is a way to still get the 4th dword even in visual studio.  I believe that there is a window that displays raw memory (somewhere under debug/windows, and if you enter the address of the string there and look at the 4th dword after that, you should see the address of your object

  • Anonymous
    October 19, 2006
    Hi Tess, Thanks,  it works. I forgot about that memory window!  I will poke around user-defined classes later.  On thing I tried on VS2005 that I would like to share: Instead of using !dumpstackobject to find out the address of my string array, I entered address operator of my string array (&m_string) in 'watch' window in VS 2005. It display as tree item and when I expanded it look like follow: Name                    Value                       Type &m_strings           0x013c2d38             string[]&*    this.m_strings   0x013c8eac             string[] the 2nd one is the address of the array that matches the !dumpstackobject which makes sense to me and VS2005 is friendly enough to show me the address of m_strings. BTW, I can't enter m_string because VS2005 is smart enough to show me the content and not the address. Thanks

  • Anonymous
    October 19, 2006
    Hi Tess, I know my last post was supposed to be my LAST question. But one more -> How do you traverse array elements if the array  > 1 from SOS/Windbg ? Thanks

  • Anonymous
    October 19, 2006
    Hi Tess, I figured out the way to traverse the elements by examing the next dword until the end of the array. However, is there a documented way of doing it ?

  • Anonymous
    October 20, 2006
    Glad you got it to work. I don't think it is documented (other than on this and perhaps some other blogs) Most of debugging is walking memory like this, and it would be impossible to document everything but you can use the above as a generic way of traversing arrays.  And for other objects you have !do.

  • Anonymous
    December 31, 2006
    I have this exact error and it's stopping me cold!  Being a simple ASP.NET developer, my first question would be, "Why am I getting this error?" and "How do I get rid of it?" I don't want to debug this error the way you describe.  I'm on a timeline with this application and I need to know how to fix this. I still receive this error message even after I've removed all references to the offending Object, re-compiled, cleared out the Temporary ASP.net folder, rebooted (many times) and for some reason, in the Temporary ASP.NET folder, the old files return. Please tell me how to fix this without creating a new application from scratch? Thank You, King Wilder info@kingwilder.com

  • Anonymous
    May 16, 2007
    i am using winforms first time it is working whenever i do the modifications to the winform (for example adding or removing the labels and textboxes and etc) i am getting the error "   Could not write to output file 'C:Documents and SettingsAdministratorDesktopazeemProject FloristProject FloristobjDebugProject Florist.exe' -- 'The process cannot access the file because it is being used by another process. ' Project Florist "    could any one help me to resolve this problem. i will thankful to them.

  • Anonymous
    May 20, 2007
    Hi Azeem, That usually means that you haven't closed down the application before rebuilding Tess