Skip to content

Commit 079e9e8

Browse files
[release/7.0-staging] [mono] Use underlying type in RuntimeHelpers.GetSpanDataFrom (#87021)
* [mono] Use underlying type in RuntimeHelpers.GetSpanDataFrom Make it work correctly for spans of enums Fixes #86865 Note that in net8 RuntimeHelpers.CreateSpan<T> 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. * test: Print all hidden field names if we can't find the right one Co-authored-by: Aleksey Kliger <[email protected]>
1 parent 527cd69 commit 079e9e8

File tree

3 files changed

+81
-1
lines changed

3 files changed

+81
-1
lines changed

src/mono/mono/metadata/icall.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -949,7 +949,7 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetSpanDataFrom (MonoCl
949949
return NULL;
950950
}
951951

952-
MonoType *type = targetTypeHandle;
952+
MonoType *type = mono_type_get_underlying_type (targetTypeHandle);
953953
if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VALUETYPE) {
954954
mono_error_set_argument (error, "array", "Cannot initialize array of non-primitive type");
955955
return NULL;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using System.Reflection;
3+
4+
namespace test86865;
5+
6+
public class test86865
7+
{
8+
public static int Main()
9+
{
10+
11+
// Regression test for https://github.com/dotnet/runtime/issues/86865
12+
// Verify that the RuntimeHelpers.GetSpanDataFrom method underlying RuntimeHelpers.CreateSpan<T>
13+
// works correctly with enums.
14+
15+
ReadOnlySpan<MyEnum> myEnums = new[]
16+
{
17+
MyEnum.A,
18+
MyEnum.B,
19+
MyEnum.C,
20+
MyEnum.B,
21+
MyEnum.C,
22+
};
23+
24+
if (string.Join(", ", myEnums.ToArray()) != "A, B, C, B, C")
25+
return 1;
26+
27+
var types = new Type[] {
28+
typeof(RuntimeFieldHandle),
29+
typeof(RuntimeTypeHandle),
30+
typeof(int).MakeByRefType(),
31+
};
32+
var mi = typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("GetSpanDataFrom", BindingFlags.Static | BindingFlags.NonPublic, types);
33+
if (mi == null)
34+
return 2;
35+
36+
var pid = typeof(MyEnum).Assembly.GetType("<PrivateImplementationDetails>");
37+
if (pid == null)
38+
return 3;
39+
40+
var fi = pid.GetField("0B77DC554B4A81403D62BE25FB5404020AD451151D4203D544BF60E3FEDBD8AE", BindingFlags.Static | BindingFlags.NonPublic);
41+
if (fi == null)
42+
{
43+
Console.WriteLine("Could not find the expected array data in <PrivateImplementationDetails>. The available static non-public fields are:");
44+
foreach (var f in pid.GetFields(BindingFlags.Static | BindingFlags.NonPublic)) {
45+
Console.WriteLine($" - '{f}'");
46+
}
47+
return 4;
48+
}
49+
50+
var parms = new object[] {
51+
fi.FieldHandle,
52+
typeof(MyEnum).TypeHandle,
53+
new int()
54+
};
55+
var result = mi.Invoke(null, parms);
56+
if (result == null)
57+
return 6;
58+
if ((int)parms[2] != myEnums.Length)
59+
return 7;
60+
61+
return 100;
62+
}
63+
}
64+
65+
enum MyEnum
66+
{
67+
A,
68+
B,
69+
C
70+
}
71+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<Compile Include="test86865.cs" />
8+
</ItemGroup>
9+
</Project>

0 commit comments

Comments
 (0)