[API Proposal]: Mark Unsafe as caller-unsafe
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
### Background and motivation
https://github.com/dotnet/runtime/issues/125145
### API Proposal
```diff
public static partial class Unsafe
{
+ /// Applies an unchecked byte offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T AddByteOffset(ref T source, System.IntPtr byteOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked byte offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T AddByteOffset(ref T source, nuint byteOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked element offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T Add(ref T source, int elementOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked element offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T Add(ref T source, System.IntPtr elementOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked element offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T Add(ref T source, nuint elementOffset) where T : allows ref struct { throw null; }
public static bool AreSame([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; }
+ /// Strips read-only protection from a reference, yielding a writable reference; writing through it to genuinely read-only memory (e.g. an RVA static field or a string literal) can corrupt memory or fault.
+ unsafe
public static ref T AsRef(scoped ref readonly T source) where T : allows ref struct { throw null; }
+ /// Reinterprets an object reference as an unrelated type with no type check; later field access can read past the object's bounds or treat arbitrary bytes as a reference.
+ unsafe
public static T? As(object? o) where T : class? { throw null; }
+ ///
+ /// Reinterprets a reference to one type as a reference to another with no type or size check;
+ /// accesses may exceed the source's bounds or fabricate references from arbitrary bytes.
+ ///
+ unsafe
public static ref TTo As(ref TFrom source) where TFrom : allows ref struct where TTo : allows ref struct { throw null; }
+ ///
+ /// Reinterprets the bits of a value as another type of the same size; may expose the source's
+ /// padding bytes or fabricate a reference/pointer field in the result from arbitrary bits.
+ ///
+ unsafe
public static TTo BitCast(TFrom source) where TFrom : allows ref struct where TTo : allows ref struct { throw null; }
public static System.IntPtr ByteOffset([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T origin, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T target) where T : allows ref struct { throw null; }
+ /// Copies a caller-specified number of bytes between two references with no bounds check; may read or write past the end of either buffer.
+ unsafe
public static void CopyBlock(ref byte destination, ref readonly byte source, uint byteCount) { }
+ ///
+ /// Copies a caller-specified number of bytes between two references with no bounds check;
+ /// may read or write past the end of either buffer.
+ ///
+ unsafe
public static void CopyBlockUnaligned(ref byte destination, ref readonly byte source, uint byteCount) { }
+ /// Writes a caller-specified number of bytes through a reference with no bounds check; may write past the end of the buffer.
+ unsafe
public static void InitBlock(ref byte startAddress, byte value, uint byteCount) { }
+ /// Writes a caller-specified number of bytes through a reference with no bounds or alignment check; may write past the end of the buffer.
+ unsafe
public static void InitBlockUnaligned(ref byte startAddress, byte value, uint byteCount) { }
public static bool IsAddressGreaterThan([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; }
public static bool IsAddressGreaterThanOrEqualTo([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; }
public static bool IsAddressLessThan([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; }
public static bool IsAddressLessThanOrEqualTo([System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T left, [System.Diagnostics.CodeAnalysis.AllowNull] ref readonly T right) where T : allows ref struct { throw null; }
public static bool IsNullRef(ref readonly T source) where T : allows ref struct { throw null; }
public static ref T NullRef() where T : allows ref struct { throw null; }
+ /// Reads a value of type T from a byte reference with no bounds or alignment check; may read past the buffer and can populate a pointer/reference field of T from arbitrary bytes.
+ unsafe
public static T ReadUnaligned(scoped ref readonly byte source) where T : allows ref struct { throw null; }
public static int SizeOf() where T : allows ref struct { throw null; }
+ /// Leaves the variable uninitialized, so subsequent reads observe arbitrary, uninitialized memory.
+ unsafe
public static void SkipInit(out T value) where T : allows ref struct { throw null; }
+ /// Applies an unchecked byte offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T SubtractByteOffset(ref T source, System.IntPtr byteOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked byte offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T SubtractByteOffset(ref T source, nuint byteOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked element offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T Subtract(ref T source, int elementOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked element offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T Subtract(ref T source, System.IntPtr elementOffset) where T : allows ref struct { throw null; }
+ /// Applies an unchecked element offset to a managed reference; the result may point outside the source object and can crash the GC even if it is never dereferenced.
+ unsafe
public static ref T Subtract(ref T source, nuint elementOffset) where T : allows ref struct { throw null; }
+ /// Returns a mutable interior reference into a boxed value with no type check; a wrong T reinterprets the box's contents.
+ unsafe
public static ref T Unbox(object box) where T : struct { throw null; }
+ /// Writes a value of type T through a byte reference with no bounds or alignment check; may write past the end of the buffer.
+ unsafe
public static void WriteUnaligned(ref byte destination, T value) where T : allows ref struct { }
}
```
### API Usage
The annotated APIs will require `unsafe{}` context at their call site.
### Alternative Designs
_No response_
### Risks
_No response_
Contributor guide
Assessment
This issue has not been assessed yet.