[corlib] Throw correct exception when array::copy elements don't match
authorMarek Safar <marek.safar@gmail.com>
Mon, 3 Feb 2014 15:13:49 +0000 (16:13 +0100)
committerMarek Safar <marek.safar@gmail.com>
Mon, 3 Feb 2014 15:13:49 +0000 (16:13 +0100)
mcs/class/corlib/System/Array.cs
mcs/class/corlib/Test/System/ArrayTest.cs

index 756378c56d850d4f7e8fbf79821b0889d72656cd..2125767a74964276a9cab8f5fe5dcb33adc5ce52 100644 (file)
@@ -1003,12 +1003,13 @@ namespace System
 
                                        try {
                                                destinationArray.SetValueImpl (srcval, dest_pos + i);
+                                       } catch (ArgumentException) {
+                                               throw CreateArrayTypeMismatchException ();
                                        } catch {
-                                               if (src_type.Equals (typeof (Object)))
-                                                       throw new InvalidCastException ();
-                                               else
-                                                       throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
-                                                               "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
+                                               if (CanAssignArrayElement (src_type, dst_type))
+                                                       throw;
+
+                                               throw CreateArrayTypeMismatchException ();
                                        }
                                }
                        }
@@ -1018,17 +1019,37 @@ namespace System
 
                                        try {
                                                destinationArray.SetValueImpl (srcval, dest_pos + i);
+                                       } catch (ArgumentException) {
+                                               throw CreateArrayTypeMismatchException ();
                                        } catch {
-                                               if (src_type.Equals (typeof (Object)))
-                                                       throw new InvalidCastException ();
-                                               else
-                                                       throw new ArrayTypeMismatchException (String.Format (Locale.GetText (
-                                                               "(Types: source={0};  target={1})"), src_type.FullName, dst_type.FullName));
+                                               if (CanAssignArrayElement (src_type, dst_type))
+                                                       throw;
+
+                                               throw CreateArrayTypeMismatchException ();
                                        }
                                }
                        }
                }
 
+               static Exception CreateArrayTypeMismatchException ()
+               {
+                       return new ArrayTypeMismatchException ();
+               }
+
+               static bool CanAssignArrayElement (Type source, Type target)
+               {
+                       if (source.IsValueType)
+                               return source.IsAssignableFrom (target);
+
+                       if (source.IsInterface)
+                               return !target.IsValueType;
+
+                       if (target.IsInterface)
+                               return !source.IsValueType;
+
+                       return source.IsAssignableFrom (target) || target.IsAssignableFrom (source);
+               }
+
                [ReliabilityContractAttribute (Consistency.MayCorruptInstance, Cer.MayFail)]
                public static void Copy (Array sourceArray, long sourceIndex, Array destinationArray,
                                         long destinationIndex, long length)
index ef41ce17946377d9b7b323e043df55c0a8922573..71a21049911737b672aaa0b19f870bd3b902d8bf 100644 (file)
@@ -61,7 +61,21 @@ public class ArrayTest
 {
        char [] arrsort = {'d', 'b', 'f', 'e', 'a', 'c'};
 
-       public ArrayTest() {}
+       interface I
+       {
+       }
+
+       class C
+       {
+       }
+
+       class DC : C
+       {
+       }
+
+       class DI : I
+       {
+       }
 
        [Test]
        public void TestIsFixedSize() {
@@ -488,14 +502,24 @@ public class ArrayTest
        }
 
        [Test]
-       [ExpectedException (typeof (InvalidCastException))]
        public void Copy_InvalidCast () {
                object[] arr1 = new object [10];
                Type[] arr2 = new Type [10];
-
                arr1 [0] = new object ();
 
-               Array.Copy (arr1, 0, arr2, 0, 10);
+               try {
+                       Array.Copy (arr1, 0, arr2, 0, 10);
+                       Assert.Fail ("#1");
+               } catch (InvalidCastException) {
+               }
+
+               var arr1_2 = new I [1] { new DI () };
+               var arr2_2 = new C [1] { new DC () };
+               try {
+                       Array.Copy (arr2_2, arr1_2, 1);
+                       Assert.Fail ("#1");
+               } catch (InvalidCastException) {
+               }
        }
 
        [Test]