From 5e9ab0cc3b0ee6428e55908c0808599c47818fc5 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 1 Jun 2023 13:18:45 -0400 Subject: [PATCH 1/4] [mono] Use underlying type in RuntimeHelpers.GetSpanDataFrom Make it work correctly for spans of enums Fixes https://github.com/dotnet/runtime/issues/86865 Note that in net8 RuntimeHelpers.CreateSpan is an intrinsic, so GetSpanDataFrom is never called directly. But in net7 CreateSpan is not intrinsified on Mono, so the underlying method really does get called. --- src/mono/mono/metadata/icall.c | 2 +- .../coreclr/GitHub_86865/test86865.cs | 65 +++++++++++++++++++ .../coreclr/GitHub_86865/test86865.csproj | 9 +++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/tests/Regressions/coreclr/GitHub_86865/test86865.cs create mode 100644 src/tests/Regressions/coreclr/GitHub_86865/test86865.csproj diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index c8b16f7f400a68..09362a731d647e 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -949,7 +949,7 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetSpanDataFrom (MonoCl return NULL; } - MonoType *type = targetTypeHandle; + MonoType *type = mono_type_get_underlying_type (targetTypeHandle); if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VALUETYPE) { mono_error_set_argument (error, "array", "Cannot initialize array of non-primitive type"); return NULL; diff --git a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs new file mode 100644 index 00000000000000..734c70ce3bd288 --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs @@ -0,0 +1,65 @@ +using System; +using System.Reflection; + +namespace test86865; + +public class test86865 +{ + public static int Main() + { + + // Regression test for https://github.com/dotnet/runtime/issues/86865 + // Verify that the RuntimeHelpers.GetSpanDataFrom method underlying RuntimeHelpers.CreateSpan + // works correctly with enums. + + ReadOnlySpan myEnums = new[] + { + MyEnum.A, + MyEnum.B, + MyEnum.C, + MyEnum.B, + MyEnum.C, + }; + + if (string.Join(", ", myEnums.ToArray()) != "A, B, C, B, C") + return 1; + + var types = new Type[] { + typeof(RuntimeFieldHandle), + typeof(RuntimeTypeHandle), + typeof(int).MakeByRefType(), + }; + var mi = typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("GetSpanDataFrom", BindingFlags.Static | BindingFlags.NonPublic, types); + if (mi == null) + return 2; + + var pid = typeof(MyEnum).Assembly.GetType(""); + if (pid == null) + return 3; + + var fi = pid.GetField("0B77DC554B4A81403D62BE25FB5404020AD451151D4203D544BF60E3FEDBD8AE4", BindingFlags.Static | BindingFlags.NonPublic); + if (fi == null) + return 4; + + var parms = new object[] { + fi.FieldHandle, + typeof(MyEnum).TypeHandle, + new int() + }; + var result = mi.Invoke(null, parms); + if (result == null) + return 6; + if (parms[2] != 5) + return 7; + + return 100; + } +} + +enum MyEnum +{ + A, + B, + C +} + diff --git a/src/tests/Regressions/coreclr/GitHub_86865/test86865.csproj b/src/tests/Regressions/coreclr/GitHub_86865/test86865.csproj new file mode 100644 index 00000000000000..dc5ae5f51c138d --- /dev/null +++ b/src/tests/Regressions/coreclr/GitHub_86865/test86865.csproj @@ -0,0 +1,9 @@ + + + Exe + true + + + + + From c4e2bf08432ec1e527273f2d0dbfe5a9cd48b19f Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 1 Jun 2023 13:24:55 -0400 Subject: [PATCH 2/4] fixup test --- src/tests/Regressions/coreclr/GitHub_86865/test86865.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs index 734c70ce3bd288..1ee57aabac1b75 100644 --- a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs +++ b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs @@ -49,7 +49,7 @@ public static int Main() var result = mi.Invoke(null, parms); if (result == null) return 6; - if (parms[2] != 5) + if ((int)parms[2] != 5) return 7; return 100; From 65b4b02bea7b1d9601c05fb944074e9ff48ecb23 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 2 Jun 2023 11:17:53 -0400 Subject: [PATCH 3/4] test: Print all hidden field names if we can't find the right one --- src/tests/Regressions/coreclr/GitHub_86865/test86865.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs index 1ee57aabac1b75..185216d1fb7081 100644 --- a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs +++ b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs @@ -39,7 +39,13 @@ public static int Main() var fi = pid.GetField("0B77DC554B4A81403D62BE25FB5404020AD451151D4203D544BF60E3FEDBD8AE4", BindingFlags.Static | BindingFlags.NonPublic); if (fi == null) + { + Console.WriteLine("Could not find the expected array data in . The available static non-public fields are:"); + foreach (var f in pid.GetFields(BindingFlags.Static | BindingFlags.NonPublic)) { + Console.WriteLine($" - '{f}'"); + } return 4; + } var parms = new object[] { fi.FieldHandle, @@ -49,7 +55,7 @@ public static int Main() var result = mi.Invoke(null, parms); if (result == null) return 6; - if ((int)parms[2] != 5) + if ((int)parms[2] != myEnums.Length) return 7; return 100; From f61bb61fad0413458c2ae20edd4fbd75f4a3ec8e Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 2 Jun 2023 13:42:00 -0400 Subject: [PATCH 4/4] fixup field name in test --- src/tests/Regressions/coreclr/GitHub_86865/test86865.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs index 185216d1fb7081..d14c8bbd8e167b 100644 --- a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs +++ b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs @@ -37,7 +37,7 @@ public static int Main() if (pid == null) return 3; - var fi = pid.GetField("0B77DC554B4A81403D62BE25FB5404020AD451151D4203D544BF60E3FEDBD8AE4", BindingFlags.Static | BindingFlags.NonPublic); + var fi = pid.GetField("0B77DC554B4A81403D62BE25FB5404020AD451151D4203D544BF60E3FEDBD8AE", BindingFlags.Static | BindingFlags.NonPublic); if (fi == null) { Console.WriteLine("Could not find the expected array data in . The available static non-public fields are:");