From 3a8a39c4b54c68c1a14d5ab1f3ddfcf8a65c9426 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Tue, 15 Sep 2026 11:08:54 -0700 Subject: [PATCH 1/7] Clarify properties of memory safety in .NET programs --- accepted/2025/memory-safety/caller-unsafe.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/accepted/2025/memory-safety/caller-unsafe.md b/accepted/2025/memory-safety/caller-unsafe.md index 25381d54f..1d1ee28cc 100644 --- a/accepted/2025/memory-safety/caller-unsafe.md +++ b/accepted/2025/memory-safety/caller-unsafe.md @@ -114,10 +114,11 @@ public sealed class RequiresUnsafeAttribute : System.Attribute ### Global invariants -Two properties which should always hold in .NET programs are: +Properties which should always hold in .NET programs are: * Memory safety * No access to uninitialized memory +* Managed references are always valid to dereference, both as references and if converted to a pointer The "safe" subset of C# must guarantee these properties by construction. The unsafe subset cannot be guaranteed entirely by the system -- it needs external validation by the user or other tooling. From 00faad47540d81918418f7a9ccab3d7681ff9f02 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 18 Sep 2026 00:55:40 -0700 Subject: [PATCH 2/7] Update caller-unsafe.md --- accepted/2025/memory-safety/caller-unsafe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2025/memory-safety/caller-unsafe.md b/accepted/2025/memory-safety/caller-unsafe.md index 1d1ee28cc..b2fdbcf8a 100644 --- a/accepted/2025/memory-safety/caller-unsafe.md +++ b/accepted/2025/memory-safety/caller-unsafe.md @@ -118,7 +118,7 @@ Properties which should always hold in .NET programs are: * Memory safety * No access to uninitialized memory -* Managed references are always valid to dereference, both as references and if converted to a pointer +* Managed references are either null, or always valid to dereference, both as references and if converted to a pointer of the same type The "safe" subset of C# must guarantee these properties by construction. The unsafe subset cannot be guaranteed entirely by the system -- it needs external validation by the user or other tooling. From 776fad6ccaca542f16b3e968d00703fc40f96320 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 18 Sep 2026 15:55:19 -0700 Subject: [PATCH 3/7] Define requirements for managed references in unsafe code Added requirements for managed references in memory safety context. --- accepted/2025/memory-safety/caller-unsafe.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/accepted/2025/memory-safety/caller-unsafe.md b/accepted/2025/memory-safety/caller-unsafe.md index b2fdbcf8a..eb1949295 100644 --- a/accepted/2025/memory-safety/caller-unsafe.md +++ b/accepted/2025/memory-safety/caller-unsafe.md @@ -118,7 +118,6 @@ Properties which should always hold in .NET programs are: * Memory safety * No access to uninitialized memory -* Managed references are either null, or always valid to dereference, both as references and if converted to a pointer of the same type The "safe" subset of C# must guarantee these properties by construction. The unsafe subset cannot be guaranteed entirely by the system -- it needs external validation by the user or other tooling. @@ -185,6 +184,15 @@ The last notable area of impact is source generation. Most users will only see c One concession we could make to source generation would be to allow more fine-grained enabling and disabling of the warning scope. This proposal does **not** recommend such configuration switches. The `unsafe` feature is specifically designed to catch dangerous situations and source generation does not eliminate that risk. Therefore our recommendation would be to **avoid enabling the feature** until all source generators are updated to produce compatible code. +### Requirements + +To uphold the global safety invariants, user code must uphold certain requirements. + +In particular, managed references have the following requirements: + +- Managed references must be aligned in safe code. Managed refereces are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. +- Managed references may be null, but if they are non-null then they must point to valid memory, _even in unsafe code_. For these purposes, one element past the end of an array is considered valid memory. + ### Examples and APIs **ArrayPool.Rent** From 9270c8d7de6bf38e3e9955fc193656e4815cd8c5 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 18 Sep 2026 16:00:40 -0700 Subject: [PATCH 4/7] Update managed references requirements in caller-unsafe.md Clarify requirements for managed references in unsafe code. --- accepted/2025/memory-safety/caller-unsafe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2025/memory-safety/caller-unsafe.md b/accepted/2025/memory-safety/caller-unsafe.md index eb1949295..6c23e7a96 100644 --- a/accepted/2025/memory-safety/caller-unsafe.md +++ b/accepted/2025/memory-safety/caller-unsafe.md @@ -191,7 +191,7 @@ To uphold the global safety invariants, user code must uphold certain requiremen In particular, managed references have the following requirements: - Managed references must be aligned in safe code. Managed refereces are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. -- Managed references may be null, but if they are non-null then they must point to valid memory, _even in unsafe code_. For these purposes, one element past the end of an array is considered valid memory. +- Managed references may be null, but if they are non-null then they must point to valid memory, _even in unsafe code_. For these purposes, one element past the end of an array is considered valid memory, as is pointing just past the end of the object. Managed references pointing past objects may not be dereferenced in either safe or unsafe code. ### Examples and APIs From 0a9bd6c6e9effdf7aa9669ca64cc5f553d0f6e91 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 18 Sep 2026 20:10:18 -0700 Subject: [PATCH 5/7] Update managed references requirements for safety Clarified requirements for managed references in safe and unsafe code, emphasizing alignment and valid memory pointers. --- accepted/2025/memory-safety/caller-unsafe.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/accepted/2025/memory-safety/caller-unsafe.md b/accepted/2025/memory-safety/caller-unsafe.md index 6c23e7a96..88f2a909c 100644 --- a/accepted/2025/memory-safety/caller-unsafe.md +++ b/accepted/2025/memory-safety/caller-unsafe.md @@ -190,8 +190,8 @@ To uphold the global safety invariants, user code must uphold certain requiremen In particular, managed references have the following requirements: -- Managed references must be aligned in safe code. Managed refereces are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. -- Managed references may be null, but if they are non-null then they must point to valid memory, _even in unsafe code_. For these purposes, one element past the end of an array is considered valid memory, as is pointing just past the end of the object. Managed references pointing past objects may not be dereferenced in either safe or unsafe code. +- In safe code, managed references must be aligned. Managed references are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. +- In both safe and unsafe code, managed references follow the rules specified in https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#ii1442 ### Examples and APIs @@ -210,7 +210,3 @@ All P/Invoke methods are unsafe because they may compromise memory safety if the **SafeHandle, GCHandle, and other handle wrappers** Safe subset of these APIs must guarantee that safe code cannot operate on invalid handle. For example, `SafeHandle.Dispose` is safe and `SafeFileHandle(IntPtr handle, bool ownsHandle)` constructor is unsafe. - -**Alignment of managed references** - -Safe code must be prohibited from creating unaligned managed references. Managed refereces are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. From 75d4d804ac4e9e9172e99f952be2982406bee913 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Fri, 18 Sep 2026 20:11:24 -0700 Subject: [PATCH 6/7] Clarify managed references requirements in documentation --- accepted/2025/memory-safety/caller-unsafe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2025/memory-safety/caller-unsafe.md b/accepted/2025/memory-safety/caller-unsafe.md index 88f2a909c..258a3fa1a 100644 --- a/accepted/2025/memory-safety/caller-unsafe.md +++ b/accepted/2025/memory-safety/caller-unsafe.md @@ -191,7 +191,7 @@ To uphold the global safety invariants, user code must uphold certain requiremen In particular, managed references have the following requirements: - In safe code, managed references must be aligned. Managed references are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. -- In both safe and unsafe code, managed references follow the rules specified in https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#ii1442 +- In both safe and unsafe code, managed references must follow the rules specified in https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#ii1442 ### Examples and APIs From 3eadb926edf440bc22f0e668b14e5277d66d0099 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 7 Oct 2026 10:17:18 -0700 Subject: [PATCH 7/7] Apply suggestion from @jkotas Co-authored-by: Jan Kotas --- accepted/2025/memory-safety/caller-unsafe.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accepted/2025/memory-safety/caller-unsafe.md b/accepted/2025/memory-safety/caller-unsafe.md index 258a3fa1a..faa5a27fc 100644 --- a/accepted/2025/memory-safety/caller-unsafe.md +++ b/accepted/2025/memory-safety/caller-unsafe.md @@ -190,7 +190,7 @@ To uphold the global safety invariants, user code must uphold certain requiremen In particular, managed references have the following requirements: -- In safe code, managed references must be aligned. Managed references are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. +- In safe code, managed references must be aligned. .NET APIs expect managed references (including Spans) to be aligned. The behavior of .NET APIs on misaligned references is undefined. Additionally, managed references are often pinned as unmanaged pointers and passed to native code using C/C++ conventions. C/C++ requires that all pointers are properly aligned, the behavior is undefined otherwise and it can lead to memory safety violations. - In both safe and unsafe code, managed references must follow the rules specified in https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md#ii1442 ### Examples and APIs