Skip to content

[API Proposal]: Batch #1 of caller-unsafe APIs #129751

Description

@EgorBo

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions