国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

記一次 .NET某上位機視覺程序卡死分析

開發 前端
看到源碼之后太無語了,其實就是一個簡單的 顏色賦值?,根據前面的探索styleManager1是由渲染線程創建的,所以主線程對它的賦值自然是得不到渲染線程的反饋。

一、背景

1. 講故事

前段時間有位朋友找到我,說他的窗體程序在客戶這邊出現了卡死,讓我幫忙看下怎么回事?dump也生成了,既然有dump了那就上 windbg 分析吧。

二、WinDbg 分析

1. 為什么會卡死

窗體程序的卡死,入口門檻很低,后續往下分析就不一定了,不管怎么說先用 !clrstack 看下主線程,輸出如下:

0:000> !clrstack
OS Thread Id: 0x3118 (0)
        Child SP               IP Call Site
000000c478afd1d8 00007ffc284e9a84 [HelperMethodFrame_1OBJ: 000000c478afd1d8] System.Threading.WaitHandle.WaitOneNative(System.Runtime.InteropServices.SafeHandle, UInt32, Boolean, Boolean)
000000c478afd300 00007ffbf2cc19ac System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle, Int64, Boolean, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\waithandle.cs @ 243]
000000c478afd330 00007ffbf2cc197f System.Threading.WaitHandle.WaitOne(Int32, Boolean) [f:\dd\ndp\clr\src\BCL\system\threading\waithandle.cs @ 194]
000000c478afd370 00007ffbf1421904 System.Windows.Forms.Control.WaitForWaitHandle(System.Threading.WaitHandle)
000000c478afd3e0 00007ffbf0c8e2f4 System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
000000c478afd520 00007ffbf1425124 System.Windows.Forms.Control.Invoke(System.Delegate, System.Object[])
000000c478afd590 00007ffb995d6fe8 DevComponents.DotNetBar.StyleManager.OnColorTintChanged(System.Drawing.Color, System.Drawing.Color)
000000c478afd5f0 00007ffb995d69ff DevComponents.DotNetBar.StyleManager.set_ColorTint(System.Drawing.Color)
000000c478afd680 00007ffb995d694c DevComponents.DotNetBar.StyleManager.set_ManagerColorTint(System.Drawing.Color)
...
000000c478afd6b0 00007ffb995d50f9 xxx.MarkInspectPadControl.InitializeComponent()

有經驗的朋友看到上面的卦象相信就知道咋事情了,即有工作線程創建了用戶控件導致的,而且這個控件貌似和 DevComponents 有關,接下來的常規套路就是挖一下 WindowsFormsSynchronizationContext 對象看看到底是哪一個線程創建的,使用 !dso 即可。

0:000> !dso
OS Thread Id: 0x3118 (0)
RSP/REG          Object           Name
000000C478AFCF98 000002093b9143c0 System.Windows.Forms.WindowsFormsSynchronizationContext
...
0:000> !do poi(20939c91588)
Name:        System.Threading.Thread
MethodTable: 00007ffbf2769580
EEClass:     00007ffbf288c658
Size:        96(0x60) bytes
00007ffbf276aaf8  4001934       4c         System.Int32  1 instance                1 m_ManagedThreadId

按照劇本的話 WindowsFormsSynchronizationContext 應該會有2個,但這里只有1個,這一個還是主線程的同步上下文,這就完犢子了。。。完全不按照劇本走,這也是真實dump分析的復雜性,那到底是誰創建的呢?天要絕人之路嗎?

2. 出路在哪里

所有東西的落地都在匯編里,而匯編又在方法里,所以突破口就是尋找線程棧中的方法,接下來到 System.Windows.Forms.Control.MarshaledInvoke 方法里看一看可有什么大貨,簡化后如下:

private object MarshaledInvoke(Control caller, Delegate method, object[] args, bool synchronous)
{
    bool flag = false;
    if (SafeNativeMethods.GetWindowThreadProcessId(new HandleRef(this, Handle), out var _) == SafeNativeMethods.GetCurrentThreadId() && synchronous)
    {
        flag = true;
    }
    ThreadMethodEntry threadMethodEntry = new ThreadMethodEntry(caller, this, method, args, synchronous, executionContext);
    lock (threadCallbackList)
    {
        if (threadCallbackMessage == 0)
        {
            threadCallbackMessage = SafeNativeMethods.RegisterWindowMessage(Application.WindowMessagesVersion + "_ThreadCallbackMessage");
        }
        threadCallbackList.Enqueue(threadMethodEntry);
    }
    if (flag)
    {
        InvokeMarshaledCallbacks();
    }
    else
    {
        UnsafeNativeMethods.PostMessage(new HandleRef(this, Handle), threadCallbackMessage, IntPtr.Zero, IntPtr.Zero);
    }
    if (synchronous)
    {
        if (!threadMethodEntry.IsCompleted)
        {
            WaitForWaitHandle(threadMethodEntry.AsyncWaitHandle);
        }
        return threadMethodEntry.retVal;
    }
    return threadMethodEntry;
}

