记一次 .NET 某工控视觉系统 卡死分析( 二 )


  • 补码:11111111 11111111 11111111 11111111 11111111 11111111 11011000 11110000
  • 反码:00000000 00000000 00000000 00000000 00000000 00000000 00100111 00001111
  • 补补:00000000 00000000 00000000 00000000 00000000 00000000 00100111 00010000
0:000> .formats 0y0000000000000000000000000000000000000000000000000010011100010000Evaluate expression:Hex:00000000`00002710Decimal: 10000Decimal (unsigned) : 10000Octal:0000000000000000023420Binary:00000000 00000000 00000000 00000000 00000000 00000000 00100111 000100000:000> ? 00002710/ 2710Evaluate expression: 1 = 00000000`00000001从卦中看当前也就暂停了 1ms,如果想验证对不对的话,仔细看mov edi, ecx 会发现做了一次备份,但不管怎么说 Thread.Sleep(1) 应该问题不大,那问题在哪里呢?
2. 问题到底在哪里既然问题不在 Sleep(1) 上那到底在哪里呢?仔细观察线程栈会发现底层做了一个 RPC 通讯,从 combase!
SyncServerCall::StubInvoke 和 rpcrt4!NdrStubCall2 方法来看,它是 RPC 的 Server 端,既然是 Server 端就必然有 Client 端,根据经验这个 RPC 应该是 命令管道 的方式,没开 windows 的RPC诊断所以不能100%确认 。
接下来看下其他线程有没有 RPC 的 rpcrt4!NdrpClientCall 请求,抱着试试看的态度搜一搜,我去,还真有10几个,截图如下:
记一次 .NET 某工控视觉系统 卡死分析

文章插图
 
仔细分析这 12 个 Reqeust,发现其中的
Cognex.VisionPro.Display.CogDisplay.set_Image 比较可疑,毕竟 Image 运作起来肯定是费时费力的 。
0:543> k # Child-SPRetAddrCall Site00 00000000`fc65def8 00007ffc`79a1c2centdll!NtWAItForMultipleObjects+0x14...04 (Inline Function) --------`--------combase!CSyncClientCall::SwitchAptAndDispatchCall+0x34a05 00000000`fc65e290 00007ffc`7cd9b015combase!CSyncClientCall::SendReceive2+0x42c06 (Inline Function) --------`--------combase!SyncClientCallRetryContext::SendReceiveWithRetry+0x25 07 (Inline Function) --------`--------combase!CSyncClientCall::SendReceiveInRetryContext+0x25 08 00000000`fc65e480 00007ffc`7cd8c55dcombase!DefaultSendReceive+0x6509 00000000`fc65e4e0 00007ffc`7cd60a54combase!CSyncClientCall::SendReceive+0x12d 0a 00000000`fc65e710 00007ffc`7cdbc54ecombase!CClientChannel::SendReceive+0x84 0b 00000000`fc65e780 00007ffc`7d151e93combase!NdrExtpProxySendReceive+0x4e 0c 00000000`fc65e7b0 00007ffc`7cdbae17rpcrt4!NdrpClientCall2+0x4630d 00000000`fc65edf0 00007ffc`7ce2ce92combase!ObjectStublessClient+0x1d7 0e 00000000`fc65f180 00007ffb`f1321db8combase!ObjectStubless+0x420f 00000000`fc65f1d0 00007ffc`4002c9060x00007ffb`f1321db810 00000000`fc65f2c0 00007ffb`f131d541Cognex_VisionPro_Display_Controls_ni!Cognex.VisionPro.Display.CogDisplay.set_Image+0xb60:543> !clrstackOS Thread Id: 0x2bbc (543)Child SPIP Call Site...00000000fc65f208 00007ffbf1321db8 [InlinedCallFrame: 00000000fc65f208] Cognex.VisionPro.Interop.CogDisplayClass.set_Image(Cognex.VisionPro.Interop.ICogImage)00000000fc65f1d0 00007ffbf1321db8 DomainBoundILStubClass.IL_STUB_CLRtoCOM(Cognex.VisionPro.Interop.ICogImage)00000000fc65f2c0 00007ffc4002c906 Cognex.VisionPro.Display.CogDisplay.set_Image(Cognex.VisionPro.ICogImage)00000000fc65f310 00007ffbf131d541 xxxx.SetDefaultRecord()...00000000fc65f680 00007ffc4bc17e46 System.Threading.ThreadPoolWorkQueue.Dispatch()00000000fc65fb20 00007ffc4d706c93 [DebuggerU2MCatchHandlerFrame: 00000000fc65fb20] 根据卦中的托管方法 xxxx.SetDefaultRecord() ,让朋友不要做 Image 赋值观察下效果,朋友反馈说,这个 Image 不赋值问题就没有了 。
既然去掉就好了,到这里只能推测当前主线程不是卡死,而是 RPC 请求过多Size过大,导致主线程一直忙碌中,具体为什么会忙碌,这就需要逆向 cogxstd 来滤清业务逻辑了,这个就太费时费力了,还是先绕过去为好 。
三:总结还是回到文章开头的那句话,这种 dump 问题,你能用 DnSpy,VS 调试出来吗?说实话很难,虽然以 .NET 程序为出口,但考察了你很多基础知识,诸如 RPC,COM,汇编,没有这些基础沉淀,这类dump很难摸清来龙去脉 。




推荐阅读