Reputation: 1471
I have a dump file which was dumped from a app pool crash in IIS. A thread contains System.NullReferenceException
. I am able to locate the NullReferenceException
in the dump but I am not able to view the _stackTrace
0:070> !wdo 00000009cea474b8
Address: 00000009cea474b8
Method Table/Token: 00007ffb53d2dc88/200011704
Class Name: System.NullReferenceException
Size : 160
EEClass: 00007ffb53ea3e88
Instance Fields: 19
Static Fields: 0
Total Fields: 19
Heap/Generation: 10/0
Module: 00007ffb53d10000
Assembly: 0000000c5a934170
Domain: 00007ffb56324100
Assembly Name: C:\Windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Inherits: System.SystemException System.Exception System.Object (00007FFB53D30660 00007FFB53DB5D20 00007FFB53DB5F88)
00007ffb53db5b70 System.String +0000 _className 0000000751fec958 System.NullReferenceException
00007ffb53dbd6b8 System.Reflection.MethodBase +0008 _exceptionMethod 000000074ffc4608
00007ffb53db5b70 System.String +0010 _exceptionMethodString 0000000000000000 (null)
00007ffb53db5b70 System.String +0018 _message 000000084c638270 オブジェクト参照がオブジェクト インスタンスに設定されていません。
00007ffb53d2de78 System.Collections.IDictionary +0020 _data 0000000751fd4340
00007ffb53db5d20 System.Exception +0028 _innerException 0000000000000000
00007ffb53db5b70 System.String +0030 _helpURL 0000000000000000 (null)
00007ffb53db5f88 System.Object +0038 _stackTrace 000000074ff7ad00 0a 00 00 00 00 00 00 00 a0 3e 09 6c 0c 00 00 00 c5 44 70 f8 fa 7f 00 00 40 04 84 5b 0c 00 00 00 .........>.l.....Dp....@..[.... (...more...)
00007ffb53db5f88 System.Object +0040 _watsonBuckets 000000074ff7aeb0 01 00 00 00 43 00 4c 00 52 00 32 00 30 00 72 00 33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ....C.L.R.2.0.r.3............... (...more...)
00007ffb53db5b70 System.String +0048 _stackTraceString 0000000000000000 (null)
00007ffb53db5b70 System.String +0050 _remoteStackTraceString 0000000000000000 (null)
00007ffb53db5f88 System.Object +0058 _dynamicMethods 0000000000000000
00007ffb53db5b70 System.String +0060 _source 0000000752028c20 System.Web
00007ffb53d495c8 System.Runtime.Serialization.SafeSeriali +0068 _safeSerializationManager 00000009cea47610
00007ffb53dbde60 System.IntPtr +0070 _xptrs 0 (0n0)
00007ffb53d99290 System.UIntPtr +0078 _ipForWatsonBuckets 0 (0n0)
00007ffb53db80f8 System.Int32 +0080 _remoteStackIndex 0 (0n0)
00007ffb53db80f8 System.Int32 +0084 _HResult 80004003 (0n-2147467261)
00007ffb53db80f8 System.Int32 +0088 _xcode e0434352 (0n-532462766)
How can I get the full stack in string from the _stackTrace
?
Also, what steps can I take to find out the origin of NullReferenceException
?
Upvotes: 0
Views: 961
Reputation: 59289
You can show the stack trace of a thrown exception using !pe
. In probably more than 90% of the cases that's all you need.
Here's a minimal reproducible example:
using System;
namespace ConsoleNetFramework
{
class Program
{
static void Main()
{
throw new ApplicationException("An exception");
}
}
}
and the debugging session:
0:000> .loadby sos clr
0:000> !pe
Exception object: 0335246c
Exception type: System.ApplicationException
Message: An exception
InnerException: <none>
StackTrace (generated):
SP IP Function
012FEFB0 01720897 ConsoleNetFramework!ConsoleNetFramework.Program.Main()+0x4f
StackTraceString: <none>
HResult: 80131600
Since I considered the answer to be too simple, I felt free to make it more interesting by adding more seldom cases to the example like so:
static void Main()
{
var b = new BadImageFormatException("Bad exception");
ApplicationException a;
try
{
throw new ApplicationException("An exception");
}
catch (ApplicationException aex)
{
a = aex;
}
var t = new Thread(ThrowAnotherException);
t.Start();
throw new DataException("Data exception");
Console.WriteLine(b.Message);
Console.WriteLine(a.Message);
}
private static void ThrowAnotherException()
{
throw new ConfigurationException("Config exception");
}
In the end we'll have 4 exception objects in memory:
A...Exception
B...Exception
C...Exception
D...Exception
and we can have a look at all of them.
The debugging session is:
0:000> .loadby sos clr
0:000> !pe
Exception object: 02eb2ca8
Exception type: System.Data.DataException
Message: Data exception
[...]
So far so normal, we stopped at the first exception that was thrown and we can have a look at that exception with !pe
.
If we switch to another thread, we can see that the exception is indicated with a #
in the list of threads, as long as it's not overwritten by the .
(current thread).
0:000> ~1s
0:001> ~
# 0 Id: 28a8.501c Suspend: 1 Teb: 00cc6000 Unfrozen
. 1 Id: 28a8.1044 Suspend: 1 Teb: 00cc9000 Unfrozen
[...]
Here's an interesting part: let's freeze thread 0 and run the application so that a second exception is thrown.
0:001> ~0f
0:001> g
System 0: 1 of 7 threads are frozen
WARNING: Continuing a non-continuable exception
System 0: 1 of 8 threads were frozen
System 0: 1 of 8 threads are frozen
(28a8.4228): CLR exception - code e0434352 (!!! second chance !!!)
System 0: 1 of 8 threads were frozen
[...]
Now we have another exception that caused the debugger to stop.
0:006> ~1s
[...]
0:001> ~
0 Id: 28a8.501c Suspend: 1 Teb: 00cc6000 Frozen
. 1 Id: 28a8.1044 Suspend: 1 Teb: 00cc9000 Unfrozen
2 Id: 28a8.1a2c Suspend: 1 Teb: 00ccc000 Unfrozen
3 Id: 28a8.5cfc Suspend: 1 Teb: 00ccf000 Unfrozen
4 Id: 28a8.490 Suspend: 1 Teb: 00cd2000 Unfrozen
5 Id: 28a8.2b60 Suspend: 1 Teb: 00cd5000 Unfrozen
# 6 Id: 28a8.4228 Suspend: 1 Teb: 00cd8000 Unfrozen
[...]
That exception happened on thread 6. We can also see that we only have one #
mark in that list, not two.
On the correct thread, we can print the exception:
0:006> !pe
Exception object: 02eb3ff4
Exception type: System.Configuration.ConfigurationException
Message: Config exception
[...]
On the wrong thread, we can't:
0:006> ~1s
[...]
0:001> !pe
The current thread is unmanaged
Lesson learned: the !pe
command is thread sensitive.
Now, what about the other two exceptions, A...
and B...
? We can find them on the heap:
0:000> !dumpheap -type BadImageFormatException
Address MT Size
02eb2a6c 6e3983c4 92
[...]
Fields:
MT Field Offset Type VT Attr Value Name
[...]
6e342734 40002ab 20 System.Object 0 instance 00000000 _stackTrace
[...]
The exception that was not thrown at all, does not have a stack trace. It's null
.
0:000> !dumpheap -type ApplicationException
Address MT Size
02eb2ae4 6e388090 84
Statistics:
MT Count TotalSize Class Name
6e388090 1 84 System.ApplicationException
Total 1 objects
0:000> !DumpObj /d 02eb2ae4
Name: System.ApplicationException
[...]
Fields:
MT Field Offset Type VT Attr Value Name
[...]
6e342734 40002ab 20 System.Object 0 instance 02eb2b7c _stackTrace
[...]
The exception that was thrown but caught, still has its stack trace.
0:000> !pe 02eb2ae4
Exception object: 02eb2ae4
Exception type: System.ApplicationException
Message: An exception
InnerException: <none>
StackTrace (generated):
SP IP Function
00EFEEA0 052F08D2 ConsoleNetFramework!ConsoleNetFramework.Program.Main()+0x8a
StackTraceString: <none>
HResult: 80131600
Lesson learned: !pe
can take an arbitrary exception as parameter and print the exception with its call stack.
Looking at the output of the managed !threads
, both exceptions will be listed (unlike ~
which shows only one #
):
0:001> !threads
ThreadCount: 3
UnstartedThread: 0
BackgroundThread: 1
PendingThread: 0
DeadThread: 0
Hosted Runtime: no
Lock
ID OSID ThreadOBJ State GC Mode GC Alloc Context Domain Count Apt Exception
0 1 501c 00fb99c0 2a020 Preemptive 02EC0714:00000000 00f815a0 0 MTA System.Data.DataException 02eb2ca8
5 2 2b60 00fc4728 2b220 Preemptive 00000000:00000000 00f815a0 0 MTA (Finalizer)
6 3 4228 00fec9a0 2b020 Preemptive 02EC5B70:00000000 00f815a0 0 MTA System.Configuration.ConfigurationException 02eb3ff4
what steps can I take to find out the origin of NullReferenceException?
With the call stack and symbols you should be able to identify a single line of code. Next step is to do a code review there. Figure out which variable is null
. Write a unit test to reproduce the issue. Then fix the bug. Like in red/green refactoring.
Upvotes: 1