Подтвердить что ты не робот

Вызов Cross-AppDomain повреждает среду выполнения

Первоначально это был гораздо более длительный вопрос, но теперь я создал более компактный примерный код, поэтому исходный текст больше не имеет отношения.

У меня есть два проекта, один из которых содержит одну структуру с без членов, с именем TestType. Этот проект ссылается на основной проект, но сборка не входит в исполняемый каталог. Основной проект создает новый домен приложения, где он регистрирует событие AssemblyResolve с именем включенной сборки. В основном домене приложения обрабатывается одно и то же событие, но оно вручную загружает сборку из ресурсов проекта.

Затем новый домен приложения создает собственную версию TestType, но с больше полей, чем исходный. Основной домен приложения использует фиктивную версию, а новый домен приложения использует сгенерированную версию.

При вызове методов, которые имеют TestType в своей сигнатуре (даже просто для возврата достаточно), кажется, что он просто дестабилизирует среду выполнения и повреждает память.

Я использую .NET 4.5, работающий под x86.

DummyAssembly:

using System;

[Serializable]
public struct TestType
{

}

Основной проект:

using System;
using System.Reflection;
using System.Reflection.Emit;

internal sealed class Program
{
    [STAThread]
    private static void Main(string[] args)
    {
        Assembly assemblyCache = null;

        AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
        {
            var name = new AssemblyName(rargs.Name);
            if(name.Name == "DummyAssembly")
            {
                return assemblyCache ?? (assemblyCache = TypeSupport.LoadDummyAssembly(name.Name));
            }
            return null;
        };

        Start();
    }

    private static void Start()
    {
        var server = ServerObject.Create();

        //prints 155680
        server.TestMethod1("Test");
        //prints 0
        server.TestMethod2("Test");
    }
}

public class ServerObject : MarshalByRefObject
{
    public static ServerObject Create()
    {
        var domain = AppDomain.CreateDomain("TestDomain");
        var t = typeof(ServerObject);
        return (ServerObject)domain.CreateInstanceAndUnwrap(t.Assembly.FullName, t.FullName);
    }

    public ServerObject()
    {
        Assembly genAsm = TypeSupport.GenerateDynamicAssembly("DummyAssembly");

        AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs rargs)
        {
            var name = new AssemblyName(rargs.Name);
            if(name.Name == "DummyAssembly")
            {
                return genAsm;
            }
            return null;
        };
    }

    public TestType TestMethod1(string v)
    {
        Console.WriteLine(v.Length);
        return default(TestType);
    }

    public void TestMethod2(string v)
    {
        Console.WriteLine(v.Length);
    }
}

public static class TypeSupport
{
    public static Assembly LoadDummyAssembly(string name)
    {
        var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name);
        if(stream != null)
        {
            var data = new byte[stream.Length];
            stream.Read(data, 0, data.Length);
            return Assembly.Load(data);
        }
        return null;
    }

    public static Assembly GenerateDynamicAssembly(string name)
    {
        var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
            new AssemblyName(name), AssemblyBuilderAccess.Run
        );

        var mod = ab.DefineDynamicModule(name+".dll");

        var tb = GenerateTestType(mod);

        tb.CreateType();

        return ab;
    }

    private static TypeBuilder GenerateTestType(ModuleBuilder mod)
    {
        var tb = mod.DefineType("TestType", TypeAttributes.Public | TypeAttributes.Serializable, typeof(ValueType));

        for(int i = 0; i < 3; i++)
        {
            tb.DefineField("_"+i.ToString(), typeof(int), FieldAttributes.Public);
        }

        return tb;
    }
}

Хотя и TestMethod1, и TestMethod2 должны печатать 4, первый обращается к некоторым странным частям памяти и, кажется, сильно повреждает стек вызовов, чтобы влиять на вызов второго метода. Если я удалю вызов первого метода, все будет хорошо.

Если я запускаю код под x64, первый метод выдает исключение NullReferenceException.

Количество полей обеих структур кажется важным. Если вторая структура больше общей, чем первая (если я сгенерирую только одно поле или ни одного), все также работает нормально, так же, если структура в DummyAssembly содержит больше полей. Это заставляет меня полагать, что JITter либо неправильно компилирует метод (не используя сгенерированную сборку), либо вызывает неправильную собственную версию метода. Я проверил, что typeof(TestType) возвращает правильную (сгенерированную) версию типа.

В общем, я не использую какой-либо небезопасный код, поэтому этого не должно быть.

4b9b3361