[bcl] Use RuntimeHelpers.GetHashCode () for getting the hash code of … (#5511)
authorZoltan Varga <vargaz@gmail.com>
Wed, 6 Sep 2017 11:56:37 +0000 (07:56 -0400)
committerBernhard Urban <bernhard.urban@xamarin.com>
Wed, 6 Sep 2017 11:56:37 +0000 (13:56 +0200)
* [bcl] Use RuntimeHelpers.GetHashCode () for getting the hash code of the delegate target to avoid calling user defined hash code implementations which can throw exceptions. Fixes a regression introduced by a48bc439850869e565833d7fe6330c289beffe40.

* add test for #59235

https://bugzilla.xamarin.com/show_bug.cgi?id=59235

* [fixup] RuntimeHelpers.GetHashCode handles null

mcs/class/corlib/System/Delegate.cs
mono/tests/Makefile.am
mono/tests/delegate-disposed-hashcode.cs [new file with mode: 0644]

index 120991b2f79a9de061acadac90235eaa9d4b15fc..48d78605147fd386f643877d855a993c146bb302 100644 (file)
@@ -499,7 +499,7 @@ namespace System
 
                        m = Method;
 
-                       return (m != null ? m.GetHashCode () : GetType ().GetHashCode ()) ^ (m_target != null ? m_target.GetHashCode () : 0);
+                       return (m != null ? m.GetHashCode () : GetType ().GetHashCode ()) ^ RuntimeHelpers.GetHashCode (m_target);
                }
 
                protected virtual MethodInfo GetMethodImpl ()
index d7b3119374d47584deb42bf0b5b4e826ceecc9d2..4e4de8f0db8ea40e7395e7fbf32f6551863f0b1c 100755 (executable)
@@ -304,6 +304,7 @@ TESTS_CS_SRC=               \
        delegate-async-exit.cs  \
        delegate-delegate-exit.cs       \
        delegate-exit.cs        \
+       delegate-disposed-hashcode.cs   \
        finalizer-abort.cs      \
        finalizer-exception.cs  \
        finalizer-exit.cs       \
diff --git a/mono/tests/delegate-disposed-hashcode.cs b/mono/tests/delegate-disposed-hashcode.cs
new file mode 100644 (file)
index 0000000..f90118a
--- /dev/null
@@ -0,0 +1,38 @@
+using System;
+
+// Regression test for bug #59235
+
+public static class Program {
+       delegate void MyDel (int i, int j);
+
+       public static void Main (string[] args) {
+               var o = new MyTarget ();
+               Console.WriteLine ("Hashcode1: " + o.GetHashCode ());
+
+               MyDel d = o.DoStuff;
+               Console.WriteLine ("Hashcode2: " + d.GetHashCode ());
+               Console.WriteLine ("Hashcode3: " + o.GetHashCode ());
+
+               o.Dispose ();
+               Console.WriteLine ("Hashcode4: " + d.GetHashCode ());
+       }
+
+       class MyTarget : IDisposable {
+               public int counter = 0;
+               bool avail = true;
+
+               public void DoStuff (int i, int j) {
+                       counter += i + j;
+               }
+
+               public void Dispose () {
+                       avail = false;
+               }
+
+               public override int GetHashCode () {
+                       if (!avail)
+                               throw new ObjectDisposedException ("MyTarget is dead");
+                       return counter.GetHashCode ();
+               }
+       }
+}