一:背景

1. 讲故事

在最近一两年内Visual Studio 2022会偶发的出现打开即崩溃的情况,本想着把VS卸载重装,但发现这东西想卸载干净还是蛮困难的,又加上我这个人比较懒,所以就直接重装系统了,最近的9月份因为它重装了一次系统,但过了一天又遇到了同样的问题,在这样一个背景下我决定认真的看下到底是什么回事?毕竟一直装系统也不是个事。

二:崩溃分析

1. 崩溃现象

打开VisualStudio之后,会弹出错误信息 Exception has been thrown by the target of an invocation. 大概意思就是在调用目标上发生了异常,截图如下:

记一次升级系统补丁导致 VS2022 崩溃分析_d3

熟悉我的朋友都知道,我个人喜欢用 procdump 来捕获异常,这里可以根据指定异常的方式获取,参考命令和截图如下:

procdump -w devenv -e 1 -f TargetInvocationException -ma -o D:\testdump\

记一次升级系统补丁导致 VS2022 崩溃分析_Windows_02

从图中的子异常TypeLoadException来看,看样子是加载了某个类型出错的,这里要提醒一下,上面的乱码是因为中文操作系统解析不了这些字符,大家可以把操作系统改成 英文版的,就可以显示全部字符,参考如下:

记一次升级系统补丁导致 VS2022 崩溃分析_d3_03

2. windbg分析

dump成功抓到之后,接下来就是启动 windbg 分析了,因为是托管层抛出的异常,直接用 !t 观察即可。

0:000> !t
ThreadCount:      22
UnstartedThread:  0
BackgroundThread: 20
PendingThread:    0
DeadThread:       2
Hosted Runtime:   no
                                                                                                        Lock  
       ID OSID ThreadOBJ           State GC Mode     GC Alloc Context                  Domain           Count Apt Exception
   0    1 2840 000001ac95d47e20    a4228 Preemptive  000001AC97806580:000001AC97807218 000001ac95d3a9d0 2     STA System.Reflection.TargetInvocationException 000001ac97804c28
   9    2 31d0 000001ac95da3d60    2b228 Preemptive  000001ACD6F92F00:000001ACD6F94E88 000001ac95d3a9d0 0     MTA (Finalizer) 
   ...

从卦中可以清晰的看到确实存在一个异常,接下来使用 pe 来观察异常详情,参考如下:

0:000> !pe -nested 000001ac97804c28
Exception object: 000001ac97804c28
Exception type:   System.Reflection.TargetInvocationException
Message:          Exception has been thrown by the target of an invocation.
InnerException:   System.TypeInitializationException, Use !PrintException 000001ac97804838 to see more.
StackTrace (generated):
    SP               IP               Function
    0000008618CFC6E0 0000000000000000 mscorlib_ni!System.RuntimeFieldHandle.GetValue(System.Reflection.RtFieldInfo, System.Object, System.RuntimeType, System.RuntimeType, Boolean ByRef)+0xffff80024c1d3360
    0000008618CFC6E0 00007FFDB2CA9F03 mscorlib_ni!System.Reflection.RtFieldInfo.UnsafeGetValue(System.Object)+0xa3

StackTraceString: <none>
HResult: 80131604
0:000> !PrintException /d 000001ac97804838
Exception object: 000001ac97804838
Exception type:   System.TypeInitializationException
Message:          The type initializer for 'System.Windows.Automation.Peers.AutomationPeer' threw an exception.
InnerException:   System.TypeLoadException, Use !PrintException 000001ac978003e8 to see more.
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80131534
0:000> !PrintException /d 000001ac978003e8
Exception object: 000001ac978003e8
Exception type:   System.TypeLoadException
Message:          程序集“PresentationCore, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35”中的类型“MS.Internal.Automation.SelectionProviderWrapper”的方法“GetSelection”没有实现。
InnerException:   <none>
StackTrace (generated):
    SP               IP               Function
    0000008618CFB520 0000000000000000 PresentationCore!System.Windows.Automation.Peers.AutomationPeer.Initialize()+0x1
    0000008618CFB5D0 00007FFD55FDD431 PresentationCore!System.Windows.Automation.Peers.AutomationPeer..cctor()+0x81

StackTraceString: <none>
HResult: 80131522

从卦中可以清晰的看到,原来是SelectionProviderWrapper 类没有 GetSelection 实现,虽然找到了错误原因,但vs不是我们写的,无法修改源码,这个时候直接拿错误信息去网上找咯。

3. 寻找沦落人

在网络上一顿找,终于在 wpf 的仓库里给找到了,链接如下: https://github.com/dotnet/wpf/issues/8056

记一次升级系统补丁导致 VS2022 崩溃分析_d3_04

根据文章描述需要卸载 KB5011048 补丁即可,打开系统补丁列表,还真的有,果断给卸载掉。

记一次升级系统补丁导致 VS2022 崩溃分析_d3_05

卸载完成之后,重启操作系统,我去,还真的就打开了。

记一次升级系统补丁导致 VS2022 崩溃分析_d3_06

4. 为什么会这样

要想找到原因得要知道 KB5011048 补丁是用来干嘛的,链接如下: https://support.microsoft.com/zh-cn/topic/microsoft-net-framework-4-8-1-适用于-windows-10-版本-21h2-windows-10-版本-22h2-windows-11-版本-21h2-windows-server-2022-desktop-azure-editions-azure-stack-21h2-和-azure-stack-22h2-kb5011048-277f9c30-7add-4150-b774-5e3667e02256#:~:text=Microsoft .NET Framework 4.8.1 (KB5011048)

记一次升级系统补丁导致 VS2022 崩溃分析_Windows_07

从 MSDN 的描述来看,这个补丁和 .NET Framework 4.8.1 有关,而且还特别提到了 高度兼容 ,看样子没有高度兼容。

到这里我大概就知道了来龙去脉,VS 用的是 .NETFramwork 4.8 ,但这个补丁导致Windows底层库更新到了 4.8.1, 结果 VS 使用的 GetSelection 方法在新的底层库中找不到方法实现了,最终导致 VS 直接崩溃。

三:总结

这次Visual Studio 2022 的启动崩溃罪魁祸首居然是 Windows 的补丁包导致的,这也太不靠谱了吧,不过这个案例也告诉我们有时候掌握一点dump分析能力,还是很容易找到问题的突破口。

记一次升级系统补丁导致 VS2022 崩溃分析_Windows_08