dotnet / runtime

.NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.
https://docs.microsoft.com/dotnet/core/
MIT License
14.98k stars 4.66k forks source link

System.AccessViolationException with Delegate.CreateDelegate #35000

Closed tangdf closed 4 years ago

tangdf commented 4 years ago

    class Program
    {
        static void Main(string[] args)
        {
            PropertyInfo property = typeof(TestData).GetProperty(nameof(TestData.InputGuid),
                BindingFlags.Instance | BindingFlags.Public);

            Func<object, object> func = GetFunc(property);

            TestData data = new TestData();

            data.InputGuid = Guid.NewGuid();

            object value1 = func(data);
            try
            {
                object value2 = func(null);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            object value3 = func(data);
            try
            {
                object value2 = func(null);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }

            Console.ReadLine();
        }

        public static Func<object, object> GetFunc(PropertyInfo propertyInfo)
        {
            var method = typeof(Program).GetMethod(nameof(CreateFunc));

            return (Func<object, object>) method
                .MakeGenericMethod(propertyInfo.DeclaringType, propertyInfo.PropertyType)
                .Invoke(null, new object[] {propertyInfo.GetMethod});
        }

        public static Func<object, object> CreateFunc<TTarget, TValue>(MethodInfo methodInfo)
        {

            var func = (Func<TTarget, TValue>) Delegate.CreateDelegate(typeof(Func<TTarget, TValue>), null, methodInfo);
            return (object o) => func((TTarget) o);
        }
    }
    public class TestData
    { 
        public virtual Guid InputGuid { get; set; }
    }

image

Demo ConsoleApp.zip

jkotas commented 4 years ago

We hit null reference in VSD_DispatchStub, but do not convert it into NullReferenceException:

(5330.4adc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
CLRStub[VSD_DispatchStub]@7ffd0363314a:
00007ffd`0363314a 483901          cmp     qword ptr [rcx],rax ds:00000000`00000000=????????????????
jkotas commented 4 years ago

cc @janvorli

janvorli commented 4 years ago

I am looking into it.

janvorli commented 4 years ago

I have found that this bug has been present since .NET Core 1.0. We don't do any check for the failure address being in the dispatch stub in the exception handling code. It works correctly in .NET Framework 4.8 though.

janvorli commented 4 years ago

Actually, the issue is even in .NET Framework 4.8. I've accidentally tested x86 version before. The x64 has the same problem as the .NET Core one. It seems that implementing AdjustContextForVirtualStub along the lines of the ARM / x86 version would fix the problem.

jkotas commented 4 years ago

Related https://github.com/dotnet/runtime/issues/9027

tangdf commented 4 years ago

In IIS , .net framework 4.5~ 4.8 has the same problem.