ڼС
梦回起点
做你害怕做的事,你会发现:不过如此
本站基于WordPress—主题by 设计窝
冀ICP备15003737号
梦回起点
Copyright © 2015-2024 All rights reserved.

记一次CoInitialize卡住而发现的死锁问题

调用CoInitialize后线程卡住,首先想到的就是死锁。

0:008> !cs -l
-----------------------------------------
DebugInfo          = 0x00432418
Critical section   = 0x75d60280 (USER32!gcsUserApiHook+0x0)
LOCKED
LockCount          = 0x1
WaiterWoken        = No
OwningThread       = 0x00000f0c
RecursionCount     = 0x1
LockSemaphore      = 0x200
SpinCount          = 0x00000000
-----------------------------------------
DebugInfo          = 0x0043e7a0
Critical section   = 0x7580773c (ole32!g_mxsSingleThreadOle+0x18)
LOCKED
LockCount          = 0x0
WaiterWoken        = No
OwningThread       = 0x00000f4c
RecursionCount     = 0x1
LockSemaphore      = 0x0
SpinCount          = 0x00000000

根据OwningThread,看一下这两个线程

0:001> ~~[f0c]
   0  Id: d40.f0c Suspend: 2 Teb: 7efdd000 Unfrozen
      Start: XXX_exe+0x15e2 (000915e2)
      Priority: 0  Priority class: 32  Affinity: 1

0:000> ~~[f4c]
   1  Id: d40.f4c Suspend: 1 Teb: 7efda000 Frozen 
      Start: XXX+0x37a7 (744537a7)
      Priority: 0  Priority class: 32  Affinity: 1

两个锁分别被0号线程和1号线程拥有,并且两个锁都是锁定状态,很像死锁
注意到0号线程的Suspend是2,其中一个计数是因为调试器加的,减去之后线程还是暂停的,说明这个线程就是暂停状态。
那1号线程为什么卡住呢。

0:001> kv
 # ChildEBP RetAddr  Args to Child              
00 01eed258 77288dd4 00000200 00000000 00000000 ntdll!NtWaitForSingleObject+0x15 (FPO: [3,0,0])
01 01eed2bc 77288cb8 00000000 00000000 00000000 ntdll!RtlpWaitOnCriticalSection+0x13e (FPO: [Non-Fpo])
02 01eed2e4 75cfaccc 75d60280 00000011 6dfe0000 ntdll!RtlEnterCriticalSection+0x150 (FPO: [Non-Fpo])
03 01eed360 75cfab0e 6dfe0000 6dff4571 0000c03b USER32!InitUserApiHook+0x21 (FPO: [Non-Fpo])
04 01eed49c 7726011a 01eed4b4 00000000 01eee758 USER32!__ClientLoadLibrary+0xb1 (FPO: [Non-Fpo])
05 01eed4dc 75cfa8e8 00000000 0000c03b 0000c03b ntdll!KiUserCallbackDispatcher+0x2e (FPO: [0,0,0])
06 01eed788 75cfaa3c 00000000 0000c03b 01eed824 USER32!VerNtUserCreateWindowEx+0x1a9 (FPO: [Non-Fpo])
07 01eed83c 75cf8a5c 00000000 0000c03b 01eed824 USER32!_CreateWindowEx+0x210 (FPO: [Non-Fpo])
08 01eed878 7570644f 00000000 0000c03b 75706470 USER32!CreateWindowExW+0x33 (FPO: [Non-Fpo])
09 01eed8b0 7570650c 75806b04 75807724 00000006 ole32!InitMainThreadWnd+0x3e (FPO: [0,0,4]) (CONV: stdcall) [d:\w7rtm\com\ole32\com\objact\mainthrd.cxx @ 160] 
0a 01eed8c8 75700b81 00000000 00000006 00000000 ole32!wCoInitializeEx+0xef (FPO: [Non-Fpo]) (CONV: stdcall) [d:\w7rtm\com\ole32\com\class\compobj.cxx @ 2437] 
0b 01eed8e8 75f0f4ae 00000002 00000006 75ed79be ole32!CoInitializeEx+0x29d (FPO: [Non-Fpo]) (CONV: stdcall) [d:\w7rtm\com\ole32\com\class\compobj.cxx @ 2110] 
WARNING: Stack unwind information not available. Following frames may be wrong.
0c 01eedd48 75f95090 00000008 00000005 02912c28 SHELL32!SHGetSpecialFolderLocation+0x136d
0d 01eedd64 75f2dbd1 02912c28 00000000 01eee754 SHELL32!Ordinal711+0x174b
0e 01eedf9c 75f2db76 00000000 02912c28 00000000 SHELL32!SHCreateDirectoryExW+0x70
0f 01eedfb4 10053d2d 00000000 02912c28 00000000 SHELL32!SHCreateDirectoryExW+0x15
...//此处省略
1a 01eef7e8 77289ed2 00000000 7721419c 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])
1b 01eef828 77289ea5 744537a7 00000000 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])
1c 01eef840 00000000 744537a7 00000000 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

我们注意到RtlEnterCriticalSection函数,查一下函数声明如下:

 NTSTATUS RtlEnterCriticalSection(RTL_CRITICAL_SECTION* crit);

第一个参数就是要找的关键区的结构

0:001> !cs 75d60280 
-----------------------------------------
Critical section   = 0x75d60280 (USER32!gcsUserApiHook+0x0)
DebugInfo          = 0x00432418
LOCKED
LockCount          = 0x1
WaiterWoken        = No
OwningThread       = 0x00000f0c
RecursionCount     = 0x1
LockSemaphore      = 0x200
SpinCount          = 0x00000000

可以看到OwningThread是0x00000f0c也就是0号线程,而0号线程之前是处于暂停状态的,如果不恢复它的运行,那么这个线程将永远的等下去。

PS:
Terminate和SuspendThread不要乱用,问题原因找到后,事后我看到了下面的文章,可以看一下,写的还可以。
线程天敌TerminateThread与SuspendThread

2022-04-10
                         
暂无评论

发表回复