一:背景

1. 讲故事

前些天有位朋友找到我,说他们工厂里面的程序不知道怎么就突然卡死了,让我帮忙看下怎么回事?dump也拿到了,对于这类程序,其实我还是非常有信心的,接下来就来分析吧。

二:卡死分析

1. 为什么会卡死

因为是窗体程序,所以我们直接看主线程,使用 ~0s;!clrstack 观察托管栈即可,输出如下:


0:000> ~0s;!clrstack
win32u!NtUserShowWindow+0x14:
00007ff8`1ac31b24 c3 ret
OS Thread Id: 0x2ac8 (0)
Child SP IP Call Site
000000b4ddbfde08 00007ff81ac31b24 System.Windows.Forms.SafeNativeMethods.ShowWindow(System.Runtime.InteropServices.HandleRef, Int32)
000000b4ddbfde08 00007fffc2f0aaf5 System.Windows.Forms.SafeNativeMethods.ShowWindow(System.Runtime.InteropServices.HandleRef, Int32)
000000b4ddbfdde0 00007fffc2f0aaf5 DomainBoundILStubClass.IL_STUB_PInvoke(System.Runtime.InteropServices.HandleRef, Int32)
000000b4ddbfde90 00007fffc2e7f395 System.Windows.Forms.Control.SetVisibleCore(Boolean)
000000b4ddbfdf60 00007fffc2e8e4d2 System.Windows.Forms.Form.SetVisibleCore(Boolean)
000000b4ddbfdfd0 00007fffc2e9801a System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
000000b4ddbfe070 00007fffc2e97dd2 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)
000000b4ddbfe0d0 00007fffc3659438 System.Windows.Forms.Form.ShowDialog(System.Windows.Forms.IWin32Window)
000000b4ddbfe1d0 00007fff67dad59f xxx.ShowConfirmDialog(System.String, xxx.InfoType)

从卦象看,应用程序通过 ShowConfirmDialog 方法来显示弹出窗,从托管栈来看没啥毛病,大家都知道托管部分最后要调用非托管代码,所以改成 k 进一步探究底层,输出如下:


0:000> k
# Child-SP RetAddr Call Site
00 000000b4`ddbfddd8 00007fff`c2f0aaf5 win32u!NtUserShowWindow+0x14
01 000000b4`ddbfdde0 00007fff`c2e7f395 System_Windows_Forms_ni+0x33aaf5
02 000000b4`ddbfde90 00007fff`c2e8e4d2 System_Windows_Forms_ni!System.Windows.Forms.Control.SetVisibleCore+0x115
03 000000b4`ddbfdf60 00007fff`c2e9801a System_Windows_Forms_ni!System.Windows.Forms.Form.SetVisibleCore+0xb2
04 000000b4`ddbfdfd0 00007fff`c2e97dd2 System_Windows_Forms_ni!System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner+0x20a
05 000000b4`ddbfe070 00007fff`c3659438 System_Windows_Forms_ni!System.Windows.Forms.Application.ThreadContext.RunMessageLoop+0x52
06 000000b4`ddbfe0d0 00007fff`67dad59f System_Windows_Forms_ni!System.Windows.Forms.Form.ShowDialog+0x428
07 000000b4`ddbfe1d0 00007fff`67da1f51 xxx!xxx.FuncLib.ShowConfirmDialog+0x4bf

从卦中可以看到当前调用栈止步于用户态 win32u!NtUserShowWindow 函数,看样子当前执行流已经通过syscall进入内核态了,可以通过 Disassembly 窗口来验证,截图如下:

2. NtUserShowWindow 到底怎么了?

至于为什么调用栈在 NtUserShowWindow 中不返回,说实话在用户态层面真的看不出来,只能获取到当前执行流的内核态栈才知道到底发生了什么事情,那如何获取执行流的内核态栈呢?有两种办法:

  • 抓此时操作系统的内核态dump。
  • 借助 procdump -mk 获取此时的线程内核态栈。

由于第一种办法比较笨重,这里就告诉朋友使用第二种方法抓取,关于procdump更多的细节,可参见:https://learn.microsoft.com/en-us/sysinternals/downloads/procdump

很快朋友就拿到了线程kernel级的调用栈文件,截图如下:

双击打开之后切到0号线程观察调用栈,输出如下:


0: kd> ~0s
0: kd> k
# Child-SP RetAddr Call Site
00 ffff9005`b03be3b0 fffff805`06e8adbb nt!DbgkpLkmdSnapThreadInContext+0x95
01 ffff9005`b03be8f0 fffff805`068c83bb nt!DbgkpLkmdSnapThreadApc+0x3b
02 ffff9005`b03be920 fffff805`06841657 nt!KiDeliverApc+0x27b
03 ffff9005`b03be9e0 fffff805`0684085f nt!KiSwapThread+0x827
04 ffff9005`b03bea90 fffff805`06840103 nt!KiCommitThreadWait+0x14f
05 ffff9005`b03beb30 fffff805`068d21bd nt!KeWaitForSingleObject+0x233
06 ffff9005`b03bec20 fffff805`068c84d1 nt!KiSchedulerApc+0x3bd
07 ffff9005`b03bed50 fffff805`06841657 nt!KiDeliverApc+0x391
08 ffff9005`b03bee10 fffff805`0684085f nt!KiSwapThread+0x827
09 ffff9005`b03beec0 fffff805`06840103 nt!KiCommitThreadWait+0x14f
0a ffff9005`b03bef60 fffff805`068cadbb nt!KeWaitForSingleObject+0x233
0b ffff9005`b03bf050 ffff8de3`c59156f2 nt!KeWaitForMultipleObjects+0x45b
0c ffff9005`b03bf160 ffff8de3`c5917ea9 win32kfull!xxxRealSleepThread+0x362
0d ffff9005`b03bf280 ffff8de3`c5916b5a win32kfull!xxxInterSendMsgEx+0xdd9
0e ffff9005`b03bf3f0 ffff8de3`c5968e33 win32kfull!xxxSendTransformableMessageTimeout+0x3ea
0f ffff9005`b03bf540 ffff8de3`c596a830 win32kfull!xxxCalcValidRects+0x3b7
10 ffff9005`b03bf6e0 ffff8de3`c596e5a3 win32kfull!xxxEndDeferWindowPosEx+0x1ac
11 ffff9005`b03bf7c0 ffff8de3`c596e3dd win32kfull!xxxSetWindowPosAndBand+0xc3
12 ffff9005`b03bf850 ffff8de3`c5936c36 win32kfull!xxxSetWindowPos+0x79
13 ffff9005`b03bf8d0 ffff8de3`c59369ca win32kfull!xxxShowWindowEx+0x22a
14 ffff9005`b03bf980 ffff8de3`c5d6866a win32kfull!NtUserShowWindow+0xda
15 ffff9005`b03bf9d0 fffff805`06a11235 win32k!NtUserShowWindow+0x16
16 ffff9005`b03bfa00 00007ff8`1ac31b24 nt!KiSystemServiceCopyEnd+0x25
17 000000b4`ddbfddd8 00000000`00000000 0x00007ff8`1ac31b24

