最近跟踪了一个程序的界面卡死问题,该卡死偶尔出现,在抓到一次dump后用windbg载入分析,打印出函数调用堆栈后,一眼可以看出是临界区死锁了。

代码:
0:000:x86> kb
ChildEBP RetAddr  Args to Child              
0032dd0c 779ed993 00000710 00000000 00000000 ntdll_779b0000!NtWaitForSingleObject+0x15
0032dd70 779ed877 00000000 00000000 024023f0 ntdll_779b0000!RtlpWaitOnCriticalSection+0x13e
0032dd98 58a2fac3 02404c50 856fd57e 024023f0 ntdll_779b0000!RtlEnterCriticalSection+0x150
0032dffc 58a0d4d7 856fea8a 00000000 001c41a0 SogouSoftware_589d0000!CDownloadListUI::UpdateDownloadListUI+0x43

输出该临界区的信息:

代码:
0:000:x86> !cs 02404c50
-----------------------------------------
Critical section   = 0x0000000002404c50 (+0x2404C50)
DebugInfo          = 0x0000000000611e08
LOCKED
LockCount          = 0xFFFFFFFF
WaiterWoken        = Yes
OwningThread       = 0x0000000000000710
RecursionCount     = 0x1A38
LockSemaphore      = 0x2433B08
SpinCount          = 0x0000000000000000

Windbg指示是0x710号线程占有该临界区在,于是看看0x710号线程是那一个,结果发现报错,一般这种情况是线程已经退出或者被终止掉了。

代码:
0:000:x86> ~~[710]
                 ^ Illegal thread error in '~~[710]'

该临界区死锁的位置部分代码如下:

代码:
void CDownloadListUI::UpdateDownloadListUI()
{
  m_vctLock.Lock();
  vector<int> vecDeleteItems(GetCount());  // record index to be delete
  std::iota(vecDeleteItems.begin(), vecDeleteItems.end(), 0);
  ......
  m_vctLock.UnLock();
}

m_vctLock是ATL一个对临界区简单封装的类,让同事仔细对m_vctLock所有加锁的位置进行检查,发现除了主线程外只有另外一个工作线程会使用,用windbg查了下改工作线程并未退出,线程ID也不为 0x710,难道又被Windbg给忽悠了?打印下该临界区的数据结构看看:

代码:
0:000:x86> dt _RTL_CRITICAL_SECTION 02404c50
DuiLib!_RTL_CRITICAL_SECTION
   +0x000 DebugInfo        : 0x00611e08 _RTL_CRITICAL_SECTION_DEBUG
   +0x004 LockCount        : 0n-6
   +0x008 RecursionCount   : 0n1
   +0x00c OwningThread     : 0x00001a38 Void
   +0x010 LockSemaphore    : 0x00000710 Void
   +0x014 SpinCount        : 0

发现这里显示的拥有者线程号和上面不一致,试试看是那个线程:

代码:
0:000:x86> ~~[1a38]
   6  Id: 2058.1a38 Suspend: 0 Teb: 7ef94000 Unfrozen
      Start: SogouSoftware_589d0000!_threadstartex (58a5192d) 
      Priority: 0  Priority class: 32  Affinity: f
0:000:x86> ~6s
ntdll_779b0000!ZwWaitForMultipleObjects+0x15:
779d019d 83c404          add     esp,4
0:006:x86> kb
ChildEBP RetAddr  Args to Child              
0370fa5c 768615f7 00000002 0370faac 00000001 ntdll_779b0000!ZwWaitForMultipleObjects+0x15
0370faf8 773519f8 0370faac 0370fb20 00000000 KERNELBASE!WaitForMultipleObjectsEx+0x100
0370fb40 773541d8 00000002 7efde000 00000000 kernel32!WaitForMultipleObjectsExImplementation+0xe0
0370fb5c 589f6ba0 00000002 0370fb84 00000000 kernel32!WaitForMultipleObjects+0x18
0370fbd4 58a51907 58aab894 862df68e 00000000 SogouSoftware_589d0000!CThreadQueue<TagDownloadTask>::ThreadProc+0x100 
0370fc0c 58a51991 00000000 0370fc24 7735336a SogouSoftware_589d0000!_callthreadstartex+0x1b [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 314]
0370fc18 7735336a 023f5170 0370fc64 779e9882 SogouSoftware_589d0000!_threadstartex+0x64 [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 292]
0370fc24 779e9882 023f5170 771cc6bb 00000000 kernel32!BaseThreadInitThunk+0xe
0370fc64 779e9855 58a5192d 023f5170 00000000 ntdll_779b0000!__RtlUserThreadStart+0x70
0370fc7c 00000000 58a5192d 023f5170 00000000 ntdll_779b0000!_RtlUserThreadStart+0x1b

6号线程正处于等待任务中,对照代码,6号线程有一个观察者的回调函数会调用到CDownloadListUI类中的m_vctLock锁,但是该回调函数已经执行完毕了。那么只有一种可能,就是锁泄露了,即Lock后没有解锁。再去看该回调函数,果然发现有一个很少出现的分支下没有调用Unlock释放临界区而直接返回了,这就造成了经典的锁泄露而引起死锁的bug。
  但 !cs 命令在此种情况下却给出了错误的信息,很容易造成误导而怀疑是一个拥有该锁的线程退出了而引起的。这应该算是Windbg的一个bug吧。
  进一步测试该情况,发现是当64位系统下的32位进程产生的dump会有此问题,32位系统下产生的dump使用 !cs 命令执行正常。

