当前位置: 首页 > news >正文

记一次 .NET某工控视觉自动化系统 卡死分析

一:背景

1. 讲故事

今天分享的dump是训练营里一位学员的,从一个啥也不会到现在分析的有模有样,真的是看他成长起来的,调试技术学会了就是真真实实自己的,话不多说,上windbg说话。

二:WinDbg 分析

1. 为什么会卡死

这位学员是从事工控大类下的视觉自动化,也是目前.NET的主战场,这个场景下大多都是WPF或者WinForm程序,不管是什么程序,先用命令 k 开路。


0:000> ~0s
ntdll!NtWaitForMultipleObjects+0x14:
00007ff8`d825cc14 c3              ret
0:000> k# Child-SP          RetAddr               Call Site
00 000000e4`c0cf87e8 00007ff8`d54f7ff7     ntdll!NtWaitForMultipleObjects+0x14
01 000000e4`c0cf87f0 00007ff8`83aa7585     KERNELBASE!WaitForMultipleObjectsEx+0x107
02 000000e4`c0cf8af0 00007ff8`83aa76fa     PylonBase_v5_1!Pylon::CInstantCameraArray::DestroyInstantCamera+0x78da1
03 000000e4`c0cf8bb0 00007ff8`83a188bc     PylonBase_v5_1!Pylon::CInstantCameraArray::DestroyInstantCamera+0x78f16
04 000000e4`c0cf8c30 00007ff8`83a22a70     PylonBase_v5_1!Pylon::CGrabResultPtr::IsUnique+0x16ec
05 000000e4`c0cf8cd0 00007ff8`41fee2dd     PylonBase_v5_1!Pylon::CGrabResultPtr::IsUnique+0xb8a0
06 000000e4`c0cf8d40 00007ff8`4218711b     0x00007ff8`41fee2dd
...

从卦象看真的很不吉利,因为这个等待是一个第三方的SDK库,从 DestroyInstantCamera 名字看就是 立即销毁相机,接下来我们看下 PylonBase_v5_1 是何方圣神?


0:000> lmvm PylonBase_v5_1
Browse full module list
start             end                 module name
00007ff8`839e0000 00007ff8`83b5b000   PylonBase_v5_1   (export symbols)       PylonBase_v5_1.dllLoaded symbol image file: PylonBase_v5_1.dllImage path: C:\Program Files\Basler\pylon 5\Runtime\x64\PylonBase_v5_1.dllImage name: PylonBase_v5_1.dllBrowse all global symbols  functions  dataTimestamp:        Fri Aug 24 20:41:55 2018 (5B7FFD13)CheckSum:         0017E66CImageSize:        0017B000File version:     5.1.0.12681Product version:  5.1.0.12681File flags:       0 (Mask 3F)File OS:          40004 NT Win32File type:        2.0 DllFile date:        00000000.00000000Translations:     0000.04b0Information from resource tables:CompanyName:      BaslerProductName:      Basler pylonInternalName:     PylonBaseOriginalFilename: PylonBase.dllProductVersion:   5.1.0.12681 FileVersion:      5.1.0.12681PrivateBuild:     SpecialBuild:     0FileDescription:  PylonBase ModuleLegalCopyright:   Copyright (c) 2006-2018 Basler AG - All rights reserved.LegalTrademarks:  Comments:         1d4ccf9b36037580c4655fde004335702d90d3e8

由于我是行外人,所以我好奇的查一下 Basler 是什么公司,🐂👃哈,截图如下:

再回过头来看,为什么会在这里被卡呢?这个库是商业产品没有pdb的,看汇编很难推进,索性就从线程栈中逆向推测,即从 NtWaitForMultipleObjects 方法入手。

2. 如何解读 NtWaitForMultipleObjects

这个方法是微软公开的方法,和C#的 Task.WaitAny 功能等价,在 MSDN 上可以看到它的签名信息。


DWORD WaitForMultipleObjects([in] DWORD        nCount,[in] const HANDLE *lpHandles,[in] BOOL         bWaitAll,[in] DWORD        dwMilliseconds
);

接下来就是提取 lpHandles 中的 handle 值,看下这个 handle 到底是什么类型,再图后续方向,根据x64调用协定,只需要提取 rdx 参数即可。


