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

UnsafeAccessor works with AOT but does not work with JIT for a type of Class<float> shape #108046

Closed
neon-sunset opened this issue Sep 20, 2024 · 9 comments

Comments

@neon-sunset
Copy link
Contributor

neon-sunset commented Sep 20, 2024

Description

It appears that UnsafeAccessor may not be working on .NET 9 as expected with JIT configuration, but continues to work with NativeAOT.

Reproduction Steps

Given simple program created from a default console template:

using System.Runtime.CompilerServices;

var holder = new Holder<float>();
Console.WriteLine(ArrayRef(holder).Length); // 8

[UnsafeAccessor(UnsafeAccessorKind.Field, Name = "array")]
static extern ref float[] ArrayRef(Holder<float> instance);

class Holder<T>
{
    T[] array = new T[8];
}

Expected behavior

> dotnet run -c Release -f net9.0
8

Actual behavior

> dotnet run -c Release net8.0
8
> dotnet run -c Release net9.0
Unhandled exception. System.MissingFieldException: Field not found: 'Holder`1.array'.
   at Program.<<Main>$>g__ArrayRef|0_0(Holder`1 instance)
   at Program.<Main>$(String[] args) in ***\AccessorRepro\Program.cs:line 4
> dotnet publish -f net8.0 -o . -p:PublishAot=true; .\AccessorRepro.exe
8
> dotnet publish -f net9.0 -o . -p:PublishAot=true; .\AccessorRepro.exe
8

Regression?

Yes

Known Workarounds

Using reflection 😢

Configuration

.NET SDK:
 Version:           9.0.100-rc.2.24468.2
 Commit:            c204043de1
 Workload version:  9.0.100-manifests.8fbc914b
 MSBuild version:   17.12.0-preview-24467-02+988196b1c

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.22631
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\9.0.100-rc.2.24468.2\

but did also reproduce with RC.1

Other information

No response

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Sep 20, 2024
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Sep 20, 2024
@neon-sunset neon-sunset changed the title In .NET 9, UnsafeAccessor works with AOT but does not work with JIT for a type of Class<float> shape UnsafeAccessor works with AOT but does not work with JIT for a type of Class<float> shape Sep 20, 2024
Copy link
Contributor

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch
See info in area-owners.md if you want to be subscribed.

@KeterSCP
Copy link

As a workaround you can use generic wrapper for the accessor (not sure what changed in .NET 9 to require that):

using System.Runtime.CompilerServices;
using Google.Protobuf.Collections;

var repeatedField = new RepeatedField<float> { 1.0f, 2.0f, 3.0f };

Console.WriteLine(MyAccessor<float>.ArrayRef(repeatedField).Length); // 8

public class MyAccessor<T>
{
    [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "array")]
    public static extern ref T[] ArrayRef(RepeatedField<T> instance);
}

@neon-sunset
Copy link
Contributor Author

neon-sunset commented Sep 20, 2024

Thanks, this works the other way around - on 9 but not on 8 (which does not support unsafe accessor generics), so I'm kind of back to square one 😀

I have simplified the example - does not need Protobuf dependency to repro.

@jkotas jkotas added area-System.Runtime.CompilerServices and removed area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI labels Sep 20, 2024
@jkotas
Copy link
Member

jkotas commented Sep 20, 2024

cc @AaronRobinsonMSFT

Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

@AaronRobinsonMSFT
Copy link
Member

Thanks, this works the other way around - on 9 but not on 8 (which does not support unsafe accessor generics), so I'm kind of back to square one 😀

I have simplified the example - does not need Protobuf dependency to repro.

@neon-sunset The solution here is to use an accessor class, as suggested in #108046 (comment). The UnsafeAccessorAttribute wasn't supposed to support generics in .NET 8. Unfortunately it did and enabled users to perform actions that weren't expected or properly spec'd. This was filed as a break-change in .NET 9, eventhough using generics in .NET 8 wasn't supported. See dotnet/docs#41769.

The documentation for UnsafeAccessorAttribute has additional details that are also relevant.

@dotnet-policy-service dotnet-policy-service bot removed the untriaged New issue has not been triaged by the area owner label Sep 23, 2024
@neon-sunset
Copy link
Contributor Author

Thanks. This is fair, the only question is the discrepancy with NativeAOT 9.0 where it does continue to work.

@AaronRobinsonMSFT
Copy link
Member

Thanks. This is fair, the only question is the discrepancy with NativeAOT 9.0 where it does continue to work.

Yes, sadly native AOT has a very different Type System API and in this case was written "properly" in .NET 8.0. Since native AOT must be computed at compile time it is much easier to reason about. The check at run-time in CoreCLR was a bit harder and took me longer to wrap my head around "how" to make it work. The lack of support in .NET 8.0 was simply me not having the knowledge to make it work in the timeframe.

@neon-sunset
Copy link
Contributor Author

neon-sunset commented Sep 23, 2024

I see, thank you for the explanation. In this case I ended up unintentionally relying on undocumented behavior where the unsafe accessor for RepeatedField<float> works in .NET 8 but no longer does in .NET 9. Its use will be removed for 8 altogether, and a working solution for 9 will be provided in net9.0-specific package instead, but it's not ideal (well, protobuf abstractions are not exactly great in general, to the point of System.Text.Json being more performance-friendly, but that's another topic).

@github-actions github-actions bot locked and limited conversation to collaborators Oct 24, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants