最近拿到一个dump,有应用崩溃,通过查看dump,异常信息如下:
0:012> !pe
Exception object: 0000000005187278
Exception type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
InnerException: <none>
StackTrace (generated):
SP IP Function
000000002144DB50 000007FEEDF84989 PresentationFramework_ni!System.Windows.Controls.TreeViewItem.ExpandRecursive(System.Windows.Controls.TreeViewItem)+0x119
000000002144DC10 000007FEEDF84B46 PresentationFramework_ni!System.Windows.Controls.TreeViewItem.ExpandRecursive(System.Windows.Controls.TreeViewItem)+0x2d6
000000002144DCD0 000007FEEDE574B8 PresentationFramework_ni!System.Windows.Controls.TreeView.ExpandSubtree(System.Windows.Controls.TreeViewItem)+0x18
000000002144DD00 000007FEEDE572F5 PresentationFramework_ni!S
ystem.Windows.Controls.TreeView.OnKeyDown(System.Windows.Input.KeyEventArgs)+0x135
000000002144DD40 000007FEF116B1E3 PresentationCore_ni!System.Windows.RoutedEventArgs.InvokeHandler(System.Delegate, System.Object)+0x53
000000002144DDA0 000007FEF116A991 PresentationCore_ni!System.Windows.EventRoute.InvokeHandlersImpl(System.Object, System.Windows.RoutedEventArgs, Boolean)+0x271
000000002144DFE0 000007FEF115408E PresentationCore_ni!System.Windows.UIElement.RaiseEventImpl(System.Windows.DependencyObject, System.Windows.RoutedEventArgs)+0x14e
000000002144E070 000007FEF114FF66 PresentationCore_ni!System.Windows.UIElement.RaiseTrustedEvent(System.Windows.RoutedEventArgs)+0x96
000000002144E0D0 000007FEF117C921 PresentationCore_ni!System.Windows.Input.InputManager.ProcessStagingArea()+0x471
000000002144E160 000007FEF117C42B PresentationCore_ni!System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs)+0xab
000000002144E1B0 000007FEF117C1BC PresentationCore_ni!System.Windows.Interop.HwndKeyboardInputProvider.ReportInput(IntPtr, System.Windows.Input.InputMode, Int32, System.Windows.Input.RawKeyboardActions, Int32, Boolean, Boolean, Int32)+0x1bc
!pe即PrintException,从异常堆栈信息上可以看到当时在TreeView上按了某个键导致TreeView要展开TreeViewItem,然后循环时抛出空指针异常。
接下来就是查看当时传递的KeyDown事件是哪个,查看google后有的人说通过!clrstack -p可以看到函数参数的地址, 但试过后发现由于是Release版本,这个windbg命令并不起效。
只能用笨办法,通过!dso来查看当时整个线程所有堆栈变量, 如下:
0:012> ~12e !dso
OS Thread Id: 0xba4 (12)
RSP/REG Object Name
00000000214479B0 0000000005187278 Syste.NullReferenceException
000000002144DCB0 00000000051840c8 System.Windows.Input.KeyEventArgs
000000002144DCC0 0000000002d728f8 System.Windows.Controls.TreeView
000000002144DCD0 00000000041c1188 System.Windows.Controls.TreeViewItem
上面12是抛异常的clr线程号,可以通过~*kb查看所有现场的堆栈,就可以知道具体线程号
从上面命令的部分信息可以看到当时KeyEventArgs的地址。
接下来通过!do命令查看具体信息
012> !do 00000000051840c8
Name: System.Windows.Input.KeyEventArgs
MethodTable: 000007fef1283900
EEClass: 000007fef0ee4de0
Size: 80(0x50) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_64\PresentationCore\v4.0_4.0.0.0__31bf3856ad364e35\PresentationCore.dll
Fields:
MT Field Offset Type VT Attr Value Name
000007fef5070c78 40001c7 80 System.EventArgs 0 shared static Empty
>> Domain:Value 00000000008083f0:0000000002bd96d0 <<
000007fef1279088 40012ff 8 ...ndows.RoutedEvent 0 instance 0000000002ba43d0 _routedEvent
000007fef5055ac8 4001300 10 System.Object 0 instance 0000000002d728f8 _source
000007fef5055ac8 4001301 18 System.Object 0 instance 00000000041c1188 _originalSource
000007fef43990a8 4001302 20 ...lized.BitVector32 1 instance 00000000051840e8 _flags
000007fef128b320 40016ce 28 ...Input.InputDevice 0 instance 0000000002bc2f00 _inputDevice
000007fef505c858 40016cf 1460 System.Int32 1 static 396682259 _timestamp
000007fef3161bf0 40018ba 38 System.Int32 1 instance 84 _realKey
000007fef3161bf0 40018bb 3c System.Int32 1 instance
84 _key
000007fef1283da8 40018bc 30 ...resentationSource 0 instance 0000000003f8d7a0 _inputSource
000007fef505d688 40018bd 44 System.Boolean 1 instance 0 _isRepeat
000007fef505c858 40018be 40 System.Int32 1 instance 55 _scanCode
000007fef505d688 40018bf 45 System.Boolean 1 instance 0 _isExtendedKey
从上面可以看到当时按键Key的值是84,
通过查看enum类型的Key源码,发现84是*
namespace
System.Windows.Input
{
[ValueSerializer(
typeof
(KeyValueSerializer))]
[TypeConverter(
typeof
(KeyConverter))]
public
enum
Key
{
NumPad9 = 83,
Multiply = 84,
Add = 85,
Separator = 86,
Subtract = 87,
Decimal = 88,
Divide = 89,
通过查看TreeView的代码也可以看出Multiply的快捷键作用是ExpandSubTree
case
Key.Multiply:
if
(ExpandSubtree(_selectedContainer))
{
e.Handled =
true
;
}
break
;
结论:
*是TreeView控件的默认系统快捷键,用来展开TreeViewItem,当TreeView的Style有问题时,导致递归展开子项时抛了异常。
解决办法:
修改Style或者屏蔽快捷键。