程序卡住了,莫名奇妙的:
现象就是联网的那个线程不正常工作,调试器查看阻塞在调用WinHTTP或者crypt32里函数的时候。
调了一天多的时间,终于找到了原因。
先看一下调用栈,为了节约篇幅,这里只看一下出问题的线程,后面有需要再展示其他的。
0:028> kv ChildEBP RetAddr Args to Child 0892f0d8 772a0420 00000104 0892f118 00000000 ntdll!NtWaitForKeyedEvent+0x15 (FPO: [4,0,0]) 0892f13c 772c081f 00877628 000006ec 00000000 ntdll!TppWaitpSet+0x206 (FPO: [Non-Fpo]) 0892f1b0 772c09d5 00877628 000006ec 00000000 ntdll!TppSetWaitInterrupt+0xf2 (FPO: [Non-Fpo]) 0892f230 76b0cb54 74ec527c 000006ec 74e48b34 ntdll!RtlRegisterWait+0x1fd (FPO: [Non-Fpo]) 0892f254 74e1c8c5 74ec527c 000006ec 74e48b34 kernel32!RegisterWaitForSingleObject+0x7f (FPO: [Non-Fpo]) 0892f288 74e1c801 00000000 7eef3000 0892f2b0 crypt32!CertDiagPrvInitProcessInfo+0xd7 (FPO: [Non-Fpo]) 0892f298 74e1a301 00000000 00000000 00000000 crypt32!CertDiagPrvAttachTls+0x16 (FPO: [Non-Fpo]) 0892f2b0 74e26dab 00000001 00000004 0892f2c8 crypt32!CertDiagPushEvent+0x1e (FPO: [Non-Fpo]) 0892f2cc 74e26ced 0892f2e8 0892f330 0892f398 crypt32!CertDiagGetCertificateChainStart+0x16 (FPO: [Non-Fpo]) 0892f2ec 00b707c8 00000000 08400b20 0892f3d4 crypt32!CertGetCertificateChain+0x1e (FPO: [Non-Fpo]) *** WARNING: Unable to verify checksum for System.ni.dll WARNING: Frame IP not in any known module. Following frames may be wrong. 0892f380 71285cb7 0892f3d4 00000000 03e8e614 0xb707c8 0892f414 712857f2 03e8e050 00000000 00000000 System_ni+0x125cb7 0892f4ec 712844e8 72d50074 2b8232e1 03e8dd5c System_ni+0x1257f2 0892f574 71283e8d 03e8d9e0 0892f59c 712b6018 System_ni+0x1244e8 0892f580 712b6018 00000000 03e872c4 03e872c4 System_ni+0x123e8d 0892f59c 712b4c1a 03e872c4 00000000 03e8d810 System_ni+0x156018 0892f5c4 712b4b76 03e872c4 00000035 00000030 System_ni+0x154c1a 0892f5f4 7169ae73 03e872c4 00000035 03e85300 System_ni+0x154b76 0892f62c 712b4278 03e85354 0892f644 712b4224 System_ni+0x53ae73 0892f638 712b4224 03e85354 0892f670 712b41a6 System_ni+0x154278 0892f644 712b41a6 03e872c4 00000000 00000000 System_ni+0x154224 0892f670 712a1fc9 00000001 03e84310 03e8d810 System_ni+0x1541a6 0892f6a8 712a507a 03e8d898 71e302ff 03e8d898 System_ni+0x141fc9 0892f6c4 712a5771 00000000 00000000 00000000 System_ni+0x14507a 0892f6e0 712a1f30 03e8d810 00000000 00000000 System_ni+0x145771 0892f70c 712a5674 00000000 03e8d810 00000000 System_ni+0x141f30 *** WARNING: Unable to verify checksum for mscorlib.ni.dll 0892f744 71ddcde4 03e8498c 00000030 00000000 System_ni+0x145674 0892f764 72d41b4c 03e8498c 00000001 0892f920 mscorlib_ni+0x1ccde4 0892f778 72d58dde 0892f914 00000001 0892f908 mscorwks!CallDescrWorker+0x33 0892f7f8 72d593cb 0892f914 00000001 0892f908 mscorwks!CallDescrWorkerWithHandler+0xa3 (FPO: [Non-Fpo]) 0892f818 72d5940c 0892f910 00000001 0892f908 mscorwks!DispatchCallBody+0x1e (FPO: [Non-Fpo]) 0892f87c 72d59479 0892f910 00000001 0892f908 mscorwks!DispatchCallDebuggerWrapper+0x3d (FPO: [Non-Fpo]) 0892f8b0 72fad877 0892f910 00000001 0892f908 mscorwks!DispatchCallNoEH+0x51 (FPO: [Non-Fpo]) 0892f91c 72d9192f 03e84960 083ff030 00000000 mscorwks!BindIoCompletionCallBack_Worker+0xb9 (FPO: [Non-Fpo]) 0892f930 72d918cb 0892fa0c 0892f9b8 72e7515b mscorwks!Thread::DoADCallBack+0x32a (FPO: [Non-Fpo]) 0892f9c4 72d917f1 0892fa0c 2b823ddd 083ff030 mscorwks!Thread::ShouldChangeAbortToUnload+0xe3 (FPO: [Non-Fpo]) 0892fa00 72d9197d 0892fa0c 00000001 00000000 mscorwks!Thread::ShouldChangeAbortToUnload+0x30a (FPO: [Non-Fpo]) 0892fa28 72d92798 00000001 72fad7ea 0892fa64 mscorwks!Thread::ShouldChangeAbortToUnload+0x33e (FPO: [Non-Fpo]) 0892fa40 72fadaa3 00000001 72fad7ea 0892fa64 mscorwks!ManagedThreadBase::ThreadPool+0x13 (FPO: [Non-Fpo]) 0892fa94 72fadad5 00000000 00000005 03e8498c mscorwks!BindIoCompletionCallbackStubEx+0x95 (FPO: [Non-Fpo]) 0892faac 72e632bd 00000000 00000005 03e8498c mscorwks!BindIoCompletionCallbackStub+0x13 (FPO: [Non-Fpo]) 0892fb14 72ea805a 00000000 0892fb44 74e11716 mscorwks!ThreadpoolMgr::CompletionPortThreadStart+0x430 (FPO: [Non-Fpo]) 0892ff38 76ae33ca 008729f8 0892ff84 77289ed2 mscorwks!Thread::intermediateThreadProc+0x49 (FPO: [Non-Fpo]) 0892ff44 77289ed2 008729f8 7f383cc0 00000000 kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo]) 0892ff84 77289ea5 72ea8014 008729f8 00000000 ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo]) 0892ff9c 00000000 72ea8014 008729f8 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo]) ...
首先,发现这个程序包含一个.net的模块,而且卡住的是一个.net线程,.net线程在调用crypt32!CertGetCertificateChain的时候卡住了。开始以为是.net的的问题,调了半天,后面慢慢的发现不是,所以就不说.net不.net了。就从最直观的地方的开始,看下面这一行。
ChildEBP RetAddr Args to Child 0892f0d8 772a0420 00000104 0892f118 00000000 ntdll!NtWaitForKeyedEvent+0x15 (FPO: [4,0,0])
这是嘛玩意?我也不知道,查了WRK,没有找到这个函数,应该是Win7上才增加的,但我知道它肯定是在等什么事件。
既然不知道,那就用ida看一下吧
这个函数什么也看不出来,只能看出来它去调用64的函数进内核去了。
那就继续看上一个函数TppWaitpSet,在这个函数中发现了我想要的:
首先看到整个函数只有一处调用了NtWaitForKeyedEvent,那只需要看一下V19是个什么东西就行了
既然如此,那就往上找,函数很简单,只有一处为V19赋值了:
通过这个图大概知道了怎么回事,找下V6是什么吧,我往上找到了这个:
也就是V6就是第一个参数,大概分析一下,这大概就是判断了一下V6指向的那个结构里面的某个成员是不是跟本线程ID相等。
如果不相等,那么就要等待这个叫做KeyEvent的东西。
这就简单了,我们来找一下这个成员的值吧。
这个IDA反编译出来的C蛮难看的,不想看可以看汇编。
上面那个比较的部分换成汇编如图:
这就好说了,用Windbg看一下对应的值是多少。
0:028> dc 00877628+A0 L1 008776c8 007dca30 0.}. 0:028> dc 007dca30+0c L1 007dca3c 000007e8 ....
这下就知道了,它在等的资源应该是000007e8这个线程的,看一下对应的线程:
0:028> ~~[7e8] 3 Id: 468.7e8 Suspend: 2 Teb: 7ef9f000 Unfrozen Start: ntdll!TppWaiterpThread (772941f3) Priority: 0 Priority class: 32 Affinity: 1
发现Suspend的值是2,正常情况下,这个值应该是1,因为线程如果正常运行的话,调试器把它暂停下来,它的SuspendCount就是1。
但是这里的值是2,说明这个线程在程序运行的时候就已经被暂停了,这样的话上面线程在等的KeyEvent永远也等不到了。
现象就是那个线程卡死,不动了。
因为这个线程暂停的原因,一共发生了两个奇怪的现象,一个是上面这个,还有另外一个,下一篇说。
PS:跟暂停线程有同样坑的还有TerminateThread这个函数,最好永远别用这个函数。
解决本问题看过的文章(饶了半天弯路,调了半天.net部分):
1.Debugging Managed Code Using the Windows Debugger
2.使用WINDBG调试.NET 程序
3.[问题记录.WinDbg]WinDbg 调试遇到 Failed to load data access DLL, 0x80004005