Bug 25717

Summary: Calling a created delegate for value type fails in Mono but works in Windows
Product: [Mono] Runtime Reporter: sornakumar
Component: JITAssignee: Zoltan Varga <vargaz>
Status: RESOLVED FIXED    
Severity: normal CC: masafa, mono-bugs+mono, mono-bugs+runtime
Priority: ---    
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Linux   
Tags: Is this bug a regression?: ---
Last known good build:

Description sornakumar 2015-01-05 12:34:49 UTC
[Unable to add attachment to 25716. Hence opening this bug]

I am trying to create a static property getter for a property in my value type.
Please see the attached file for a sample. When I call the created getter, it
throws the following exception in Mono:

System.NullReferenceException: Object reference not set to an instance of an
object
  at System.IO.TextWriter.Write (System.Object value) [0x00000] in <filename
unknown>:0 
  at System.IO.TextWriter.WriteLine (System.Object value) [0x00000] in
<filename unknown>:0 
  at System.IO.SynchronizedWriter.WriteLine (System.Object value) [0x00000] in
<filename unknown>:0 
  at System.Console.WriteLine (System.Object value) [0x00000] in <filename
unknown>:0 
  at MvcProgram.PropertyHelper.Main () [0x00000] in <filename unknown>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object
reference not set to an instance of an object
  at System.IO.TextWriter.Write (System.Object value) [0x00000] in <filename
unknown>:0 
  at System.IO.TextWriter.WriteLine (System.Object value) [0x00000] in
<filename unknown>:0 
  at System.IO.SynchronizedWriter.WriteLine (System.Object value) [0x00000] in
<filename unknown>:0 
  at System.Console.WriteLine (System.Object value) [0x00000] in <filename
unknown>:0 
  at MvcProgram.PropertyHelper.Main () [0x00000] in <filename unknown>:0 

This however works without any issues in Windows. I am guessing this is a bug
in CreateDelegate.

Thanks.

--- Attached File: (In case you are not able to see the attached file)
using System;
using System.Collections.Concurrent;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Reflection;

namespace MvcProgram
{
    internal class PropertyHelper
    {
    	public struct Test
    	{
    	    public string MyProp {get; set;}
    	    public string StringProp {get; set;}
    	}
    	
    	public static void Main()
        {
    	    Test tt = new Test { MyProp = "1", StringProp = "Hello" };
    	    var prop1 = MakeFastPropertyGetter(typeof(Test).GetProperty("MyProp"));
    	    var prop2 = MakeFastPropertyGetter(typeof(Test).GetProperty("StringProp"));
    	    

    	    Console.WriteLine(prop1(tt));
    	    Console.WriteLine(prop2(tt));
    	}

        // Delegate type for a by-ref property getter
        private delegate TValue ByRefFunc<TDeclaringType, TValue>(ref TDeclaringType arg);

        private static readonly MethodInfo CallPropertyGetterByReferenceOpenGenericMethod =
            typeof(PropertyHelper).GetTypeInfo().GetDeclaredMethod("CallPropertyGetterByReference");

        public static Func<object, object> MakeFastPropertyGetter(PropertyInfo propertyInfo)
        {
            var getMethod = propertyInfo.GetMethod;
            
            var typeInput = getMethod.DeclaringType;
            var typeOutput = getMethod.ReturnType;

            Delegate callPropertyGetterDelegate;
            var delegateType = typeof(ByRefFunc<,>).MakeGenericType(typeInput, typeOutput);
            var propertyGetterAsFunc = getMethod.CreateDelegate(delegateType);

            var callPropertyGetterClosedGenericMethod =
               CallPropertyGetterByReferenceOpenGenericMethod.MakeGenericMethod(typeInput, typeOutput);

            callPropertyGetterDelegate =
                callPropertyGetterClosedGenericMethod.CreateDelegate(
                   typeof(Func<object, object>), propertyGetterAsFunc);

            return (Func<object, object>)callPropertyGetterDelegate;
        }

        // Called via reflection
        private static object CallPropertyGetterByReference<TDeclaringType, TValue>(
            ByRefFunc<TDeclaringType, TValue> getter,
            object target)
        {
            var unboxed = (TDeclaringType)target;
            return getter(ref unboxed);
        }
    }
}
Comment 1 Marek Safar 2015-04-14 10:43:19 UTC
*** Bug 25716 has been marked as a duplicate of this bug. ***
Comment 2 Marek Safar 2015-04-15 07:09:17 UTC
This looks like jit issue.

Comparing prop2 (tt) with null returns false but calling any instance on it throws NRE
Comment 3 Zoltan Varga 2015-04-16 15:10:40 UTC
Fixed in mono master c73363cee456b32c726ef7a0c4d504f1d07eaad2.