From 63462357025b7928e0f541ffebafe2e82406485c Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Sat, 6 Apr 2019 11:17:32 +0200 Subject: [PATCH] [netcore] More Array.Copy fixes (#13842) Remaining errors: ``` /Users/filipnavara/Documents/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs(391,0): at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) System.Tests.ArrayTests.Copy_SZArray(sourceArray: [0, 1, 2, 3, null, ...], sourceIndex: 2, destinationArray: [204, 204, 204, 204, 204, ...], destinationIndex: 5, length: 3, expected: [204, 204, 204, 204, 204, ...]) [FAIL] System.InvalidCastException : Specified cast is not valid. Stack Trace: /Users/filipnavara/Documents/mono/mcs/class/System.Private.CoreLib/System/Array.cs(170,0): at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Boolean reliable) /Users/filipnavara/Documents/mono/mcs/class/System.Private.CoreLib/System/Array.cs(87,0): at System.Array.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length) /Users/vsts/agent/2.149.2/work/1/s/src/System.Runtime/tests/System/ArrayTests.cs(1293,0): at System.Tests.ArrayTests.Copy(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Array expected) /Users/vsts/agent/2.149.2/work/1/s/src/System.Runtime/tests/System/ArrayTests.cs(1243,0): at System.Tests.ArrayTests.Copy_SZArray(Array sourceArray, Int32 sourceIndex, Array destinationArray, Int32 destinationIndex, Int32 length, Array expected) /Users/filipnavara/Documents/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs(391,0): at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) System.Tests.ArrayTests.SetValue_Casting_Invalid [FAIL] Assert.Throws() Failure Expected: typeof(System.InvalidCastException) Actual: (No exception was thrown) Stack Trace: /Users/vsts/agent/2.149.2/work/1/s/src/System.Runtime/tests/System/ArrayTests.cs(3939,0): at System.Tests.ArrayTests.SetValue_Casting_Invalid() /Users/filipnavara/Documents/mono/mcs/class/corlib/System.Reflection/RuntimeMethodInfo.cs(391,0): at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture) ``` The last Copy_SZArray test case is `yield return new object[] { new object[] { 0, 1, 2, 3, null, 5, 6, 7, 8, 9 }, 2, new int?[] { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc }, 5, 3, new int?[] { 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 2, 3, null, 0xcc, 0xcc } };` --- mcs/class/System.Private.CoreLib/System/Array.cs | 56 ++++++++++++---------- .../System.Private.CoreLib/System/DefaultBinder.cs | 4 +- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/mcs/class/System.Private.CoreLib/System/Array.cs b/mcs/class/System.Private.CoreLib/System/Array.cs index 6ee7ae56e9d..f1836e4fdfe 100644 --- a/mcs/class/System.Private.CoreLib/System/Array.cs +++ b/mcs/class/System.Private.CoreLib/System/Array.cs @@ -134,19 +134,13 @@ namespace System dst_type = Enum.GetUnderlyingType (dst_type); if (reliable) { - var src_etype = RuntimeTypeHandle.GetCorElementType ((RuntimeType)src_type); - var dst_etype = RuntimeTypeHandle.GetCorElementType ((RuntimeType)dst_type); - if (src_etype != dst_etype) { + if (!dst_type.Equals (src_type)) { throw new ArrayTypeMismatchException (SR.ArrayTypeMismatch_CantAssignType); } - } - - // Need to check types even if nothing is copied - if (length == 0) { + } else { if (!CanAssignArrayElement (src_type, dst_type)) { throw new ArrayTypeMismatchException (SR.ArrayTypeMismatch_CantAssignType); } - return; } if (!Object.ReferenceEquals (sourceArray, destinationArray) || source_pos > dest_pos) { @@ -160,10 +154,6 @@ namespace System destinationArray.SetValueImpl (srcval, dest_pos + i); } catch (ArgumentException) { throw CreateArrayTypeMismatchException (); - } catch (InvalidCastException) { - if (CanAssignArrayElement (src_type, dst_type)) - throw; - throw CreateArrayTypeMismatchException (); } } } else { @@ -174,11 +164,6 @@ namespace System destinationArray.SetValueImpl (srcval, dest_pos + i); } catch (ArgumentException) { throw CreateArrayTypeMismatchException (); - } catch { - if (CanAssignArrayElement (src_type, dst_type)) - throw; - - throw CreateArrayTypeMismatchException (); } } } @@ -191,16 +176,35 @@ namespace System 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; + if (!target.IsValueType && !target.IsPointer) { + if (!source.IsValueType && !source.IsPointer) { + // Reference to reference copy + return + source.IsInterface || target.IsInterface || + source.IsAssignableFrom (target) || target.IsAssignableFrom (source); + } else { + // Value to reference copy + if (source.IsPointer) + return false; + return target.IsAssignableFrom (source); + } + } else { + if (source.IsEquivalentTo (target)) { + return true; + } else if (source.IsPointer && target.IsPointer) { + return true; + } else if (source.IsPrimitive && target.IsPrimitive) { + // Allow primitive type widening + return DefaultBinder.CanChangePrimitive (source, target); + } else if (!source.IsValueType && !source.IsPointer) { + // Source is base class or interface of destination type + if (target.IsPointer) + return false; + return source.IsAssignableFrom (target); + } + } - return source.IsAssignableFrom (target) || target.IsAssignableFrom (source); + return false; } public static Array CreateInstance (Type elementType, int length) diff --git a/mcs/class/System.Private.CoreLib/System/DefaultBinder.cs b/mcs/class/System.Private.CoreLib/System/DefaultBinder.cs index 6905672235c..4f0b1aaa4ef 100644 --- a/mcs/class/System.Private.CoreLib/System/DefaultBinder.cs +++ b/mcs/class/System.Private.CoreLib/System/DefaultBinder.cs @@ -26,7 +26,7 @@ namespace System return (type >= CorElementType.ELEMENT_TYPE_VOID && type <= CorElementType.ELEMENT_TYPE_R8) || type == CorElementType.ELEMENT_TYPE_I || type == CorElementType.ELEMENT_TYPE_U; } - static bool CanChangePrimitive (Type source, Type target) + internal static bool CanChangePrimitive (Type source, Type target) { var src = RuntimeTypeHandle.GetCorElementType ((RuntimeType)source); var dst = RuntimeTypeHandle.GetCorElementType ((RuntimeType)target); @@ -36,6 +36,8 @@ namespace System // This handles I/U if (src == dst) return true; + if (src > CorElementType.ELEMENT_TYPE_R8) + return false; return ((1 << (int)dst) & PrimitiveAttributes [(int)src]) != 0; } -- 2.11.4.GIT