[release/6.0] [mono] Fix downcast check in Array.CopySlow (#64479)
authorgithub-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Mon, 7 Feb 2022 19:41:40 +0000 (11:41 -0800)
committerGitHub <noreply@github.com>
Mon, 7 Feb 2022 19:41:40 +0000 (11:41 -0800)
* Add regression test for object[] -> Int32Enum[] array copy

where each element in the source array is the appropriate type

* Fix downcast check in slow array copy

When we have to resort to checking element by element, compare the type of each
actual element with the destination type. In particular, not the destinations
underlying type when it's an enum - we don't want to allow unrelated enums
using the same representation to copy over.

Fixes https://github.com/dotnet/runtime/issues/64387

Co-authored-by: Aleksey Kliger <alklig@microsoft.com>
src/libraries/System.Runtime/tests/System/ArrayTests.cs
src/mono/System.Private.CoreLib/src/System/Array.Mono.cs

index b7bdc5f..7917c4e 100644 (file)
@@ -1275,6 +1275,9 @@ namespace System.Tests
 
             // Interface[] -> Class[]
             yield return new object[] { new NonGenericInterface1[10], 0, new NonGenericClass1[10], 0, 10, new NonGenericClass1[10] };
+
+            // object[] -> Int32Enum[] when values are all Int32Enum
+            yield return new object[] { new object[] { Int32Enum.Case3 }, 0, new Int32Enum[1], 0, 1, new Int32Enum[] { Int32Enum.Case3 } };
         }
 
         public static IEnumerable<object[]> Copy_Array_UnreliableConversion_CanPerform_TestData()
index 94cb9eb..6a61e0e 100644 (file)
@@ -164,6 +164,7 @@ namespace System
 
             Type src_type = sourceArray.GetType().GetElementType()!;
             Type dst_type = destinationArray.GetType().GetElementType()!;
+            Type dst_elem_type = dst_type;
             bool dst_type_vt = dst_type.IsValueType && Nullable.GetUnderlyingType(dst_type) == null;
 
             bool src_is_enum = src_type.IsEnum;
@@ -196,12 +197,9 @@ namespace System
                 {
                     object srcval = sourceArray.GetValueImpl(source_pos + i);
 
-                    if (!src_type.IsValueType && dst_is_enum)
+                    if (dst_type_vt && (srcval == null || (src_type == typeof(object) && !dst_elem_type.IsAssignableFrom (srcval.GetType()))))
                         throw new InvalidCastException(SR.InvalidCast_DownCastArrayElement);
 
-                    if (dst_type_vt && (srcval == null || (src_type == typeof(object) && srcval.GetType() != dst_type)))
-                        throw new InvalidCastException();
-
                     try
                     {
                         destinationArray.SetValueRelaxedImpl(srcval, dest_pos + i);