從卦中的代碼來看,這個 SafeNativeMethods.GetWindowThreadProcessId 方法是關鍵,它可以拿到這個窗口創建的processid和threadid,接下來觀察下簡化后的匯編代碼。

0:000> !U /d 00007ffbf0c8e2f4
preJIT generated code
System.Windows.Forms.Control.MarshaledInvoke(System.Windows.Forms.Control, System.Delegate, System.Object[], Boolean)
Begin 00007ffbf0c8dec0, size 4e9
00007ffb`f0c8dec0 55              push    rbp
00007ffb`f0c8dec1 4157            push    r15
00007ffb`f0c8dec3 4156            push    r14
00007ffb`f0c8dec5 4155            push    r13
00007ffb`f0c8dec7 4154            push    r12
00007ffb`f0c8dec9 57              push    rdi
00007ffb`f0c8deca 56              push    rsi
00007ffb`f0c8decb 53              push    rbx
00007ffb`f0c8decc 4881ecf8000000  sub     rsp,0F8h
00007ffb`f0c8ded3 488dac2430010000 lea     rbp,[rsp+130h]
...
00007ffb`f0c8dff0 488d55b0        lea     rdx,[rbp-50h]
00007ffb`f0c8dff4 ff151e1eddff    call    qword ptr [System_Windows_Forms_ni+0x8fe18 (00007ffb`f0a5fe18)] (System.Windows.Forms.SafeNativeMethods.GetWindowThreadProcessId(System.Runtime.InteropServices.HandleRef, Int32 ByRef), mdToken: 00000000060033c4)
00007ffb`f0c8dffa 448bf0          mov     r14d,eax

根據卦中的匯編以及x64調用協定,lea rdx,[rbp-50h] 就是我們的 processid,同時 mov r14d,eax 中的 r14d 就是我們的 threadid,突破口已找到,接下來就是深挖了。

3. 如何挖出進程ID和線程ID

有一點要知道 000000c478afd520 和 MarshaledInvoke 方法的 rsp 隔了一個 0x8,同時方法中影響 rsp 的 push 和 sub 都要計算進去,這里就不贅述了,具體可以參考文章:https://www.cnblogs.com/huangxincheng/p/17250240.html 簡單計算后如下:

0:000> ? 000000c478afd520-0x8-(0n8*0n8)-0xF8+0x130
Evaluate expression: 843838379280 = 000000c4`78afd510
0:000> dp 000000c4`78afd510-0x50 L1
000000c4`78afd4c0  00000000`000029dc

0:000> r r14
r14=000000c478afcf14
0:000> dp 000000c478afcf14 L1
000000c4`78afcf14  00000000`00000080

從卦中可以看到 processid=29dc ,threadid=0x80,這東西是何方神圣呢,我們用 ~ 來找它的真身吧。

0:000> ~
...
  18  Id: 29dc.80 Suspend: 0 Teb: 000000c4`7890d000 Unfrozen
...

0:018> k
 # Child-SP          RetAddr               Call Site
00 000000c4`7a2ffcc8 00007ffc`28028ba3     ntdll!NtWaitForSingleObject+0x14
01 000000c4`7a2ffcd0 00007ffb`fa651cf8     KERNELBASE!WaitForSingleObjectEx+0x93
02 000000c4`7a2ffd70 00007ffb`fa652a51     wpfgfx_v0400!CPartitionManager::GetWork+0x17b
03 000000c4`7a2ffdc0 00007ffb`fa67a2fb     wpfgfx_v0400!CPartitionThread::Run+0x21
04 000000c4`7a2ffdf0 00007ffc`2a037bd4     wpfgfx_v0400!CPartitionThread::ThreadMain+0x2b
05 000000c4`7a2ffe20 00007ffc`2a76ced1     kernel32!BaseThreadInitThunk+0x14
06 000000c4`7a2ffe50 00000000`00000000     ntdll!RtlUserThreadStart+0x21

現在有點傻傻分不清了,怎么 winform 里還有 wpf 的渲染線程,有可能是 DevComponents 這種第三方控件在底層引入的吧。到這里路子又被堵死了,接下來該往哪里走呢?三步一回頭,繼續看主線程上的方法代碼吧。

4. 在源碼中尋找答案

雖然在兩條路上的突圍都失敗了,但可以明顯的看到離真相真的越來越近,也收獲到了大量的作戰信息,通過上面的 set_ManagerColorTint 方法的反編譯,參考如下:

private void InitializeComponent()
{
    this.styleManager1.ManagerColorTint = System.Drawing.Color.Black;
}

[Description("Indicates color current style is tinted with.")]
[Category("Appearance")]
public Color ManagerColorTint
{
    get
    {
        return ColorTint;
    }
    set
    {
        ColorTint = value;
    }
}

看到源碼之后太無語了,其實就是一個簡單的 顏色賦值,根據前面的探索styleManager1是由渲染線程創建的,所以主線程對它的賦值自然是得不到渲染線程的反饋。

那這個問題該怎么辦呢?大概是如下兩種吧。

  1. 重點關注 styleManager1 控件,用排除法觀察程序運行狀況。
  2. 看文檔是否用了錯誤的方式使用 styleManager1 控件。

三:總結

這次生產事故還是挺有意思的,為什么 WinForm 中可以存在 CPartitionThread 渲染線程,最后還禍在其身,給我幾百例dump分析之旅中添加了一筆色彩!

責任編輯:武曉燕 來源: 一線碼農聊技術
相關推薦

2024-07-12 11:20:34

.NET崩潰視覺程序

2024-06-06 10:51:15

自動化系統推測

2024-12-27 13:31:18

.NETdump調試

2024-05-28 10:18:30

WPF程序數據

2023-09-27 07:23:10

.NET監控軟件

2024-05-20 09:39:02

.NETurl線程池

2022-10-13 18:40:05

.NETOA后端

2024-07-01 13:00:24

.NET網絡邊緣計算

2024-11-29 10:06:59

2023-05-15 11:15:50

.NET門診語句

2022-01-17 21:28:36

管理系統.NET

2025-09-02 01:35:00

.NET光學定位軟件

2022-10-09 10:47:37

NET視覺軟件

2022-10-25 14:17:01

.NET代碼程序

2023-06-26 00:12:46

2024-03-28 12:56:36

2023-04-06 10:52:18

2023-07-06 10:11:38

.NET模式dump

2023-03-26 20:24:50

ERP網站系統

2024-03-26 00:44:53

.NETCIM系統
點贊
收藏

51CTO技術棧公眾號

视频一区视频二区视频三区视频四区国产 | 亚洲黄色录像| 一区二区三区日韩精品视频| 日韩在线电影一区| 精品福利久久久| 亚洲一级黄色av| a黄色在线观看| 福利一区福利二区| 久久久久无码国产精品一区| 国产精品自拍区| 精品国产一区av| 国产丝袜在线| 色综合天天综合| 日韩中文字幕二区| 国产成人8x视频一区二区| 狠狠色综合欧美激情| 欧美色蜜桃97| 97碰在线观看| 国产一区二区三区精品在线观看| 精品无人区乱码1区2区3区在线| jizzjizz在线观看| 中文字幕2019第三页| 亚洲国产精品ⅴa在线观看| 国产高清一区视频| 国产一区不卡| 亚州国产精品久久久| 91天天综合| 精品无人国产偷自产在线| 成人片在线看| 欧美日免费三级在线| 中出在线观看| 一区二区三区91| 国产黄色高清在线| 久久久精品日韩欧美| 妞干网在线视频观看| 国产麻豆精品95视频| 一本久久a久久精品vr综合 | 女仆av观看一区| 久久综合国产精品台湾中文娱乐网| 操喷在线视频| 欧美成人精品高清在线播放| 看女生喷水的网站在线观看| 欧美在线看片a免费观看| 香蕉av在线| 欧美主播一区二区三区| 精品一二三区视频| 日本韩国欧美一区二区三区| 性色视频在线| 欧美男人的天堂一二区| 动漫一区在线| 亚洲精品av在线| 欧美性猛交xxx高清大费中文| 亚洲国产天堂网精品网站| 超级白嫩亚洲国产第一| 伊人青青综合网站| 羞羞视频在线观看一区二区| 久久久久久久一区二区| 国产99久久| 亚洲一区二区三区xxx视频| 国内综合精品午夜久久资源| 久久伊人一区二区| 蜜桃视频免费观看一区| 成人黄色片免费| 久久人人97超碰com| av线上观看| 欧美日韩小视频| 中文字幕在线看片| 久久视频在线直播| 女厕嘘嘘一区二区在线播放| 国产精品一区二区免费看| 久久国产精品区| 韩国一区二区av| 亚洲国产另类av| av免费在线免费观看| 中日韩美女免费视频网址在线观看| 日韩精品三级| 国产欧美一区二区白浆黑人| 天堂资源在线中文精品| 自慰无码一区二区三区| 亚洲电影激情视频网站| 91黄色在线| 欧美贵妇videos办公室| 亚洲天天影视网| 国产高清不卡无码视频| 亚洲同性同志一二三专区| 麻豆网站在线看| 久久国产精彩视频| 欧美va天堂| 精品少妇一区二区三区在线| 欧美丝袜第一区| 午夜欧美巨大性欧美巨大| 日本一区二区三区在线播放| 久久久人人人| www.久久91 | 看电视剧不卡顿的网站| av无码精品一区二区三区| 欧美色道久久88综合亚洲精品| 国产日本一区二区| heyzo在线欧美播放| 亚洲综合av影视| 国产精品97| 九色porny丨国产首页在线| 免费成人午夜视频| 日韩一区二区三区视频在线观看 | 欧美日韩伊人| 国产精品免费观看| 欧美日韩一区二区三| 美女av一区二区三区| 欧美亚洲丝袜传媒另类| 国产色产综合色产在线视频| 日韩精品成人一区二区在线| 国产伦精品一区二区三区在线播放| 日本三级视频在线播放| va中文字幕| 99精品视频网站| 69xxxx欧美| 久久不见久久见中文字幕免费| 国产精品豆花视频| 久久精品视频免费| 一区二区三区四区av| 欧美剧在线免费观看网站| 亚洲伊人伊色伊影伊综合网| 国产成人小视频| 久久不见久久见免费视频7| 国产精品高清一区二区| 91社区在线观看| 中文字幕亚洲乱码| 欧美一区二区在线| 日韩av免费在线观看| www国产精品视频| 国产小视频国产精品| 国产精品久99| 香蕉综合视频| 国产亚洲人成a在线v网站| 97福利网站在线观看视频| www.av中文字幕| 欧美精品久久久| 91视频在线免费观看| 91在线视频精品| 日韩欧美亚洲精品| 男人天堂成人网| 国产999精品视频| 久久久久久久久久久久久久久久久久av | 蜜臀av免费观看| 国产日韩欧美亚洲一区| 欧美与欧洲交xxxx免费观看| 最近2019中文字幕一页二页| 日韩午夜中文字幕| 日韩欧美一区二区三区| 一区二区三区在线播| 日韩一区二区三区在线观看| 91精品国产手机| 91精品国产高清自在线看超| 精品福利一区二区| 亚洲成a人片在线观看中文| 欧美四级电影网| 国产小视频国产精品| 亚洲91精品在线观看| 国产精品999999| 久久久视频精品| 不卡av在线播放| 欧美综合欧美视频| 91电影在线观看| 亚洲成av人片在www色猫咪| 久久先锋影音av| 欧美日韩一区三区四区| 亚洲精品国产精华液| 亚洲精品第一国产综合野| 精品欧美aⅴ在线网站| 欧美亚洲国产怡红院影院| 日韩av综合中文字幕| 欧美激情国产精品| 国产精品theporn88| 337p粉嫩大胆噜噜噜鲁| 高清孕妇孕交╳╳交| 米奇777四色精品人人爽| 青娱乐极品盛宴一区二区| 日韩大片在线| 91亚洲精品乱码久久久久久蜜桃| 欧美日高清视频| 51视频国产精品一区二区| 日本国产一区二区三区| 亚洲.欧美.日本.国产综合在线| 哪个网站能看毛片| 天堂a中文在线| 精品国产乱码久久久久久图片| 日韩黄色在线观看| 中文字幕在线官网| www.中文字幕在线| 国产mv免费观看入口亚洲| 色呦呦网站一区| 日日夜夜一区二区| 999精品嫩草久久久久久99| 99热99在线| 91免费在线观看网站| 亚洲国产精品小视频| 中文字幕免费不卡| 午夜国产欧美理论在线播放| av免费不卡国产观看| 国产精品分类|