从内核态调用栈来看,有一个函数 InterSendMsgEx 特别刺眼,对,它就是翻版的 SendMessage,也就是说当前执行流在内核态中给其他窗口发消息时,对方窗口不响应导致当前线程直接卡死在内核态。。。

那到底是给哪一个窗口发消息呢?看下用户态 NtUserShowWindow 方法的 rcx 参数即可,输出如下:


0:000> r
rax=0000000000001057 rbx=0000028fe4171560 rcx=0000000000290476
rdx=0000000000000005 rsi=000000b4ddbfdee8 rdi=0000000000000005
rip=00007ff81ac31b24 rsp=000000b4ddbfddd8 rbp=000000b4ddbfde80
r8=0000028fe5f26b44 r9=00007fffc4c75dd8 r10=0000000000000000
r11=0000028fe4171560 r12=0000028fe4171560 r13=0000000000000202
r14=0000028fe7879eb0 r15=0000000000000010
iopl=0 nv up ei pl zr na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
win32u!NtUserShowWindow+0x14:
00007ff8`1ac31b24 c3 ret

从卦中可以看到是因为主线程给窗口 wnd=290476 打消息导致的程序系统性卡死,这个窗体可能是本程序创建的,也有可能不是本程序创建的,接下来该如何找到 wnd=290476 窗口句柄呢? 这是一个老生常谈的问题了哈,这里我就不赘述了,参见我的几篇文章即可。

三:总结

这次事故最值得学习的一个点,那就是当用户态层面找不出卡死的祸根时,巧妙的使用 procdump -mk 获取线程的内核态栈,最终找到问题祸根,轻量又实用。

记一次 .NET 某自动化智能制造软件 卡死分析的更多相关文章

  1. 记一次 .NET 某自动化集采软件 崩溃分析

    一:背景 1.讲故事 前段时间有位朋友找到我,说他的程序在客户的机器上跑着跑着会出现偶发卡死,然后就崩掉了,但在本地怎么也没复现,dump也抓到了,让我帮忙看下到底怎么回事,其实崩溃类的dump也有简 ...

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

    一:背景 1. 讲故事 这几个月经常被朋友问,为什么不更新这个系列了,哈哈,确实停了好久,主要还是打基础去了,分析 dump 的能力不在于会灵活使用 windbg,而是对底层知识有一个深厚的理解,比如 ...

  3. 记一次 .NET 某企业OA后端服务 卡死分析

    一:背景 1.讲故事 前段时间有位朋友微信找到我,说他生产机器上的 Console 服务看起来像是卡死了,也不生成日志,对方也收不到我的httpclient请求,不知道程序出现什么情况了,特来寻求帮助 ...

  4. 记一次 .NET某医疗器械清洗系统 卡死分析

    一:背景 1. 讲故事 前段时间协助训练营里的一位朋友分析了一个程序卡死的问题,回过头来看这个案例比较经典,这篇稍微整理一下供后来者少踩坑吧. 二:WinDbg 分析 1. 为什么会卡死 因为是窗体程 ...

  5. 智能制造(MES)四大阶段

    智能制造的发展会经历标准化.自动化.信息化.智能化四个阶段标准化,对于生产流程.业务流程.生产制造多方面的标准化.质量检测标准化.企业管理.供应链等.标准化是组织现代化生产的重要组成部分,对于生产专业 ...

  6. 易普优APS-3C行业解决方案助力国家智能制造示范车间实现高效计划排程

    一.      项目背景 广东劲胜智能集团国家智能制造专项——移动终端金属加工智能制造新模式项目是2015年国家94家智能制1.造专项之一.本项目实施车间为金属CNC加工车间(下称“智能制造示范车间” ...

  7. 一个美国人对"智能制造"的思考!

    世界上制造业最强的国家仍然是美国!如今,国内工业4.0概念讨论日益喧嚣,中德合作如火如荼,但我们不能否认这个事实. “ 当下,美国似乎失去了世界第一制造大国的称号,而中国的企业也正面临产值下滑.利润下 ...

  8. 毕马威&阿里:通向智能制造的转型之路

    文章发布于公号[数智物语] (ID:decision_engine),关注公号不错过每一篇干货. 2019 年 4 月 17 日,毕马威与阿里研究院携手举办了智能经济主题报告发布会,从技术.制造.组织 ...

  9. MES被重新定义?做到这几点才算智能制造

    在工业4.0背景下,推动智能制造,构建智能工厂.智能生产.智能物流和智能服务体系,我们需要对MES系统重新进行定义,主要从以下几个方面进行说明: MES深度融入企业运营环节 智能工厂中的机器将全部由软 ...

  10. MES应用案例|新宏泰电器乘上智能制造的东风

    企业背景: 无锡新宏泰电器科技股份有限公司(下文简称:新宏泰电器)创立于1984年,公司主要生产断路器.微型电机.BMC/SMC材料.BMC/SMC模压制品及各类塑料模具的设计制造.已于2016年在沪 ...

随机推荐

  1. REVM移植小记

      之前做过的一些部署移植的工作,基本都是用C++语言写的,在后来我学了一些Rust,并且慢慢熟悉了Rust的工具链,最近也在尝试部署一些Rust的开源项目到OpenEuler RISC-V操作系统上 ...

  2. win10将python打包成apk详细文档

    打包不支持windows所以可以找一台linux的电脑 或者用win10子系统(推荐) 我用的是Ubuntu 方法:https://www.jianshu.com/p/fcf21d45ea74 我简单 ...

  3. stm32cubemx+DMA+freertos实现usart不定长数据接收和发送

    本博客讲解如何在stm32cubemx+freertos+dma的情况下实现usart不定长接收和发送数据 cubemx配置 波特率随意 freertos没啥特别的配置,打开即可,我用的是CMSIS_ ...

  4. 华为MAAS、阿里云PAI、亚马逊AWS SageMaker、微软Azure ML各大模型深度分析对比

    一.技术架构深度对比 1. 硬件基础设施 平台 自研芯片 分布式训练方案 边缘协同能力 华为MAAS 昇腾Ascend 910 + Atlas 900集群 MindSpore + HCCL(华为集合通 ...

  5. Fastapi中Swagger UI加载缓慢的解决方案

    在国内网络经常遇到Swagger UI加载缓慢的问题,这是由于Swagger UI的CSS和JS代码源在国外导致的,所以我们的解决方法是更改Swagger UI的CSS代码和JS代码源到国内的CND实 ...

  6. SwanLab入门深度学习:Qwen3大模型指令微调

    一.概述 Qwen3是通义千问团队的开源大语言模型,由阿里云通义实验室研发.以Qwen2作为基座大模型,通过指令微调的方式实现高准确率的文本分类,是学习大语言模型微调的入门任务. 指令微调是一种通过在 ...

  7. SpringBoot集成openGauss

    1.pom依赖 <dependencies> <dependency> <groupId>org.springframework.boot</groupId& ...

  8. [网络安全]工具-quasar开源远控软件使用教程

    首先声明本文仅作科普,若用作违法途径与作者无关!!! quasar是著名的开源后门软件,本文来分享它的基本使用.一些常见问题及其解决方法 一.下载地址 Quasar v1.4.1下载地址:https: ...

  9. Win7 64位安装版系统用U盘在固态硬盘上安装

    为什么要用原版?为什么要用安装版?因为GHOST版被删掉了太多内容,制作者认为不重要的东西全删了,可是,做为一些行业的需要,还是要完整版的才能用.但win7是在固态硬盘大面积使用之前就被发布的.所以支 ...

  10. jq通过自定义属性获取标签对象

    https://blog.csdn.net/qq_44927883/article/details/106360358$("td[data-field='fieldHtmlType']&qu ...