日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

記一次 .NET某工業設計軟件崩潰分析

來源: 責編: 時間:2024-06-05 17:47:08 173觀看
導讀一、背景1. 講故事前些天有位朋友找到我,說他的軟件在客戶那邊不知道什么原因崩掉了,從windows事件日志看崩潰在 clr 里,讓我能否幫忙定位下,dump 也抓到了,既然dump有了,接下來就上 windbg 分析吧。二、WinDbg 分析1. 為什

一、背景

1. 講故事

前些天有位朋友找到我,說他的軟件在客戶那邊不知道什么原因崩掉了,從windows事件日志看崩潰在 clr 里,讓我能否幫忙定位下,dump 也抓到了,既然dump有了,接下來就上 windbg 分析吧。CbJ28資訊網——每日最新資訊28at.com

二、WinDbg 分析

1. 為什么崩潰在 clr

一般來說崩潰在clr里都不是什么好事情,這預示著 clr 在執行自身代碼的時候拋了異常,即災難的 ExecutionEngineException,可以用 !t 驗證下。CbJ28資訊網——每日最新資訊28at.com

0:000> !tThreadCount:      18UnstartedThread:  0BackgroundThread: 7PendingThread:    0DeadThread:       11Hosted Runtime:   no                                                                         Lock         ID OSID ThreadOBJ    State GC Mode     GC Alloc Context  Domain   Count Apt Exception   0    1 52e8 18998d50     24220 Preemptive  639B0D58:00000000 18c361f0 0     STA System.ExecutionEngineException 1f421120   ...

既然是災難性異常,那為什么會出現呢?可以用 !analyze -v 觀察下。CbJ28資訊網——每日最新資訊28at.com

0:000> !analyze -vCONTEXT:  0115a98c -- (.cxr 0x115a98c)eax=00000000 ebx=00000000 ecx=00000000 edx=18c364a4 esi=00030000 edi=18998d50eip=552bfff1 esp=0115ae6c ebp=0115af24 iopl=0         nv up ei pl zr na pe nccs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246clr!VirtualCallStubManager::ResolveWorker+0x33:552bfff1 8bb968020000    mov     edi,dword ptr [ecx+268h] ds:002b:00000268=????????Resetting default scopeREAD_ADDRESS:  00000268 STACK_TEXT:  0115af24 552c0698     0115afdc 1f4222c0 00030000 clr!VirtualCallStubManager::ResolveWorker+0x330115affc 552c070b     0115b010 1f4222c0 00030000 clr!VSD_ResolveWorker+0x1d20115b024 28a3a949     639b0d38 00000000 00000000 clr!ResolveWorkerAsmStub+0x1b0115b0a4 28a3a8bd     00000000 00000000 00000000 xxxx!xxx...

我去,真無語了,我卦中數據看,這是一個接口Stub調用的崩潰,在這里崩潰真的是少之又少,從匯編代碼 edi,dword ptr [ecx+268h] ds:002b:00000268=???????? 上看就是因為 ecx =0 導致的,接下來觀察下方法的匯編代碼。CbJ28資訊網——每日最新資訊28at.com

圖片圖片CbJ28資訊網——每日最新資訊28at.com

從匯編上看這個 ecx 其實就是這個方法的 this 指針,那為什么 this =null 呢?這就很奇葩了。CbJ28資訊網——每日最新資訊28at.com

2. 為什么 this =null

要想找到這個答案,只能看clr源代碼,簡化后如下:CbJ28資訊網——每日最新資訊28at.com

PCODE VSD_ResolveWorker(TransitionBlock* pTransitionBlock,                        TADDR siteAddrForRegisterIndirect,                        size_t token                        ){    ...    VirtualCallStubManager::StubKind stubKind = VirtualCallStubManager::SK_UNKNOWN;    VirtualCallStubManager* pMgr = VirtualCallStubManager::FindStubManager(callSiteTarget, &stubKind);        ...    target = pMgr->ResolveWorker(&callSite, protectedObj, representativeToken, stubKind);}

從卦中代碼看,問題就是 pMgr=null 導致的,無語了,這個 VirtualCallStubManager::FindStubManager 方法的本意就是根據 callSite的stub的前綴找到對應的 虛調用管理器,它的核心邏輯如下:CbJ28資訊網——每日最新資訊28at.com

