导致FatalExecutionEngineError的AppDomain.FirstChanceException事件订阅

时间:2013-10-09 15:29:18

标签: c# .net

此类存在于其自己的DLL中。显然,调用Ex方法会导致异常被抛出并处理:

class Foo : MarshalByRefObject
{
    public void Ex()
    {
        object o = null;

        try
        {
            string s = o.ToString();
        }
        catch { }
    }
}

以下将包含Foo的DLL加载到另一个AppDomain中,创建一个Foo并调用Ex方法。

using System;
using System.Diagnostics;
using System.Runtime.ExceptionServices;
using RemoteCode;

namespace AppDomainTraceTest
{
    class Program
    {
        static void Main()
        {
            AppDomain appDomain = AppDomain.CreateDomain("TEST",
                null,
                new AppDomainSetup
                {
                    ApplicationBase = AppDomain.CurrentDomain.BaseDirectory
                });

            // appDomain.FirstChanceException +=
            //     (s, e) => Debug.WriteLine("* " + e.Exception.Message);

            Bar bar = new Bar();
            bar.Subscribe(appDomain);

            Foo foo = (Foo)appDomain.CreateInstance("RemoteCode", "RemoteCode.Foo").Unwrap();
            foo.Ex();
        }
    }

    public class Bar : MarshalByRefObject
    {
        public void Subscribe(AppDomain ad)
        {
            ad.FirstChanceException += OnFirstChanceException;
        }

        private void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
        {
            Debug.WriteLine("* " + e.Exception.Message);
        }
    }
}

结果是FatalExecutionEngineError:

  

运行时遇到了致命错误。错误的地址是0x62c6529d,位于线程0x26f0上。错误代码是0x80131506。此错误可能是CLR中的错误,也可能是用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括COM-interop或PInvoke的用户封送错误,这可能会破坏堆栈。

它出现在Foo的这一行:

string s = o.ToString();

如果我注释掉包含Bar的行,并取消注释前一行,那么代码工作正常,并将异常消息写入调试控制台:

appDomain.FirstChanceException +=
    (s, e) => Debug.WriteLine("* " + e.Exception.Message);

//Bar bar = new Bar();
//bar.Subscribe(appDomain);

Foo foo = (Foo)appDomain.CreateInstance("RemoteCode", "RemoteCode.Foo").Unwrap();
foo.Ex();

我做了些蠢事,还是这个错误?

1 个答案:

答案 0 :(得分:1)

标签“bug”在这种情况下非常合适,绝不应该使用普通托管代码的FEEE。但是,您正在给CLR一个非常困难的时间,在非常关键的时间将事件处理程序调用从一个AppDomain调度到另一个AppDomain。显然它没有能力处理这个问题。

你需要强烈考虑避免这种情况。只要将事件处理程序保存在同一AppDomain中,它就可以正常工作。这很好,例如:

public class Foo : MarshalByRefObject {
    public Foo() {
        AppDomain.CurrentDomain.FirstChanceException += (s, e) => {
            Debug.WriteLine("* " + e.Exception.Message);
        };
    }
    // etc...
}

我想象的可能不便于伐木。您可以在connect.microsoft.com

上为此错误提交反馈报告