Bug 37436 - Invocation of Func<> based delegates fails on v4.2.1.124 on OSX & Linux: Delegate is never actually invoked by runtime
Summary: Invocation of Func<> based delegates fails on v4.2.1.124 on OSX & Linux: Dele...
Status: RESOLVED FIXED
Alias: None
Product: Runtime
Classification: Mono
Component: JIT (show other bugs)
Version: 4.2.0 (C6)
Hardware: All All
: --- normal
Target Milestone: ---
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2016-01-06 06:45 UTC by Pablo Ruiz García
Modified: 2016-01-06 15:55 UTC (History)
7 users (show)

See Also:
Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Sample code/proyect demonstrating the issue (10.82 KB, application/gzip)
2016-01-06 06:45 UTC, Pablo Ruiz García
Details

Description Pablo Ruiz García 2016-01-06 06:45:17 UTC
Created attachment 14457 [details]
Sample code/proyect demonstrating the issue

Hi,

The code show at the end of this issue demonstrates a failure by which a method assigned to a "Func<T, T, bool>" variable, when invoked is silently ignored by runtime, returning false (default(bool)) as result, but never actually invoking the actual method:

This code has been tested (sucessfully) on MS.NET as well as mono-3.10.0/linux. While it has been found to fail on mono v4.2.1 (6dd2d0d) on OSX, and on mono v4.2.1.124 (from tarball) on Linux.

The output of a successfull execution (ie. MS.NET or mono v3.10.0 on linux) is as follows:

  [root@mono-3.10.0 ~]# mono /tmp/TestEquality.exe
  Testing left.Equals: True (1/1/2001 12:00:00 AM vs 1/1/2001 12:00:00 AM)
  Testing left.Equals: False (2/2/2002 12:00:00 AM vs 3/3/2003 12:00:00 AM)
  Success!!!

While a failing execution looks like:

   thismac:TestEquality dir$ mono ./bin/Debug/TestEquality.exe

   Unhandled Exception:
   System.InvalidOperationException: Inconsistent Equalitiy Comparer
     at TestEquality.Program.Main () <0x71ded8 + 0x00193> in <filename unknown>:0
   [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: Inconsistent Equalitiy Comparer
     at TestEquality.Program.Main () <0x71ded8 + 0x00193> in <filename unknown>:0

In order to build/test the issue a sample project (build-able using xbuild) has been attached to this issue, including the actual binaries failing at my system.

NOTE: It looks like minor modifications to this code (like removing any method from 'IComparer' interface declaration) may provoke this same code to work fine.. So care must be taken to maintain the same code and method signatures in order to repro.

The actual failing code:

using System;

namespace TestEquality
{
	public interface IComparer
	{
		bool ApproximatelyEqual<TValue, TDifference>(TValue left, TValue right, TDifference delta);
		int Compare<T>(T left, T right);
		bool Equals(object left, object right);
		bool Equals<T>(T left, T right);
	}

	public class Comparer : IComparer
	{
		public new bool Equals(object left, object right)
		{
			return this.Equals<object>(left, right);
		}

		public bool Equals<T>(T left, T right)
		{
			if (object.ReferenceEquals(left, right))
			{
				Console.WriteLine("object.ReferenceEquals is true");
				return true;
			}
			if (object.ReferenceEquals(null, left) || object.ReferenceEquals(null, right))
			{
				Console.WriteLine("object.ReferenceEquals with null: return false");
				return false;
			}

			var result = left.Equals(right);
			Console.WriteLine("Testing left.Equals: {0} ({1} vs {2})", result, Convert.ToString(left), Convert.ToString(right));

			return result;
		}

		public int Compare<T>(T left, T right)
		{
			throw new NotImplementedException("Compare");
		}

		public bool ApproximatelyEqual<TValue, TDifference>(TValue left, TValue right, TDifference delta)
		{
			throw new NotImplementedException("Compare");
		}
	}

	public class Program
	{
		public static bool EqualsTest<T>(T left, T right)
		{
			IComparer ec = (IComparer)new Comparer();

			Func<T, T, bool> comparer = ec.Equals<T>;

			var result1 = comparer(left, right);

			return result1;
		}

		public static void Main()
		{
			var date1a = new DateTime(2001, 1, 1);
			var date1b = new DateTime(2001, 1, 1);
			var date2 = new DateTime(2002, 2, 2);
			var date3 = new DateTime(2003, 3, 3);

			var test1 = EqualsTest<DateTime>(date1a, date1b);
			var test2 = EqualsTest<DateTime>(date2, date3);
			if (test1 == test2)
				throw new InvalidOperationException("Inconsistent Equalitiy Comparer");

			Console.WriteLine("Success!!!");
		}
	}
}
Comment 1 Zoltan Varga 2016-01-06 08:32:28 UTC
Reduced testcase:
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
using System;

	public interface IComparer2
	{
		bool Equals<T>(T left, T right);
	}

	public class Comparer : IComparer2
	{
		public bool Equals<T>(T left, T right)
		{
			Console.WriteLine ("A: " + left);
			Console.WriteLine ("A: " + right);
			return false;
		}
	}

	public class Program
	{
		public static void Main()
		{
			var date1a = new DateTime(2001, 1, 1);
			var date1b = new DateTime(2001, 1, 1);

			IComparer2 ec = (IComparer2)new Comparer();

			Func<DateTime, DateTime, bool> comparer = ec.Equals<DateTime>;

			//Console.WriteLine (comparer.Method);
			comparer(date1a, date1b);
		}
	}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

The problem is probably in mono_get_delegate_virtual_invoke_impl () in mini-runtime.c.
This change seems to fix it:

diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c
index 9f62e40..2f61cb1 100644
--- a/mono/mini/mini-runtime.c
+++ b/mono/mini/mini-runtime.c
@@ -2993,7 +2993,7 @@ mono_get_delegate_virtual_invoke_impl (MonoMethodSignature *sig, MonoMethod *met
        is_interface = method->klass->flags & TYPE_ATTRIBUTE_INTERFACE ? TRUE : FALSE;
        load_imt_reg = is_virtual_generic || is_interface;
 
-       if (is_interface && !is_virtual_generic)
+       if (is_interface)
                offset = ((gint32)mono_method_get_imt_slot (method) - MONO_IMT_SIZE) * SIZEOF_VOID_P;
        else
                offset = G_STRUCT_OFFSET (MonoVTable, vtable) + ((mono_method_get_vtable_index (method)) * (SIZEOF_VOID_P));
Comment 2 Zoltan Varga 2016-01-06 08:59:35 UTC
Fixed in mono master a0d5b21a455f3d5b11076e3e8b907a6a234b5fc6.
Comment 3 Pablo Ruiz García 2016-01-06 15:55:14 UTC
Amazing job Zoltan!.. Thnks ;)

Note You need to log in before you can comment on or make changes to this bug.