StubKind getStubKind(PCODE stubStartAddress, BOOL usePredictStubKind = TRUE){    StubKind predictedKind = (usePredictStubKind) ? predictStubKind(stubStartAddress) : SK_UNKNOWN;    ...    if (predictedKind == SK_LOOKUP)    {        if (isLookupStub(stubStartAddress))            return SK_LOOKUP;    }    ...    return SK_UNKNOWN;}VirtualCallStubManager::StubKind VirtualCallStubManager::predictStubKind(TADDR stubStartAddress){    StubKind stubKind = SK_UNKNOWN;    WORD firstWord = *((WORD*)stubStartAddress);    if (firstWord == 0x05ff)    {        stubKind = SK_DISPATCH;    }    else if (firstWord == 0x6850)    {        stubKind = SK_LOOKUP;    }    else if (firstWord == 0x8b50)    {        stubKind = SK_RESOLVE;    }    return stubKind;}

接下來需要找到 stubStartAddress 的地址是多少?這個只需要提取 ResolveWorker 方法的第一個參數 callSite 即可。CbJ28資訊網——每日最新資訊28at.com

0:000> dp poi(0115afdc) L10c740040  0c7460120:000> u 0c7460120c746012 50              push    eax0c746013 6800000300      push    30000h0c746018 e9d3a6b748      jmp     clr!ResolveWorkerAsmStub (552c06f0)0c74601d 0000            add     byte ptr [eax],al0c74601f 0000            add     byte ptr [eax],al0c746021 005068          add     byte ptr [eax+68h],dl0c746024 0000            add     byte ptr [eax],al0c746026 46              inc     esi0:000> dp 0c746012 L10c746012  00006850

對比剛才的代碼既然都返回來了 SK_LOOKUP 那為什么還是 SK_UNKNOWN 呢?這個也可以通過在線程棧上找到 &stubKind 變量得到驗證。CbJ28資訊網——每日最新資訊28at.com

0:000> uf 552c0698...clr!VSD_ResolveWorker+0x1ab:552c065f 8b85e0ffffff    mov     eax,dword ptr [ebp-20h]552c0665 83a5ecffffff00  and     dword ptr [ebp-14h],0552c066c 8d95ecffffff    lea     edx,[ebp-14h]552c0672 8b08            mov     ecx,dword ptr [eax]552c0674 e858feffff      call    clr!VirtualCallStubManager::FindStubManager (552c04d1)552c0679 ffb5ecffffff    push    dword ptr [ebp-14h]552c067f 51              push    ecx552c0680 8bcc            mov     ecx,esp552c0682 8931            mov     dword ptr [ecx],esi552c0684 ffb5e8ffffff    push    dword ptr [ebp-18h]552c068a 8d8de0ffffff    lea     ecx,[ebp-20h]552c0690 51              push    ecx552c0691 8bc8            mov     ecx,eax552c0693 e823f9ffff      call    clr!VirtualCallStubManager::ResolveWorker (552bffbb)552c0698 8bf0            mov     esi,eax...0:000> dp 0115affc-0x14 L10115afe8  00000000

我感覺這邏輯也只有clr團隊幫忙解釋,我已經搞不清楚了,接下來我們回頭看托管方法,看能不能繼續下去。CbJ28資訊網——每日最新資訊28at.com

3. 在托管層尋找突破口

高級調試就是這樣,一個方向走不通就需要在另一個方向上突破,接下來使用 !clrstack 觀察一下。CbJ28資訊網——每日最新資訊28at.com

0:000> !clrstackOS Thread Id: 0x52e8 (0)Child SP       IP Call Site0115af50 775c2aac [GCFrame: 0115af50] 0115afac 775c2aac [StubDispatchFrame: 0115afac]xxx.GetListDrawerType(System.String)0115b02c 28a3a949 xxx.PluginInvoker.InvokeMothod[[System.__Canon, mscorlib]](System.String, System.Object[])0115b0b0 28a3a8bd xxx.xxx.OnFinishSizeCheck(Int64)...

從調用棧來看,貌似是用反射來實現功能增強,不管怎么說先看下xxxCheck 方法干了什么?簡化后的代碼如下:CbJ28資訊網——每日最新資訊28at.com