0:000> r
rax=000000000000005b rbx=0000000000000001 rcx=0000000000000001
rdx=000000e4c0cf8b58 rsi=0000000000000000 rdi=0000000000000001
rip=00007ff8d825cc14 rsp=000000e4c0cf87e8 rbp=000000e4c0cf8c00r8=000002aedcc62701  r9=ffffffffffffffe8 r10=000002ae86a12580
r11=000000e4c0cf8680 r12=00000000fffffffe r13=000000e4c0cf8b58
r14=000000e4c0cf8840 r15=0000000000000000
iopl=0         nv up ei pl zr na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!NtWaitForMultipleObjects+0x14:
00007ff8`d825cc14 c3              ret0:000> !handle poi(000000e4c0cf8b58) f
Handle 0000000000001790Type         	ThreadAttributes   	0GrantedAccess	0x1fffff:Delete,ReadControl,WriteDac,WriteOwner,SynchTerminate,Suspend,Alert,GetContext,SetContext,SetInfo,QueryInfo,SetToken,Impersonate,DirectImpersonateHandleCount  	6PointerCount 	201480Name         	<none>Object specific informationThread Id   4714.ff4Priority    10Base Priority 0

从卦中数据看,居然是一个线程句柄,而且信息 Thread Id 4714.ff4也标出来了,真tmd的是 山重水复疑无路,柳暗花明又一村 。。。

3. f44号线程正在做什么

有了线索之后,后面就是顺藤摸瓜了,先切到 f44 号线程。


0:137> !clrstack
OS Thread Id: 0xff4 (137)Child SP               IP Call Site
000000e4c53fd418 00007ff8d825cc14 [GCFrame: 000000e4c53fd418] 
000000e4c53fd610 00007ff8d825cc14 [GCFrame: 000000e4c53fd610] 
000000e4c53fd668 00007ff8d825cc14 [HelperMethodFrame: 000000e4c53fd668] System.Threading.Monitor.Enter(System.Object)
000000e4c53fd760 00007ff84218d827 Basler.xxx.OnImageGrabbed(System.Object, Basler.Pylon.ImageGrabbedEventArgs)
...

从卦象看,这个线程正在 lock锁上等待,那这个lock锁被谁持有着呢?这个就比较简单了,查看下同步块索引即可。


0:137> !syncblk
Index SyncBlock MonitorHeld Recursion Owning Thread Info  SyncBlock Owner321 000002ae81012218            7         1 000002ae83701520 2e74  57   000002aedea354e8 System.Object

卦中的 2e74号线程正是持有锁,接下来就是探究下 2e74号线程此时正在干什么?

4. 2e74号线程正在干什么

一路摸瓜,有种预感马上就能看到光了,切到这个线程继续观察。


0:057> !clrstack
OS Thread Id: 0x2e74 (57)Child SP               IP Call Site
000000e4c4efcdb8 00007ff8d825cc14 [HelperMethodFrame_1OBJ: 000000e4c4efcdb8] System.Threading.WaitHandle.WaitOneNative(System.Runtime.InteropServices.SafeHandle, UInt32, Boolean, Boolean)
000000e4c4efcee0 00007ff89ed99ccc System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle, Int64, Boolean, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\waithandle.cs @ 243]
000000e4c4efcf10 00007ff89ed99c9f System.Threading.WaitHandle.WaitOne(Int32, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\waithandle.cs @ 194]
000000e4c4efcf50 00007ff89af8ac84 System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle)
000000e4c4efcfc0 00007ff89a7f3264 System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
000000e4c4efd100 00007ff89af8e4a4 System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[])
000000e4c4efd170 00007ff84219c223 xxx.MCamera_RetrieveImageCompleted1(System.Object, System.EventArgs)
...

从卦中看这个线程正在用 Invoke 给主线程的 Queue 塞数据,并等待主线程的提取唤醒,所以这是一个经典的 三角循环死锁

有了完整的前因后果之后,改动方案就比较简单了。

  • Invoke 改成 BeginInvoke
  • 缩小 lock 的粒度

三:总结

这个dump所呈现的 三角循环死锁 还是非常经典的,更开心的是这位学员的分析能力已经出了新手村。。。

相关文章:

  • 简单聊一下Oracle,MySQL,postgresql三种锁表的机制,行锁和表锁
  • python爬虫:实现动态网页的爬取,以爬取视频为例
  • 【C++进阶学习】第一弹——继承(上)——探索代码复用的乐趣
  • 6.14作业
  • 【Ardiuno】实验ESP32单片机自动配置Wifi功能(图文)
  • Solr7.4.0报错org.apache.solr.common.SolrException
  • 3、matlab单目相机标定原理、流程及实验
  • Linux2(文件类型分类 基本命令2 重定向)
  • 英伟达算法岗面试,问的贼专业。。。
  • 干货!电脑如何录屏?6款win10录屏大师软件深度测评
  • ElasticSearch的桶聚合
  • 如何基于 Python 快速搭建 QQ 开放平台 QQ 群官方机器人详细教程(更新中)
  • 学了这篇面试经,轻松收割网络安全的offer
  • 主流后端开发语言对比
  • linux 网桥学习
  • IE9 : DOM Exception: INVALID_CHARACTER_ERR (5)
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • CentOS 7 修改主机名
  • chrome扩展demo1-小时钟
  • Codepen 每日精选(2018-3-25)
  • Fastjson的基本使用方法大全
  • js递归,无限分级树形折叠菜单
  • Laravel Mix运行时关于es2015报错解决方案
  • maven工程打包jar以及java jar命令的classpath使用
  • mysql中InnoDB引擎中页的概念
  • React中的“虫洞”——Context
  • 第2章 网络文档
  • 记录一下第一次使用npm
  • 聊聊redis的数据结构的应用
  • 深度学习中的信息论知识详解
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 小程序 setData 学问多
  • 小程序、APP Store 需要的 SSL 证书是个什么东西?
  • 2017年360最后一道编程题
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • 国内开源镜像站点
  • 智能情侣枕Pillow Talk,倾听彼此的心跳
  • ​虚拟化系列介绍(十)
  • #stm32整理(一)flash读写
  • (10)STL算法之搜索(二) 二分查找
  • (13):Silverlight 2 数据与通信之WebRequest
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (delphi11最新学习资料) Object Pascal 学习笔记---第2章第五节(日期和时间)
  • (floyd+补集) poj 3275
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (笔试题)合法字符串
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (亲测)设​置​m​y​e​c​l​i​p​s​e​打​开​默​认​工​作​空​间...
  • (十)T检验-第一部分
  • (一)认识微服务
  • (译)2019年前端性能优化清单 — 下篇