Thoughts on Improving C# Memory Safety
Published on 2026/05/29 by Igor Levicki
Richard Lander, a product manager on .NET Team has recently posted a blog article titled Improving C# Memory Safety.
The blog post goes to great lengths to try to explain (read: rationalize) planned "improvements" to memory safety model and the unsafe keyword that are coming in C# 16.
Here is the summary of changes condensed from that 75 KB wall of text into 5 easy to understand points:
- Mandatory
unsafe {}Blocks: Previously only pointer dereferences had to be wrapped, now even calls to methods markedunsafemust be explicitly wrapped in anunsafe { }block. - Signature Propagation: Adding
unsafeto a member signature now passes the safety obligations up to the next caller. - Safety Docs: Unsafe members must use a
/// <safety>comment block to document caller obligations, or analyzers will flag them. - Signature Decoupling: Pointer types (
byte*,void*) as well asnint, andIntPtrin a method signature no longer propagate unsafety automatically. - Structural Restrictions: Classes, structs, static constructors, and finalizers can't be marked as
unsafe.
While some of those changes make sense (#2, #4, #5), the rest of them (#1,#3) are, and I am being generous here, controversial at the minimum.
After reading the blog post I felt compelled to respond to it and I did so originally by writing a comment in which I tore into the overall tone of the article, the real motivation for making a change, divorce from reality, and a fake notion of safety provided by the above-mentioned points #1 and #3.
I am including the screenshot of my original comment here since it was deleted:

Now I admit I put it over the top to make a point, and Richard Lander has the right to dislike the tone of my comment. However, deleting it in its entirety just shows he's incapable or unwilling (or both) to structurally answer the actual and factual criticism embedded in it.
Here are the technical points I made in the comment which went unanswered:
- Instead of adding a method keyword such as
boundaryor using the existingsafekeyword as mandatory on a method using unsafe code to force developers to actually implement correct safety boundaries it just tosses a live grenade up the stack for someone else to handle. - In its current state, it does ABSOLUTELY NOTHING to guarantee memory access safety — your
NativeBufferexample shows that perfectly as theDisposemethod isn't memory safe despiteunsafeblock andSafetycomment claiming otherwise. You can't have full memory safety without thread safety, those are intertwined and this proposal falls short of addressing that part. Not doing it now is only going to make it harder once the infestation of nestedunsafeblocks and walls ofsafetycomments spreads through the codebases. - It feels like a knee-jerk reaction to June 24, 2025 CISA report titled Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development except they totally ignored "use-after-free" and "data races" points and screamed "OMG we have to do something" and someone said "let's make
unsafemore cumbersome to use, that will improve safety" and nobody objected.
TL;DR — There's no proper memory safety without thread safety, and forcing developers to add more boilerplate code and comments to make unsafe code more visible (instead of safer!) is a security theater which might result in even worse code safety going forward.