meetings/2025/LDM-2025-10-29.md
I did not record any particularly amusing quotes today, sorry
Champion issue: https://github.com/dotnet/csharplang/issues/9704
Specification: https://github.com/333fred/csharplang/blob/1b22088adb4e42323a3906c4e26105d001c79761/proposals/unsafe-evolution.md
Related: https://github.com/dotnet/designs/blob/2b9e1b311d16ea142b4047d6eddeef15979ba6de/proposed/caller-unsafe.md
Today, we started reviewing the initial specification for evolving unsafe at the C# level. We spent most of the session simply
getting clarity on what is being proposed, the impacts to code, and the limits of what can be detected by the compiler. Of
particular interest was the boundary between safe and unsafe code: can we strengthen guarantees about what must be in an unsafe
block? We considered this hypothetical bug:
int* ptr = stackalloc int[] { 1, 2, };
int addr = 0;
AddOne(ref addr);
unsafe
{
Console.WriteLine(ptr[addr]);
}
void AddOne(ref int i)
{
i++;
i++; // Oops, someone accidentally duplicated a line
}
If that bug were checked in, the memory unsafety occurs in the unsafe section, but the true bug that caused the unsafety
occurred in C# that has no reason to be marked as unsafe, and no part of the calculation that was in error is required to be
inside the unsafe block. Could there perhaps be an expanding rule, such that any inputs to an unsafe operation must also be
in an unsafe block? We ultimately don't think this expansion is worth it; in general, we do not expect that it will be possible
to detect every single input that is ultimately unsafe. A counterexample is something like:
void ReadFromArrayWithOffset(int[] array, int addr)
{
if (addr + 1 >= array.Length)
{
throw new ArgumentOutOfRangeException();
}
AddOne(ref addr);
fixed (int* ptr = array)
{
unsafe
{
Console.WriteLine(ptr[addr]);
}
}
}
How would the compiler be able to detect that, in fact, addr (up until the AddOne call) was actually perfectly safe and valid?
It is an input to the unsafe operation, so virality would likely demand that ReadFromArrayWithOffset be declared as unsafe.
Aliasing rules further complicate this. The goal of the unsafe feature is to better call out what parts of the code need more
manual scrutiny, but they ultimately don't replace that scrutiny. We think it is the job of the reviewers looking at this code
to understand what is really involved in the calculations and enforce unsafe boundaries appropriately here.
We made no conclusions today, but have a better understanding of where the boundaries of the feature are and what the principles we will be using to make further decisions are. We will come back next week to continue work here.