我們的應用程序調用一個混合模式組件,其具有在它的非託管代碼已知的錯誤導致的AccessViolationException被拋出。
我們的目標是在我們終止應用程序之前,捕獲AV異常並將其包裝並拋出一個新的異常,這個異常會在堆棧中被更高地捕獲並記錄下來。
問題
我們的代碼並沒有表現得如我們預期......我們用來包裹的表現就像它的AV例外是CSE的「香草」的例外,並沒有因我們的頂級抓級別的異常處理程序。相反,它冒泡到了操作系統,終止了這個過程。這隻會在Windows事件日誌中留下令人困惑的日誌消息,表明InvalidOperationException已經設法繞過所有異常處理程序並終止進程。
請注意,此行爲僅在AV異常設置爲包裝異常上的內部異常時纔會顯示。
下面是一個例子:
[Test]
public void RunTest()
{
try
{
ProvokeAccessViolation();
}
catch (InvalidOperationException e)
{
// We never get here!
Console.WriteLine("Log exception: " + e);
}
}
[HandleProcessCorruptedStateExceptions]
[SecurityCritical]
public static void ProvokeAccessViolation()
{
try
{
var ptr = new IntPtr(1);
const bool someValue = true;
Marshal.StructureToPtr(someValue, ptr, true); // Will throw AccessViolationException
}
catch (AccessViolationException ex)
{
Console.WriteLine("Caught AV exception: " + ex);
throw new InvalidOperationException("Wrapping AV exception", ex);
}
}
我的問題是,怎麼了CLR知道治療包皮異常(InvalidOperationException異常在上面的示例)就像是一個CSE?
同樣,爲什麼如果你只是從託管代碼拋出一個新的AccessViolationException它而不是行爲像一個CSE? (...我承擔同樣的機制在起作用在這兩種情況下)
UPDATE: 繼漢斯的答案,這裏是表示AV異常的截圖被拋出一把抓住:
感謝漢斯 - 有趣的信息......但我沒有在我的機器上得到相同的行爲(例如,它肯定是調用Marshal.StructureToPtr()時被拋出的AVE)。 在原始示例中,我感興趣的是爲什麼它沒有在RunTest()中捕獲InvalidOperationException。 CLR不會將它呈現給catch塊,因爲它認爲它是一個CSE。如果將HPCSE屬性添加到RunTest,則會按設計吞下InvalidOperationException。 – 2015-01-16 09:25:30
不,它絕對是一個被拋出的NullReferenceException。只需將其更改爲'var ptr = new IntPtr(65536);'以獲得AccessViolationException。 – 2015-01-16 09:39:22
不在我的機器上:0)...我附上了一個截圖來演示。無論如何,ProvokeAccessViolation()中的catch可能只是catch(Exception ex)。我的問題是真的爲什麼然後不能捕捉RunTest()中的InvalidOperationException? – 2015-01-16 10:42:11