Back to Csharplang

C# Language Design Meeting for November 5th, 2025

meetings/2025/LDM-2025-11-05.md

latest4.3 KB
Original Source

C# Language Design Meeting for November 5th, 2025

Agenda

Quote of the Day

  • "Do COM interfaces need to be unsafe?" "[with a look of visible pain] Well that's a **** question"

Discussion

Unsafe evolution

Champion issue: https://github.com/dotnet/csharplang/issues/9704
Specification: https://github.com/dotnet/csharplang/blob/ff88c654e26def239d2f7bcab52fe4e4d016dfba/proposals/unsafe-evolution.md
Related: https://github.com/dotnet/designs/blob/2b9e1b311d16ea142b4047d6eddeef15979ba6de/proposed/caller-unsafe.md

Picking up from last time, we continue to discuss how we want to evolve unsafe in C#. From the last time, the proposal was revised to include a few more open questions, as well as to reduce the level of breaking change it was proposing. Today, we were able to discuss 2 main topics:

  1. Do we accept the core kernel of the proposal, moving unsafe from meaning "there exists a pointer type" to "there exists memory unsafety, as defined by the caller unsafe document being proposed for the platform?
  2. Will the new rules be warnings, errors, or some form of suppressible error between?

For the first question, we agreed that yes, this moving unsafe into this newer world is acceptable. That left the majority of the meeting for discussion on warning vs error, which also bridges into areas of "how would the state be controllable?". The repeated analogy here is to the nullable reference types feature, and we discussed nearly every way in which nullable allows configuration. However, while the analogy works quite well, we think there are two major differences from the nullable feature:

  • We expect the amount of code in the average project that will need to change to adopt new memory safety rules is quite low. The majority of projects shouldn't even be impacted. This is extremely different to nullable, where every single line of executable code, and most lines of definitions, were impacted. We expect that this should reduce the number of configuration options needed.
  • Ignoring nullable warnings can cause bugs, and potentially even vulnerabilities in the form of DOS attacks, but memory safety issues are much more severe. Reading an unintentional null can crash an app, but reading uninitialized or unmanaged memory incorrectly can expose the app's data or users to attack. We therefore feel much more strongly about getting memory safety properly annotated across the ecosystem.

Given both the expected smaller blast radius and the higher importance of addressing issues, we believe that we want to start with stricter versions of the rules. We will therefore start with memory safety diagnostics being errors, with no dedicated suppression mechanism. Wrapping new errors in unsafe with todo comments attached will be the main form of "suppress for now and come back later" available to authors.

This does pose some adoption problems for users who depend on source generators, as there will be no special affordance given to source generators. This can mean that if a generator is not updated, and is emitting code that has new memory safety errors in it, the consumer of the generated code will be blocked from enabling the new rules. While this is harsh, we expect that the majority of the generators that use unsafe code are either first-party, or are from highly-engaged community members who will be quick to jump on the new rules. If these rules prove too onerous and block widespread adoption of the feature, we can revisit, but we want to start at the more secure end of the spectrum. We also don't expect that source generators need to be concerned by "unexpected" unsafe. Either the generator was written with the intent of using unsafe code in mind, or it is an error on the consumption side to provide the generator an unsafe member to interact with if it wasn't expecting it.

Next up, we will be discussing how members are marked unsafe, and what unsafe on a type means.

Conclusion

The core principle of the unsafe evolution feature is accepted. unsafe diagnostics will be errors by default, and no affordance for source generated code will be given.