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

[Breaking change]: Unintentional UnsafeAccessor support for non-open generics is altered in .NET 9. #41769

Closed
1 of 3 tasks
AaronRobinsonMSFT opened this issue Jul 16, 2024 · 0 comments · Fixed by #41941
Closed
1 of 3 tasks
Assignees
Labels
breaking-change Indicates a .NET Core breaking change doc-idea Indicates issues that are suggestions for new topics [org][type][category] Pri1 High priority, do before Pri2 and Pri3 📌 seQUESTered Identifies that an issue has been imported into Quest.

Comments

@AaronRobinsonMSFT
Copy link
Member

AaronRobinsonMSFT commented Jul 16, 2024

Description

In .NET 8, we introduced the UnsafeAccessor API. This permitted access to non-visible members of types (a.k.a., "fast private reflection") - see [API Proposal]: Zero-overhead member access with suppressed visibility checks · Issue #81741 · dotnet/runtime (github.com). The initial design supported generics, but we didn't add support in .NET 8 due to time constraints. However, in CoreCLR and native AOT, some very narrow and not officially supported scenarios did work. These scenarios weren't intentionally blocked, but should have been.

In .NET 9, official support was added with dotnet/runtime#99468.

Version

.NET 9 Preview 6

Previous behavior

A naive signature look-up on types was implemented, which caused use of generic types to be valid in some cases. For example, the below should have been deemed invalid:

[UnsafeAccessor(UnsafeAccessorKind.Method, Name = ".ctor")]
extern static void CtorAsMethod(List<int> c);

New behavior

The fully supported and documented way to consume generic types is to ensure type parameters match type parameters and method parameters match method parameters. This is because the runtime performs a strict metadata signature match. Examples and remarks can be found here.

class Accessor<T>
{
    [UnsafeAccessor(UnsafeAccessorKind.Method, Name = ".ctor")]
    public extern static void CtorAsMethod(List<T> c);
}

Type of breaking change

  • Binary incompatible: Existing binaries might encounter a breaking change in behavior, such as failure to load or execute, and if so, require recompilation.
  • Source incompatible: When recompiled using the new SDK or component or to target the new runtime, existing source code might require source changes to compile successfully.
  • Behavioral change: Existing binaries might behave differently at run time.

Reason for change

The reasoning for the change is that the previous behavior was not intended to be supported in the official release. It was, early in development, a possibly supported scenario, but was later deferred until .NET 9 for complexity issues encountered. The official documentation did not mention generics nor provide any examples using generics.

Recommended action

Users are encouraged to examine the updated documentation for the UnsafeAccessorAttribute API. Support for this scenario in .NET 8 is considered unintentional and uses deemed an error.

Feature area

Core .NET libraries

Affected APIs

System.Runtime.CompilerServices.UnsafeAccessorAttribute


Associated WorkItem - 286111

@AaronRobinsonMSFT AaronRobinsonMSFT added doc-idea Indicates issues that are suggestions for new topics [org][type][category] breaking-change Indicates a .NET Core breaking change Pri1 High priority, do before Pri2 and Pri3 labels Jul 16, 2024
@dotnet-bot dotnet-bot added ⌚ Not Triaged Not triaged labels Jul 16, 2024
@gewarren gewarren removed the ⌚ Not Triaged Not triaged label Jul 16, 2024
@dotnet-bot dotnet-bot added the ⌚ Not Triaged Not triaged label Jul 16, 2024
@gewarren gewarren added the 🗺️ reQUEST Triggers an issue to be imported into Quest. label Jul 16, 2024
@dotnet-bot dotnet-bot removed the ⌚ Not Triaged Not triaged label Jul 16, 2024
@sequestor sequestor bot added 📌 seQUESTered Identifies that an issue has been imported into Quest. and removed 🗺️ reQUEST Triggers an issue to be imported into Quest. labels Jul 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Indicates a .NET Core breaking change doc-idea Indicates issues that are suggestions for new topics [org][type][category] Pri1 High priority, do before Pri2 and Pri3 📌 seQUESTered Identifies that an issue has been imported into Quest.
Projects
No open projects
Status: ✅ Done
Development

Successfully merging a pull request may close this issue.

3 participants