From bc6d349ecd72eec162f0532e6b6218fdbaa07ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aleksey=20Kliger=20=28=CE=BBgeek=29?= Date: Sun, 30 Jan 2022 15:57:40 -0500 Subject: [PATCH] [mono] Fix downcast check in Array.CopySlow (#64469) * 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 --- src/libraries/System.Runtime/tests/System/ArrayTests.cs | 3 +++ src/mono/System.Private.CoreLib/src/System/Array.Mono.cs | 6 ++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Runtime/tests/System/ArrayTests.cs b/src/libraries/System.Runtime/tests/System/ArrayTests.cs index e0108b81f3e57..372a4b3416388 100644 --- a/src/libraries/System.Runtime/tests/System/ArrayTests.cs +++ b/src/libraries/System.Runtime/tests/System/ArrayTests.cs @@ -1275,6 +1275,9 @@ public static IEnumerable Copy_SZArray_UnreliableConversion_CanPerform // 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 Copy_Array_UnreliableConversion_CanPerform_TestData() diff --git a/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs index 5a7bab2f73986..cb1bd0d52d26b 100644 --- a/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs @@ -167,6 +167,7 @@ private static void CopySlow(Array sourceArray, int sourceIndex, Array destinati 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; @@ -199,12 +200,9 @@ private static void CopySlow(Array sourceArray, int sourceIndex, Array destinati { 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);