public string OnFinishSizeCheck(long uuid){    return PluginInvoker.InvokeMothod<string>("xxxCheck", new object[1] { uuid });}public static T InvokeMothod<T>(string methodName, params object[] args){    IPluginInvoker pluginInvoker = GetPluginInvoker();    return (T)pluginInvoker.InvokeMothod(methodName, args);}

從代碼上可以看到原來是使用 (T)pluginInvoker.InvokeMothod(methodName, args); 實現的接口調用,在coreclr層面也能觀察得到,找到對象 1f4222c0 之后按圖索驥即可。CbJ28資訊網——每日最新資訊28at.com

0:000> !do 1f4222c0Name:        xxx.xxx.BusinessAppDomainInvokerMethodTable: 0c73a144EEClass:     0c6d6f0cSize:        12(0xc) bytesFile:        E:/xxx/xxx.dllFields:      MT    Field   Offset                 Type VT     Attr    Value Name0c73a4e8  400000a        4 ....AppDomainManager  0 instance 1f42236c appDomainManager0c73a2dc  4000009       18 ..., xxx]]  0   static 1f422214 lazy0:000> !dumpmt -md 0c73a144EEClass:         0c6d6f0cModule:          0c7383dcName:            xxx.xxx.BusinessAppDomainInvokermdToken:         02000006File:            E:/xxx/xxx.dllBaseSize:        0xcComponentSize:   0x0Slots in VTable: 10Number of IFaces in IFaceMap: 1--------------------------------------MethodDesc Table   Entry MethodDe    JIT Name   ...0c6c3400 0c73a110    JIT xxx.xxx.InvokeMothod(System.String, System.Object[])0:000> !do  poi(0c73a144+0x24)Name:        xxx.IPluginInvokerMethodTable: 0c739f30EEClass:     0c6d6d34Size:        0(0x0) bytesFile:        E:/xxx/xxx.dllFields:NoneThinLock owner 1 (18998d50), Recursive 0

對比那個 token=30000h 發現什么地方都沒有問題,奇葩的就是一個簡單接口調用就出現了問題,仔細觀察代碼之后發現了兩個和別人不一樣的地方。CbJ28資訊網——每日最新資訊28at.com

4. 與眾不同的地方在哪里

第一個是他的程序是多 AppDomain 的,可以用 !dumpdomain 觀察。CbJ28資訊網——每日最新資訊28at.com

0:000> !dumpdomain--------------------------------------System Domain:      55a6caa0...--------------------------------------Shared Domain:      55a6c750LowFrequencyHeap:   55a6cdc4Stage:              OPEN--------------------------------------Domain 1:           18b04690LowFrequencyHeap:   18b04afcName:               DefaultDomain--------------------------------------Domain 2:           18c361f0LowFrequencyHeap:   18c3665c...

第二個是我發現托管調用棧上還有很多 托管C++,這種混合編程真的是無語了。CbJ28資訊網——每日最新資訊28at.com

到這里我想到了三個辦法:CbJ28資訊網——每日最新資訊28at.com

1)如果可以先把接口方法預熱,clr會直接把方法入口塞到匯編里,就不會再走clr底層邏輯了。CbJ28資訊網——每日最新資訊28at.com

2)能否將 托管C++ 和 C# 隔離,不要混合編程。CbJ28資訊網——每日最新資訊28at.com

3)重點觀察下多Domain下這個托管調用是不是有什么問題。CbJ28資訊網——每日最新資訊28at.com

三、總結

這種 多domain + 托管C++混合C# 編程,真出問題了基本上就是無解,一般人hold不住,無語了。CbJ28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-92192-0.html記一次 .NET某工業設計軟件崩潰分析

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: .NET Core中的DDD設計模式與分層架構

下一篇: 如何在 .NET Core 中執行 Linux 命令

標簽:
  • 熱門焦點
Top 主站蜘蛛池模板: 道孚县| 镶黄旗| 乌拉特后旗| 日喀则市| 休宁县| 茶陵县| 西平县| 黔西| 包头市| 牟定县| 满洲里市| 阳江市| 遂平县| 马山县| 堆龙德庆县| 黄冈市| 德惠市| 昌江| 白银市| 巴林右旗| 灌南县| 林西县| 江都市| 武川县| 隆昌县| 黔南| 若羌县| 门源| 澳门| 沅江市| 梁山县| 冷水江市| 弥渡县| 射洪县| 罗定市| 淮阳县| 山丹县| 宣化县| 开阳县| 买车| 丰镇市|