记一次 .NET 某物管后台服务 卡死分析

一:背景

1. 讲故事

这几个月经常被朋友问,为什么不更新这个系列了,哈哈,确实停了好久,主要还是打基础去了,分析 dump 的能力不在于会灵活使用 windbg,而是对底层知识有一个深厚的理解,比如:汇编,C, C++,Win32 Api,虚拟内存,Windows 用户态和内核态,这是我今年看的书给大家分享一下。

b10c400877e8bbc3b542bea7375dd3df.png

前段时候微信上有位朋友说他的程序出现了卡死,所有线程都不工作了,听起来还挺吓人的,截图如下:

1649412ba40ced12affb69c2feae7e89.png

接下来直接上 WinDbg 分析吧。

二:Windbg 分析

1. 卡死分析

既然说程序所有线程都不工作了,大概率应该是此时 GC 触发了,曾经看过一个dump中 GC 在创建 background thread 时,由于 dllmain 的死锁造成了 background thread 无法生成引发的死锁问题。

有了这个思路,接下来用 ~* k 看一下所有的线程栈,是否有GarbageCollectGeneration 函数,因为它是 GC 触发入口点, 果然不出所料,46号线程触发了 GC 操作。

46  Id: 396c.3198 Suspend: 0 Teb: 00007ff6`22646000 Unfrozen# Child-SP          RetAddr               Call Site
00 00000028`d420bc18 00007ffa`8b6b8b61     ntdll!NtWaitForSingleObject+0xa
01 00000028`d420bc20 00007ffa`8b6b7124     ntdll!RtlpWaitOnCriticalSection+0xe1
02 00000028`d420bcf0 00000001`8000a725     ntdll!RtlpEnterCriticalSectionContended+0xa4
03 00000028`d420bd30 00000001`80011773     WiseVectorHelperOne_X64+0xa725
04 00000028`d420bd90 00007ffa`888faf8f     WiseVectorHelperOne_X64+0x11773
05 00000028`d420d2d0 00007ffa`79db4d45     KERNELBASE!ResumeThread+0xf
06 00000028`d420d300 00007ffa`79db8bee     coreclr!Thread::ResumeThread+0x29 [d:\a\_work\1\s\src\vm\threadsuspend.cpp @ 466] 
07 00000028`d420d350 00007ffa`79e13905     coreclr!ThreadSuspend::SuspendRuntime+0x17a [d:\a\_work\1\s\src\vm\threadsuspend.cpp @ 4046] 
08 00000028`d420d420 00007ffa`79db61cf     coreclr!ThreadSuspend::SuspendEE+0x16d [d:\a\_work\1\s\src\vm\threadsuspend.cpp @ 6517] 
09 (Inline Function) --------`--------     coreclr!GCToEEInterface::SuspendEE+0x21 [d:\a\_work\1\s\src\vm\gcenv.ee.cpp @ 25] 
0a 00000028`d420d5c0 00007ffa`79e325be     coreclr!WKS::GCHeap::GarbageCollectGeneration+0xff [d:\a\_work\1\s\src\gc\gc.cpp @ 36545] 
0b (Inline Function) --------`--------     coreclr!WKS::gc_heap::trigger_gc_for_alloc+0x12 [d:\a\_work\1\s\src\gc\gc.cpp @ 13832] 
0c 00000028`d420d610 00007ffa`79e35118     coreclr!WKS::gc_heap::try_allocate_more_space+0x24e [d:\a\_work\1\s\src\gc\gc.cpp @ 13934] 
0d (Inline Function) --------`--------     coreclr!WKS::gc_heap::allocate_more_space+0x11 [d:\a\_work\1\s\src\gc\gc.cpp @ 14369] 
0e (Inline Function) --------`--------     coreclr!WKS::gc_heap::allocate+0x58 [d:\a\_work\1\s\src\gc\gc.cpp @ 14400] 
0f 00000028`d420d690 00007ffa`79dcda8e     coreclr!WKS::GCHeap::Alloc+0x88 [d:\a\_work\1\s\src\gc\gc.cpp @ 35827]

从线程栈看,流程大概是:C# 分配一个对象,触发了 GC,然后暂停了所有托管线程,然后又恢复了其中一个线程,应该是此线程没有停留在 gc 安全点上,重启是为了让它在安全点暂停,在 coreclr 源码上也能看的出来。

d63e55d34e09cc6dd7115962e380f379.png

接下来就进入了 WiseVectorHelperOne_X64 类库 ,很陌生的一个 dll,最后进入了 临界区 CriticalSection ,所谓的 临界区 是一个 win32 函数,用法和我们的 lock 差不多,最后就停留在 临界区,其实到这里现象就很明朗了,所有的托管线程都暂停了,也符合朋友说的程序卡死,接下来就要分析为什么程序退不出 临界区

2. 为啥退不出 CriticalSection

要想寻找这个答案,可以用 !locks 来观察当前处于 临界区 的线程,输出如下:

0:000> !locksCritSec +63218af0 at 0000002863218af0
WaiterWoken        No
LockCount          0
RecursionCount     1
OwningThread       3198
EntryCount         0
ContentionCount    16d
*** LockedCritSec WiseVectorHelperOne_X64+6a9a8 at 000000018006a9a8
WaiterWoken        No
LockCount          1
RecursionCount     1
OwningThread       3090
EntryCount         0
ContentionCount    1
*** LockedScanned 64 critical sections

根据经验,第一反应应该是 临界区死锁 了,经验归经验,接下来我们依次看下  31983090 各自都在等什么?

3. 真的是临界区死锁吗

首先用命令切到 3198 线程,看看它正在等待什么资源?

0:038>  ~~[3198]s
ntdll!NtWaitForSingleObject+0xa:
00007ffa`8b710c8a c3              ret
0:046> kb# RetAddr               : Args to Child                                                           : Call Site
00 00007ffa`8b6b8b61     : 00000001`8006a9a8 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!NtWaitForSingleObject+0xa
01 00007ffa`8b6b7124     : 00000000`00000000 00000000`00000000 00000001`8006a9a8 00000000`00000000 : ntdll!RtlpWaitOnCriticalSection+0xe1
02 00000001`8000a725     : 00000028`00668230 00000000`00000000 00000028`7fc9d9b0 00000028`00668230 : ntdll!RtlpEnterCriticalSectionContended+0xa4
03 00000001`80011773     : 00000001`00000aa8 00000000`00000000 00000000`00000000 00000000`00000000 : WiseVectorHelperOne_X64+0xa725
04 00007ffa`888faf8f     : 00000000`00000aa8 00000028`d420d308 00000000`00000000 00000000`00000000 : WiseVectorHelperOne_X64+0x11773
05 00007ffa`79db4d45     : 00000000`00000000 00000000`00000000 00000028`04dec6e0 00000001`8000cc3a : KERNELBASE!ResumeThread+0xf
06 00007ffa`79db8bee     : 00000028`00668230 00000000`00000040 00000000`00000001 00000000`00000000 : coreclr!Thread::ResumeThread+0x29 [d:\a\_work\1\s\src\vm\threadsuspend.cpp @ 466] 
07 00007ffa`79e13905     : 00000000`00000003 00000000`00000001 00000000`00000001 00000000`00000000 : coreclr!ThreadSuspend::SuspendRuntime+0x17a [d:\a\_work\1\s\src\vm\threadsuspend.cpp @ 4046] 
08 00007ffa`79db61cf     : 00000000`00001e73 00000000`00001e01 00000028`7f9f6698 00000000`00000000 : coreclr!ThreadSuspend::SuspendEE+0x16d [d:\a\_work\1\s\src\vm\threadsuspend.cpp @ 6517] 
09 (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!GCToEEInterface::SuspendEE+0x21 [d:\a\_work\1\s\src\vm\gcenv.ee.cpp @ 25] 
0a 00007ffa`79e325be     : a2098c12`cdff0000 00007ffa`79e35118 00007ffa`7a28c668 00000000`00000000 : coreclr!WKS::GCHeap::GarbageCollectGeneration+0xff [d:\a\_work\1\s\src\gc\gc.cpp @ 36545] 
0b (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!WKS::gc_heap::trigger_gc_for_alloc+0x12 [d:\a\_work\1\s\src\gc\gc.cpp @ 13832] 
0c 00007ffa`79e35118     : 00000028`7fc9da08 00000028`12bba6d8 00000000`00000002 00007ffa`79dbfc9f : coreclr!WKS::gc_heap::try_allocate_more_space+0x24e [d:\a\_work\1\s\src\gc\gc.cpp @ 13934] 
0d (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!WKS::gc_heap::allocate_more_space+0x11 [d:\a\_work\1\s\src\gc\gc.cpp @ 14369] 
0e (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!WKS::gc_heap::allocate+0x58 [d:\a\_work\1\s\src\gc\gc.cpp @ 14400] 
0f 00007ffa`79dcda8e     : 00000000`00000000 00000028`d420daa0 00007ffa`1a908888 00000028`7fc9da08 : coreclr!WKS::GCHeap::Alloc+0x88 [d:\a\_work\1\s\src\gc\gc.cpp @ 35827] 
10 (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!Alloc+0x18b [d:\a\_work\1\s\src\vm\gchelpers.cpp @ 240] 
11 (Inline Function)     : --------`-------- --------`-------- --------`-------- --------`-------- : coreclr!AllocateObject+0x22d [d:\a\_work\1\s\src\vm\gchelpers.cpp @ 1209] 
12 00007ffa`1b3337e2     : 00007ffa`1a908888 00000028`84d75cc0 00000028`12bb9ce0 00000028`64df1360 : coreclr!JIT_New+0x31e [d:\a\_work\1\s\src\vm\jithelpers.cpp @ 2724] 
....

从输出信息看: NtWaitForSingleObject 正在等待 000000018006a9a8 临界区资源,而这个正好是 !locks3090 线程持有的资源,截图如下:

bf92b2b75ff974c85ff7eba544c6bdb3.png

接下来再看下 3090 线程正在干什么。

0:038> ~~[3090]s
WiseVectorHelperOne_X64+0xcc3a:
00000001`8000cc3a 4889442408      mov     qword ptr [rsp+8],rax ss:00000028`04dec6e8=0000000000000000
0:038> k# Child-SP          RetAddr               Call Site
00 00000028`04dec6e0 00000001`8000f1cb     WiseVectorHelperOne_X64+0xcc3a
01 00000028`04dec710 00000001`8000a751     WiseVectorHelperOne_X64+0xf1cb
02 00000028`04dec7a0 00000001`80011773     WiseVectorHelperOne_X64+0xa751
03 00000028`04dec800 00007ffa`888faf8f     WiseVectorHelperOne_X64+0x11773
04 00000028`04dedd40 00007ffa`79e19796     KERNELBASE!ResumeThread+0xf
05 (Inline Function) --------`--------     coreclr!Thread::StartThread+0x15 [d:\a\_work\1\s\src\vm\threads.cpp @ 528] 
06 00000028`04dedd70 00007ffa`79eaacea     coreclr!ThreadNative::StartInner+0x35a [d:\a\_work\1\s\src\vm\comsynchronizable.cpp @ 501] 
07 00000028`04dee010 00007ffa`1b3afc02     coreclr!ThreadNative::Start+0x8a [d:\a\_work\1\s\src\vm\comsynchronizable.cpp @ 387] 
08 00000028`04dee160 00007ffa`1b3cb018     System_Private_CoreLib!System.Threading.Tasks.Task.ScheduleAndStart+0x102
09 00000028`04dee1b0 00007ffa`1b40005a     System_Private_CoreLib!System.Threading.Tasks.Task.InternalStartNew+0x78
0a 00000028`04dee230 00007ffa`1b41f181     System_Private_CoreLib!System.Threading.Tasks.TaskFactory.StartNew+0x5a
...

从线程栈信息看,托管层执行了一个 Task.Start 操作,然后通过 Win32 Api 生成了一个 OS 线程,在准备调度 OS线程 的时候,遇上了 WiseVectorHelperOne_X64 ,最后就在这里无限期等待,tmd的真奇怪,在两个线程中都看到了这个函数,它到底是干嘛呢?

4. 研究 WiseVectorHelperOne_X64

这个奇怪的 dll,看样子来者不善,上 baidu 查查看。

2d36c8b84e3ba13b0249a053b234d4b3.png

我去,原来被一款叫做 智量杀毒软件 给劫持了。。。具体什么原因被劫持,我也不想研究了,然后拿这个结果和朋友做了一下沟通,尝试停掉它看看。

886fee57e63fea90dd7b9b4fdaf47f6e.png

三:总结

综合两处线程栈的特征,发现都是Win32 Api 在做 Thread::ResumeThread 时被杀毒软件劫持,一般来说 clr 在内部生成 OS 线程时,会先 Suspended,然后再 Resume,参考源码:

BOOL Thread::CreateNewOSThread(SIZE_T sizeToCommitOrReserve, LPTHREAD_START_ROUTINE start, void* args)
{HANDLE h = NULL;DWORD dwCreationFlags = CREATE_SUSPENDED;dwCreationFlags |= STACK_SIZE_PARAM_IS_A_RESERVATION;h = ::CreateThread(NULL     /*=SECURITY_ATTRIBUTES*/,sizeToCommitOrReserve,start,args,dwCreationFlags,&ourId);
}

劫持的原因,这个只能问厂家了,我们能做的就是停掉它 😄,最后朋友太客气了,发了一个大红包😁😁😁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/285498.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言试题111之 s=a+aa+aaa+aaaa+aa...a 的值,其中 a 是一个数字。例如 2+22+222+2222+22222(此时 共有 5 个数相加),几个数相加有键盘控制。

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目: s=a+aa+aaa+aaaa+aa…a 的值,其中 a 是一个数字。例如 2+22+222+2222+22222(此时 共…

MathType插入带序号公式的两种方法

方法一: 由于我之前使用表格15% 70% 15%来布局的,所以最开始相的就是如何录入公示后插入公式序号,如下图所示 先设置序号格式 录好公式后点“Insert Number”就好了,这样的话需要紧挨着公式,用空格把他空到最右侧就好了…

【系统设计】邻近服务

在本文中,我们将设计一个邻近服务,用来发现用户附近的地方,比如餐馆,酒店,商场等。设计要求 从一个小明去面试的故事开始。面试官:你好,我想考察一下你的设计能力,如果让你设计一个…

[转]Redis持久化存储(AOF与RDB两种模式)

Redis中数据存储模式有2种:cache-only,persistence; cache-only即只做为“缓存”服务,不持久数据,数据在服务终止后将消失,此模式下也将不存在“数据恢复”的手段,是一种安全性低/效率高/容易扩展的方式;pe…

C语言试题112之一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如 6=1+2+3.编程 找出 1000 以内的所有完数。

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:一个数如果恰好等于它的因子之和,这个数就称为“完数”。例如 6=1+2+3.编程 找出 …

关于jstl.jar引用问题及解决方法

在前文SSM说到因为从MyEclipse换成了Eclipse。有些架包自动缺失。 造成:"org.apache.jasper.JasperException: This absolute uri (http://java.sun.com/jsp/jstl/core ) cannot be resolved in either web.xml or the jar files deployed with this applicati…

网络技术基础与计算思维实验教程_2.3_单交换机VLAN配置实验

2.3.1 实验内容 2.3.2实验目的 实验的目的一是验证交换机 VLAN 配置过程; 二是验证属于同一 VLAN的终端之间的通信过程; 三是验证每一个 VLAN 为独立的广播域; 四是验证属于不同 VLAN的两个终端之间不能通信; 五是验证转发项和 VLAN的对应关系。 2.3.3实验原理 默认情况下,交换…

dotnet-exec 0.5.0 released

dotnet-exec 0.5.0 releasedIntrodotnet-exec 是一个 C# 程序的小工具,可以用来运行一些简单的 C# 程序而无需创建项目文件,而且可以自定义项目的入口方法,支持但不限于 Main 方法Install/Updatedotnet-exec 是一个 dotnet tool,可…

C语言试题113之一球从 100 米高度自由落下,每次落地后反跳回原高度的一半;再落下,求它在 第 10 次落地时,共经过多少米?第 10 次反弹多高?

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:一球从 100 米高度自由落下,…

超酷的 Vim 搜索技巧

尽管目前我们已经涉及[1] Vim 的多种特性,但此编辑器的特性集如此庞大,不管我们学习多少,似乎仍然远远不足。承接我们的 Vim 教程系列,本文我们将讨论 Vim 提供的多种搜索技术。 不过在此之前,请注意文中涉及到的所有…

对面的00后萌新看过来:浅析计算机编程在高等职业GIS专业中的重要性

文章目录什么是传说中的GIS?GIS必修哪些课程?学GIS到底何去何从?什么是计算机编程?编程在GIS中的地位如何?高等职业GIS如何教学?专科生怎样学好GIS?什么是传说中的GIS? GIS是“3S”之…

SQLServer Agent执行[分发清除: distribution] 无法删除快照文件

由于之前创建的发布订阅造成严重的性能压力,症状表现为发布订阅表查询产生CMEMTHREAD suspend等待,由于开发配置每隔十分钟会产生大量的SQLCOMMAND(create table,create index大量的命令)发布订阅 复制监视器 有Memor…

C语言试题114之猴子吃桃问题

📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 ✅作者简介:大家好,我是码莎拉蒂,CSDN博客专家(全站排名Top 50),阿里云博客专家、51CTO博客专家、华为云享专家 1、题目 题目:猴子吃桃问题:猴子第一天摘…

.NET 7 的 JWT 配置太方便了!

微软宣布 .NET 7 preview5 有一些较大的改进, 包括 JWT 身份验证的简化和自动配置。我安装了 preview 5 尝试了新的 JWT 身份配置。如果您想把现有的项目更新到 .Net 7 preview 5, 下面是一个快速更新的命令。Update all Microsoft.AspNetCore.* package references…

[转]面试官,不要再问我三次握手和四次挥手

文章目录 1. 三次握手 1.1 为什么需要三次握手,两次不行吗?1.2 什么是半连接队列?1.3 ISN(Initial Sequence Number)是固定的吗?1.4 三次握手过程中可以携带数据吗?1.5 SYN攻击是什么?2. 四次挥手 2.1 挥手…

C语言试题115之两个乒乓球队进行比赛,各出三人。甲队为 a,b,c 三人,乙队为 x,y,z 三人。已抽签决定 比赛名单。有人向队员打听比赛的名单。a 说他不和 x 比,c 说他不和 x,z 比,请

✅作者简介:大家好我是码莎拉蒂,CSDN博客专家🥇🥇🥇 📃个人主页:个人主页 🔥系列专栏:C语言试题200例 💬推荐一款模拟面试、刷题神器👉 点击跳转进入网站 1、题目 题目:两个乒乓球队进行比赛,各出三人。甲队为 a,b,c 三人,乙队为 x,y,z 三人。已抽签决定…

(04).NET MAUI实战 MVVM

1.概要本章将讲解如何在MAUI中使用简单的MVVM模式开发“ListView”内容的增删功能,MVVM在MAUI中也同样适用。Microsoft.Toolkit.Mvvm在学习之前我们先了解一个nuget包,它可以帮助我们省去一些代码的开发时间。包Microsoft.Toolkit.Mvvm (aka MVVM Toolki…

WTM重大更新,多租户和单点登录

WTM重大更新多租户单点登录随着WTM被越来越多地应用于企业,用户对于多租户和单点登录的需求越来越强烈。经过了几个月的努力,我们把WTM底层代码又进行了一次优化和重构,加入了多租户和单点登录的功能。VUE,Blazor,LayU…

struts2注解

2019独角兽企业重金招聘Python工程师标准>>> 以下均为本人工作中的笔记内容,不够全面具体。碰到什么我就记录什么,只是作为笔记使用,希望大家多提宝贵意见,共同进步。Action("login"):定义action //或者写…

[转]H5直播之从推流服务搭建到视频直播

转自http://www.php.cn/html5-tutorial-403035.html 最近视频直播比较火,发现目前 WEB 上主流的视频直播方案有 HLS 和 RTMP,移动 WEB 端目前以 HLS 为主,PC端则以 RTMP 为主实时性较好,接下来将围绕这两种视频流协议来展开H5直播…