Windbg跟踪临界区的BUG的更多相关文章

  1. 缺陷跟踪系统Mantis Bug Tracker

    缺陷管理平台Mantis,也做MantisBT,全称Mantis Bug Tracker. 项目在github的地址:https://github.com/mantisbt/mantisbt Mant ...

  2. Windows系统上release版本程序bug跟踪解决方案-.dmp文件。

    使用场景: Win32程序在release模式下编译完成,发送给最终用户使用时,我们的程序有时候也会出现崩溃的情况,这个时候如果能快速定位崩溃原因或提供一些程序崩溃时的状态信息,对我们解决问题将会带来 ...

  3. 一个bug在redmine中的诞生到终结

    1.測试员測试出bug,跟踪状态为支持,状态为新建,指派给产品经理. 2.产品经理鉴定确觉得bug.改动跟踪状态为bug.指派给技术经理: 3.技术经理收到bug,指派给开发者: 4.开发者收到bug ...

  4. Android_通过Bugtags平台,方便測试人员提交bug及整个bug系统的管理

    Bugtags 是什么? Bugtags 是一款缺陷发现及管理工具. 当您的 App 集成了 Bugtags SDK 后,測试人员就可直接在 App 里所见即所得的提交 Bug. SDK 会自己主动截 ...

  5. 【测试基础第六篇】bug定义及生命周期

    bug定义 狭义:软件程序的漏洞或缺陷 广义:测试工程师或用户所发现和提出的软件可改进的细节(增强型.建议性)或需求文档存在差异的功能实现 职责:发现bug,提给开发,让其修改 bug类型--了解 代 ...

  6. Linux和Windows设备驱动架构比较

    毕业后一直在学操作系统, 有时候觉得什么都懂了,有时候又觉得好像什么都不懂,但总体来说自认为对操作系统实现机制的了解比周围的人还是要多一些.去年曾花了几个星期的晚上时间断断续续翻译了这篇对Linux和 ...

  7. .NET对象与Windows句柄(三):句柄泄露实例分析

    在上篇文章.NET对象与Windows句柄(二):句柄分类和.NET句柄泄露的例子中,我们有一个句柄泄露的例子.例子中多次创建和Dispose了DataReceiver和DataAnalyzer对象, ...

  8. NetHogs下载和监控

    转自:http://blog.csdn.net/testcs_dn/article/details/40506225 CentOS6.5下使用NetHogs监控进程网络使用情况 分类: CentOS2 ...

  9. Bugtags,产品经理的瑞士军刀

    做为设计移动应用的产品经理,每天的主要工作就是在手机上不停的体验自己的产品,发现问题.优化体验.你是否经常工作在这样的尴尬场景: 发现界面问题,将问题界面截屏传到电脑,用图片标记工具将问题标记出来,然 ...

随机推荐

  1. C#循环测试题

    关于如下程序结构的描述中,哪一项是正确的?   for ( ; ; ) { 循环体; //何问起   }   a) 不执行循环体b) 一直执行循环体,即死循环c) 执行循环体一次d) 程序不符合语法要 ...

  2. C#学习笔记-封装

    前言 说起来惭愧,学了大半年的C#,其实最开始就接触到了封装的部分,但是一直模模糊糊的弄不清楚,也觉得没什么影响就没怎么在意,现在才开始认真的看这部分内容,看懂了过后好多东西清晰了不少,才发现封装这个 ...

  3. C#开发微信门户及应用(29)--微信个性化菜单的实现

    有一段时间没有接着微信的主题继续介绍里面的功能模块了,这段时间来,微信也做了不少的变化改动,针对这些特性我全面核对了一下相关的微信公众号和企业号的接口,对原有的微信API和系统管理做了全面的更新,本随 ...

  4. KMP算法-next函数求解

    KMP函数求解:一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为KMP算法.KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串 ...

  5. uct框架数据库sql文件导入错误之 sql_mode

    uct框架在导入sql文件时可能会出现一种错误 ERROR 1101 (42000): BLOB/TEXT column 'brief' can't have a default value 这是由于 ...

  6. easyui datagrid 动态操作editor 的方法

    easyui本身是不提供这么细节的功能的,需要我们自己拓展下: 在easyui.min.js中扩展: $.extend($.fn.datagrid.methods, { addEditor : fun ...

  7. MVC中实现Area几种方法

    概述        ASP.NET MVC中,是依靠某些文件夹以及类的固定命名规则去组织model实体层,views视图层和控制层的.如果是大规模的应用程序,经常会由不同功能的模块组成,而每个功能模块 ...

  8. .Net Core WebAPI 基于Task的同步&异步编程快速入门

    .Net Core WebAPI 基于Task的同步&异步编程快速入门 Task.Result async & await 总结 并行任务(Task)以及基于Task的异步编程(asy ...

  9. 简单介绍JSON

    如下图:

  10. 纯前端JSON文件编辑器[0]

    准备工作 参考资料: FileReader(用来获取上传文件的数据) <download>(用来设置下载文件的名称) Blob(用来存储数据的一个容器) createObjectURL(用 ...