Background and motivation
#125145
API Proposal
namespace System;
public static class GC
{
+ /// <safety>Returns a T[] whose elements are not zero-initialized, so reads observe leftover, uninitialized heap bytes.</safety>
+ unsafe
public static T[] AllocateUninitializedArray<T>(int length, bool pinned = false);
}
namespace System.Runtime.CompilerServices;
public static class RuntimeHelpers
{
+ /// <safety>Reads SizeOf(type) bytes from a caller-supplied reference and boxes them as that type; the bytes may be out of range, uninitialized, or contain a fabricated reference field.</safety>
+ unsafe
public static object? Box(ref byte target, System.RuntimeTypeHandle type);
}
namespace System.Security.Cryptography;
public sealed partial class DSAOpenSsl : System.Security.Cryptography.DSA
{
+ /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety>
+ unsafe
public DSAOpenSsl(System.IntPtr handle);
}
namespace System.Security.Cryptography;
public sealed partial class ECDiffieHellmanOpenSsl : System.Security.Cryptography.ECDiffieHellman
{
+ /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety>
+ unsafe
public ECDiffieHellmanOpenSsl(System.IntPtr handle);
}
namespace System.Security.Cryptography;
public sealed partial class ECDsaOpenSsl : System.Security.Cryptography.ECDsa
{
+ /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety>
+ unsafe
public ECDsaOpenSsl(System.IntPtr handle);
}
namespace System.Security.Cryptography;
public sealed partial class RSAOpenSsl : System.Security.Cryptography.RSA
{
+ /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety>
+ unsafe
public RSAOpenSsl(System.IntPtr handle);
}
namespace System.Security.Cryptography.X509Certificates;
public partial class X509Certificate : System.IDisposable, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable
{
+ /// <safety>Wraps a raw, caller-supplied PCCERT_CONTEXT pointer that the certificate stack later dereferences.</safety>
+ unsafe
public X509Certificate(System.IntPtr handle);
}
namespace System.Security.Cryptography.X509Certificates;
public partial class X509Certificate2 : System.Security.Cryptography.X509Certificates.X509Certificate
{
+ /// <safety>Wraps a raw, caller-supplied PCCERT_CONTEXT pointer that the certificate stack later dereferences.</safety>
+ unsafe
public X509Certificate2(System.IntPtr handle);
}
namespace System.Security.Cryptography.X509Certificates;
public partial class X509Chain : System.IDisposable
{
+ /// <safety>Wraps a raw, caller-supplied PCCERT_CHAIN_CONTEXT pointer that the chain engine later dereferences.</safety>
+ unsafe
public X509Chain(System.IntPtr chainContext);
}
namespace System.Security.Cryptography.X509Certificates;
public sealed partial class X509Store : System.IDisposable
{
+ /// <safety>Wraps a raw, caller-supplied HCERTSTORE handle (a pointer to a native store) that the store stack later dereferences.</safety>
+ unsafe
public X509Store(System.IntPtr storeHandle);
}
namespace System.Diagnostics.SymbolStore;
public partial interface ISymbolBinder1
{
+ /// <safety>Dereferences a raw, caller-supplied native/COM importer interface pointer.</safety>
+ unsafe
System.Diagnostics.SymbolStore.ISymbolReader? GetReader(System.IntPtr importer, string filename, string searchPath);
}
namespace System.Diagnostics.SymbolStore;
public partial interface ISymbolWriter
{
+ /// <safety>Dereferences a raw, caller-supplied native/COM emitter interface pointer.</safety>
+ unsafe
void Initialize(System.IntPtr emitter, string filename, bool fFullBuild);
+ /// <safety>Dereferences a raw, caller-supplied native/COM writer interface pointer.</safety>
+ unsafe
void SetUnderlyingWriter(System.IntPtr underlyingWriter);
}
namespace System.Transactions;
public partial interface IDtcTransaction
{
+ /// <safety>Reads the abort-reason structure through a raw, caller-supplied IntPtr.</safety>
+ unsafe
void Abort(System.IntPtr reason, int retaining, int async);
+ /// <safety>Writes XACTTRANSINFO through a raw, caller-supplied IntPtr.</safety>
+ unsafe
void GetTransactionInfo(System.IntPtr transactionInformation);
}
namespace System.Security.Principal;
public sealed partial class SecurityIdentifier : System.Security.Principal.IdentityReference, System.IComparable<System.Security.Principal.SecurityIdentifier>
{
+ /// <safety>Reads the binary SID through a raw, caller-supplied address.</safety>
+ unsafe
public SecurityIdentifier(System.IntPtr binaryForm);
}
namespace System;
public struct RuntimeTypeHandle
{
+ /// <safety>Builds a handle from a raw, unvalidated MethodTable* pointer that the runtime later dereferences.</safety>
+ unsafe
public static RuntimeTypeHandle FromIntPtr(System.IntPtr value);
}
namespace System;
public struct RuntimeMethodHandle
{
+ /// <safety>Builds a handle from a raw, unvalidated MethodDesc* pointer that the runtime later dereferences.</safety>
+ unsafe
public static RuntimeMethodHandle FromIntPtr(System.IntPtr value);
}
namespace System;
public struct RuntimeFieldHandle
{
+ /// <safety>Builds a handle from a raw, unvalidated FieldDesc* pointer that the runtime later dereferences.</safety>
+ unsafe
public static RuntimeFieldHandle FromIntPtr(System.IntPtr value);
}
namespace System.Security.Cryptography;
public sealed partial class SafeEvpPKeyHandle : System.Runtime.InteropServices.SafeHandle
{
+ /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety>
+ unsafe
public SafeEvpPKeyHandle(System.IntPtr handle, bool ownsHandle);
}
namespace System.Buffers;
public abstract partial class ArrayPool<T>
{
+ /// <safety>Returns an array whose elements may be uninitialized — the shared pool allocates primitive-typed buffers via GC.AllocateUninitializedArray, so reads before writing observe leftover, undefined heap bytes.</safety>
+ unsafe
public abstract T[] Rent(int minimumLength);
}
namespace System.Buffers;
public abstract partial class MemoryPool<T> : System.IDisposable
{
+ /// <safety>Returns an IMemoryOwner whose Memory may be uninitialized — the shared pool rents from the shared ArrayPool (GC.AllocateUninitializedArray) and exposes the full rented buffer, so reads before writing observe leftover, undefined heap bytes.</safety>
+ unsafe
public abstract System.Buffers.IMemoryOwner<T> Rent(int minBufferSize = -1);
}
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafeAccessTokenHandle : System.Runtime.InteropServices.SafeHandle
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafeAccessTokenHandle(System.IntPtr handle);
}
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafeFileHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafeFileHandle(System.IntPtr preexistingHandle, bool ownsHandle);
}
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafeNCryptKeyHandle : Microsoft.Win32.SafeHandles.SafeNCryptHandle
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafeNCryptKeyHandle(System.IntPtr handle, System.Runtime.InteropServices.SafeHandle parentHandle);
}
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafePipeHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafePipeHandle(System.IntPtr preexistingHandle, bool ownsHandle);
}
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafeProcessHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafeProcessHandle(System.IntPtr existingHandle, bool ownsHandle);
}
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafeRegistryHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafeRegistryHandle(System.IntPtr preexistingHandle, bool ownsHandle);
}
namespace Microsoft.Win32.SafeHandles;
public sealed partial class SafeWaitHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafeWaitHandle(System.IntPtr existingHandle, bool ownsHandle);
}
namespace System.Net.Sockets;
public sealed partial class SafeSocketHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid
{
+ /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety>
+ unsafe
public SafeSocketHandle(nint preexistingHandle, bool ownsHandle);
}
API Usage
The annotated APIs will require unsafe { } context at their call site once the language-level unsafe requirement is enforced.
Alternative Designs
No response
Risks
No response
Background and motivation
#125145
API Proposal
namespace System; public static class GC { + /// <safety>Returns a T[] whose elements are not zero-initialized, so reads observe leftover, uninitialized heap bytes.</safety> + unsafe public static T[] AllocateUninitializedArray<T>(int length, bool pinned = false); }namespace System.Runtime.CompilerServices; public static class RuntimeHelpers { + /// <safety>Reads SizeOf(type) bytes from a caller-supplied reference and boxes them as that type; the bytes may be out of range, uninitialized, or contain a fabricated reference field.</safety> + unsafe public static object? Box(ref byte target, System.RuntimeTypeHandle type); }namespace System.Security.Cryptography; public sealed partial class DSAOpenSsl : System.Security.Cryptography.DSA { + /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety> + unsafe public DSAOpenSsl(System.IntPtr handle); }namespace System.Security.Cryptography; public sealed partial class ECDiffieHellmanOpenSsl : System.Security.Cryptography.ECDiffieHellman { + /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety> + unsafe public ECDiffieHellmanOpenSsl(System.IntPtr handle); }namespace System.Security.Cryptography; public sealed partial class ECDsaOpenSsl : System.Security.Cryptography.ECDsa { + /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety> + unsafe public ECDsaOpenSsl(System.IntPtr handle); }namespace System.Security.Cryptography; public sealed partial class RSAOpenSsl : System.Security.Cryptography.RSA { + /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety> + unsafe public RSAOpenSsl(System.IntPtr handle); }namespace System.Security.Cryptography.X509Certificates; public partial class X509Certificate : System.IDisposable, System.Runtime.Serialization.IDeserializationCallback, System.Runtime.Serialization.ISerializable { + /// <safety>Wraps a raw, caller-supplied PCCERT_CONTEXT pointer that the certificate stack later dereferences.</safety> + unsafe public X509Certificate(System.IntPtr handle); }namespace System.Security.Cryptography.X509Certificates; public partial class X509Certificate2 : System.Security.Cryptography.X509Certificates.X509Certificate { + /// <safety>Wraps a raw, caller-supplied PCCERT_CONTEXT pointer that the certificate stack later dereferences.</safety> + unsafe public X509Certificate2(System.IntPtr handle); }namespace System.Security.Cryptography.X509Certificates; public partial class X509Chain : System.IDisposable { + /// <safety>Wraps a raw, caller-supplied PCCERT_CHAIN_CONTEXT pointer that the chain engine later dereferences.</safety> + unsafe public X509Chain(System.IntPtr chainContext); }namespace System.Security.Cryptography.X509Certificates; public sealed partial class X509Store : System.IDisposable { + /// <safety>Wraps a raw, caller-supplied HCERTSTORE handle (a pointer to a native store) that the store stack later dereferences.</safety> + unsafe public X509Store(System.IntPtr storeHandle); }namespace System.Diagnostics.SymbolStore; public partial interface ISymbolBinder1 { + /// <safety>Dereferences a raw, caller-supplied native/COM importer interface pointer.</safety> + unsafe System.Diagnostics.SymbolStore.ISymbolReader? GetReader(System.IntPtr importer, string filename, string searchPath); }namespace System.Diagnostics.SymbolStore; public partial interface ISymbolWriter { + /// <safety>Dereferences a raw, caller-supplied native/COM emitter interface pointer.</safety> + unsafe void Initialize(System.IntPtr emitter, string filename, bool fFullBuild); + /// <safety>Dereferences a raw, caller-supplied native/COM writer interface pointer.</safety> + unsafe void SetUnderlyingWriter(System.IntPtr underlyingWriter); }namespace System.Transactions; public partial interface IDtcTransaction { + /// <safety>Reads the abort-reason structure through a raw, caller-supplied IntPtr.</safety> + unsafe void Abort(System.IntPtr reason, int retaining, int async); + /// <safety>Writes XACTTRANSINFO through a raw, caller-supplied IntPtr.</safety> + unsafe void GetTransactionInfo(System.IntPtr transactionInformation); }namespace System.Security.Principal; public sealed partial class SecurityIdentifier : System.Security.Principal.IdentityReference, System.IComparable<System.Security.Principal.SecurityIdentifier> { + /// <safety>Reads the binary SID through a raw, caller-supplied address.</safety> + unsafe public SecurityIdentifier(System.IntPtr binaryForm); }namespace System; public struct RuntimeTypeHandle { + /// <safety>Builds a handle from a raw, unvalidated MethodTable* pointer that the runtime later dereferences.</safety> + unsafe public static RuntimeTypeHandle FromIntPtr(System.IntPtr value); }namespace System; public struct RuntimeMethodHandle { + /// <safety>Builds a handle from a raw, unvalidated MethodDesc* pointer that the runtime later dereferences.</safety> + unsafe public static RuntimeMethodHandle FromIntPtr(System.IntPtr value); }namespace System; public struct RuntimeFieldHandle { + /// <safety>Builds a handle from a raw, unvalidated FieldDesc* pointer that the runtime later dereferences.</safety> + unsafe public static RuntimeFieldHandle FromIntPtr(System.IntPtr value); }namespace System.Security.Cryptography; public sealed partial class SafeEvpPKeyHandle : System.Runtime.InteropServices.SafeHandle { + /// <safety>Wraps a raw, caller-supplied EVP_PKEY* pointer that the crypto stack later dereferences.</safety> + unsafe public SafeEvpPKeyHandle(System.IntPtr handle, bool ownsHandle); }namespace System.Buffers; public abstract partial class ArrayPool<T> { + /// <safety>Returns an array whose elements may be uninitialized — the shared pool allocates primitive-typed buffers via GC.AllocateUninitializedArray, so reads before writing observe leftover, undefined heap bytes.</safety> + unsafe public abstract T[] Rent(int minimumLength); }namespace System.Buffers; public abstract partial class MemoryPool<T> : System.IDisposable { + /// <safety>Returns an IMemoryOwner whose Memory may be uninitialized — the shared pool rents from the shared ArrayPool (GC.AllocateUninitializedArray) and exposes the full rented buffer, so reads before writing observe leftover, undefined heap bytes.</safety> + unsafe public abstract System.Buffers.IMemoryOwner<T> Rent(int minBufferSize = -1); }namespace Microsoft.Win32.SafeHandles; public sealed partial class SafeAccessTokenHandle : System.Runtime.InteropServices.SafeHandle { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafeAccessTokenHandle(System.IntPtr handle); }namespace Microsoft.Win32.SafeHandles; public sealed partial class SafeFileHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafeFileHandle(System.IntPtr preexistingHandle, bool ownsHandle); }namespace Microsoft.Win32.SafeHandles; public sealed partial class SafeNCryptKeyHandle : Microsoft.Win32.SafeHandles.SafeNCryptHandle { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafeNCryptKeyHandle(System.IntPtr handle, System.Runtime.InteropServices.SafeHandle parentHandle); }namespace Microsoft.Win32.SafeHandles; public sealed partial class SafePipeHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafePipeHandle(System.IntPtr preexistingHandle, bool ownsHandle); }namespace Microsoft.Win32.SafeHandles; public sealed partial class SafeProcessHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafeProcessHandle(System.IntPtr existingHandle, bool ownsHandle); }namespace Microsoft.Win32.SafeHandles; public sealed partial class SafeRegistryHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafeRegistryHandle(System.IntPtr preexistingHandle, bool ownsHandle); }namespace Microsoft.Win32.SafeHandles; public sealed partial class SafeWaitHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafeWaitHandle(System.IntPtr existingHandle, bool ownsHandle); }namespace System.Net.Sockets; public sealed partial class SafeSocketHandle : Microsoft.Win32.SafeHandles.SafeHandleMinusOneIsInvalid { + /// <safety>Wraps a raw, caller-supplied OS handle; the safe Dispose/finalizer later closes it, so a bogus or non-owned handle can close an unrelated handle and corrupt process state.</safety> + unsafe public SafeSocketHandle(nint preexistingHandle, bool ownsHandle); }API Usage
The annotated APIs will require
unsafe { }context at their call site once the language-levelunsaferequirement is enforced.Alternative Designs
No response
Risks
No response