Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot initialize array of non-primitive type #86865

Closed
1 task done
codemonkey85 opened this issue May 29, 2023 · 9 comments · Fixed by #87019
Closed
1 task done

Cannot initialize array of non-primitive type #86865

codemonkey85 opened this issue May 29, 2023 · 9 comments · Fixed by #87019
Assignees

Comments

@codemonkey85
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When trying to initialize a ReadOnlySpan of an enum, I'm hitting a runtime issue, "cannot initialize array of non-primitive type".

Expected Behavior

I should be able to initialize a ReadOnlySpan of an enum, based on this issue: dotnet/roslyn#61414

Steps To Reproduce

Here's a minimalistic solution with an example of the same code working in a console app, and crashing in a Blazor WASM app: https://github.com/codemonkey85/BlazorWasmIssueWithArrayInitializationWithRelevantPrimitives

The relevant code is:

ReadOnlySpan<MyEnum> myEnums = new[]
{
    MyEnum.A,
    MyEnum.B,
    MyEnum.C
};

Console.WriteLine(string.Join(", ", myEnums.ToArray()));

enum MyEnum
{
    A,
    B,
    C
}

Exceptions (if any)

crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: Cannot initialize array of non-primitive type (Parameter 'array')
System.ArgumentException: Cannot initialize array of non-primitive type (Parameter 'array')
   at System.Runtime.CompilerServices.RuntimeHelpers.GetSpanDataFrom(RuntimeFieldHandle fldHandle, RuntimeTypeHandle targetTypeHandle, Int32& count)
   at System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan[MyEnum](RuntimeFieldHandle fldHandle)
   at DoesntWorkInBlazorWasm.wwwroot.Pages.Index.OnInitialized() in C:\git\BlazorWasmIssueWithArrayInitializationWithRelevantPrimitives\BlazorWasmIssueWithArrayInitializationWithRelevantPrimitives\wwwroot\Pages\Index.razor:line 22
   at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()

.NET Version

7.0.5

Anything else?

Please note, I do have .NET 8 preview 4 installed, but I am using .NET 7.0.5 (SDK 7.0.302) for this project.

PowerShell 7.3.4
PS C:\git\BlazorWasmIssueWithArrayInitializationWithRelevantPrimitives> dotnet --version
8.0.100-preview.4.23260.5
PS C:\git\BlazorWasmIssueWithArrayInitializationWithRelevantPrimitives> dotnet --info
.NET SDK:
 Version:   8.0.100-preview.4.23260.5
 Commit:    2268e7b15c

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22621
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\8.0.100-preview.4.23260.5\

.NET workloads installed:
There are no installed workloads to display.

Host:
  Version:      8.0.0-preview.4.23259.5
  Architecture: x64
  Commit:       84a3d0e37e

.NET SDKs installed:
  7.0.302 [C:\Program Files\dotnet\sdk]
  7.0.400-preview.23225.8 [C:\Program Files\dotnet\sdk]
  8.0.100-preview.4.23260.5 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 6.0.16 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 8.0.0-preview.4.23260.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.16 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.0-preview.4.23259.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 6.0.15 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.16 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 7.0.5 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 8.0.0-preview.4.23260.1 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Other architectures found:
  x86   [C:\Program Files (x86)\dotnet]
    registered at [HKLM\SOFTWARE\dotnet\Setup\InstalledVersions\x86\InstallLocation]

Environment variables:
  Not set

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download
@stephentoub
Copy link
Member

@lambdageek, could you take a look?

@javiercn javiercn transferred this issue from dotnet/aspnetcore May 29, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label May 29, 2023
@lambdageek lambdageek self-assigned this May 29, 2023
@lambdageek
Copy link
Member

lambdageek commented May 29, 2023

Works with the net8 runtime, fails with the net7 runtime
Tomorrow I'll try to find the PR that fixed it...

@lambdageek lambdageek removed the untriaged New issue has not been triaged by the area owner label May 29, 2023
@codemonkey85
Copy link
Author

@lambdageek Thanks for looking into this. Is there a possibility this can be fixed in an update to .NET 7?

@lambdageek
Copy link
Member

Still haven't been able to track down why it is working in net8 and not in net7. The roslyn change dotnet/roslyn#61414 is complicating things...

@lambdageek
Copy link
Member

Oh, I see. it's due to #81695 and #82093

Which both call mini_get_underlying_type on the type argument of the RuntimeHelpers.CreateSpan<T> call.

The non-intrinsic implementation doesn't have the underlying type logic. So (if it was possible to call ref-struct methods using reflection) calling CreateSpan indirectly will probably still assert in net8.

@lambdageek
Copy link
Member

Ok, so this throws on net8 (and probably on net7):

using System.Reflection;

ReadOnlySpan<MyEnum> myEnums = new[]
{
    MyEnum.A,
    MyEnum.B,
    MyEnum.C
};

Console.WriteLine(string.Join(", ", myEnums.ToArray()));

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);
Console.WriteLine (mi);

var pid = typeof(MyEnum).Assembly.GetType("<PrivateImplementationDetails>");
Console.WriteLine (pid);
var fis = pid.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
var fi = fis[0];
Console.WriteLine (fi);

var parms = new object[] {
        fi.FieldHandle,
        typeof(MyEnum).TypeHandle,
        new int()
};
var result = mi.Invoke(null, parms);
Console.WriteLine (result);
Console.WriteLine (parms[2]);

enum MyEnum
{
    A,
    B,
    C
}

So now I can add a one-line fix for net 8 and backport to net7

lambdageek added a commit to lambdageek/runtime that referenced this issue Jun 1, 2023
Make it work correctly for spans of enums

Fixes dotnet#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.
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jun 1, 2023
github-actions bot pushed a commit that referenced this issue Jun 1, 2023
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.
@codemonkey85
Copy link
Author

Amazing. Thank you so much @lambdageek!

lambdageek added a commit that referenced this issue Jun 3, 2023
* [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
lambdageek added a commit that referenced this issue Jun 7, 2023
…tSpanDataFrom (#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 <alklig@microsoft.com>
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jun 7, 2023
@codemonkey85
Copy link
Author

@lambdageek Just wanted to check in - looks like this fix didn't make it for .NET SDK 7.0.7 / 7.0.304?

@lambdageek
Copy link
Member

@lambdageek Just wanted to check in - looks like this fix didn't make it for .NET SDK 7.0.7 / 7.0.304?

I think that's right. For non-security related issues it can sometimes take a month or so for the changes to make it to a servicing release, depending on when the changes go into the staging branchm, and from the staging branch to the release branch

@ghost ghost locked as resolved and limited conversation to collaborators Jul 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants