From 11e9cd1e40f5bdd0c50bd311a5c43f8efd4c2f45 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 May 2025 16:50:58 -0700 Subject: [PATCH 01/29] Use UnsafeAccessorType in StackFrameHelper --- .../System/Diagnostics/StackFrameHelper.cs | 45 ++++++------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs index fca904ac8482e2..4e0736cb78aa4f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs @@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; namespace System.Diagnostics @@ -38,11 +39,18 @@ internal sealed class StackFrameHelper private int iFrameCount; #pragma warning restore 414 - private delegate void GetSourceLineInfoDelegate(Assembly? assembly, string assemblyPath, IntPtr loadedPeAddress, + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType("System.Diagnostics.StackTraceSymbols, System.Diagnostics.StackTrace, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] + private static extern object CreateStackTraceSymbols(); + + [UnsafeAccessor(UnsafeAccessorKind.Method)] + private static extern void GetSourceLineInfo( + [UnsafeAccessorType("System.Diagnostics.StackTraceSymbols, System.Diagnostics.StackTrace, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] object target, + Assembly? assembly, string assemblyPath, IntPtr loadedPeAddress, int loadedPeSize, bool isFileLayout, IntPtr inMemoryPdbAddress, int inMemoryPdbSize, int methodToken, int ilOffset, out string? sourceFile, out int sourceLine, out int sourceColumn); - private static GetSourceLineInfoDelegate? s_getSourceLineInfo; + private static object? s_stackTraceSymbolsCache; [ThreadStatic] private static int t_reentrancy; @@ -97,38 +105,11 @@ internal void InitializeSourceInfo(bool fNeedFileInfo, Exception? exception) t_reentrancy++; try { - if (s_getSourceLineInfo == null) + if (s_stackTraceSymbolsCache == null) { - Type? symbolsType = Type.GetType( - "System.Diagnostics.StackTraceSymbols, System.Diagnostics.StackTrace, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", - throwOnError: false); - - if (symbolsType == null) - { - return; - } - - Type[] parameterTypes = - [ - typeof(Assembly), typeof(string), typeof(IntPtr), typeof(int), typeof(bool), typeof(IntPtr), - typeof(int), typeof(int), typeof(int), - typeof(string).MakeByRefType(), typeof(int).MakeByRefType(), typeof(int).MakeByRefType() - ]; - MethodInfo? symbolsMethodInfo = symbolsType.GetMethod("GetSourceLineInfo", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, parameterTypes, null); - if (symbolsMethodInfo == null) - { - return; - } - - // Create an instance of System.Diagnostics.Stacktrace.Symbols - object? target = Activator.CreateInstance(symbolsType); - - // Create an instance delegate for the GetSourceLineInfo method - GetSourceLineInfoDelegate getSourceLineInfo = symbolsMethodInfo.CreateDelegate(target); - // We could race with another thread. It doesn't matter if we win or lose, the losing instance will be GC'ed and all threads including this one will // use the winning instance - Interlocked.CompareExchange(ref s_getSourceLineInfo, getSourceLineInfo, null); + Interlocked.CompareExchange(ref s_stackTraceSymbolsCache, CreateStackTraceSymbols(), null); } for (int index = 0; index < iFrameCount; index++) @@ -137,7 +118,7 @@ internal void InitializeSourceInfo(bool fNeedFileInfo, Exception? exception) // ENC or the source/line info was already retrieved, the method token is 0. if (rgiMethodToken![index] != 0) { - s_getSourceLineInfo!(rgAssembly![index], rgAssemblyPath![index]!, rgLoadedPeAddress![index], rgiLoadedPeSize![index], rgiIsFileLayout![index], + GetSourceLineInfo(s_stackTraceSymbolsCache!, rgAssembly![index], rgAssemblyPath![index]!, rgLoadedPeAddress![index], rgiLoadedPeSize![index], rgiIsFileLayout![index], rgInMemoryPdbAddress![index], rgiInMemoryPdbSize![index], rgiMethodToken![index], rgiILOffset![index], out rgFilename![index], out rgiLineNumber![index], out rgiColumnNumber![index]); } From 6166c511b81de6fcb4e921a236a5c6bfa673a835 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 May 2025 19:28:21 -0700 Subject: [PATCH 02/29] Convert ComActivator to use UnsafeAccessorType --- .../Runtime/InteropServices/ComActivator.cs | 169 +++++++++--------- .../LicenseManager.LicenseInteropHelper.cs | 2 +- 2 files changed, 87 insertions(+), 84 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs index a649aa0ab335dd..6572d1cf64cd7f 100644 --- a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs +++ b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Loader; using System.Runtime.Versioning; @@ -616,7 +617,6 @@ public void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock) [RequiresUnreferencedCode("Built-in COM support is not trim compatible", Url = "https://aka.ms/dotnet-illink/com")] private sealed class LicenseClassFactory : IClassFactory2 { - private readonly LicenseInteropProxy _licenseProxy = new LicenseInteropProxy(); private readonly Guid _classId; [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces | DynamicallyAccessedMemberTypes.PublicConstructors)] @@ -643,7 +643,7 @@ public void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock) public void GetLicInfo(ref LICINFO licInfo) { - _licenseProxy.GetLicInfo(_classType, out bool runtimeKeyAvail, out bool licVerified); + LicenseInteropProxy.GetLicInfo(_classType, out bool runtimeKeyAvail, out bool licVerified); // The LICINFO is a struct with a DWORD size field and two BOOL fields. Each BOOL // is typedef'd from a DWORD, therefore the size is manually computed as below. @@ -654,7 +654,7 @@ public void GetLicInfo(ref LICINFO licInfo) public void RequestLicKey(int dwReserved, [MarshalAs(UnmanagedType.BStr)] out string pBstrKey) { - pBstrKey = _licenseProxy.RequestLicKey(_classType); + pBstrKey = LicenseInteropProxy.RequestLicKey(_classType); } public void CreateInstanceLic( @@ -677,7 +677,7 @@ private void CreateInstanceInner( { var interfaceType = BasicClassFactory.CreateValidatedInterfaceType(_classType, ref riid, pUnkOuter); - object obj = _licenseProxy.AllocateAndValidateLicense(_classType, key, isDesignTime); + object obj = LicenseInteropProxy.AllocateAndValidateLicense(_classType, key, isDesignTime); if (pUnkOuter != null) { obj = BasicClassFactory.CreateAggregatedObject(pUnkOuter, obj); @@ -699,52 +699,69 @@ internal sealed class LicenseInteropProxy private static readonly Type? s_licenseAttrType = Type.GetType("System.ComponentModel.LicenseProviderAttribute, System.ComponentModel.TypeConverter", throwOnError: false); private static readonly Type? s_licenseExceptionType = Type.GetType("System.ComponentModel.LicenseException, System.ComponentModel.TypeConverter", throwOnError: false); - // LicenseManager - private readonly MethodInfo _createWithContext; - - // LicenseInteropHelper - private readonly MethodInfo _validateTypeAndReturnDetails; - private readonly MethodInfo _getCurrentContextInfo; - - // CLRLicenseContext - private readonly MethodInfo _createDesignContext; - private readonly MethodInfo _createRuntimeContext; - - // LicenseContext - private readonly MethodInfo _setSavedLicenseKey; - - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] - private readonly Type _licInfoHelper; - - private readonly MethodInfo _licInfoHelperContains; + private const string LicenseManagerTypeName = "System.ComponentModel.LicenseManager, System.ComponentModel.TypeConverter"; + private const string LicenseContextTypeName = "System.ComponentModel.LicenseContext, System.ComponentModel.TypeConverter"; + private const string LicenseInteropHelperTypeName = "System.ComponentModel.LicenseManager+LicenseInteropHelper, System.ComponentModel.TypeConverter"; + private const string CLRLicenseContextTypeName = "System.ComponentModel.LicenseManager+CLRLicenseContext, System.ComponentModel.TypeConverter"; + private const string LicenseTypeName = "System.ComponentModel.License, System.ComponentModel.TypeConverter"; + private const string LicInfoHelperLicenseContextTypeName = "System.ComponentModel.LicenseManager+LicInfoHelperLicenseContext, System.ComponentModel.TypeConverter"; + + [UnsafeAccessor(UnsafeAccessorKind.Method)] + private static extern void SetSavedLicenseKey( + [UnsafeAccessorType(LicenseContextTypeName)] object licContext, + Type type, + string key); + + [UnconditionalSuppressMessage("Trimming", "IL2111", Justification = "Manually validated that the annotations are kept in sync.")] + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + private static extern object? CreateWithContext( + [UnsafeAccessorType(LicenseManagerTypeName)] object? licManager, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, + [UnsafeAccessorType(LicenseContextTypeName)] object licContext + ); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + private static extern bool ValidateAndRetrieveLicenseDetails( + [UnsafeAccessorType(LicenseInteropHelperTypeName)] object? licInteropHelper, + [UnsafeAccessorType(LicenseContextTypeName)] object? licContext, + Type type, + [UnsafeAccessorType(LicenseTypeName)] out object? license, + out string? licenseKey); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + [return: UnsafeAccessorType(LicenseContextTypeName)] + private static extern object? GetCurrentContextInfo( + [UnsafeAccessorType(LicenseInteropHelperTypeName)] object? licInteropHelper, + Type type, + out bool isDesignTime, + out string? key); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + [return: UnsafeAccessorType(CLRLicenseContextTypeName)] + private static extern object CreateDesignContext( + [UnsafeAccessorType(CLRLicenseContextTypeName)] object? context, + Type type); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + [return: UnsafeAccessorType(CLRLicenseContextTypeName)] + private static extern object CreateRuntimeContext( + [UnsafeAccessorType(CLRLicenseContextTypeName)] object? context, + Type type, + string? key); + + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return:UnsafeAccessorType(LicInfoHelperLicenseContextTypeName)] + private static extern object? CreateLicInfoHelperLicenseContext(); + + [UnsafeAccessor(UnsafeAccessorKind.Method)] + private static extern bool Contains( + [UnsafeAccessorType(LicInfoHelperLicenseContextTypeName)] object? licInfoHelperContext, + string assemblyName); // RCW Activation private object? _licContext; private Type? _targetRcwType; - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2111:ReflectionToDynamicallyAccessedMembers", - Justification = "The type parameter to LicenseManager.CreateWithContext method has PublicConstructors annotation. We only invoke this method" + - "from AllocateAndValidateLicense which annotates the value passed in with the same annotation.")] - public LicenseInteropProxy() - { - Type licManager = Type.GetType("System.ComponentModel.LicenseManager, System.ComponentModel.TypeConverter", throwOnError: true)!; - - Type licContext = Type.GetType("System.ComponentModel.LicenseContext, System.ComponentModel.TypeConverter", throwOnError: true)!; - _setSavedLicenseKey = licContext.GetMethod("SetSavedLicenseKey", BindingFlags.Instance | BindingFlags.Public)!; - _createWithContext = licManager.GetMethod("CreateWithContext", [typeof(Type), licContext])!; - - Type interopHelper = licManager.GetNestedType("LicenseInteropHelper", BindingFlags.NonPublic)!; - _validateTypeAndReturnDetails = interopHelper.GetMethod("ValidateAndRetrieveLicenseDetails", BindingFlags.Static | BindingFlags.Public)!; - _getCurrentContextInfo = interopHelper.GetMethod("GetCurrentContextInfo", BindingFlags.Static | BindingFlags.Public)!; - - Type clrLicContext = licManager.GetNestedType("CLRLicenseContext", BindingFlags.NonPublic)!; - _createDesignContext = clrLicContext.GetMethod("CreateDesignContext", BindingFlags.Static | BindingFlags.Public)!; - _createRuntimeContext = clrLicContext.GetMethod("CreateRuntimeContext", BindingFlags.Static | BindingFlags.Public)!; - - _licInfoHelper = licManager.GetNestedType("LicInfoHelperLicenseContext", BindingFlags.NonPublic)!; - _licInfoHelperContains = _licInfoHelper.GetMethod("Contains", BindingFlags.Instance | BindingFlags.Public)!; - } - // Helper function to create an object from the native side public static object Create() { @@ -769,35 +786,35 @@ public static bool HasLicense(Type type) // // COM normally doesn't expect this function to fail so this method // should only throw in the case of a catastrophic error (stack, memory, etc.) - public void GetLicInfo(Type type, out bool runtimeKeyAvail, out bool licVerified) + public static void GetLicInfo(Type type, out bool runtimeKeyAvail, out bool licVerified) { runtimeKeyAvail = false; licVerified = false; - // Types are as follows: - // LicenseContext, Type, out License, out string - object licContext = Activator.CreateInstance(_licInfoHelper)!; - var parameters = new object?[] { licContext, type, /* out */ null, /* out */ null }; - bool isValid = (bool)_validateTypeAndReturnDetails.Invoke(null, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null)!; + object? licContext = CreateLicInfoHelperLicenseContext(); + bool isValid = ValidateAndRetrieveLicenseDetails(null!, licContext!, type, out object? license, out _); if (!isValid) { return; } - var license = (IDisposable?)parameters[2]; - if (license != null) + if (license is IDisposable disp) { - license.Dispose(); + // Dispose of the license if it implements IDisposable + // and we are not in design mode. This is a bit of a hack + // but we need to do this to avoid leaking the license. + // The license will be disposed of when the context is + // disposed of. + disp.Dispose(); licVerified = true; } - parameters = [type.AssemblyQualifiedName]; - runtimeKeyAvail = (bool)_licInfoHelperContains.Invoke(licContext, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null)!; + runtimeKeyAvail = Contains(licContext, type.AssemblyQualifiedName!); } // The CLR invokes this whenever a COM client invokes // IClassFactory2::RequestLicKey on a managed class. - public string RequestLicKey(Type type) + public static string RequestLicKey(Type type) { // License will be null, since we passed no instance, // however we can still retrieve the "first" license @@ -806,20 +823,14 @@ public string RequestLicKey(Type type) // like LicFileLicenseProvider that don't require the // instance to grant a key. - // Types are as follows: - // LicenseContext, Type, out License, out string - var parameters = new object?[] { /* use global LicenseContext */ null, type, /* out */ null, /* out */ null }; - bool isValid = (bool)_validateTypeAndReturnDetails.Invoke(null, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null)!; - if (!isValid) + if (!ValidateAndRetrieveLicenseDetails(null, null, type, out object? license, out string? licenseKey)) { throw new COMException(); // E_FAIL } - ((IDisposable?)parameters[2])?.Dispose(); - - var licenseKey = (string?)parameters[3] ?? throw new COMException(); // E_FAIL + ((IDisposable?)license)?.Dispose(); - return licenseKey; + return licenseKey ?? throw new COMException(); // E_FAIL } // The CLR invokes this whenever a COM client invokes @@ -832,25 +843,21 @@ public string RequestLicKey(Type type) // If we are being entered because of a call to ICF::CreateInstanceLic(), // "isDesignTime" will be "false" and "key" will point to a non-null // license key. - public object AllocateAndValidateLicense([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, string? key, bool isDesignTime) + public static object AllocateAndValidateLicense([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type, string? key, bool isDesignTime) { - object?[] parameters; - object? licContext; + object licContext; if (isDesignTime) { - parameters = [type]; - licContext = _createDesignContext.Invoke(null, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null); + licContext = CreateDesignContext(null, type); } else { - parameters = [type, key]; - licContext = _createRuntimeContext.Invoke(null, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null); + licContext = CreateRuntimeContext(null, type, key); } try { - parameters = [type, licContext]; - return _createWithContext.Invoke(null, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null)!; + return CreateWithContext(null, type, licContext)!; } catch (Exception exception) when (exception.GetType() == s_licenseExceptionType) { @@ -864,14 +871,10 @@ public void GetCurrentContextInfo(RuntimeTypeHandle rth, out bool isDesignTime, { Type targetRcwTypeMaybe = Type.GetTypeFromHandle(rth)!; - // Types are as follows: - // Type, out bool, out string -> LicenseContext - var parameters = new object?[] { targetRcwTypeMaybe, /* out */ null, /* out */ null }; - _licContext = _getCurrentContextInfo.Invoke(null, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null); + _licContext = GetCurrentContextInfo(null, targetRcwTypeMaybe, out isDesignTime, out string? key); _targetRcwType = targetRcwTypeMaybe; - isDesignTime = (bool)parameters[1]!; - bstrKey = Marshal.StringToBSTR((string)parameters[2]!); + bstrKey = Marshal.StringToBSTR((string)key!); } // The CLR invokes this when instantiating a licensed COM @@ -886,8 +889,8 @@ public void SaveKeyInCurrentContext(IntPtr bstrKey) } string key = Marshal.PtrToStringBSTR(bstrKey); - var parameters = new object?[] { _targetRcwType, key }; - _setSavedLicenseKey.Invoke(_licContext, BindingFlags.DoNotWrapExceptions, binder: null, parameters: parameters, culture: null); + + SetSavedLicenseKey(_licContext!, _targetRcwType!, key); } } } diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/LicenseManager.LicenseInteropHelper.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/LicenseManager.LicenseInteropHelper.cs index 31ad7d28060722..80e0e256346e78 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/LicenseManager.LicenseInteropHelper.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/LicenseManager.LicenseInteropHelper.cs @@ -83,7 +83,7 @@ private static class LicenseInteropHelper // Used to validate a type and retrieve license details // when activating a managed COM server from an IClassFactory2 instance. public static bool ValidateAndRetrieveLicenseDetails( - LicenseContext context, + LicenseContext? context, Type type, out License? license, out string? licenseKey) From df05d6b3a5df56db2a4d754d1ae7635739d00ef2 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 May 2025 19:37:40 -0700 Subject: [PATCH 03/29] ConvertDefaultValueAttribute to use UnsafeAccessorType --- .../ComponentModel/DefaultValueAttribute.cs | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/DefaultValueAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/ComponentModel/DefaultValueAttribute.cs index 40d082a8c406e8..f36cd0d0544803 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ComponentModel/DefaultValueAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ComponentModel/DefaultValueAttribute.cs @@ -4,7 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; namespace System.ComponentModel @@ -20,9 +20,6 @@ public class DefaultValueAttribute : Attribute /// private object? _value; - // Delegate ad hoc created 'TypeDescriptor.ConvertFromInvariantString' reflection object cache - private static object? s_convertFromInvariantString; - [FeatureSwitchDefinition("System.ComponentModel.DefaultValueAttribute.IsSupported")] [FeatureGuard(typeof(RequiresUnreferencedCodeAttribute))] #pragma warning disable IL4000 @@ -82,20 +79,9 @@ static bool TryConvertFromInvariantString( { conversionResult = null; - // lazy init reflection objects - if (s_convertFromInvariantString == null) - { - Type? typeDescriptorType = Type.GetType("System.ComponentModel.TypeDescriptor, System.ComponentModel.TypeConverter", throwOnError: false); - MethodInfo? mi = typeDescriptorType?.GetMethod("ConvertFromInvariantString", BindingFlags.NonPublic | BindingFlags.Static); - s_convertFromInvariantString = mi == null ? new object() : mi.CreateDelegate>(); - } - - if (s_convertFromInvariantString is not Func convertFromInvariantString) - return false; - try { - conversionResult = convertFromInvariantString(typeToConvert, stringValue); + conversionResult = ConvertFromInvariantString(null, typeToConvert, stringValue!); } catch { @@ -103,6 +89,14 @@ static bool TryConvertFromInvariantString( } return true; + + [RequiresUnreferencedCode("DefaultValueAttribute usage of TypeConverter is not compatible with trimming.")] + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "ConvertFromInvariantString")] + static extern object ConvertFromInvariantString( + [UnsafeAccessorType("System.ComponentModel.TypeDescriptor, System.ComponentModel.TypeConverter")] object? _, + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type type, + string stringValue + ); } } catch From 22cd4be0f561a5a48958c6c5c139a3bd0cce40d6 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 May 2025 19:52:53 -0700 Subject: [PATCH 04/29] Move AppDomain to use UnsafeAccessorType --- .../src/System/AppDomain.cs | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs index b13dd6137cc980..c78b82a074d6b3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs @@ -7,6 +7,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.Loader; using System.Runtime.Remoting; @@ -23,8 +24,6 @@ public sealed partial class AppDomain : MarshalByRefObject private IPrincipal? _defaultPrincipal; private PrincipalPolicy _principalPolicy = PrincipalPolicy.NoPrincipal; - private Func? s_getWindowsPrincipal; - private Func? s_getUnauthenticatedPrincipal; private AppDomain() { } @@ -404,34 +403,32 @@ public void SetThreadPrincipal(IPrincipal principal) switch (_principalPolicy) { case PrincipalPolicy.UnauthenticatedPrincipal: - if (s_getUnauthenticatedPrincipal == null) - { - Type type = Type.GetType("System.Security.Principal.GenericPrincipal, System.Security.Claims", throwOnError: true)!; - MethodInfo? mi = type.GetMethod("GetDefaultInstance", BindingFlags.NonPublic | BindingFlags.Static); - Debug.Assert(mi != null); - // Don't throw PNSE if null like for WindowsPrincipal as UnauthenticatedPrincipal should - // be available on all platforms. - s_getUnauthenticatedPrincipal = mi.CreateDelegate>(); - } - - principal = s_getUnauthenticatedPrincipal(); + principal = GetDefaultPrincipal(null); break; - case PrincipalPolicy.WindowsPrincipal: - if (s_getWindowsPrincipal == null) + try { - Type type = Type.GetType("System.Security.Principal.WindowsPrincipal, System.Security.Principal.Windows", throwOnError: true)!; - MethodInfo mi = type.GetMethod("GetDefaultInstance", BindingFlags.NonPublic | BindingFlags.Static) ?? - throw new PlatformNotSupportedException(SR.PlatformNotSupported_Principal); - s_getWindowsPrincipal = mi.CreateDelegate>(); + principal = GetDefaultWindowsPrincipal(null); + break; + } + catch (TypeLoadException ex) + { + // WindowsPrincipal is not available, throw PNSE + throw new PlatformNotSupportedException(SR.PlatformNotSupported_Principal, ex); } - - principal = s_getWindowsPrincipal(); - break; } } return principal; + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetDefaultInstance")] + static extern IPrincipal GetDefaultPrincipal( + [UnsafeAccessorType("System.Security.Principal.GenericPrincipal, System.Security.Claims")] object? _); + + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetDefaultInstance")] + static extern IPrincipal GetDefaultWindowsPrincipal( + [UnsafeAccessorType("System.Security.Principal.WindowsPrincipal, System.Security.Claims")] object? _); } } } From 7cee5e348d32ea3ea52eb8761717e81217f365bf Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 13 May 2025 20:06:06 -0700 Subject: [PATCH 05/29] Convert ResourceReader to use UnsafeAccessorType --- .../System/Resources/ResourceReader.Core.cs | 74 +++++++++---------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs index 80e7c851145ed1..a1ba5901e16d56 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs @@ -19,10 +19,6 @@ public partial class ResourceReader private object? _binaryFormatter; // binary formatter instance to use for deserializing // statics used to dynamically call into BinaryFormatter - // When successfully located s_binaryFormatterType will point to the BinaryFormatter type - // and s_deserializeMethod will point to an unbound delegate to the deserialize method. - [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] - private static Type? s_binaryFormatterType; private static Func? s_deserializeMethod; // This is the constructor the RuntimeResourceSet calls, @@ -69,19 +65,34 @@ private object DeserializeObject(int typeIndex) if (Volatile.Read(ref _binaryFormatter) is null) { - if (!InitializeBinaryFormatterLocal()) + try { - // Trimming took away the BinaryFormatter implementation and we can't call into it. - // We'll throw an exception with the same text that BinaryFormatter would have thrown - // had we been able to call into it. Keep this resource string in sync with the same - // resource from the Formatters assembly. - throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed); + if (!InitializeBinaryFormatterLocal()) + { + // Trimming took away the BinaryFormatter implementation and we can't call into it. + // We'll throw an exception with the same text that BinaryFormatter would have thrown + // had we been able to call into it. Keep this resource string in sync with the same + // resource from the Formatters assembly. + throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed); + } + } + catch (Exception ex) when (ex is TypeLoadException or MissingMethodException) + { + throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed, ex); + } } - } Type type = FindType(typeIndex); - object graph = s_deserializeMethod!(_binaryFormatter, _store.BaseStream); + object graph; + try + { + graph = s_deserializeMethod!(_binaryFormatter, _store.BaseStream); + } + catch (Exception ex) when (ex is TypeLoadException or MissingMethodException) + { + throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed, ex); + } // guard against corrupted resources if (graph.GetType() != type) @@ -96,38 +107,23 @@ private object DeserializeObject(int typeIndex) "Custom readers as well as custom objects on the resources file are not observable by the trimmer and so required assemblies, types and members may be removed.")] private bool InitializeBinaryFormatter() { + const string BinaryFormatterTypeName = "System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, System.Runtime.Serialization.Formatters"; // If BinaryFormatter support is disabled for the app, the trimmer will replace this entire - // method body with "return false;", skipping all reflection code below. - - if (Volatile.Read(ref s_binaryFormatterType) is null || Volatile.Read(ref s_deserializeMethod) is null) - { - Type binaryFormatterType = Type.GetType("System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, System.Runtime.Serialization.Formatters", throwOnError: true)!; - MethodInfo? binaryFormatterDeserialize = binaryFormatterType.GetMethod("Deserialize", [typeof(Stream)]); - Func? deserializeMethod = (Func?) - typeof(ResourceReader) - .GetMethod(nameof(CreateUntypedDelegate), BindingFlags.NonPublic | BindingFlags.Static) - ?.MakeGenericMethod(binaryFormatterType) - .Invoke(null, new[] { binaryFormatterDeserialize }); - - Interlocked.CompareExchange(ref s_binaryFormatterType, binaryFormatterType, null); - Interlocked.CompareExchange(ref s_deserializeMethod, deserializeMethod, null); - } + // method body with "return false;", skipping the UnsafeAccessors below. + Volatile.Write(ref _binaryFormatter, CreateBinaryFormatter()); + Volatile.Write(ref s_deserializeMethod, Deserialize); - Volatile.Write(ref _binaryFormatter, Activator.CreateInstance(s_binaryFormatterType!)); + return true; - return s_deserializeMethod != null; - } - - // generic method that we specialize at runtime once we've loaded the BinaryFormatter type - // permits creating an unbound delegate so that we can avoid reflection after the initial - // lightup code completes. - private static Func CreateUntypedDelegate(MethodInfo method) - { - Func typedDelegate = (Func)Delegate.CreateDelegate(typeof(Func), null, method); + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType(BinaryFormatterTypeName)] + static extern object? CreateBinaryFormatter(); - return (obj, stream) => typedDelegate((TInstance)obj, stream); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Deserialize")] + static extern object Deserialize( + [UnsafeAccessorType(BinaryFormatterTypeName)] object? formatter, + Stream serializationStream); } - private static bool ValidateReaderType(string readerType) { return ResourceManager.IsDefaultType(readerType, ResourceManager.ResReaderTypeName); From 7b696e75afbf8233711dba87a12f6ce1239fd5fd Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 14 May 2025 11:57:08 -0700 Subject: [PATCH 06/29] Convert X509ResourceClient to use UnsafeAccessor --- .../src/System/Net/Http/X509ResourceClient.cs | 179 ++++++++++-------- 1 file changed, 98 insertions(+), 81 deletions(-) diff --git a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs index 3b54a30b7c89a3..369e1ce45e0e71 100644 --- a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs +++ b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -80,6 +81,73 @@ internal static partial class X509ResourceClient return null; } + private const string SocketsHttpHandlerTypeName = "System.Net.Http.SocketsHttpHandler, System.Net.Http"; + private const string HttpMessageHandlerTypeName = "System.Net.Http.HttpMessageHandler, System.Net.Http"; + private const string HttpClientTypeName = "System.Net.Http.HttpClient, System.Net.Http"; + private const string HttpRequestMessageTypeName = "System.Net.Http.HttpRequestMessage, System.Net.Http"; + private const string HttpResponseMessageTypeName = "System.Net.Http.HttpResponseMessage, System.Net.Http"; + private const string HttpResponseHeadersTypeName = "System.Net.Http.Headers.HttpResponseHeaders, System.Net.Http"; + private const string HttpContentTypeName = "System.Net.Http.HttpContent, System.Net.Http"; + private const string TaskOfHttpResponseMessageTypeName = "System.Threading.Tasks.Task`1[[System.Net.Http.HttpResponseMessage, System.Net.Http]], System.Runtime"; + + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType(SocketsHttpHandlerTypeName)] + private static extern object? CreateHttpHandler(); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_PooledConnectionIdleTimeout")] + private static extern TimeSpan GetPooledConnectionIdleTimeout([UnsafeAccessorType(SocketsHttpHandlerTypeName)] object handler); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_AllowAutoRedirect")] + private static extern bool GetAllowAutoRedirect([UnsafeAccessorType(SocketsHttpHandlerTypeName)] object handler); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_AllowAutoRedirect")] + private static extern void SetAllowAutoRedirect([UnsafeAccessorType(SocketsHttpHandlerTypeName)] object handler, bool value); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_PooledConnectionIdleTimeout")] + private static extern void SetPooledConnectionIdleTimeout([UnsafeAccessorType(SocketsHttpHandlerTypeName)] object handler, TimeSpan value); + + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType(HttpClientTypeName)] + private static extern object? CreateHttpClient([UnsafeAccessorType(HttpMessageHandlerTypeName)] object handler); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_MaxResponseContentBufferSize")] + private static extern long GetMaxResponseContentBufferSize([UnsafeAccessorType(HttpClientTypeName)] object client); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_MaxResponseContentBufferSize")] + private static extern void SetMaxResponseContentBufferSize([UnsafeAccessorType(HttpClientTypeName)] object client, long value); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_RequestUri")] + private static extern Uri? GetRequestUri([UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_RequestUri")] + private static extern void SetRequestUri([UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage, Uri? value); + + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType(HttpRequestMessageTypeName)] + private static extern object? CreateRequestMessage(); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Send")] + [return: UnsafeAccessorType(HttpResponseMessageTypeName)] + private static extern object? Send([UnsafeAccessorType(HttpClientTypeName)] object client, [UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage, CancellationToken cancellationToken); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "SendAsync")] + [return: UnsafeAccessorType(TaskOfHttpResponseMessageTypeName)] + private static extern object? SendAsync([UnsafeAccessorType(HttpClientTypeName)] object client, [UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage, CancellationToken cancellationToken); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Content")] + [return: UnsafeAccessorType(HttpContentTypeName)] + private static extern object? GetContent([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_StatusCode")] + private static extern int GetStatusCode([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Headers")] + [return: UnsafeAccessorType(HttpResponseHeadersTypeName)] + private static extern object? GetHeaders([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Location")] + private static extern Uri? GetLocation([UnsafeAccessorType(HttpResponseHeadersTypeName)] object headers); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "ReadAsStream")] + private static extern Stream ReadAsStream([UnsafeAccessorType(HttpContentTypeName)] object content); + private static Func>? CreateDownloadBytesFunc() { try @@ -89,48 +157,13 @@ internal static partial class X509ResourceClient // the latter can't in turn have an explicit dependency on the former. // Get the relevant types needed. - Type? socketsHttpHandlerType = Type.GetType("System.Net.Http.SocketsHttpHandler, System.Net.Http", throwOnError: false); - Type? httpMessageHandlerType = Type.GetType("System.Net.Http.HttpMessageHandler, System.Net.Http", throwOnError: false); - Type? httpClientType = Type.GetType("System.Net.Http.HttpClient, System.Net.Http", throwOnError: false); - Type? httpRequestMessageType = Type.GetType("System.Net.Http.HttpRequestMessage, System.Net.Http", throwOnError: false); - Type? httpResponseMessageType = Type.GetType("System.Net.Http.HttpResponseMessage, System.Net.Http", throwOnError: false); - Type? httpResponseHeadersType = Type.GetType("System.Net.Http.Headers.HttpResponseHeaders, System.Net.Http", throwOnError: false); - Type? httpContentType = Type.GetType("System.Net.Http.HttpContent, System.Net.Http", throwOnError: false); - Type? taskOfHttpResponseMessageType = Type.GetType("System.Threading.Tasks.Task`1[[System.Net.Http.HttpResponseMessage, System.Net.Http]], System.Runtime", throwOnError: false); - - if (socketsHttpHandlerType == null || httpMessageHandlerType == null || httpClientType == null || httpRequestMessageType == null || - httpResponseMessageType == null || httpResponseHeadersType == null || httpContentType == null || taskOfHttpResponseMessageType == null) - { - Debug.Fail("Unable to load required type."); - return null; - } + Type? taskOfHttpResponseMessageType = Type.GetType(TaskOfHttpResponseMessageTypeName, throwOnError: false); + + PropertyInfo? taskResultProperty = taskOfHttpResponseMessageType?.GetProperty("Result"); - // Get the methods on those types. - ConstructorInfo? socketsHttpHandlerCtor = socketsHttpHandlerType.GetConstructor(Type.EmptyTypes); - PropertyInfo? pooledConnectionIdleTimeoutProp = socketsHttpHandlerType.GetProperty("PooledConnectionIdleTimeout"); - PropertyInfo? allowAutoRedirectProp = socketsHttpHandlerType.GetProperty("AllowAutoRedirect"); - ConstructorInfo? httpClientCtor = httpClientType.GetConstructor(new Type[] { httpMessageHandlerType }); - PropertyInfo? requestUriProp = httpRequestMessageType.GetProperty("RequestUri"); - ConstructorInfo? httpRequestMessageCtor = httpRequestMessageType.GetConstructor(Type.EmptyTypes); - MethodInfo? sendMethod = httpClientType.GetMethod("Send", new Type[] { httpRequestMessageType, typeof(CancellationToken) }); - MethodInfo? sendAsyncMethod = httpClientType.GetMethod("SendAsync", new Type[] { httpRequestMessageType, typeof(CancellationToken) }); - PropertyInfo? maxResponseContentBufferSizeProp = httpClientType.GetProperty("MaxResponseContentBufferSize"); - PropertyInfo? responseContentProp = httpResponseMessageType.GetProperty("Content"); - PropertyInfo? responseStatusCodeProp = httpResponseMessageType.GetProperty("StatusCode"); - PropertyInfo? responseHeadersProp = httpResponseMessageType.GetProperty("Headers"); - PropertyInfo? responseHeadersLocationProp = httpResponseHeadersType.GetProperty("Location"); - MethodInfo? readAsStreamMethod = httpContentType.GetMethod("ReadAsStream", Type.EmptyTypes); - PropertyInfo? taskOfHttpResponseMessageResultProp = taskOfHttpResponseMessageType.GetProperty("Result"); - - if (socketsHttpHandlerCtor == null || pooledConnectionIdleTimeoutProp == null || - allowAutoRedirectProp == null || httpClientCtor == null || - requestUriProp == null || httpRequestMessageCtor == null || - sendMethod == null || sendAsyncMethod == null || maxResponseContentBufferSizeProp == null || - responseContentProp == null || responseStatusCodeProp == null || - responseHeadersProp == null || responseHeadersLocationProp == null || - readAsStreamMethod == null || taskOfHttpResponseMessageResultProp == null) + if (taskResultProperty == null) { - Debug.Fail("Unable to load required members."); + Debug.Fail("Unable to load required type."); return null; } @@ -138,18 +171,13 @@ internal static partial class X509ResourceClient const int PooledConnectionIdleTimeoutSeconds = 15; const int MaxRedirections = 10; - // Equivalent of: - // var socketsHttpHandler = new SocketsHttpHandler() { - // PooledConnectionIdleTimeout = TimeSpan.FromSeconds(PooledConnectionIdleTimeoutSeconds), - // AllowAutoRedirect = false - // }; - // var httpClient = new HttpClient(socketsHttpHandler); - // Note: using a ConstructorInfo instead of Activator.CreateInstance, so the ILLinker can see the usage through the lambda method. - object? socketsHttpHandler = socketsHttpHandlerCtor.Invoke(null); - pooledConnectionIdleTimeoutProp.SetValue(socketsHttpHandler, TimeSpan.FromSeconds(PooledConnectionIdleTimeoutSeconds)); - allowAutoRedirectProp.SetValue(socketsHttpHandler, false); - object? httpClient = httpClientCtor.Invoke(new object?[] { socketsHttpHandler }); - maxResponseContentBufferSizeProp.SetValue(httpClient, AiaDownloadLimit); + // Use UnsafeAccessors for construction and property access + object? socketsHttpHandler = CreateHttpHandler(); + SetAllowAutoRedirect(socketsHttpHandler!, false); + SetPooledConnectionIdleTimeout(socketsHttpHandler!, TimeSpan.FromSeconds(PooledConnectionIdleTimeoutSeconds)); + + object? httpClient = CreateHttpClient(socketsHttpHandler!); + SetMaxResponseContentBufferSize(httpClient!, AiaDownloadLimit); return async (string uriString, CancellationToken cancellationToken, bool async) => { @@ -160,23 +188,19 @@ internal static partial class X509ResourceClient return null; } - // Equivalent of: - // HttpRequestMessage requestMessage = new HttpRequestMessage() { RequestUri = new Uri(uri) }; - // HttpResponseMessage responseMessage = httpClient.Send(requestMessage, cancellationToken); - // Note: using a ConstructorInfo instead of Activator.CreateInstance, so the ILLinker can see the usage through the lambda method. - object requestMessage = httpRequestMessageCtor.Invoke(null); - requestUriProp.SetValue(requestMessage, uri); + object requestMessage = CreateRequestMessage()!; + SetRequestUri(requestMessage, uri); object responseMessage; if (async) { - Task sendTask = (Task)sendAsyncMethod.Invoke(httpClient, new object[] { requestMessage, cancellationToken })!; - await sendTask.ConfigureAwait(false); - responseMessage = taskOfHttpResponseMessageResultProp.GetValue(sendTask)!; + object sendTask = SendAsync(httpClient!, requestMessage, cancellationToken)!; + await ((Task)sendTask).ConfigureAwait(false); + responseMessage = taskResultProperty.GetValue(sendTask)!; } else { - responseMessage = sendMethod.Invoke(httpClient, new object[] { requestMessage, cancellationToken })!; + responseMessage = Send(httpClient!, requestMessage, cancellationToken)!; } int redirections = 0; @@ -184,10 +208,10 @@ internal static partial class X509ResourceClient bool hasRedirect; while (true) { - int statusCode = (int)responseStatusCodeProp.GetValue(responseMessage)!; - object responseHeaders = responseHeadersProp.GetValue(responseMessage)!; - Uri? location = (Uri?)responseHeadersLocationProp.GetValue(responseHeaders); - redirectUri = GetUriForRedirect((Uri)requestUriProp.GetValue(requestMessage)!, statusCode, location, out hasRedirect); + int statusCode = GetStatusCode(responseMessage); + object responseHeaders = GetHeaders(responseMessage)!; + Uri? location = GetLocation(responseHeaders); + redirectUri = GetUriForRedirect(GetRequestUri(requestMessage)!, statusCode, location, out hasRedirect); if (redirectUri == null) { break; @@ -199,28 +223,23 @@ internal static partial class X509ResourceClient if (redirections > MaxRedirections) { ReportRedirectsExceeded(); - return null; } ReportRedirected(redirectUri); - // Equivalent of: - // requestMessage = new HttpRequestMessage() { RequestUri = redirectUri }; - // requestMessage.RequestUri = redirectUri; - // responseMessage = httpClient.Send(requestMessage, cancellationToken); - requestMessage = httpRequestMessageCtor.Invoke(null); - requestUriProp.SetValue(requestMessage, redirectUri); + requestMessage = CreateRequestMessage()!; + SetRequestUri(requestMessage, redirectUri); if (async) { - Task sendTask = (Task)sendAsyncMethod.Invoke(httpClient, new object[] { requestMessage, cancellationToken })!; - await sendTask.ConfigureAwait(false); - responseMessage = taskOfHttpResponseMessageResultProp.GetValue(sendTask)!; + object sendTask = SendAsync(httpClient!, requestMessage, cancellationToken)!; + await ((Task)sendTask).ConfigureAwait(false); + responseMessage = taskResultProperty.GetValue(sendTask)!; } else { - responseMessage = sendMethod.Invoke(httpClient, new object[] { requestMessage, cancellationToken })!; + responseMessage = Send(httpClient!, requestMessage, cancellationToken)!; } } @@ -229,10 +248,8 @@ internal static partial class X509ResourceClient return null; } - // Equivalent of: - // using Stream responseStream = resp.Content.ReadAsStream(); - object content = responseContentProp.GetValue(responseMessage)!; - using Stream responseStream = (Stream)readAsStreamMethod.Invoke(content, null)!; + object content = GetContent(responseMessage)!; + using Stream responseStream = ReadAsStream(content); var result = new MemoryStream(); if (async) From 15d985f7275e245d476814c845aa0eec80bc473d Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 14 May 2025 13:01:49 -0700 Subject: [PATCH 07/29] Convert TypeDescriptor to use UnsafeAccessorType --- .../src/System/ComponentModel/TypeDescriptor.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs index 6b782a9fdda039..350f782851a89c 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs @@ -10,6 +10,7 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Threading; @@ -3044,6 +3045,10 @@ private sealed class TypeDescriptorComObject // string method is the failure is silent during type load making diagnosing the issue difficult. private sealed class ComNativeDescriptorProxy : TypeDescriptionProvider { + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, System.Windows.Forms")] + private static extern object CreateComNativeDescriptor(); + private readonly TypeDescriptionProvider _comNativeDescriptor; public ComNativeDescriptorProxy() @@ -3053,8 +3058,7 @@ public ComNativeDescriptorProxy() throw new NotSupportedException(SR.ComObjectDescriptorsNotSupported); } - Type realComNativeDescriptor = Type.GetType("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, System.Windows.Forms", throwOnError: true)!; - _comNativeDescriptor = (TypeDescriptionProvider)Activator.CreateInstance(realComNativeDescriptor)!; + _comNativeDescriptor = (TypeDescriptionProvider)CreateComNativeDescriptor(); } [return: NotNullIfNotNull(nameof(instance))] From 77ba50d6252aa64dd39d62840bbb635f14fe457c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 14 May 2025 13:07:12 -0700 Subject: [PATCH 08/29] Convert DelegateHelpers to use UnsafeAccessorType --- .../System/Dynamic/Utils/DelegateHelpers.cs | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs index ef812058dc5025..f35ca59c603587 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs @@ -20,24 +20,16 @@ internal static class DelegateHelpers // with the Reflection.Emit statics below. private static class DynamicDelegateLightup { - public static Func, Delegate> CreateObjectArrayDelegate { get; } - = CreateObjectArrayDelegateInternal(); - - private static Func, Delegate> CreateObjectArrayDelegateInternal() + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + private static extern Delegate CreateObjectArrayDelegate( + [UnsafeAccessorType("Internal.Runtime.Augments.DynamicDelegateAugments, System.Private.CoreLib")] object? _, + Type delegateType, + Func invoker + ); + + internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func invoker) { - // This is only supported by NativeAOT which always expects CanEmitObjectArrayDelegate to be false. - // This check guards static constructor of trying to resolve 'Internal.Runtime.Augments.DynamicDelegateAugments' - // on runtimes which do not support this private API. - if (!CanEmitObjectArrayDelegate) - { - return Type.GetType("Internal.Runtime.Augments.DynamicDelegateAugments, System.Private.CoreLib", throwOnError: true)! - .GetMethod("CreateObjectArrayDelegate")! - .CreateDelegate, Delegate>>(); - } - else - { - return new Func, Delegate>((_x, _y) => throw new NotImplementedException()); - } + return CreateObjectArrayDelegate(null, delegateType, invoker); } } From fe47df6ea93c8443f157f88161bc13e102be29fd Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 14 May 2025 13:15:35 -0700 Subject: [PATCH 09/29] Convert HttpWebRequest to use UnsafeAccessorType --- .../src/System/Net/HttpWebRequest.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs index 9daef1edd78bd4..2445be74a2619e 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs @@ -1693,11 +1693,16 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http { // This is legacy feature and we don't have public API at the moment. // So we want to process it only if explicitly set. - var settings = typeof(SocketsHttpHandler).GetField("_settings", BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(handler); - Debug.Assert(settings != null); - FieldInfo? fi = Type.GetType("System.Net.Http.HttpConnectionSettings, System.Net.Http")?.GetField("_impersonationLevel", BindingFlags.NonPublic | BindingFlags.Instance); - Debug.Assert(fi != null); - fi.SetValue(settings, request.ImpersonationLevel); + GetImpersonationLevel(GetSettings(handler)) = request.ImpersonationLevel; + + const string HttpConnectionSettingsTypeName = "System.Net.Http.HttpConnectionSettings, System.Net.Http"; + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_settings")] + [return: UnsafeAccessorType(HttpConnectionSettingsTypeName)] + static extern object GetSettings(SocketsHttpHandler handler); + + [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_impersonationLevel")] + static extern ref TokenImpersonationLevel GetImpersonationLevel([UnsafeAccessorType(HttpConnectionSettingsTypeName)] object settings); } if (parameters.CookieContainer != null) From d71b334ff786b51382c444f8848869dfb93881e6 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 14 May 2025 13:47:08 -0700 Subject: [PATCH 10/29] Convert XmlKeyHelper to use UnsafeAccessorType --- .../Security/Cryptography/XmlKeyHelper.cs | 65 +++++++++---------- 1 file changed, 29 insertions(+), 36 deletions(-) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs index 7c689475ded4f8..f9ea73634624ff 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs @@ -5,7 +5,7 @@ using System.Collections; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Reflection; +using System.Runtime.CompilerServices; using System.Text; namespace System.Security.Cryptography @@ -259,51 +259,44 @@ internal bool HasElement(string localName) private static class Functions { private const string XmlLinqAssemblyString = ", System.Private.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"; + private const string XDocumentTypeName = "System.Xml.Linq.XDocument" + XmlLinqAssemblyString; + private const string XContainerTypeName = "System.Xml.Linq.XContainer" + XmlLinqAssemblyString; + private const string XElementTypeName = "System.Xml.Linq.XElement" + XmlLinqAssemblyString; + private const string XNameTypeName = "System.Xml.Linq.XName" + XmlLinqAssemblyString; - private static readonly Func s_xDocumentCreate; - private static readonly PropertyInfo s_docRootProperty; - private static readonly MethodInfo s_getElementsMethod; - private static readonly PropertyInfo s_elementNameProperty; - private static readonly PropertyInfo s_elementValueProperty; - private static readonly PropertyInfo s_nameNameProperty; + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "Parse")] + [return: UnsafeAccessorType(XDocumentTypeName)] + private static extern object XDocument_Parse( + [UnsafeAccessorType(XDocumentTypeName)] object?_, string xmlString); -#pragma warning disable CA1810 // explicit static cctor - static Functions() - { - Type xDocument = Type.GetType("System.Xml.Linq.XDocument" + XmlLinqAssemblyString)!; - s_xDocumentCreate = xDocument.GetMethod( - "Parse", - BindingFlags.Static | BindingFlags.Public, - new[] { typeof(string) })! - .CreateDelegate>(); - - s_docRootProperty = xDocument.GetProperty("Root")!; - - Type xElement = Type.GetType("System.Xml.Linq.XElement" + XmlLinqAssemblyString)!; - s_getElementsMethod = xElement.GetMethod( - "Elements", - BindingFlags.Instance | BindingFlags.Public, - Type.EmptyTypes)!; - - s_elementNameProperty = xElement.GetProperty("Name")!; - s_elementValueProperty = xElement.GetProperty("Value")!; - - Type xName = Type.GetType("System.Xml.Linq.XName" + XmlLinqAssemblyString)!; - s_nameNameProperty = xName.GetProperty("LocalName")!; - } -#pragma warning restore CA1810 + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Root")] + [return: UnsafeAccessorType(XElementTypeName)] + private static extern object? XDocument_GetRoot([UnsafeAccessorType(XDocumentTypeName)] object xDocument); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Elements")] + private static extern IEnumerable XContainer_Elements([UnsafeAccessorType(XContainerTypeName)] object xElement); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Name")] + [return: UnsafeAccessorType(XNameTypeName)] + private static extern object XElement_GetName([UnsafeAccessorType(XElementTypeName)] object xElement); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Value")] + private static extern string? XElement_GetValue([UnsafeAccessorType(XElementTypeName)] object xElement); + + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_LocalName")] + private static extern string? XName_GetLocalName([UnsafeAccessorType(XNameTypeName)] object xName); internal static object? ParseDocument(string xmlString) => - s_docRootProperty.GetValue(s_xDocumentCreate(xmlString)); + XDocument_GetRoot(XDocument_Parse(null, xmlString)); internal static IEnumerable? GetElements(object? element) => - (IEnumerable?)s_getElementsMethod.Invoke(element, Array.Empty()); + XContainer_Elements(element!); internal static string? GetLocalName(object? element) => - (string?)s_nameNameProperty.GetValue(s_elementNameProperty.GetValue(element)); + XName_GetLocalName(XElement_GetName(element!)); internal static string? GetValue(object? element) => - (string?)s_elementValueProperty.GetValue(element); + XElement_GetValue(element!); } } } From a1f3bc7d02d1ca2bdd65df1080a046d512f2ee2e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 14 May 2025 17:48:58 -0700 Subject: [PATCH 11/29] Update XmlKeyHelper.cs Co-authored-by: Jan Kotas --- .../src/System/Security/Cryptography/XmlKeyHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs index f9ea73634624ff..f33fda2cf179fd 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs @@ -258,7 +258,7 @@ internal bool HasElement(string localName) private static class Functions { - private const string XmlLinqAssemblyString = ", System.Private.Xml.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51"; + private const string XmlLinqAssemblyString = ", System.Private.Xml.Linq"; private const string XDocumentTypeName = "System.Xml.Linq.XDocument" + XmlLinqAssemblyString; private const string XContainerTypeName = "System.Xml.Linq.XContainer" + XmlLinqAssemblyString; private const string XElementTypeName = "System.Xml.Linq.XElement" + XmlLinqAssemblyString; From e26d7fa6d1ffe1ddce40e10d63d3645472c381a4 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 15 May 2025 13:58:44 -0700 Subject: [PATCH 12/29] PR feedback --- .../src/System/Net/Http/X509ResourceClient.cs | 40 +++++++++---------- .../src/System/Net/HttpWebRequest.cs | 2 +- .../System/Resources/ResourceReader.Core.cs | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs index 369e1ce45e0e71..85e7b362e7acba 100644 --- a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs +++ b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs @@ -92,7 +92,7 @@ internal static partial class X509ResourceClient [UnsafeAccessor(UnsafeAccessorKind.Constructor)] [return: UnsafeAccessorType(SocketsHttpHandlerTypeName)] - private static extern object? CreateHttpHandler(); + private static extern object CreateHttpHandler(); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_PooledConnectionIdleTimeout")] private static extern TimeSpan GetPooledConnectionIdleTimeout([UnsafeAccessorType(SocketsHttpHandlerTypeName)] object handler); @@ -107,7 +107,7 @@ internal static partial class X509ResourceClient [UnsafeAccessor(UnsafeAccessorKind.Constructor)] [return: UnsafeAccessorType(HttpClientTypeName)] - private static extern object? CreateHttpClient([UnsafeAccessorType(HttpMessageHandlerTypeName)] object handler); + private static extern object CreateHttpClient([UnsafeAccessorType(HttpMessageHandlerTypeName)] object handler); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_MaxResponseContentBufferSize")] private static extern long GetMaxResponseContentBufferSize([UnsafeAccessorType(HttpClientTypeName)] object client); @@ -121,26 +121,26 @@ internal static partial class X509ResourceClient [UnsafeAccessor(UnsafeAccessorKind.Constructor)] [return: UnsafeAccessorType(HttpRequestMessageTypeName)] - private static extern object? CreateRequestMessage(); + private static extern object CreateRequestMessage(); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Send")] [return: UnsafeAccessorType(HttpResponseMessageTypeName)] - private static extern object? Send([UnsafeAccessorType(HttpClientTypeName)] object client, [UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage, CancellationToken cancellationToken); + private static extern object Send([UnsafeAccessorType(HttpClientTypeName)] object client, [UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage, CancellationToken cancellationToken); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "SendAsync")] [return: UnsafeAccessorType(TaskOfHttpResponseMessageTypeName)] - private static extern object? SendAsync([UnsafeAccessorType(HttpClientTypeName)] object client, [UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage, CancellationToken cancellationToken); + private static extern object SendAsync([UnsafeAccessorType(HttpClientTypeName)] object client, [UnsafeAccessorType(HttpRequestMessageTypeName)] object requestMessage, CancellationToken cancellationToken); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Content")] [return: UnsafeAccessorType(HttpContentTypeName)] - private static extern object? GetContent([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); + private static extern object GetContent([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_StatusCode")] private static extern int GetStatusCode([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Headers")] [return: UnsafeAccessorType(HttpResponseHeadersTypeName)] - private static extern object? GetHeaders([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); + private static extern object GetHeaders([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Location")] private static extern Uri? GetLocation([UnsafeAccessorType(HttpResponseHeadersTypeName)] object headers); @@ -172,12 +172,12 @@ internal static partial class X509ResourceClient const int MaxRedirections = 10; // Use UnsafeAccessors for construction and property access - object? socketsHttpHandler = CreateHttpHandler(); - SetAllowAutoRedirect(socketsHttpHandler!, false); - SetPooledConnectionIdleTimeout(socketsHttpHandler!, TimeSpan.FromSeconds(PooledConnectionIdleTimeoutSeconds)); + object socketsHttpHandler = CreateHttpHandler(); + SetAllowAutoRedirect(socketsHttpHandler, false); + SetPooledConnectionIdleTimeout(socketsHttpHandler, TimeSpan.FromSeconds(PooledConnectionIdleTimeoutSeconds)); - object? httpClient = CreateHttpClient(socketsHttpHandler!); - SetMaxResponseContentBufferSize(httpClient!, AiaDownloadLimit); + object httpClient = CreateHttpClient(socketsHttpHandler); + SetMaxResponseContentBufferSize(httpClient, AiaDownloadLimit); return async (string uriString, CancellationToken cancellationToken, bool async) => { @@ -188,19 +188,19 @@ internal static partial class X509ResourceClient return null; } - object requestMessage = CreateRequestMessage()!; + object requestMessage = CreateRequestMessage(); SetRequestUri(requestMessage, uri); object responseMessage; if (async) { - object sendTask = SendAsync(httpClient!, requestMessage, cancellationToken)!; + object sendTask = SendAsync(httpClient, requestMessage, cancellationToken); await ((Task)sendTask).ConfigureAwait(false); responseMessage = taskResultProperty.GetValue(sendTask)!; } else { - responseMessage = Send(httpClient!, requestMessage, cancellationToken)!; + responseMessage = Send(httpClient, requestMessage, cancellationToken); } int redirections = 0; @@ -209,7 +209,7 @@ internal static partial class X509ResourceClient while (true) { int statusCode = GetStatusCode(responseMessage); - object responseHeaders = GetHeaders(responseMessage)!; + object responseHeaders = GetHeaders(responseMessage); Uri? location = GetLocation(responseHeaders); redirectUri = GetUriForRedirect(GetRequestUri(requestMessage)!, statusCode, location, out hasRedirect); if (redirectUri == null) @@ -228,18 +228,18 @@ internal static partial class X509ResourceClient ReportRedirected(redirectUri); - requestMessage = CreateRequestMessage()!; + requestMessage = CreateRequestMessage(); SetRequestUri(requestMessage, redirectUri); if (async) { - object sendTask = SendAsync(httpClient!, requestMessage, cancellationToken)!; + object sendTask = SendAsync(httpClient, requestMessage, cancellationToken); await ((Task)sendTask).ConfigureAwait(false); responseMessage = taskResultProperty.GetValue(sendTask)!; } else { - responseMessage = Send(httpClient!, requestMessage, cancellationToken)!; + responseMessage = Send(httpClient, requestMessage, cancellationToken); } } @@ -248,7 +248,7 @@ internal static partial class X509ResourceClient return null; } - object content = GetContent(responseMessage)!; + object content = GetContent(responseMessage); using Stream responseStream = ReadAsStream(content); var result = new MemoryStream(); diff --git a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs index 2445be74a2619e..c7c0159f5bf989 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs @@ -1699,7 +1699,7 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_settings")] [return: UnsafeAccessorType(HttpConnectionSettingsTypeName)] - static extern object GetSettings(SocketsHttpHandler handler); + static extern ref object GetSettings(SocketsHttpHandler handler); [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_impersonationLevel")] static extern ref TokenImpersonationLevel GetImpersonationLevel([UnsafeAccessorType(HttpConnectionSettingsTypeName)] object settings); diff --git a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs index a1ba5901e16d56..09daa074947000 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs @@ -80,7 +80,7 @@ private object DeserializeObject(int typeIndex) { throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed, ex); } - } + } Type type = FindType(typeIndex); From 84b0be2e36da74d9c7ef0714713fc387b9d9556a Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 15 May 2025 15:38:10 -0700 Subject: [PATCH 13/29] Fix trimming test failures --- .../System.Private.CoreLib/src/System/AppDomain.cs | 11 ++++++----- .../src/System/Security/Cryptography/XmlKeyHelper.cs | 9 ++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs index c78b82a074d6b3..8e8c28e095c501 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs @@ -403,12 +403,12 @@ public void SetThreadPrincipal(IPrincipal principal) switch (_principalPolicy) { case PrincipalPolicy.UnauthenticatedPrincipal: - principal = GetDefaultPrincipal(null); + principal = (IPrincipal?)GetDefaultPrincipal(null); break; case PrincipalPolicy.WindowsPrincipal: try { - principal = GetDefaultWindowsPrincipal(null); + principal = (IPrincipal?)GetDefaultWindowsPrincipal(null); break; } catch (TypeLoadException ex) @@ -422,12 +422,13 @@ public void SetThreadPrincipal(IPrincipal principal) return principal; [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetDefaultInstance")] - static extern IPrincipal GetDefaultPrincipal( + [return: UnsafeAccessorType("System.Security.Principal.GenericPrincipal, System.Security.Claims")] + static extern object GetDefaultPrincipal( [UnsafeAccessorType("System.Security.Principal.GenericPrincipal, System.Security.Claims")] object? _); - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetDefaultInstance")] - static extern IPrincipal GetDefaultWindowsPrincipal( + [return: UnsafeAccessorType("System.Security.Principal.WindowsPrincipal, System.Security.Claims")] + static extern object GetDefaultWindowsPrincipal( [UnsafeAccessorType("System.Security.Principal.WindowsPrincipal, System.Security.Claims")] object? _); } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs index f33fda2cf179fd..88d2b7040e0a05 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/XmlKeyHelper.cs @@ -262,6 +262,8 @@ private static class Functions private const string XDocumentTypeName = "System.Xml.Linq.XDocument" + XmlLinqAssemblyString; private const string XContainerTypeName = "System.Xml.Linq.XContainer" + XmlLinqAssemblyString; private const string XElementTypeName = "System.Xml.Linq.XElement" + XmlLinqAssemblyString; + private const string IEnumerableOfXElementTypeName = $"System.Collections.Generic.IEnumerable`1[[{XElementTypeName}]], System.Runtime"; + private const string XNameTypeName = "System.Xml.Linq.XName" + XmlLinqAssemblyString; [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "Parse")] @@ -274,7 +276,8 @@ private static extern object XDocument_Parse( private static extern object? XDocument_GetRoot([UnsafeAccessorType(XDocumentTypeName)] object xDocument); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Elements")] - private static extern IEnumerable XContainer_Elements([UnsafeAccessorType(XContainerTypeName)] object xElement); + [return: UnsafeAccessorType(IEnumerableOfXElementTypeName)] + private static extern object XContainer_Elements([UnsafeAccessorType(XContainerTypeName)] object xElement); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Name")] [return: UnsafeAccessorType(XNameTypeName)] @@ -289,8 +292,8 @@ private static extern object XDocument_Parse( internal static object? ParseDocument(string xmlString) => XDocument_GetRoot(XDocument_Parse(null, xmlString)); - internal static IEnumerable? GetElements(object? element) => - XContainer_Elements(element!); + internal static IEnumerable GetElements(object? element) => + (IEnumerable)XContainer_Elements(element!); internal static string? GetLocalName(object? element) => XName_GetLocalName(XElement_GetName(element!)); From 8973fc58dd3a56d6870577890bc863837858b31a Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 16 May 2025 11:03:44 -0700 Subject: [PATCH 14/29] PR feedback --- .../System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs | 3 +++ .../System.Net.Requests/src/System/Net/HttpWebRequest.cs | 4 ++-- .../src/System/Resources/ResourceReader.Core.cs | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs index bfced3b900faaf..14153d8e869274 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/SocketsHttpHandler.cs @@ -23,6 +23,9 @@ public sealed class SocketsHttpHandler : HttpMessageHandler private Func? _decompressionHandlerFactory; private bool _disposed; + // Accessed via UnsafeAccessor from HttpWebRequest. + internal HttpConnectionSettings Settings => _settings; + private void CheckDisposedOrStarted() { ObjectDisposedException.ThrowIf(_disposed, this); diff --git a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs index c7c0159f5bf989..9356341fbfb002 100644 --- a/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs +++ b/src/libraries/System.Net.Requests/src/System/Net/HttpWebRequest.cs @@ -1697,9 +1697,9 @@ private static HttpClient CreateHttpClient(HttpClientParameters parameters, Http const string HttpConnectionSettingsTypeName = "System.Net.Http.HttpConnectionSettings, System.Net.Http"; - [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_settings")] + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Settings")] [return: UnsafeAccessorType(HttpConnectionSettingsTypeName)] - static extern ref object GetSettings(SocketsHttpHandler handler); + static extern object GetSettings(SocketsHttpHandler handler); [UnsafeAccessor(UnsafeAccessorKind.Field, Name = "_impersonationLevel")] static extern ref TokenImpersonationLevel GetImpersonationLevel([UnsafeAccessorType(HttpConnectionSettingsTypeName)] object settings); diff --git a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs index 09daa074947000..87a2d29537b57e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs @@ -117,11 +117,11 @@ private bool InitializeBinaryFormatter() [UnsafeAccessor(UnsafeAccessorKind.Constructor)] [return: UnsafeAccessorType(BinaryFormatterTypeName)] - static extern object? CreateBinaryFormatter(); + static extern object CreateBinaryFormatter(); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Deserialize")] static extern object Deserialize( - [UnsafeAccessorType(BinaryFormatterTypeName)] object? formatter, + [UnsafeAccessorType(BinaryFormatterTypeName)] object formatter, Stream serializationStream); } private static bool ValidateReaderType(string readerType) From a2db7575ec18c3a94546944b270d825fa0c8da1f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 16 May 2025 11:15:25 -0700 Subject: [PATCH 15/29] Migrate over cases where the type name is on a separate line --- .../System/Diagnostics/Tracing/EventSource.cs | 20 ++++++--------- .../src/System/Reflection/AssemblyName.cs | 25 ++++++------------- 2 files changed, 14 insertions(+), 31 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index 0d5178bda06a1c..a92c8ba15e1cbd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3921,20 +3921,14 @@ internal static class EventSourceInitHelper internal static EventSource? GetMetricsEventSource() { - Type? metricsEventSourceType = Type.GetType( - "System.Diagnostics.Metrics.MetricsEventSource, System.Diagnostics.DiagnosticSource", - throwOnError: false); + const string MetricsEventSourceTypeName = "System.Diagnostics.Metrics.MetricsEventSource, System.Diagnostics.DiagnosticSource"; - if (metricsEventSourceType == null) - { - return null; - } - MethodInfo? getInstanceMethod = metricsEventSourceType.GetMethod("GetInstance", BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, null, Type.EmptyTypes, null); - if (getInstanceMethod == null) - { - return null; - } - return getInstanceMethod.Invoke(null, null) as EventSource; + return GetInstance() as EventSource; + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + [return: UnsafeAccessorType(MetricsEventSourceTypeName)] + static extern object GetInstance( + [UnsafeAccessorType(MetricsEventSourceTypeName)] object? _); } // Pre-registration creates and registers an EventProvider prior to the EventSource being constructed. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs index f7d96dd1721912..577c046c1237e8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs @@ -6,6 +6,7 @@ using System.Configuration.Assemblies; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using CultureInfo = System.Globalization.CultureInfo; @@ -165,23 +166,6 @@ public object Clone() return name; } - private static Func? s_getAssemblyName; - private static Func InitGetAssemblyName() - { - Type readerType = Type.GetType( - "System.Reflection.Metadata.MetadataReader, System.Reflection.Metadata", - throwOnError: true)!; - - MethodInfo? getAssemblyNameMethod = readerType.GetMethod( - "GetAssemblyName", - BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static, - null, - [typeof(string)], - null) ?? - throw new MissingMethodException(readerType.FullName, "GetAssemblyName"); - return s_getAssemblyName = getAssemblyNameMethod.CreateDelegate>(); - } - /* * Get the AssemblyName for a given file. This will only work * if the file contains an assembly manifest. This method causes @@ -189,7 +173,12 @@ private static Func InitGetAssemblyName() */ public static AssemblyName GetAssemblyName(string assemblyFile) { - return (s_getAssemblyName ?? InitGetAssemblyName())(assemblyFile); + return GetName(null, assemblyFile); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetAssemblyName")] + static extern AssemblyName GetName( + [UnsafeAccessorType("System.Reflection.Metadata.MetadataReader", "System.Reflection.Metadata")] object? _, + string assemblyFile); } public byte[]? GetPublicKey() From bcc5d8d3fd81f5d8fe0f0f9f24389e585b16116f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 16 May 2025 11:30:16 -0700 Subject: [PATCH 16/29] Convert HttpClientHandler's calls up to various native platform handlers on mobile to use UnsafeAccessorType --- ...ntHandler.AnyMobile.InvokeNativeHandler.cs | 299 +++++++++++------- .../Net/Http/HttpClientHandler.AnyMobile.cs | 2 - 2 files changed, 188 insertions(+), 113 deletions(-) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs index 183ab043cbea66..b05aaa1d2f4be5 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs @@ -15,8 +15,6 @@ namespace System.Net.Http { public partial class HttpClientHandler : HttpMessageHandler { - private static MethodInfo? _nativeHandlerMethod; - #if TARGET_ANDROID private const string NativeHandlerType = "Xamarin.Android.Net.AndroidMessageHandler, Mono.Android"; private const string GetHttpMessageHandlerType = "Android.Runtime.AndroidEnvironment, Mono.Android"; @@ -33,156 +31,235 @@ public partial class HttpClientHandler : HttpMessageHandler #error Unknown target #endif + // UnsafeAccessor declarations for all native handler properties/methods private ICredentials? GetDefaultProxyCredentials() - => (ICredentials?)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_DefaultProxyCredentials")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_DefaultProxyCredentials")] + static extern ICredentials? CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetDefaultProxyCredentials(ICredentials? value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_DefaultProxyCredentials")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_DefaultProxyCredentials")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, ICredentials? value); + CallNative(_nativeUnderlyingHandler!, value); + } private int GetMaxConnectionsPerServer() - => (int)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_MaxConnectionsPerServer")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_MaxConnectionsPerServer")] + static extern int CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetMaxConnectionsPerServer(int value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_MaxConnectionsPerServer")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_MaxConnectionsPerServer")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, int value); + CallNative(_nativeUnderlyingHandler!, value); + } private int GetMaxResponseHeadersLength() - => (int)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_MaxResponseHeadersLength")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_MaxResponseHeadersLength")] + static extern int CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetMaxResponseHeadersLength(int value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_MaxResponseHeadersLength")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_MaxResponseHeadersLength")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, int value); + CallNative(_nativeUnderlyingHandler!, value); + } private ClientCertificateOption GetClientCertificateOptions() - => (ClientCertificateOption)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_ClientCertificateOptions")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_ClientCertificateOptions")] + static extern ClientCertificateOption CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetClientCertificateOptions(ClientCertificateOption value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_ClientCertificateOptions")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_ClientCertificateOptions")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, ClientCertificateOption value); + CallNative(_nativeUnderlyingHandler!, value); + } private X509CertificateCollection GetClientCertificates() - => (X509CertificateCollection)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_ClientCertificates")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_ClientCertificates")] + static extern X509CertificateCollection CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private Func GetServerCertificateCustomValidationCallback() - => (Func)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_ServerCertificateCustomValidationCallback")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_ServerCertificateCustomValidationCallback")] + static extern Func CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetServerCertificateCustomValidationCallback(Func? value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_ServerCertificateCustomValidationCallback")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_ServerCertificateCustomValidationCallback")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, Func? value); + CallNative(_nativeUnderlyingHandler!, value); + } private bool GetCheckCertificateRevocationList() - => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_CheckCertificateRevocationList")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_CheckCertificateRevocationList")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetCheckCertificateRevocationList(bool value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_CheckCertificateRevocationList")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_CheckCertificateRevocationList")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); + CallNative(_nativeUnderlyingHandler!, value); + } private SslProtocols GetSslProtocols() - => (SslProtocols)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SslProtocols")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SslProtocols")] + static extern SslProtocols CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetSslProtocols(SslProtocols value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_SslProtocols")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_SslProtocols")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, SslProtocols value); + CallNative(_nativeUnderlyingHandler!, value); + } private IDictionary GetProperties() - => (IDictionary)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_Properties")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Properties")] + static extern IDictionary CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private bool GetSupportsAutomaticDecompression() - => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SupportsAutomaticDecompression")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SupportsAutomaticDecompression")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private bool GetSupportsProxy() - => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SupportsProxy")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SupportsProxy")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private bool GetSupportsRedirectConfiguration() - => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_SupportsRedirectConfiguration")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SupportsRedirectConfiguration")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private DecompressionMethods GetAutomaticDecompression() - => (DecompressionMethods)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_AutomaticDecompression")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_AutomaticDecompression")] + static extern DecompressionMethods CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetAutomaticDecompression(DecompressionMethods value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_AutomaticDecompression")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_AutomaticDecompression")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, DecompressionMethods value); + CallNative(_nativeUnderlyingHandler!, value); + } private bool GetUseProxy() - => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_UseProxy")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_UseProxy")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetUseProxy(bool value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_UseProxy")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_UseProxy")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); + CallNative(_nativeUnderlyingHandler!, value); + } private IWebProxy GetProxy() - => (IWebProxy)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_Proxy")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Proxy")] + static extern IWebProxy CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetProxy(IWebProxy value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_Proxy")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_Proxy")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, IWebProxy value); + CallNative(_nativeUnderlyingHandler!, value); + } private bool GetPreAuthenticate() - => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_PreAuthenticate")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_PreAuthenticate")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetPreAuthenticate(bool value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_PreAuthenticate")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_PreAuthenticate")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); + CallNative(_nativeUnderlyingHandler!, value); + } private int GetMaxAutomaticRedirections() - => (int)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_MaxAutomaticRedirections")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_MaxAutomaticRedirections")] + static extern int CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetMaxAutomaticRedirections(int value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_MaxAutomaticRedirections")!, value); - - private bool GetUseCookies() => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_UseCookies")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_MaxAutomaticRedirections")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, int value); + CallNative(_nativeUnderlyingHandler!, value); + } + private bool GetUseCookies() + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_UseCookies")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetUseCookies(bool value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_UseCookies")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_UseCookies")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); + CallNative(_nativeUnderlyingHandler!, value); + } private CookieContainer GetCookieContainer() - => (CookieContainer)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_CookieContainer")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_CookieContainer")] + static extern CookieContainer CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetCookieContainer(CookieContainer value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_CookieContainer")!, value); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_CookieContainer")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, CookieContainer value); + CallNative(_nativeUnderlyingHandler!, value); + } private bool GetAllowAutoRedirect() - => (bool)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_AllowAutoRedirect")!); - + { + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_AllowAutoRedirect")] + static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); + } private void SetAllowAutoRedirect(bool value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_AllowAutoRedirect")!, value); - - private ICredentials GetCredentials() - => (ICredentials)InvokeNativeHandlerGetter(() => Type.GetType(NativeHandlerType)!.GetMethod("get_Credentials")!); - - private void SetCredentials(ICredentials? value) - => InvokeNativeHandlerSetter(() => Type.GetType(NativeHandlerType)!.GetMethod("set_Credentials")!, value); - - private static HttpMessageHandler CreateNativeHandler() { - if (_nativeHandlerMethod == null) - { - Type? runtimeOptions = Type.GetType(GetHttpMessageHandlerType); - _nativeHandlerMethod = runtimeOptions!.GetMethod("GetHttpMessageHandler", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static); - } - - return (HttpMessageHandler)_nativeHandlerMethod!.Invoke(null, null)!; + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_AllowAutoRedirect")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); + CallNative(_nativeUnderlyingHandler!, value); } - - private object InvokeNativeHandlerGetter(Func getMethod, [CallerMemberName] string? cachingKey = null) + private ICredentials GetCredentials() { - return InvokeNativeHandlerMethod(getMethod, parameters: null, cachingKey!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Credentials")] + static extern ICredentials CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); + return CallNative(_nativeUnderlyingHandler!); } - - private void InvokeNativeHandlerSetter(Func getMethod, object? value, [CallerMemberName] string? cachingKey = null) + private void SetCredentials(ICredentials? value) { - InvokeNativeHandlerMethod(getMethod, parameters: new object?[] { value }, cachingKey!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_Credentials")] + static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, ICredentials? value); + CallNative(_nativeUnderlyingHandler!, value); } - - private object InvokeNativeHandlerMethod(Func getMethod, object?[]? parameters, string cachingKey) + private static HttpMessageHandler CreateNativeHandler() { - MethodInfo? method; - - if (!s_cachedMethods.TryGetValue(cachingKey, out method)) - { - method = getMethod(); - s_cachedMethods[cachingKey] = method; - } - - try - { - return method!.Invoke(_nativeUnderlyingHandler, parameters)!; - } - catch (TargetInvocationException e) - { - ExceptionDispatchInfo.Capture(e.InnerException!).Throw(); - throw; - } + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetHttpMessageHandler")] + [return: UnsafeAccessorType(NativeHandlerType)] + static extern object CallNative(); + return (HttpMessageHandler)CallNative(); } } } diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs index c2ada8aa3aaf1d..da2eb54de9b8d9 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.cs @@ -20,8 +20,6 @@ namespace System.Net.Http { public partial class HttpClientHandler : HttpMessageHandler { - private static readonly ConcurrentDictionary s_cachedMethods = new(); - private readonly HttpMessageHandler? _nativeUnderlyingHandler; private IMeterFactory? _nativeMeterFactory; private HttpMessageHandler? _nativeFirstHandler; // DiagnosticsHandler or MetricsHandler, depending on global configuration. From 7a7bb755f98d035361ca4a523000dee770a31f98 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 16 May 2025 11:39:30 -0700 Subject: [PATCH 17/29] Various fixes --- .../src/System/Diagnostics/Tracing/EventSource.cs | 8 +++----- .../src/System/Reflection/AssemblyName.cs | 2 +- .../src/System/Resources/ResourceReader.Core.cs | 4 ++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index a92c8ba15e1cbd..b44fa743befe58 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3921,14 +3921,12 @@ internal static class EventSourceInitHelper internal static EventSource? GetMetricsEventSource() { - const string MetricsEventSourceTypeName = "System.Diagnostics.Metrics.MetricsEventSource, System.Diagnostics.DiagnosticSource"; - - return GetInstance() as EventSource; + return GetInstance(null) as EventSource; [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] - [return: UnsafeAccessorType(MetricsEventSourceTypeName)] + [return: UnsafeAccessorType("System.Diagnostics.Metrics.MetricsEventSource, System.Diagnostics.DiagnosticSource")] static extern object GetInstance( - [UnsafeAccessorType(MetricsEventSourceTypeName)] object? _); + [UnsafeAccessorType("System.Diagnostics.Metrics.MetricsEventSource, System.Diagnostics.DiagnosticSource")] object? _); } // Pre-registration creates and registers an EventProvider prior to the EventSource being constructed. diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs index 577c046c1237e8..c5325bc99ae607 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs @@ -177,7 +177,7 @@ public static AssemblyName GetAssemblyName(string assemblyFile) [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetAssemblyName")] static extern AssemblyName GetName( - [UnsafeAccessorType("System.Reflection.Metadata.MetadataReader", "System.Reflection.Metadata")] object? _, + [UnsafeAccessorType("System.Reflection.Metadata.MetadataReader, System.Reflection.Metadata")] object? _, string assemblyFile); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs index 87a2d29537b57e..8d25a79f6f3cfb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs @@ -19,7 +19,7 @@ public partial class ResourceReader private object? _binaryFormatter; // binary formatter instance to use for deserializing // statics used to dynamically call into BinaryFormatter - private static Func? s_deserializeMethod; + private static Func? s_deserializeMethod; // This is the constructor the RuntimeResourceSet calls, // passing in the stream to read from and the RuntimeResourceSet's @@ -87,7 +87,7 @@ private object DeserializeObject(int typeIndex) object graph; try { - graph = s_deserializeMethod!(_binaryFormatter, _store.BaseStream); + graph = s_deserializeMethod!(_binaryFormatter!, _store.BaseStream); } catch (Exception ex) when (ex is TypeLoadException or MissingMethodException) { From 6945bc808a53789b12f68b8503252bca83faab04 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 16 May 2025 14:28:42 -0700 Subject: [PATCH 18/29] Fix out param type --- .../Internal/Runtime/InteropServices/ComActivator.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs index 6572d1cf64cd7f..53e979f45ea30f 100644 --- a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs +++ b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs @@ -703,7 +703,7 @@ internal sealed class LicenseInteropProxy private const string LicenseContextTypeName = "System.ComponentModel.LicenseContext, System.ComponentModel.TypeConverter"; private const string LicenseInteropHelperTypeName = "System.ComponentModel.LicenseManager+LicenseInteropHelper, System.ComponentModel.TypeConverter"; private const string CLRLicenseContextTypeName = "System.ComponentModel.LicenseManager+CLRLicenseContext, System.ComponentModel.TypeConverter"; - private const string LicenseTypeName = "System.ComponentModel.License, System.ComponentModel.TypeConverter"; + private const string LicenseRefTypeName = "System.ComponentModel.License&, System.ComponentModel.TypeConverter"; private const string LicInfoHelperLicenseContextTypeName = "System.ComponentModel.LicenseManager+LicInfoHelperLicenseContext, System.ComponentModel.TypeConverter"; [UnsafeAccessor(UnsafeAccessorKind.Method)] @@ -725,7 +725,7 @@ private static extern bool ValidateAndRetrieveLicenseDetails( [UnsafeAccessorType(LicenseInteropHelperTypeName)] object? licInteropHelper, [UnsafeAccessorType(LicenseContextTypeName)] object? licContext, Type type, - [UnsafeAccessorType(LicenseTypeName)] out object? license, + [UnsafeAccessorType(LicenseRefTypeName)] out object? license, out string? licenseKey); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] @@ -751,7 +751,7 @@ private static extern object CreateRuntimeContext( [UnsafeAccessor(UnsafeAccessorKind.Constructor)] [return:UnsafeAccessorType(LicInfoHelperLicenseContextTypeName)] - private static extern object? CreateLicInfoHelperLicenseContext(); + private static extern object CreateLicInfoHelperLicenseContext(); [UnsafeAccessor(UnsafeAccessorKind.Method)] private static extern bool Contains( @@ -791,8 +791,8 @@ public static void GetLicInfo(Type type, out bool runtimeKeyAvail, out bool licV runtimeKeyAvail = false; licVerified = false; - object? licContext = CreateLicInfoHelperLicenseContext(); - bool isValid = ValidateAndRetrieveLicenseDetails(null!, licContext!, type, out object? license, out _); + object licContext = CreateLicInfoHelperLicenseContext(); + bool isValid = ValidateAndRetrieveLicenseDetails(null, licContext, type, out object? license, out _); if (!isValid) { return; From 6cfd8780d43d6814b3f657ae780e6da43fd7c8ad Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 16 May 2025 16:48:08 -0700 Subject: [PATCH 19/29] Fix trimming tests --- .../src/System/AppDomain.cs | 4 +-- .../System/Diagnostics/Tracing/EventSource.cs | 2 +- .../Linker.Steps/UnsafeAccessorMarker.cs | 35 +++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs index 8e8c28e095c501..c43c4dfca74e1d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs @@ -427,9 +427,9 @@ static extern object GetDefaultPrincipal( [UnsafeAccessorType("System.Security.Principal.GenericPrincipal, System.Security.Claims")] object? _); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetDefaultInstance")] - [return: UnsafeAccessorType("System.Security.Principal.WindowsPrincipal, System.Security.Claims")] + [return: UnsafeAccessorType("System.Security.Principal.WindowsPrincipal, System.Security.Principal.Windows")] static extern object GetDefaultWindowsPrincipal( - [UnsafeAccessorType("System.Security.Principal.WindowsPrincipal, System.Security.Claims")] object? _); + [UnsafeAccessorType("System.Security.Principal.WindowsPrincipal, System.Security.Principal.Windows")] object? _); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index b44fa743befe58..34ccb44fa09327 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -3923,7 +3923,7 @@ internal static class EventSourceInitHelper { return GetInstance(null) as EventSource; - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetInstance")] [return: UnsafeAccessorType("System.Diagnostics.Metrics.MetricsEventSource, System.Diagnostics.DiagnosticSource")] static extern object GetInstance( [UnsafeAccessorType("System.Diagnostics.Metrics.MetricsEventSource, System.Diagnostics.DiagnosticSource")] object? _); diff --git a/src/tools/illink/src/linker/Linker.Steps/UnsafeAccessorMarker.cs b/src/tools/illink/src/linker/Linker.Steps/UnsafeAccessorMarker.cs index 38a8f101d1bf17..ac1a7f4d15ac08 100644 --- a/src/tools/illink/src/linker/Linker.Steps/UnsafeAccessorMarker.cs +++ b/src/tools/illink/src/linker/Linker.Steps/UnsafeAccessorMarker.cs @@ -40,6 +40,8 @@ public void ProcessUnsafeAccessorMethod (MethodDefinition method) } } + ProcessUnsafeAccessorTypeAttributes (method); + switch (kind) { case UnsafeAccessorKind.Constructor: ProcessConstructorAccessor (method, name); @@ -68,6 +70,39 @@ public void ProcessUnsafeAccessorMethod (MethodDefinition method) } } + void ProcessUnsafeAccessorTypeAttributes (MethodDefinition method) + { + // A type named in UnsafeAccessorType may point to a type that is forwarded. + // Mark the type forwarders so we can avoid needing to rewrite the type name + // in the UnsafeAccessorTypeAttribute. + + foreach (CustomAttribute attr in method.MethodReturnType.CustomAttributes) { + if (attr.Constructor.DeclaringType.FullName == "System.Runtime.CompilerServices.UnsafeAccessorTypeAttribute") { + if (attr.HasConstructorArguments && attr.ConstructorArguments[0].Value is string typeName) { + if (!_context.TypeNameResolver.TryResolveTypeName (method.Module.Assembly, typeName, out _, out System.Collections.Generic.List? records)) + return; // We can't find the target type, so there's nothing to rewrite. + + foreach (var typeResolutionRecord in records) { + _context.MarkingHelpers.MarkMatchingExportedType (typeResolutionRecord.ResolvedType, typeResolutionRecord.ReferringAssembly, new DependencyInfo (DependencyKind.AccessedViaReflection, method), new MessageOrigin(method)); + } + } + } + } + + foreach (var param in method.Parameters) { + foreach (CustomAttribute attr in param.CustomAttributes) { + if (attr.HasConstructorArguments && attr.ConstructorArguments[0].Value is string typeName) { + if (!_context.TypeNameResolver.TryResolveTypeName (method.Module.Assembly, typeName, out _, out System.Collections.Generic.List? records)) + return; // We can't find the target type, so there's nothing to rewrite. + + foreach (var typeResolutionRecord in records) { + _context.MarkingHelpers.MarkMatchingExportedType (typeResolutionRecord.ResolvedType, typeResolutionRecord.ReferringAssembly, new DependencyInfo (DependencyKind.AccessedViaReflection, method), new MessageOrigin (method)); + } + } + } + } + } + bool TryResolveTargetType(TypeReference targetTypeReference, ICustomAttributeProvider unsafeAccessorTypeProvider, AssemblyDefinition assembly, [NotNullWhen(true)] out TypeDefinition? targetType) { targetType = null; From 314b22b3232e3b2e569a382d7e4125d05c1ad142 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 16 May 2025 18:36:53 -0700 Subject: [PATCH 20/29] Update AssemblyName.cs Co-authored-by: Aaron Robinson --- .../src/System/Reflection/AssemblyName.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs index c5325bc99ae607..de95ea49016867 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/AssemblyName.cs @@ -173,10 +173,10 @@ public object Clone() */ public static AssemblyName GetAssemblyName(string assemblyFile) { - return GetName(null, assemblyFile); + return GetAssemblyNameInternal(null, assemblyFile); [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetAssemblyName")] - static extern AssemblyName GetName( + static extern AssemblyName GetAssemblyNameInternal( [UnsafeAccessorType("System.Reflection.Metadata.MetadataReader, System.Reflection.Metadata")] object? _, string assemblyFile); } From 870775eb8e07abf15955add22a512f22552f72dd Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Mon, 19 May 2025 17:50:46 -0700 Subject: [PATCH 21/29] Rewrite BinarySerializer path to ensure we still trim out System.Runtime.Serialization.Formatters.dll completely while writing more straightforward code as long as BinarySerializer is disabled. --- .../ILLink/ILLink.Substitutions.Shared.xml | 3 - .../System/Resources/ResourceReader.Core.cs | 110 ++++++++---------- 2 files changed, 50 insertions(+), 63 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml index 1dfb1d930c587d..4e3073d3e3174a 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.Shared.xml @@ -16,9 +16,6 @@ - - - diff --git a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs index 8d25a79f6f3cfb..93f154ce570f4d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs @@ -15,12 +15,11 @@ namespace System.Resources { public partial class ResourceReader { + private const string BinaryFormatterTypeName = "System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, System.Runtime.Serialization.Formatters"; + private readonly bool _permitDeserialization; // can deserialize BinaryFormatted resources private object? _binaryFormatter; // binary formatter instance to use for deserializing - // statics used to dynamically call into BinaryFormatter - private static Func? s_deserializeMethod; - // This is the constructor the RuntimeResourceSet calls, // passing in the stream to read from and the RuntimeResourceSet's // internal hash table (hash table of names with file offsets @@ -53,77 +52,68 @@ private object DeserializeObject(int typeIndex) throw new NotSupportedException(SR.NotSupported_ResourceObjectSerialization); } - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", - Justification = "InitializeBinaryFormatter will get trimmed out when AllowCustomResourceTypes is set to false. " + - "When set to true, we will already throw a warning for this feature switch, so we suppress this one in order for" + - "the user to only get one error.")] - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", - Justification = "InitializeBinaryFormatter will get trimmed out when AllowCustomResourceTypes is set to false. " + - "When set to true, we will already throw a warning for this feature switch, so we suppress this one in order for" + - "the user to only get one error.")] - bool InitializeBinaryFormatterLocal() => InitializeBinaryFormatter(); + // Issue https://github.com/dotnet/runtime/issues/39290 tracks finding an alternative to BinaryFormatter + if (!EnableUnsafeBinaryFormatterSerialization) + { + throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed); + } - if (Volatile.Read(ref _binaryFormatter) is null) + if (_binaryFormatter is null) { - try - { - if (!InitializeBinaryFormatterLocal()) - { - // Trimming took away the BinaryFormatter implementation and we can't call into it. - // We'll throw an exception with the same text that BinaryFormatter would have thrown - // had we been able to call into it. Keep this resource string in sync with the same - // resource from the Formatters assembly. - throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed); - } - } - catch (Exception ex) when (ex is TypeLoadException or MissingMethodException) - { - throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed, ex); - } + InitializeBinaryFormatter(); } + Debug.Assert(_binaryFormatter is not null, "BinaryFormatter should be initialized or we should have thrown an exception!"); + Type type = FindType(typeIndex); - object graph; - try - { - graph = s_deserializeMethod!(_binaryFormatter!, _store.BaseStream); - } - catch (Exception ex) when (ex is TypeLoadException or MissingMethodException) - { - throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed, ex); - } + object graph = DeserializeLocal(_store.BaseStream); // guard against corrupted resources if (graph.GetType() != type) throw new BadImageFormatException(SR.Format(SR.BadImageFormat_ResType_SerBlobMismatch, type.FullName, graph.GetType().FullName)); return graph; - } - // Issue https://github.com/dotnet/runtime/issues/39290 tracks finding an alternative to BinaryFormatter - [RequiresDynamicCode("The native code for this instantiation might not be available at runtime.")] - [RequiresUnreferencedCode("The CustomResourceTypesSupport feature switch has been enabled for this app which is being trimmed. " + - "Custom readers as well as custom objects on the resources file are not observable by the trimmer and so required assemblies, types and members may be removed.")] - private bool InitializeBinaryFormatter() - { - const string BinaryFormatterTypeName = "System.Runtime.Serialization.Formatters.Binary.BinaryFormatter, System.Runtime.Serialization.Formatters"; - // If BinaryFormatter support is disabled for the app, the trimmer will replace this entire - // method body with "return false;", skipping the UnsafeAccessors below. - Volatile.Write(ref _binaryFormatter, CreateBinaryFormatter()); - Volatile.Write(ref s_deserializeMethod, Deserialize); - - return true; - - [UnsafeAccessor(UnsafeAccessorKind.Constructor)] - [return: UnsafeAccessorType(BinaryFormatterTypeName)] - static extern object CreateBinaryFormatter(); - - [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Deserialize")] - static extern object Deserialize( - [UnsafeAccessorType(BinaryFormatterTypeName)] object formatter, - Stream serializationStream); + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "InitializeBinaryFormatter will get trimmed out when AllowCustomResourceTypes is set to false. " + + "When set to true, we will already throw a warning for this feature switch, so we suppress this one in order for" + + "the user to only get one error.")] + void InitializeBinaryFormatter() + { + _binaryFormatter = CreateBinaryFormatter(); + } + + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "InitializeBinaryFormatter will get trimmed out when AllowCustomResourceTypes is set to false. " + + "When set to true, we will already throw a warning for this feature switch, so we suppress this one in order for" + + "the user to only get one error.")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2121:RequiresUnreferencedCode", + Justification = "InitializeBinaryFormatter will get trimmed out when AllowCustomResourceTypes is set to false. " + + "When set to true, we will already throw a warning for this feature switch, so we suppress this one in order for" + + "the user to only get one error.")] + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "InitializeBinaryFormatter will get trimmed out when AllowCustomResourceTypes is set to false. " + + "When set to true, we will already throw a warning for this feature switch, so we suppress this one in order for" + + "the user to only get one error.")] + object DeserializeLocal(Stream stream) => Deserialize(_binaryFormatter, stream); } + + [FeatureSwitchDefinition("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization")] + private static bool EnableUnsafeBinaryFormatterSerialization { get; } = AppContext.TryGetSwitch("System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization", out bool value) + ? value + : false; + + [RequiresUnreferencedCode("BinaryFormatter serialization is not trim compatible because the type of objects being processed cannot be statically discovered.")] + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "Deserialize")] + private static extern object Deserialize( + [UnsafeAccessorType(BinaryFormatterTypeName)] object formatter, + Stream serializationStream); + + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType(BinaryFormatterTypeName)] + private static extern object CreateBinaryFormatter(); + private static bool ValidateReaderType(string readerType) { return ResourceManager.IsDefaultType(readerType, ResourceManager.ResReaderTypeName); From 4bf982628f39e6e33f8ad2aa41d8cb1891116e67 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 20 May 2025 08:16:57 -0700 Subject: [PATCH 22/29] suppress warning from bug --- .../Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs index b05aaa1d2f4be5..b0a5453ca12c0f 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.AnyMobile.InvokeNativeHandler.cs @@ -15,6 +15,7 @@ namespace System.Net.Http { public partial class HttpClientHandler : HttpMessageHandler { +#pragma warning disable CA1823 // Unused field 'NativeHandlerType'. The field is used only in local functions. Tracked at https://github.com/dotnet/roslyn-analyzers/issues/7666 #if TARGET_ANDROID private const string NativeHandlerType = "Xamarin.Android.Net.AndroidMessageHandler, Mono.Android"; private const string GetHttpMessageHandlerType = "Android.Runtime.AndroidEnvironment, Mono.Android"; @@ -30,6 +31,7 @@ public partial class HttpClientHandler : HttpMessageHandler #else #error Unknown target #endif +#pragma warning restore CA1823 // Unused field 'NativeHandlerType' // UnsafeAccessor declarations for all native handler properties/methods private ICredentials? GetDefaultProxyCredentials() From 1691219d69af91d5d0d70eabc1edf672341c758c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 20 May 2025 12:06:43 -0700 Subject: [PATCH 23/29] Remove tests that test removed reflection infra and add librarybuild descriptor for new settings property --- .../ILLink.Descriptors.LibraryBuild.xml | 8 ++++++ .../TrimCompatibilityTests.cs | 24 ---------------- .../DefaultValueAttributeTests.cs | 28 ------------------- 3 files changed, 8 insertions(+), 52 deletions(-) create mode 100644 src/libraries/System.Net.Http/src/ILLink/ILLink.Descriptors.LibraryBuild.xml diff --git a/src/libraries/System.Net.Http/src/ILLink/ILLink.Descriptors.LibraryBuild.xml b/src/libraries/System.Net.Http/src/ILLink/ILLink.Descriptors.LibraryBuild.xml new file mode 100644 index 00000000000000..c315fa8a96d312 --- /dev/null +++ b/src/libraries/System.Net.Http/src/ILLink/ILLink.Descriptors.LibraryBuild.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/libraries/System.Runtime/tests/System.Resources.ResourceManager.Tests/TrimCompatibilityTests.cs b/src/libraries/System.Runtime/tests/System.Resources.ResourceManager.Tests/TrimCompatibilityTests.cs index 6fb396505e714f..1ab47a6550b1aa 100644 --- a/src/libraries/System.Runtime/tests/System.Resources.ResourceManager.Tests/TrimCompatibilityTests.cs +++ b/src/libraries/System.Runtime/tests/System.Resources.ResourceManager.Tests/TrimCompatibilityTests.cs @@ -12,30 +12,6 @@ namespace System.Resources.Tests { public static class TrimCompatibilityTests { - /// - /// Verifies that ResourceReader.CreateUntypedDelegate doesn't have any DynamicallyAccessedMembers attributes, - /// so we can safely call MakeGenericMethod on its methods. - /// - [Fact] - public static void VerifyMethodsCalledWithMakeGenericMethod() - { - Type type = typeof(ResourceReader); - MethodInfo mi = type.GetMethod("CreateUntypedDelegate", BindingFlags.NonPublic | BindingFlags.Static); - - Type[] genericTypes = mi.GetGenericArguments(); - if (genericTypes != null) - { - foreach(Type genericType in genericTypes) - { - // The generic type should not have DynamicallyAccessedMembersAttribute on it. - Assert.Null(genericType.GetCustomAttribute()); - - // The generic type should not have a 'where new()' constraint since that will tell the trimmer to keep the ctor - Assert.False(genericType.GenericParameterAttributes.HasFlag(GenericParameterAttributes.DefaultConstructorConstraint)); - } - } - } - [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] public static void VerifyFeatureSwitchGeneratesTheRightException() { diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ComponentModel/DefaultValueAttributeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ComponentModel/DefaultValueAttributeTests.cs index 641b74c9408731..31ee7c9a1aa505 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ComponentModel/DefaultValueAttributeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/ComponentModel/DefaultValueAttributeTests.cs @@ -77,34 +77,6 @@ public static void Ctor_CustomTypeConverter() Assert.Equal(42, ((CustomType)attr.Value).Value); } - [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [InlineData(typeof(CustomType), true, "", 0)] - [InlineData(typeof(int), false, "42", 42)] - public void Ctor_TypeDescriptorNotFound_ExceptionFallback(Type type, bool returnNull, string stringToConvert, int expectedValue) - { - RemoteExecutor.Invoke((innerType, innerReturnNull, innerStringToConvert, innerExpectedValue) => - { - FieldInfo s_convertFromInvariantString = typeof(DefaultValueAttribute).GetField("s_convertFromInvariantString", BindingFlags.GetField | Reflection.BindingFlags.NonPublic | Reflection.BindingFlags.Static); - Assert.NotNull(s_convertFromInvariantString); - - // simulate TypeDescriptor.ConvertFromInvariantString not found - s_convertFromInvariantString.SetValue(null, new object()); - - // we fallback to empty catch in DefaultValueAttribute constructor - DefaultValueAttribute attr = new DefaultValueAttribute(Type.GetType(innerType), innerStringToConvert); - - if (bool.Parse(innerReturnNull)) - { - Assert.Null(attr.Value); - } - else - { - Assert.Equal(int.Parse(innerExpectedValue), attr.Value); - } - - }, type.ToString(), returnNull.ToString(), stringToConvert, expectedValue.ToString()).Dispose(); - } - [ConditionalTheory(nameof(DefaultValueAttributeIsSupported))] [InlineData(typeof(CustomType2))] [InlineData(typeof(DefaultValueAttribute))] From eb866c92478300008e5f5844e2421f026b79182c Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 20 May 2025 15:31:51 -0700 Subject: [PATCH 24/29] Fix exception for WindowsPrincipal --- src/libraries/System.Private.CoreLib/src/System/AppDomain.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs index c43c4dfca74e1d..9f5e7eb1f4bdae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs @@ -411,6 +411,11 @@ public void SetThreadPrincipal(IPrincipal principal) principal = (IPrincipal?)GetDefaultWindowsPrincipal(null); break; } + catch (MissingMethodException ex) + { + // WindowsPrincipal is not available, throw PNSE + throw new PlatformNotSupportedException(SR.PlatformNotSupported_Principal, ex); + } catch (TypeLoadException ex) { // WindowsPrincipal is not available, throw PNSE From 337d5048ec4e03be786eb84823ed44c79d3c1af2 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 21 May 2025 23:01:32 +0000 Subject: [PATCH 25/29] Fix GetStatusCode return --- .../Common/src/System/Net/Http/X509ResourceClient.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs index 85e7b362e7acba..8d2a62aa62ead3 100644 --- a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs +++ b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs @@ -136,7 +136,7 @@ internal static partial class X509ResourceClient private static extern object GetContent([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_StatusCode")] - private static extern int GetStatusCode([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); + private static extern HttpStatusCode GetStatusCode([UnsafeAccessorType(HttpResponseMessageTypeName)] object responseMessage); [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Headers")] [return: UnsafeAccessorType(HttpResponseHeadersTypeName)] @@ -208,7 +208,7 @@ internal static partial class X509ResourceClient bool hasRedirect; while (true) { - int statusCode = GetStatusCode(responseMessage); + int statusCode = (int)GetStatusCode(responseMessage); object responseHeaders = GetHeaders(responseMessage); Uri? location = GetLocation(responseHeaders); redirectUri = GetUriForRedirect(GetRequestUri(requestMessage)!, statusCode, location, out hasRedirect); From e86536feb08c19db9dd888dcbec095b34b3652fe Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 23 May 2025 14:35:50 -0700 Subject: [PATCH 26/29] PR feedback --- .../System/Dynamic/Utils/DelegateHelpers.cs | 39 ++--- ...ntHandler.AnyMobile.InvokeNativeHandler.cs | 151 +++++++++++++----- .../src/System/AppDomain.cs | 9 +- .../System/Resources/ResourceReader.Core.cs | 1 - 4 files changed, 128 insertions(+), 72 deletions(-) diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs index f35ca59c603587..2296346b5e9d7e 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs @@ -16,33 +16,20 @@ internal static class DelegateHelpers [FeatureSwitchDefinition("System.Linq.Expressions.CanEmitObjectArrayDelegate")] internal static bool CanEmitObjectArrayDelegate => true; - // Separate class so that the it can be trimmed away and doesn't get conflated - // with the Reflection.Emit statics below. - private static class DynamicDelegateLightup + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + private static extern Delegate CreateObjectArrayDelegate( + [UnsafeAccessorType("Internal.Runtime.Augments.DynamicDelegateAugments, System.Private.CoreLib")] object? _, + Type delegateType, + Func invoker + ); + + internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func invoker) { - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] - private static extern Delegate CreateObjectArrayDelegate( - [UnsafeAccessorType("Internal.Runtime.Augments.DynamicDelegateAugments, System.Private.CoreLib")] object? _, - Type delegateType, - Func invoker - ); - - internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func invoker) - { - return CreateObjectArrayDelegate(null, delegateType, invoker); - } + return CreateObjectArrayDelegate(null, delegateType, invoker); } - private static class ForceAllowDynamicCodeLightup - { - public static Func? ForceAllowDynamicCodeDelegate { get; } - = ForceAllowDynamicCodeDelegateInternal(); - - private static Func? ForceAllowDynamicCodeDelegateInternal() - => typeof(AssemblyBuilder) - .GetMethod("ForceAllowDynamicCode", BindingFlags.NonPublic | BindingFlags.Static) - ?.CreateDelegate>(); - } + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] + public static extern IDisposable ForceAllowDynamicCode(AssemblyBuilder? _ = null); internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func handler) { @@ -55,7 +42,7 @@ internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func GetServerCertificateCustomValidationCallback() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_ServerCertificateCustomValidationCallback")] static extern Func CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetServerCertificateCustomValidationCallback(Func? value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_ServerCertificateCustomValidationCallback")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, Func? value); - CallNative(_nativeUnderlyingHandler!, value); } + private bool GetCheckCertificateRevocationList() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_CheckCertificateRevocationList")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetCheckCertificateRevocationList(bool value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_CheckCertificateRevocationList")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); - CallNative(_nativeUnderlyingHandler!, value); } + private SslProtocols GetSslProtocols() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SslProtocols")] static extern SslProtocols CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetSslProtocols(SslProtocols value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_SslProtocols")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, SslProtocols value); - CallNative(_nativeUnderlyingHandler!, value); } + private IDictionary GetProperties() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Properties")] static extern IDictionary CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private bool GetSupportsAutomaticDecompression() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SupportsAutomaticDecompression")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private bool GetSupportsProxy() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SupportsProxy")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private bool GetSupportsRedirectConfiguration() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_SupportsRedirectConfiguration")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private DecompressionMethods GetAutomaticDecompression() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_AutomaticDecompression")] static extern DecompressionMethods CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetAutomaticDecompression(DecompressionMethods value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_AutomaticDecompression")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, DecompressionMethods value); - CallNative(_nativeUnderlyingHandler!, value); } + private bool GetUseProxy() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_UseProxy")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetUseProxy(bool value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_UseProxy")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); - CallNative(_nativeUnderlyingHandler!, value); } + private IWebProxy GetProxy() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Proxy")] static extern IWebProxy CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetProxy(IWebProxy value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_Proxy")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, IWebProxy value); - CallNative(_nativeUnderlyingHandler!, value); } + private bool GetPreAuthenticate() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_PreAuthenticate")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetPreAuthenticate(bool value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_PreAuthenticate")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); - CallNative(_nativeUnderlyingHandler!, value); } + private int GetMaxAutomaticRedirections() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_MaxAutomaticRedirections")] static extern int CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetMaxAutomaticRedirections(int value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_MaxAutomaticRedirections")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, int value); - CallNative(_nativeUnderlyingHandler!, value); } + private bool GetUseCookies() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_UseCookies")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetUseCookies(bool value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_UseCookies")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); - CallNative(_nativeUnderlyingHandler!, value); } + private CookieContainer GetCookieContainer() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_CookieContainer")] static extern CookieContainer CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetCookieContainer(CookieContainer value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_CookieContainer")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, CookieContainer value); - CallNative(_nativeUnderlyingHandler!, value); } + private bool GetAllowAutoRedirect() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_AllowAutoRedirect")] static extern bool CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetAllowAutoRedirect(bool value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_AllowAutoRedirect")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, bool value); - CallNative(_nativeUnderlyingHandler!, value); } + private ICredentials GetCredentials() { + return CallNative(_nativeUnderlyingHandler!); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "get_Credentials")] static extern ICredentials CallNative([UnsafeAccessorType(NativeHandlerType)] object handler); - return CallNative(_nativeUnderlyingHandler!); } + private void SetCredentials(ICredentials? value) { + CallNative(_nativeUnderlyingHandler!, value); + [UnsafeAccessor(UnsafeAccessorKind.Method, Name = "set_Credentials")] static extern void CallNative([UnsafeAccessorType(NativeHandlerType)] object handler, ICredentials? value); - CallNative(_nativeUnderlyingHandler!, value); } + private static HttpMessageHandler CreateNativeHandler() { + return (HttpMessageHandler)CallNative(); + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "GetHttpMessageHandler")] [return: UnsafeAccessorType(NativeHandlerType)] static extern object CallNative(); - return (HttpMessageHandler)CallNative(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs index 9f5e7eb1f4bdae..9c3b4a76f36ead 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AppDomain.cs @@ -403,12 +403,12 @@ public void SetThreadPrincipal(IPrincipal principal) switch (_principalPolicy) { case PrincipalPolicy.UnauthenticatedPrincipal: - principal = (IPrincipal?)GetDefaultPrincipal(null); + principal = (IPrincipal)GetDefaultPrincipal(null); break; case PrincipalPolicy.WindowsPrincipal: try { - principal = (IPrincipal?)GetDefaultWindowsPrincipal(null); + principal = (IPrincipal)GetDefaultWindowsPrincipal(null); break; } catch (MissingMethodException ex) @@ -416,11 +416,6 @@ public void SetThreadPrincipal(IPrincipal principal) // WindowsPrincipal is not available, throw PNSE throw new PlatformNotSupportedException(SR.PlatformNotSupported_Principal, ex); } - catch (TypeLoadException ex) - { - // WindowsPrincipal is not available, throw PNSE - throw new PlatformNotSupportedException(SR.PlatformNotSupported_Principal, ex); - } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs index 93f154ce570f4d..ae5bf2b28eb730 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Resources/ResourceReader.Core.cs @@ -52,7 +52,6 @@ private object DeserializeObject(int typeIndex) throw new NotSupportedException(SR.NotSupported_ResourceObjectSerialization); } - // Issue https://github.com/dotnet/runtime/issues/39290 tracks finding an alternative to BinaryFormatter if (!EnableUnsafeBinaryFormatterSerialization) { throw new NotSupportedException(SR.BinaryFormatter_SerializationDisallowed); From 9c474cdd48bd19b0da7112ba64238f26bbccd15b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 23 May 2025 14:59:36 -0700 Subject: [PATCH 27/29] PR Feedback --- .../src/System/Dynamic/Utils/DelegateHelpers.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs index 2296346b5e9d7e..aa90d7c1021e38 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs @@ -23,11 +23,6 @@ private static extern Delegate CreateObjectArrayDelegate( Func invoker ); - internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func invoker) - { - return CreateObjectArrayDelegate(null, delegateType, invoker); - } - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] public static extern IDisposable ForceAllowDynamicCode(AssemblyBuilder? _ = null); @@ -42,7 +37,7 @@ internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func Date: Thu, 29 May 2025 10:41:21 -0700 Subject: [PATCH 28/29] PR feedback --- .../Runtime/InteropServices/ComActivator.cs | 8 +++---- .../src/System/Net/Http/X509ResourceClient.cs | 8 +++---- .../System/ComponentModel/TypeDescriptor.cs | 8 +++---- .../System/Dynamic/Utils/DelegateHelpers.cs | 22 +++++++++---------- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs index 53e979f45ea30f..5ac78f35cdcee0 100644 --- a/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs +++ b/src/coreclr/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs @@ -706,6 +706,10 @@ internal sealed class LicenseInteropProxy private const string LicenseRefTypeName = "System.ComponentModel.License&, System.ComponentModel.TypeConverter"; private const string LicInfoHelperLicenseContextTypeName = "System.ComponentModel.LicenseManager+LicInfoHelperLicenseContext, System.ComponentModel.TypeConverter"; + // RCW Activation + private object? _licContext; + private Type? _targetRcwType; + [UnsafeAccessor(UnsafeAccessorKind.Method)] private static extern void SetSavedLicenseKey( [UnsafeAccessorType(LicenseContextTypeName)] object licContext, @@ -758,10 +762,6 @@ private static extern bool Contains( [UnsafeAccessorType(LicInfoHelperLicenseContextTypeName)] object? licInfoHelperContext, string assemblyName); - // RCW Activation - private object? _licContext; - private Type? _targetRcwType; - // Helper function to create an object from the native side public static object Create() { diff --git a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs index 8d2a62aa62ead3..ebb4fd0a446bba 100644 --- a/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs +++ b/src/libraries/Common/src/System/Net/Http/X509ResourceClient.cs @@ -194,8 +194,8 @@ internal static partial class X509ResourceClient if (async) { - object sendTask = SendAsync(httpClient, requestMessage, cancellationToken); - await ((Task)sendTask).ConfigureAwait(false); + Task sendTask = (Task)SendAsync(httpClient, requestMessage, cancellationToken); + await sendTask.ConfigureAwait(false); responseMessage = taskResultProperty.GetValue(sendTask)!; } else @@ -233,8 +233,8 @@ internal static partial class X509ResourceClient if (async) { - object sendTask = SendAsync(httpClient, requestMessage, cancellationToken); - await ((Task)sendTask).ConfigureAwait(false); + Task sendTask = (Task)SendAsync(httpClient, requestMessage, cancellationToken); + await sendTask.ConfigureAwait(false); responseMessage = taskResultProperty.GetValue(sendTask)!; } else diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs index 350f782851a89c..2c80d5f1c364fb 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs @@ -3045,10 +3045,6 @@ private sealed class TypeDescriptorComObject // string method is the failure is silent during type load making diagnosing the issue difficult. private sealed class ComNativeDescriptorProxy : TypeDescriptionProvider { - [UnsafeAccessor(UnsafeAccessorKind.Constructor)] - [return: UnsafeAccessorType("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, System.Windows.Forms")] - private static extern object CreateComNativeDescriptor(); - private readonly TypeDescriptionProvider _comNativeDescriptor; public ComNativeDescriptorProxy() @@ -3059,6 +3055,10 @@ public ComNativeDescriptorProxy() } _comNativeDescriptor = (TypeDescriptionProvider)CreateComNativeDescriptor(); + + [UnsafeAccessor(UnsafeAccessorKind.Constructor)] + [return: UnsafeAccessorType("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, System.Windows.Forms")] + private static extern object CreateComNativeDescriptor(); } [return: NotNullIfNotNull(nameof(instance))] diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs index aa90d7c1021e38..9ace2b92daeffb 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs @@ -16,16 +16,6 @@ internal static class DelegateHelpers [FeatureSwitchDefinition("System.Linq.Expressions.CanEmitObjectArrayDelegate")] internal static bool CanEmitObjectArrayDelegate => true; - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] - private static extern Delegate CreateObjectArrayDelegate( - [UnsafeAccessorType("Internal.Runtime.Augments.DynamicDelegateAugments, System.Private.CoreLib")] object? _, - Type delegateType, - Func invoker - ); - - [UnsafeAccessor(UnsafeAccessorKind.StaticMethod)] - public static extern IDisposable ForceAllowDynamicCode(AssemblyBuilder? _ = null); - internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func handler) { if (CanEmitObjectArrayDelegate) @@ -38,6 +28,12 @@ internal static Delegate CreateObjectArrayDelegate(Type delegateType, Func invoker); } } @@ -196,8 +192,10 @@ private static Delegate CreateObjectArrayDelegateRefEmit(Type delegateType, Func // for example when running on CoreClr with PublishAot=true, this will allow IL to be emitted. // If we are running on a runtime that really doesn't support dynamic code, like NativeAOT, // CanEmitObjectArrayDelegate will be flipped to 'false', and this method won't be invoked. - return ForceAllowDynamicCode(); - } + return ForceAllowDynamicCode(null); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="ForceAllowDynamicCode")] + static extern IDisposable ForceAllowDynamicCode(AssemblyBuilder? _); return null; } From b792af257d8efeddff374682001990c83245530b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Wed, 4 Jun 2025 10:50:35 -0700 Subject: [PATCH 29/29] Fix typos --- .../src/System/ComponentModel/TypeDescriptor.cs | 2 +- .../src/System/Dynamic/Utils/DelegateHelpers.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs index 1d836da922e2ea..6d6d041bb1a53b 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs @@ -3067,7 +3067,7 @@ public ComNativeDescriptorProxy() [UnsafeAccessor(UnsafeAccessorKind.Constructor)] [return: UnsafeAccessorType("System.Windows.Forms.ComponentModel.Com2Interop.ComNativeDescriptor, System.Windows.Forms")] - private static extern object CreateComNativeDescriptor(); + static extern object CreateComNativeDescriptor(); } [return: NotNullIfNotNull(nameof(instance))] diff --git a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs index 9ace2b92daeffb..63ed733ef0ef81 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Dynamic/Utils/DelegateHelpers.cs @@ -196,7 +196,7 @@ private static Delegate CreateObjectArrayDelegateRefEmit(Type delegateType, Func [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name="ForceAllowDynamicCode")] static extern IDisposable ForceAllowDynamicCode(AssemblyBuilder? _); - + } return null; }