1. 程式人生 > 其它 >升級到 dotnet core 之後 HandleProcessCorruptedStateExceptions 無法接住異常

升級到 dotnet core 之後 HandleProcessCorruptedStateExceptions 無法接住異常

技術標籤:dotnetcorec#C#dotnetdotnet core

這是 dotnet core 的破壞性改動之一,在 dotnet framework 裡面,可以使用 HandleProcessCorruptedStateExceptionsAttribute 接住非託管層丟擲的異常,如 C++ 異常等。但是這個功能在 dotnet core 下存在行為的變更,從 .NET Core 1.0 開始,損壞程序狀態異常無法由託管程式碼進行處理。 公共語言執行時不會將損壞程序狀態異常傳遞給託管程式碼

如果邏輯程式碼完全使用 C# 實現,那麼應用程式可以稱為是安全的。這裡的安全指的是記憶體安全。這是 dotnet 的一個優勢,在於異常處理上,和 C++ 等的異常處理不同的是,很少會有異常能讓整個程式閃退。可以很方便在應用程式裡面接住軟體執行異常,然後通過各個方法讓軟體繼續執行

但如果 C# 呼叫了 C++ 的庫,那就不好玩了,這就意味著如果 C++ 的庫如果實現不夠好的話,那麼這個庫是能帶著整個應用程式閃退的。而有趣的是,其實我到現在還沒遇到幾個團隊寫出的 C++ 庫是穩定的,基本上通過我的 DUMP 分析可以看到,每多加一個 C++ 庫,軟體的穩定性就下降一半。好在,有一些 C++ 庫丟擲來的異常,咱勉強還是能接住的,至少不會讓整個應用程式就閃退了

接住 C++ 異常的其中一個方法就是通過 HandleProcessCorruptedStateExceptions 特性,在方法上面標記 HandleProcessCorruptedStateExceptions 特性,此時在方法裡面使用 try catch 是可以接住大部分的 C++ 異常的,如 System.AccessViolationException 異常

請看下面程式碼

        [HandleProcessCorruptedStateExceptions]
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine(HeederajiYeafalludall());
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
} [DllImport("BeyajaydahifallChecheecaifelwarlerenel.dll")] static extern Int16 HeederajiYeafalludall();

上面程式碼的 HeederajiYeafalludall 方法是由 BeyajaydahifallChecheecaifelwarlerenel.dll 提供的,這是一個由 C++ 寫的庫,在這裡面的實現將會出現越界

extern "C" __declspec(dllexport) int HeederajiYeafalludall() 
{
    int* p = (int*)123;
    while (true)
    {
        *p = 123;
        p++;
    }

    return 123;
}

在標記了 HandleProcessCorruptedStateExceptionsAttribute 特性之後,將可以看到斷點能進入到 catch 程式碼裡,而且程式不會閃退

但是這個機制在 dotnet core 就跑不起來了,根據 從 .NET Framework 到 .NET Core 的中斷性變更 文件,可以看到在 .NET Core 1.0 開始,損壞程序狀態異常無法由託管程式碼進行處理,將上面的 C# 程式碼切換到 dotnet core 下執行,此時將會發現不會進入到 catch 的程式碼,應用程式將會退出

大家可以嘗試使用我放在 github 的程式碼進行測試,切換框架為 .NET Framework 和 .NET Core 比較這裡的行為

知識共享許可協議
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。歡迎轉載、使用、重新發布,但務必保留文章署名林德熙(包含連結:http://blog.csdn.net/lindexi_gd ),不得用於商業目的,基於本文修改後的作品務必以相同的許可釋出。如有任何疑問,請與我聯絡。