From afb83b4965fe69eb198611c47b9ef3a724c260f6 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 1 Jun 2023 13:18:45 -0400 Subject: [PATCH 1/3] [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 0a7dbc9749595c..a4ec470a2ddb62 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -985,7 +985,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 78806bce1f2deed7b9ab8f4c7ce397b5223e4faa Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Thu, 1 Jun 2023 13:24:55 -0400 Subject: [PATCH 2/3] 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 d37d2480387c5bbd2df2049668b35fd74fb492c4 Mon Sep 17 00:00:00 2001 From: Aleksey Kliger Date: Fri, 2 Jun 2023 11:19:17 -0400 Subject: [PATCH 3/3] test: Print all hidden field names if we can't find the right one --- src/tests/Regressions/coreclr/GitHub_86865/test86865.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs b/src/tests/Regressions/coreclr/GitHub_86865/test86865.cs index 1ee57aabac1b75..a8d65dea58be92 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; @@ -62,4 +68,3 @@ enum MyEnum B, C } -