We’re in the process of significantly improving memory safety in C#. The unsafe keyword is being redesigned to inform callers that they have obligations that must be discharged to maintain safety, documented via a new safety comment style. The keyword will expand from marking pointers to any code that interacts with memory in ways the compiler cannot validate as safe. The compiler will enforce that the unsafe keyword is used to encapsulate unsafe operations. The result is that safety contracts and assumptions become visible and reviewable instead of implied by convention.
We plan to release the new model and syntax (nominally a C# 16 feature) as a preview in .NET 11 and as a production release in .NET 12. It will initially be opt-in and may become the default in a later release. We will update templates to enable the new model just like we have done with nullable reference types. The early compiler implementation has landed in main and is taking shape.
C# 1.0 introduced the unsafe keyword as the way to establish an unsafe context on types, methods, and interior method blocks, letting developers choose the most convenient scope. An unsafe context grants access to pointer features. A method marked unsafe can use those features in its signature and implementation while unmarked methods cannot. We also exposed a set of unsafe types like System.Runtime.CompilerServices.Unsafe and System.Runtime.InteropServices.Marshal that required careful usage as a convention.
The unsafe keyword has since been reused and remixed in Rust and Swift, where those language teams gave it stricter, propagation-oriented semantics. C# 16 follows the same path, applies unsafe uniformly (including on Unsafe and Marshal members) in the .NET runtime libraries, and most closely resembles the Rust implementation. The result: unsafe stops marking a kind of syntax and starts marking a kind of contract; one the compiler can’t verify, that a skilled developer has to read and uphold.
C# already blocks unsafe code by default. Most developers won’t notice any change when they enable the new model because they don’t enable or use unsafe APIs. The default block will cover a much larger surface area when the C# 16 safety model is enabled. The new model establishes strong guard rails that are visible, reviewable, and enforced by the compiler. It is also an important tool to enforce engineering and supply chain standards. Memory safety has been a rising priority across industry and government for several years, and AI-assisted code generation adds a new dimension as software production scales faster than human review.
Safety
An earlier post discusses the structural safety mechanisms in .NET:
safety is enforced by a combination of the language and the runtime … Variables either reference live objects, are null, or are out of scope. Memory is auto-initialized by default such that new objects do not use uninitialized memory. Bounds checking ensures that accessing an element with an invalid index will not allow reading undefined memory — often caused by off-by-one errors — but instead will result in a IndexOutOfRangeException .
Source: What is .NET, and why should you choose it?
C# comes with strong safety enforcement for regular safe code. The new model enables developers and agents to accurately mark safety boundaries in unsafe code. There are two reasons to write unsafe code: interoperating with native code, and in some cases for performance. Go, Rust, and Swift also include an unsafe dialect for these cases. The language typically cannot help you write unsafe code; its role is to make clear where unsafe code is used and how it transitions back to safe code.
... continue reading