From f831e852ff62d0503bb2882be149dca7cedf80d1 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 29 Oct 2025 01:03:43 -0700 Subject: [PATCH 1/9] Add RequiresUnsafeAttribute and start annotating corelib --- .../System.Private.CoreLib.csproj | 1 + src/libraries/Directory.Build.props | 1 + .../System.Private.CoreLib.Shared.projitems | 1 + .../src/System/Buffers/SharedArrayPool.cs | 10 ++++-- .../src/System/Delegate.cs | 10 ++++-- .../CodeAnalysis/RequiresUnsafeAttribute.cs | 18 ++++++++++ .../src/System/Memory.cs | 12 +++++-- .../src/System/MemoryExtensions.cs | 5 ++- .../src/System/ReadOnlyMemory.cs | 21 ++++++++---- .../CompilerServices/ConditionalWeakTable.cs | 5 ++- .../System/Runtime/CompilerServices/Unsafe.cs | 1 + .../AsciiStringSearchValuesTeddyBase.cs | 33 ++++++++++++------- .../src/System/Threading/Tasks/Task.cs | 5 ++- .../src/System/Threading/Tasks/ValueTask.cs | 15 +++++++-- .../Microsoft.NET.ILLink.Analyzers.props | 1 + 15 files changed, 109 insertions(+), 30 deletions(-) create mode 100644 src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index c12d6c854ac0..d7ac59703f4b 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -22,6 +22,7 @@ true true true + true diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 33938989e386..1c0841e0fe91 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -50,6 +50,7 @@ annotations true + true diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index d3b69efe615e..a312398fab0f 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -286,6 +286,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs index ad4488005dac..da600c91337e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs @@ -60,7 +60,10 @@ public override T[] Rent(int minimumLength) SharedArrayPoolThreadLocalArray[]? tlsBuckets = t_tlsBuckets; if (tlsBuckets is not null && (uint)bucketIndex < (uint)tlsBuckets.Length) { - buffer = Unsafe.As(tlsBuckets[bucketIndex].Array); + unsafe + { + buffer = Unsafe.As(tlsBuckets[bucketIndex].Array); + } if (buffer is not null) { tlsBuckets[bucketIndex].Array = null; @@ -79,7 +82,10 @@ public override T[] Rent(int minimumLength) SharedArrayPoolPartitions? b = perCoreBuckets[bucketIndex]; if (b is not null) { - buffer = Unsafe.As(b.TryPop()); + unsafe + { + buffer = Unsafe.As(b.TryPop()); + } if (buffer is not null) { if (log.IsEnabled()) diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs index 6efa9f48554f..6ba2252a52bf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs @@ -128,9 +128,15 @@ public TDelegate Current public bool MoveNext() { int index = _index + 1; - if ((_current = Unsafe.As(_delegate?.TryGetAt(index))) == null) + unsafe { - return false; + unsafe + { + if ((_current = Unsafe.As(_delegate?.TryGetAt(index))) == null) + { + return false; + } + } } _index = index; return true; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs new file mode 100644 index 000000000000..1b30230d95c7 --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Diagnostics.CodeAnalysis +{ + /// + /// Indicates that the specified method requires dynamic access to code that is not referenced + /// statically, for example through . + /// + /// + /// This allows tools to understand which methods are unsafe to call when removing unreferenced + /// code from an application. + /// + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)] + internal sealed class RequiresUnsafeAttribute : Attribute + { + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Memory.cs b/src/libraries/System.Private.CoreLib/src/System/Memory.cs index c8eac110cb52..b37ef4260a6b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Memory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Memory.cs @@ -284,8 +284,11 @@ public Span Span { // Special-case string since it's the most common for ROM. - refToReturn = ref Unsafe.As(ref ((string)tmpObject).GetRawStringData()); - lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; + unsafe + { + refToReturn = ref Unsafe.As(ref ((string)tmpObject).GetRawStringData()); + lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; + } } else if (RuntimeHelpers.ObjectHasComponentSize(tmpObject)) { @@ -379,6 +382,11 @@ public Span Span /// /// An instance with nonprimitive (non-blittable) members cannot be pinned. /// + /// + /// To use this method safely, the target must not be torn while the + /// returned is in use. + /// + [RequiresUnsafe] public unsafe MemoryHandle Pin() { // Just like the Span property getter, we have special support for a mutable Memory diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index 9687896e6fc6..8ead6e27e160 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -5905,7 +5905,10 @@ internal SpanSplitEnumerator(ReadOnlySpan source, ReadOnlySpan separators) _source = source; if (typeof(T) == typeof(char) && separators.Length == 0) { - _searchValues = Unsafe.As>(string.SearchValuesStorage.WhiteSpaceChars); + unsafe + { + _searchValues = Unsafe.As>(string.SearchValuesStorage.WhiteSpaceChars); + } _splitMode = SpanSplitEnumeratorMode.SearchValues; } else diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs index 85e4feace8cd..7ad6d2af92ef 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs @@ -206,8 +206,11 @@ public ReadOnlySpan Span { // Special-case string since it's the most common for ROM. - refToReturn = ref Unsafe.As(ref ((string)tmpObject).GetRawStringData()); - lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; + unsafe + { + refToReturn = ref Unsafe.As(ref ((string)tmpObject).GetRawStringData()); + lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; + } } else if (RuntimeHelpers.ObjectHasComponentSize(tmpObject)) { @@ -223,8 +226,11 @@ public ReadOnlySpan Span // 'tmpObject is T[]' below also handles things like int[] <-> uint[] being convertible Debug.Assert(tmpObject is T[]); - refToReturn = ref MemoryMarshal.GetArrayDataReference(Unsafe.As(tmpObject)); - lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; + unsafe + { + refToReturn = ref MemoryMarshal.GetArrayDataReference(Unsafe.As(tmpObject)); + lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; + } } else { @@ -235,8 +241,11 @@ public ReadOnlySpan Span // constructor or other public API which would allow such a conversion. Debug.Assert(tmpObject is MemoryManager); - Span memoryManagerSpan = Unsafe.As>(tmpObject).GetSpan(); - refToReturn = ref MemoryMarshal.GetReference(memoryManagerSpan); + unsafe + { + Span memoryManagerSpan = Unsafe.As>(tmpObject).GetSpan(); + refToReturn = ref MemoryMarshal.GetReference(memoryManagerSpan); + } lengthOfUnderlyingSpan = memoryManagerSpan.Length; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs index bdbb94609cd6..044f8647baa6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -711,7 +711,10 @@ internal bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value) if (entryIndex != -1) { RemoveIndex(entryIndex); - value = Unsafe.As(valueObject!); + unsafe + { + value = Unsafe.As(valueObject!); + } return true; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 154cd64a421e..09e395994506 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -63,6 +63,7 @@ public static int SizeOf() // Mono:As [NonVersionable] [MethodImpl(MethodImplOptions.AggressiveInlining)] + [RequiresUnsafe] [return: NotNullIfNotNull(nameof(o))] public static T? As(object? o) where T : class? { diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/AsciiStringSearchValuesTeddyBase.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/AsciiStringSearchValuesTeddyBase.cs index b764e3a22d81..2cb026919f9e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/AsciiStringSearchValuesTeddyBase.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/AsciiStringSearchValuesTeddyBase.cs @@ -560,11 +560,14 @@ private bool TryFindMatch(ReadOnlySpan span, ref char searchSpace, Vector1 object? bucket = _buckets[candidateOffset]; Debug.Assert(bucket is not null); - if (TBucketized.Value - ? StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket)) - : StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket))) + unsafe { - return true; + if (TBucketized.Value + ? StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket)) + : StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket))) + { + return true; + } } candidateMask = BitOperations.ResetLowestSetBit(candidateMask); @@ -605,11 +608,14 @@ private bool TryFindMatch(ReadOnlySpan span, ref char searchSpace, Vector2 object? bucket = _buckets[candidateOffset]; Debug.Assert(bucket is not null); - if (TBucketized.Value - ? StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket)) - : StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket))) + unsafe { - return true; + if (TBucketized.Value + ? StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket)) + : StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket))) + { + return true; + } } candidateMask = BitOperations.ResetLowestSetBit(candidateMask); @@ -650,11 +656,14 @@ private bool TryFindMatch(ReadOnlySpan span, ref char searchSpace, Vector5 object? bucket = _buckets[candidateOffset]; Debug.Assert(bucket is not null); - if (TBucketized.Value - ? StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket)) - : StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket))) + unsafe { - return true; + if (TBucketized.Value + ? StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket)) + : StartsWith(ref matchRef, lengthRemaining, Unsafe.As(bucket))) + { + return true; + } } candidateMask = BitOperations.ResetLowestSetBit(candidateMask); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 1cd3b2e3b540..70e778010cde 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -6743,7 +6743,10 @@ private static Task WhenAny(IEnumerable tasks) where TTask // since if argument was strongly-typed as an array, it would have bound to the array-based overload. if (tasks.GetType() == typeof(List)) { - return WhenAnyCore((ReadOnlySpan)CollectionsMarshal.AsSpan(Unsafe.As>(tasks))); + unsafe + { + return WhenAnyCore((ReadOnlySpan)CollectionsMarshal.AsSpan(Unsafe.As>(tasks))); + } } if (tasks is TTask[] tasksAsArray) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs index 90f86c68159c..5de25750326e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs @@ -762,7 +762,10 @@ public bool IsFaulted return t.IsFaulted; } - return Unsafe.As>(obj).GetStatus(_token) == ValueTaskSourceStatus.Faulted; + unsafe + { + return Unsafe.As>(obj).GetStatus(_token) == ValueTaskSourceStatus.Faulted; + } } } @@ -789,7 +792,10 @@ public bool IsCanceled return t.IsCanceled; } - return Unsafe.As>(obj).GetStatus(_token) == ValueTaskSourceStatus.Canceled; + unsafe + { + return Unsafe.As>(obj).GetStatus(_token) == ValueTaskSourceStatus.Canceled; + } } } @@ -814,7 +820,10 @@ public TResult Result return t.ResultOnSuccess; } - return Unsafe.As>(obj).GetResult(_token); + unsafe + { + return Unsafe.As>(obj).GetResult(_token); + } } } diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props b/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props index 18ae6cb8fd5e..e8a5e17d0c57 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props @@ -3,6 +3,7 @@ + From 41893f5d67390527fd87788b1143326147fc3363 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 29 Oct 2025 01:08:30 -0700 Subject: [PATCH 2/9] Follow onboarding instructions --- .github/CODEOWNERS | 117 ------------------------------------------ Directory.Build.props | 2 +- eng/Versions.props | 2 +- 3 files changed, 2 insertions(+), 119 deletions(-) delete mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 9a575e240931..000000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,117 +0,0 @@ -# Users referenced in this file will automatically be requested as reviewers for PRs that modify the given paths. -# See https://help.github.com/articles/about-code-owners/ - -/src/libraries/Common/src/System/Net/Http/aspnetcore/ @dotnet/http -/src/libraries/Common/tests/Tests/System/Net/aspnetcore/ @dotnet/http - -# CoreCLR Code Owners - -/src/coreclr/inc/corinfo.h @dotnet/jit-contrib -/src/coreclr/inc/corjit.h @dotnet/jit-contrib -/src/coreclr/jit/ @dotnet/jit-contrib -/src/coreclr/interpreter/ @brzvlad @janvorli @kg -/src/coreclr/vm/interpexec* @brzvlad @janvorli @kg -/src/coreclr/nativeaot @MichalStrehovsky -/src/coreclr/tools/Common @dotnet/crossgen-contrib @MichalStrehovsky -/src/coreclr/tools/aot @dotnet/crossgen-contrib -/src/coreclr/tools/aot/ILCompiler.Compiler @MichalStrehovsky -/src/coreclr/tools/aot/ILCompiler.RyuJit @MichalStrehovsky -/src/coreclr/tools/aot/ILCompiler.MetadataTransform @MichalStrehovsky - -# Mono Code Owners - -/src/mono @steveisok @vitek-karas - -/src/mono/llvm @steveisok @vitek-karas - -/src/mono/mono/arch @steveisok @vitek-karas -/src/mono/mono/eglib @steveisok @vitek-karas - -/src/mono/mono/metadata @thaystg @steveisok @vitek-karas -/src/mono/mono/metadata/*-win* @lateralusX @steveisok -/src/mono/mono/metadata/handle* @steveisok @vitek-karas -/src/mono/mono/metadata/monitor* @brzvlad @steveisok @vitek-karas -/src/mono/mono/metadata/sgen* @brzvlad @steveisok @vitek-karas -/src/mono/mono/metadata/thread* @lateralusX @steveisok @vitek-karas -/src/mono/mono/metadata/w32* @lateralusX @steveisok @vitek-karas - -/src/mono/mono/eventpipe @lateralusX @steveisok @vitek-karas - -/src/mono/mono/mini @steveisok @vitek-karas -/src/mono/mono/mini/*cfgdump* @steveisok @vitek-karas -/src/mono/mono/mini/*exceptions* @BrzVlad @steveisok @vitek-karas -/src/mono/mono/mini/*llvm* @steveisok @vitek-karas -/src/mono/mono/mini/*ppc* @steveisok @vitek-karas -/src/mono/mono/mini/*profiler* @BrzVlad @steveisok @vitek-karas -/src/mono/mono/mini/*riscv* @steveisok @vitek-karas -/src/mono/mono/mini/*type-check* @steveisok @vitek-karas -/src/mono/mono/mini/debugger-agent.c @thaystg @steveisok @vitek-karas -/src/mono/mono/mini/interp/* @BrzVlad @kotlarmilos @steveisok @vitek-karas -/src/mono/mono/mini/interp/*jiterp* @kg @steveisok @vitek-karas -/src/mono/mono/mini/*simd* @steveisok @vitek-karas - -/src/mono/mono/profiler @BrzVlad @steveisok @vitek-karas -/src/mono/mono/sgen @BrzVlad @steveisok @vitek-karas - -/src/mono/mono/utils @steveisok @vitek-karas -/src/mono/mono/utils/*-win* @lateralusX @steveisok @vitek-karas -/src/mono/mono/utils/atomic* @steveisok @vitek-karas -/src/mono/mono/utils/mono-hwcap* @steveisok @vitek-karas -/src/mono/mono/utils/mono-mem* @steveisok @vitek-karas -/src/mono/mono/utils/mono-threads* @steveisok @vitek-karas - -/src/mono/dlls @thaystg @steveisok @vitek-karas - -/src/native/public/mono @steveisok @vitek-karas -/src/native/eventpipe @noahfalk @lateralusX @mdh1418 -/src/native/external/libunwind @janvorli @AaronRobinsonMSFT @dotnet/dotnet-diag -/src/native/external/libunwind_extras @janvorli @AaronRobinsonMSFT @dotnet/dotnet-diag - -/src/libraries/sendtohelix-browser.targets @akoeplinger -/src/libraries/sendtohelix-wasm.targets @akoeplinger -/src/libraries/sendtohelix-wasi.targets @akoeplinger -/src/mono/browser @lewing @pavelsavara -/src/mono/wasi @lewing @pavelsavara -/src/mono/wasm @lewing @pavelsavara -/src/mono/browser/debugger @thaystg @ilonatommy -/src/mono/wasm/build @maraf @akoeplinger -/src/mono/wasi/build @maraf @akoeplinger -/src/mono/browser/build @maraf @akoeplinger -/src/mono/sample/wasm @lewing @pavelsavara -/src/mono/sample/wasi @lewing @pavelsavara -/src/libraries/System.Runtime.InteropServices.JavaScript @lewing @pavelsavara - -/src/mono/nuget/*WebAssembly*/ @lewing @akoeplinger -/src/mono/nuget/*MonoTargets*/ @lewing @akoeplinger -/src/mono/nuget/*BrowserDebugHost*/ @lewing @akoeplinger -/src/mono/nuget/*Workload.Mono.Toolchain*/ @lewing @akoeplinger -/src/mono/nuget/*MonoAOTCompiler*/ @lewing @akoeplinger - -/src/mono/wasm/Wasm* @maraf @ilonatommy -/src/mono/wasm/testassets @maraf @ilonatommy -/src/mono/wasi/testassets @maraf @ilonatommy -/src/tasks/WasmAppBuilder/ @maraf @akoeplinger -/src/tasks/WorkloadBuildTasks/ @akoeplinger -/src/tasks/AotCompilerTask/ @akoeplinger -/src/tasks/WasmBuildTasks/ @maraf @akoeplinger - -/eng/pipelines/**/*wasm* @akoeplinger - -# ILLink codeowners -/src/tools/illink/ @marek-safar -/src/tools/illink/src/analyzer/ @radekdoulik -/src/tools/illink/src/ILLink.Tasks/ @sbomer -/src/tools/illink/src/ILLink.RoslynAnalyzer/ @sbomer -/src/tools/illink/src/linker/ @marek-safar @mrvoorhe -/src/tools/illink/test/ @marek-safar @mrvoorhe - -# Obsoletions / Custom Diagnostics - -/docs/project/list-of-diagnostics.md @jeffhandley -/src/libraries/Common/src/System/Obsoletions.cs @jeffhandley - -# Area ownership and repo automation -/docs/area-owners.* @jeffhandley -/docs/issue*.md @jeffhandley -/.github/policies/ @jeffhandley @mkArtakMSFT -/.github/workflows/ @jeffhandley @dotnet/runtime-infrastructure diff --git a/Directory.Build.props b/Directory.Build.props index 99eee260233d..b082475fb5e8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -229,7 +229,7 @@ - runtime + runtimelab https://github.com/dotnet/$(GitHubRepositoryName) https://dot.net microsoft,dotnetframework diff --git a/eng/Versions.props b/eng/Versions.props index 28f6b0c3ea4b..cabfa3d622d2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -12,7 +12,7 @@ 8.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet9)').Build),11)) 7.0.20 6.0.36 - rc + unsafe 1 false From 73b3389269119fe6e2d824cd6bdfff22c6c9f16a Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 29 Oct 2025 01:19:50 -0700 Subject: [PATCH 3/9] Typo --- .../System.Private.CoreLib/src/System/ReadOnlyMemory.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs index 7ad6d2af92ef..abbba4c39694 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs @@ -245,8 +245,8 @@ public ReadOnlySpan Span { Span memoryManagerSpan = Unsafe.As>(tmpObject).GetSpan(); refToReturn = ref MemoryMarshal.GetReference(memoryManagerSpan); + lengthOfUnderlyingSpan = memoryManagerSpan.Length; } - lengthOfUnderlyingSpan = memoryManagerSpan.Length; } // If the Memory or ReadOnlyMemory instance is torn, this property getter has undefined behavior. From 8aec308a51243dfb1e0bd2c78803ba3843f78e95 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Sat, 8 Nov 2025 13:13:36 -0800 Subject: [PATCH 4/9] Initial work from Claude --- .../src/System/Array.CoreCLR.cs | 21 ++++-- .../src/System/Delegate.CoreCLR.cs | 4 +- .../src/System/MulticastDelegate.CoreCLR.cs | 9 ++- .../src/System/RuntimeType.CoreCLR.cs | 14 +++- .../Concurrent/ConcurrentDictionary.cs | 4 +- .../System/Collections/Generic/Dictionary.cs | 7 +- .../src/System/Collections/Generic/HashSet.cs | 4 +- .../src/System/ComAwareWeakReference.cs | 22 ++++-- .../src/System/Delegate.cs | 16 +++- .../src/System/IO/BinaryReader.cs | 13 +++- .../src/System/IO/RandomAccess.Unix.cs | 6 +- .../src/System/Memory.cs | 16 +++- .../src/System/ReadOnlyMemory.cs | 17 ++++- .../CompilerServices/ConditionalWeakTable.cs | 12 ++- .../ConfiguredValueTaskAwaitable.cs | 42 +++++++++-- .../CompilerServices/RuntimeHelpers.cs | 5 +- .../CompilerServices/ValueTaskAwaiter.cs | 42 +++++++++-- .../Runtime/InteropServices/ComWrappers.cs | 16 +++- .../Runtime/InteropServices/GCHandle.T.cs | 7 +- .../Marshalling/PointerArrayMarshaller.cs | 28 ++++++- .../Runtime/InteropServices/MemoryMarshal.cs | 20 ++++- .../InteropServices/PinnedGCHandle.T.cs | 7 +- .../InteropServices/TrackerObjectManager.cs | 6 +- .../Runtime/InteropServices/WeakGCHandle.T.cs | 6 +- .../Strings/Helpers/AhoCorasickNode.cs | 7 +- .../src/System/String.Manipulation.cs | 6 +- .../src/System/Threading/Tasks/Task.cs | 2 +- .../src/System/Threading/Tasks/ValueTask.cs | 74 ++++++++++++++++--- .../Threading/ThreadInt64PersistentCounter.cs | 21 +++++- .../System/Threading/ThreadPoolWorkQueue.cs | 7 +- .../src/System/Threading/Volatile.cs | 11 ++- .../src/System/WeakReference.T.cs | 6 +- 32 files changed, 394 insertions(+), 84 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index 83287c4a4d0c..121cceb2ec66 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -401,7 +401,8 @@ internal IEnumerator GetEnumerator() { // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! - T[] @this = Unsafe.As(this); + T[] @this; + unsafe { @this = Unsafe.As(this); } int length = @this.Length; return length == 0 ? SZGenericArrayEnumerator.Empty : new SZGenericArrayEnumerator(@this, length); } @@ -411,7 +412,8 @@ private void CopyTo(T[] array, int index) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! - T[] @this = Unsafe.As(this); + T[] @this; + unsafe { @this = Unsafe.As(this); } Array.Copy(@this, 0, array, index, @this.Length); } @@ -419,7 +421,8 @@ internal int get_Count() { // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! - T[] @this = Unsafe.As(this); + T[] @this; + unsafe { @this = Unsafe.As(this); } return @this.Length; } @@ -427,7 +430,8 @@ internal T get_Item(int index) { // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! - T[] @this = Unsafe.As(this); + T[] @this; + unsafe { @this = Unsafe.As(this); } if ((uint)index >= (uint)@this.Length) { ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException(); @@ -440,7 +444,8 @@ internal void set_Item(int index, T value) { // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! - T[] @this = Unsafe.As(this); + T[] @this; + unsafe { @this = Unsafe.As(this); } if ((uint)index >= (uint)@this.Length) { ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException(); @@ -459,7 +464,8 @@ private bool Contains(T value) { // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! - T[] @this = Unsafe.As(this); + T[] @this; + unsafe { @this = Unsafe.As(this); } return Array.IndexOf(@this, value, 0, @this.Length) >= 0; } @@ -480,7 +486,8 @@ private int IndexOf(T value) { // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! - T[] @this = Unsafe.As(this); + T[] @this; + unsafe { @this = Unsafe.As(this); } return Array.IndexOf(@this, value, 0, @this.Length); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index 358dab7f4367..944bce459876 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -435,7 +435,9 @@ private bool BindToMethodInfo(object? target, IRuntimeMethodInfo method, Runtime private static MulticastDelegate InternalAlloc(RuntimeType type) { Debug.Assert(type.IsAssignableTo(typeof(MulticastDelegate))); - return Unsafe.As(RuntimeTypeHandle.InternalAlloc(type)); + MulticastDelegate result; + unsafe { result = Unsafe.As(RuntimeTypeHandle.InternalAlloc(type)); } + return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs index 1c9a4c6c384b..ae9c52f1f5bd 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs @@ -55,7 +55,8 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj) // the types are the same, obj should also be a // MulticastDelegate Debug.Assert(obj is MulticastDelegate, "Shouldn't have failed here since we already checked the types are the same!"); - MulticastDelegate d = Unsafe.As(obj); + MulticastDelegate d; + unsafe { d = Unsafe.As(obj); } if (_invocationCount != 0) { @@ -168,7 +169,11 @@ private static bool TrySetSlot(object?[] a, int index, object o) private unsafe MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready) { // First, allocate a new multicast delegate just like this one, i.e. same type as the this object - MulticastDelegate result = Unsafe.As(RuntimeTypeHandle.InternalAllocNoChecks(RuntimeHelpers.GetMethodTable(this))); + MulticastDelegate result; + unsafe + { + result = Unsafe.As(RuntimeTypeHandle.InternalAllocNoChecks(RuntimeHelpers.GetMethodTable(this))); + } // Performance optimization - if this already points to a true multicast delegate, // copy _methodPtr and _methodPtrAux fields rather than calling into the EE to get them diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index b64899d34bde..92ca7c41ef05 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -2448,7 +2448,12 @@ private RuntimeTypeCache? CacheIfExists { object? cache = GCHandle.InternalGet(m_cache); Debug.Assert(cache == null || cache is RuntimeTypeCache); - return Unsafe.As(cache); + RuntimeTypeCache? result; + unsafe + { + result = Unsafe.As(cache); + } + return result; } return null; } @@ -2465,7 +2470,12 @@ private RuntimeTypeCache Cache if (cache != null) { Debug.Assert(cache is RuntimeTypeCache); - return Unsafe.As(cache); + RuntimeTypeCache result; + unsafe + { + result = Unsafe.As(cache); + } + return result; } } return InitializeCache(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs index 74fafc9c8cb9..f6825abc6352 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -2321,7 +2321,9 @@ private static IAlternateEqualityComparer GetAlternateCompa where TAlternateKey : notnull, allows ref struct { Debug.Assert(IsCompatibleKey(tables)); - return Unsafe.As>(tables._comparer!); + IAlternateEqualityComparer result; + unsafe { result = Unsafe.As>(tables._comparer!); } + return result; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs index f6b9e545c405..7c87d4043873 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs @@ -737,7 +737,12 @@ internal static bool IsCompatibleKey(Dictionary dictionary) internal static IAlternateEqualityComparer GetAlternateComparer(Dictionary dictionary) { Debug.Assert(IsCompatibleKey(dictionary)); - return Unsafe.As>(dictionary._comparer)!; + IAlternateEqualityComparer result; + unsafe + { + result = Unsafe.As>(dictionary._comparer)!; + } + return result; } /// Gets the value associated with the specified alternate key. diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs index b7a30cbd904a..86146212066d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs @@ -444,7 +444,9 @@ internal static bool IsCompatibleItem(HashSet set) internal static IAlternateEqualityComparer GetAlternateComparer(HashSet set) { Debug.Assert(IsCompatibleItem(set)); - return Unsafe.As>(set._comparer)!; + IAlternateEqualityComparer result; + unsafe { result = Unsafe.As>(set._comparer)!; } + return result; } /// Adds the specified element to a set. diff --git a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs index 404bc41c5a68..4f14d6713665 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs @@ -112,7 +112,7 @@ private void SetTarget(object? target, ComInfo? comInfo) if (_comInfo != null) { // Check if the target is still null - target = Unsafe.As(GCHandle.InternalGet(_weakHandle)); + unsafe { target = Unsafe.As(GCHandle.InternalGet(_weakHandle)); } if (target == null) { // Resolve and reset. Perform runtime cast to catch bugs @@ -146,22 +146,32 @@ private static ComAwareWeakReference EnsureComAwareReference(ref nint taggedHand GC.SuppressFinalize(newRef); } - return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + ComAwareWeakReference result; + unsafe { result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } + return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static ComAwareWeakReference GetFromTaggedReference(nint taggedHandle) { Debug.Assert((taggedHandle & ComAwareBit) != 0); - return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + ComAwareWeakReference result; + unsafe { result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } + return result; } [MethodImpl(MethodImplOptions.NoInlining)] internal static void SetTarget(ref nint taggedHandle, object? target, ComInfo? comInfo) { - ComAwareWeakReference comAwareRef = comInfo != null ? - EnsureComAwareReference(ref taggedHandle) : - Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + ComAwareWeakReference comAwareRef; + if (comInfo != null) + { + comAwareRef = EnsureComAwareReference(ref taggedHandle); + } + else + { + unsafe { comAwareRef = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } + } comAwareRef.SetTarget(target, comInfo); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs index 6ba2252a52bf..0059bf634b4e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs @@ -78,7 +78,15 @@ public abstract partial class Delegate : ICloneable, ISerializable /// Gets a value that indicates whether the has a single invocation target. /// /// true if the has a single invocation target. - public bool HasSingleTarget => Unsafe.As(this).HasSingleTarget; + public bool HasSingleTarget + { + get + { + MulticastDelegate md; + unsafe { md = Unsafe.As(this); } + return md.HasSingleTarget; + } + } #endif /// @@ -94,7 +102,11 @@ public abstract partial class Delegate : ICloneable, ISerializable /// The method returns an empty enumerator for null delegate. /// public static System.Delegate.InvocationListEnumerator EnumerateInvocationList(TDelegate? d) where TDelegate : System.Delegate - => new InvocationListEnumerator(Unsafe.As(d)); + { + MulticastDelegate? md; + unsafe { md = Unsafe.As(d); } + return new InvocationListEnumerator(md); + } /// /// Provides an enumerator for the invocation list of a delegate. diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs index 5a8bba6a6d2e..32471b9a43fe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs @@ -357,7 +357,11 @@ private int InternalReadChars(Span buffer) if (_isMemoryStream) { Debug.Assert(_stream is MemoryStream); - MemoryStream mStream = Unsafe.As(_stream); + MemoryStream mStream; + unsafe + { + mStream = Unsafe.As(_stream); + } int position = mStream.InternalGetPosition(); numBytes = mStream.InternalEmulateRead(numBytes); @@ -477,7 +481,12 @@ private ReadOnlySpan InternalRead(Span buffer) { // read directly from MemoryStream buffer Debug.Assert(_stream is MemoryStream); - return Unsafe.As(_stream).InternalReadSpan(buffer.Length); + MemoryStream mStream; + unsafe + { + mStream = Unsafe.As(_stream); + } + return mStream.InternalReadSpan(buffer.Length); } else { diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs index 147e3815812d..11be3f564397 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs @@ -70,7 +70,11 @@ internal static unsafe long ReadScatterAtOffset(SafeFileHandle handle, IReadOnly for (int i = 0; i < buffersCount; i++) { Memory buffer = buffers[i]; - MemoryHandle memoryHandle = buffer.Pin(); + MemoryHandle memoryHandle; + unsafe + { + memoryHandle = buffer.Pin(); + } vectors[i] = new Interop.Sys.IOVector { Base = (byte*)memoryHandle.Pointer, Count = (UIntPtr)buffer.Length }; handles[i] = memoryHandle; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Memory.cs b/src/libraries/System.Private.CoreLib/src/System/Memory.cs index b37ef4260a6b..6133a373d59a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Memory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Memory.cs @@ -304,8 +304,13 @@ public Span Span // 'tmpObject is T[]' below also handles things like int[] <-> uint[] being convertible Debug.Assert(tmpObject is T[]); - refToReturn = ref MemoryMarshal.GetArrayDataReference(Unsafe.As(tmpObject)); - lengthOfUnderlyingSpan = Unsafe.As(tmpObject).Length; + T[] array; + unsafe + { + array = Unsafe.As(tmpObject); + } + refToReturn = ref MemoryMarshal.GetArrayDataReference(array); + lengthOfUnderlyingSpan = array.Length; } else { @@ -316,7 +321,12 @@ public Span Span // constructor or other public API which would allow such a conversion. Debug.Assert(tmpObject is MemoryManager); - Span memoryManagerSpan = Unsafe.As>(tmpObject).GetSpan(); + MemoryManager manager; + unsafe + { + manager = Unsafe.As>(tmpObject); + } + Span memoryManagerSpan = manager.GetSpan(); refToReturn = ref MemoryMarshal.GetReference(memoryManagerSpan); lengthOfUnderlyingSpan = memoryManagerSpan.Length; } diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs index abbba4c39694..80cb8e9a92ad 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlyMemory.cs @@ -331,25 +331,36 @@ public unsafe MemoryHandle Pin() // 'tmpObject is T[]' below also handles things like int[] <-> uint[] being convertible Debug.Assert(tmpObject is T[]); + T[] array; + unsafe + { + array = Unsafe.As(tmpObject); + } + // Array is already pre-pinned if (_index < 0) { // Unsafe.AsPointer is safe since it's pinned - void* pointer = Unsafe.Add(Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(Unsafe.As(tmpObject))), _index & RemoveFlagsBitMask); + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(array)), _index & RemoveFlagsBitMask); return new MemoryHandle(pointer); } else { // Unsafe.AsPointer is safe since the handle pins it GCHandle handle = GCHandle.Alloc(tmpObject, GCHandleType.Pinned); - void* pointer = Unsafe.Add(Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(Unsafe.As(tmpObject))), _index); + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(array)), _index); return new MemoryHandle(pointer, handle); } } else { Debug.Assert(tmpObject is MemoryManager); - return Unsafe.As>(tmpObject).Pin(_index); + MemoryManager manager; + unsafe + { + manager = Unsafe.As>(tmpObject); + } + return manager.Pin(_index); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs index 044f8647baa6..e311bdc755a3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -631,7 +631,10 @@ internal bool TryGetValueWorker(TKey key, [MaybeNullWhen(false)] out TValue valu Debug.Assert(key != null); // Key already validated as non-null int entryIndex = FindEntry(key, out object? secondary); - value = Unsafe.As(secondary); + unsafe + { + value = Unsafe.As(secondary); + } return entryIndex != -1; } @@ -682,8 +685,11 @@ internal bool TryGetEntry(int index, [NotNullWhen(true)] out TKey? key, [MaybeNu if (oKey != null) { - key = Unsafe.As(oKey); - value = Unsafe.As(oValue!); + unsafe + { + key = Unsafe.As(oKey); + value = Unsafe.As(oValue!); + } return true; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 1700fb0cca8a..78dbffc1eeab 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -60,7 +60,12 @@ public void OnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + source.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.FlowExecutionContext | (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); } @@ -82,7 +87,12 @@ public void UnsafeOnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + source.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else @@ -102,7 +112,12 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + source.OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else @@ -165,7 +180,12 @@ public void OnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + source.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.FlowExecutionContext | (_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None)); } @@ -187,7 +207,12 @@ public void UnsafeOnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + source.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else @@ -207,7 +232,12 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + source.OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, _value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None); } else diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs index 83e401940e4d..091387459e2e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.cs @@ -51,7 +51,10 @@ public static T[] GetSubArray(T[] array, Range range) // an array of the exact same backing type. The cast to T[] will // never fail. - dest = Unsafe.As(Array.CreateInstanceFromArrayType(array.GetType(), length)); + unsafe + { + dest = Unsafe.As(Array.CreateInstanceFromArrayType(array.GetType(), length)); + } } // In either case, the newly-allocated array is the exact same type as the diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs index c242ad3f2ad2..78200ab3ad65 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs @@ -55,7 +55,12 @@ public void OnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + source.OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); } else { @@ -75,7 +80,12 @@ public void UnsafeOnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As(obj).OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + source.OnCompleted(s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { @@ -94,7 +104,12 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + source.OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { @@ -137,7 +152,12 @@ public void OnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + source.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext | ValueTaskSourceOnCompletedFlags.FlowExecutionContext); } else { @@ -157,7 +177,12 @@ public void UnsafeOnCompleted(Action continuation) } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + source.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { @@ -176,7 +201,12 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { - Unsafe.As>(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + source.OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token, ValueTaskSourceOnCompletedFlags.UseSchedulingContext); } else { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs index f1ce1193e789..a344023d0632 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs @@ -132,7 +132,12 @@ public partial struct ComInterfaceDispatch public static unsafe T GetInstance(ComInterfaceDispatch* dispatchPtr) where T : class { ManagedObjectWrapper* comInstance = ToManagedObjectWrapper(dispatchPtr); - return Unsafe.As(comInstance->Holder!.WrappedObject); + T result; + unsafe + { + result = Unsafe.As(comInstance->Holder!.WrappedObject); + } + return result; } internal static unsafe ManagedObjectWrapper* ToManagedObjectWrapper(ComInterfaceDispatch* dispatchPtr) @@ -226,7 +231,14 @@ public ManagedObjectWrapperHolder? Holder if (handle == IntPtr.Zero) return null; else - return Unsafe.As(GCHandle.FromIntPtr(handle).Target); + { + ManagedObjectWrapperHolder? holder; + unsafe + { + holder = Unsafe.As(GCHandle.FromIntPtr(handle).Target); + } + return holder; + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs index 7aa92f995342..1e29d10b7953 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs @@ -49,7 +49,12 @@ public readonly T Target IntPtr handle = _handle; GCHandle.CheckUninitialized(handle); // Skip the type check to provide lowest overhead. - return Unsafe.As(GCHandle.InternalGet(handle)!); + T result; + unsafe + { + result = Unsafe.As(GCHandle.InternalGet(handle)!); + } + return result; } set { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs index d0a3dfae3e8d..27e0ad4c7fe3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs @@ -50,7 +50,14 @@ public static unsafe class PointerArrayMarshaller /// The managed array to get a source for. /// The containing the managed elements to marshal. public static ReadOnlySpan GetManagedValuesSource(T*[]? managed) - => Unsafe.As(managed); + { + IntPtr[]? result; + unsafe + { + result = Unsafe.As(managed); + } + return result; + } /// /// Gets a destination for the unmanaged elements in the array. @@ -86,7 +93,14 @@ public static Span GetUnmanagedValuesDestination(TUnmanagedEl /// The managed array to get a destination for. /// The of managed elements. public static Span GetManagedValuesDestination(T*[]? managed) - => Unsafe.As(managed); + { + IntPtr[]? result; + unsafe + { + result = Unsafe.As(managed); + } + return result; + } /// /// Gets a source for the unmanaged elements in the array. @@ -166,7 +180,15 @@ public void FromManaged(T*[]? array, Span buffer) /// Returns a span that points to the memory where the managed values of the array are stored. /// /// A span over managed values of the array. - public ReadOnlySpan GetManagedValuesSource() => Unsafe.As(_managedArray); + public ReadOnlySpan GetManagedValuesSource() + { + IntPtr[]? result; + unsafe + { + result = Unsafe.As(_managedArray); + } + return result; + } /// /// Returns a span that points to the memory where the unmanaged values of the array should be stored. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index 15e8b05dd5c8..2d412e02af45 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -287,7 +287,12 @@ public static bool TryGetArray(ReadOnlyMemory memory, out ArraySegment // The array may be prepinned, so remove the high bit from the start index in the line below. // The ArraySegment ctor will perform bounds checking on index & length. - segment = new ArraySegment(Unsafe.As(obj), index & ReadOnlyMemory.RemoveFlagsBitMask, length); + T[] array; + unsafe + { + array = Unsafe.As(obj); + } + segment = new ArraySegment(array, index & ReadOnlyMemory.RemoveFlagsBitMask, length); return true; } else @@ -296,7 +301,12 @@ public static bool TryGetArray(ReadOnlyMemory memory, out ArraySegment // is MemoryManager. The ArraySegment ctor will perform bounds checking on index & length. Debug.Assert(obj is MemoryManager); - if (Unsafe.As>(obj).TryGetArray(out ArraySegment tempArraySegment)) + MemoryManager manager; + unsafe + { + manager = Unsafe.As>(obj); + } + if (manager.TryGetArray(out ArraySegment tempArraySegment)) { segment = new ArraySegment(tempArraySegment.Array!, tempArraySegment.Offset + index, length); return true; @@ -408,7 +418,11 @@ static IEnumerable FromString(string s, int offset, int count) // enumerable. Otherwise, return an iterator dedicated to enumerating the object. if (RuntimeHelpers.ObjectHasComponentSize(obj)) // Same check as in TryGetArray to confirm that obj is a T[] or a U[] which is blittable to a T[]. { - T[] array = Unsafe.As(obj); + T[] array; + unsafe + { + array = Unsafe.As(obj); + } index &= ReadOnlyMemory.RemoveFlagsBitMask; // the array may be prepinned, so remove the high bit from the start index in the line below. return index == 0 && length == array.Length ? array : diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs index 9f2434af1ae3..9871d44945dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs @@ -51,7 +51,12 @@ public readonly T Target IntPtr handle = _handle; GCHandle.CheckUninitialized(handle); // Skip the type check to provide lowest overhead. - return Unsafe.As(GCHandle.InternalGet(handle)!); + T result; + unsafe + { + result = Unsafe.As(GCHandle.InternalGet(handle)!); + } + return result; } set { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.cs index 4243caf0097f..a2e3b3beb8da 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/TrackerObjectManager.cs @@ -72,7 +72,11 @@ internal static void ReleaseExternalObjectsFromCurrentThread() { foreach (GCHandle weakNativeObjectWrapperHandle in s_referenceTrackerNativeObjectWrapperCache) { - ReferenceTrackerNativeObjectWrapper? nativeObjectWrapper = Unsafe.As(weakNativeObjectWrapperHandle.Target); + ReferenceTrackerNativeObjectWrapper? nativeObjectWrapper; + unsafe + { + nativeObjectWrapper = Unsafe.As(weakNativeObjectWrapperHandle.Target); + } if (nativeObjectWrapper != null && nativeObjectWrapper._contextToken == contextToken) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs index 348dfc7657d8..41b67129c8db 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs @@ -53,7 +53,11 @@ public readonly bool TryGetTarget([NotNullWhen(true)] out T? target) IntPtr handle = _handle; GCHandle.CheckUninitialized(handle); // Skip the type check to provide lowest overhead. - T? obj = Unsafe.As(GCHandle.InternalGet(handle)); + T? obj; + unsafe + { + obj = Unsafe.As(GCHandle.InternalGet(handle)); + } target = obj; return obj != null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs index d2f2d9de6f07..cc9ed2ebe552 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs @@ -53,7 +53,12 @@ public readonly bool TryGetChild(char c, out int index) } else { - return Unsafe.As>(children).TryGetValue(c, out index); + Dictionary dict; + unsafe + { + dict = Unsafe.As>(children); + } + return dict.TryGetValue(c, out index); } index = 0; diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index 7acc23d53c65..e16bf7499838 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -947,7 +947,11 @@ private static string JoinCore(ReadOnlySpan separator, IEnumerable v // and string.Concat(IEnumerable) can be used as an efficient // enumerable-based equivalent of new string(char[]). - IEnumerator en = Unsafe.As>(e); + IEnumerator en; + unsafe + { + en = Unsafe.As>(e); + } char c = en.Current; // save the first value if (!en.MoveNext()) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 70e778010cde..64a86952c707 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -2382,7 +2382,7 @@ private void ExecuteWithThreadLocal(ref Task? currentTaskSlot, Thread? threadPoo { Debug.Assert(obj is Task); // Only used privately to pass directly to EC.Run - Unsafe.As(obj).InnerInvoke(); + unsafe { Unsafe.As(obj).InnerInvoke(); } }; /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs index 5de25750326e..260b2a675b3e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs @@ -173,10 +173,20 @@ public Task AsTask() { object? obj = _obj; Debug.Assert(obj == null || obj is Task || obj is IValueTaskSource); - return - obj == null ? Task.CompletedTask : - obj as Task ?? - GetTaskForValueTaskSource(Unsafe.As(obj)); + if (obj == null) + { + return Task.CompletedTask; + } + if (obj is Task t) + { + return t; + } + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + return GetTaskForValueTaskSource(source); } /// Gets a that may be used at any point in the future. @@ -310,7 +320,12 @@ public bool IsCompleted return t.IsCompleted; } - return Unsafe.As(obj).GetStatus(_token) != ValueTaskSourceStatus.Pending; + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + return source.GetStatus(_token) != ValueTaskSourceStatus.Pending; } } @@ -333,7 +348,12 @@ public bool IsCompletedSuccessfully return t.IsCompletedSuccessfully; } - return Unsafe.As(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded; + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + return source.GetStatus(_token) == ValueTaskSourceStatus.Succeeded; } } @@ -355,7 +375,12 @@ public bool IsFaulted return t.IsFaulted; } - return Unsafe.As(obj).GetStatus(_token) == ValueTaskSourceStatus.Faulted; + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + return source.GetStatus(_token) == ValueTaskSourceStatus.Faulted; } } @@ -382,7 +407,12 @@ public bool IsCanceled return t.IsCanceled; } - return Unsafe.As(obj).GetStatus(_token) == ValueTaskSourceStatus.Canceled; + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + return source.GetStatus(_token) == ValueTaskSourceStatus.Canceled; } } @@ -401,7 +431,12 @@ internal void ThrowIfCompletedUnsuccessfully() } else { - Unsafe.As(obj).GetResult(_token); + IValueTaskSource source; + unsafe + { + source = Unsafe.As(obj); + } + source.GetResult(_token); } } } @@ -585,7 +620,12 @@ public Task AsTask() return t; } - return GetTaskForValueTaskSource(Unsafe.As>(obj)); + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + return GetTaskForValueTaskSource(source); } /// Gets a that may be used at any point in the future. @@ -717,7 +757,12 @@ public bool IsCompleted return t.IsCompleted; } - return Unsafe.As>(obj).GetStatus(_token) != ValueTaskSourceStatus.Pending; + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + return source.GetStatus(_token) != ValueTaskSourceStatus.Pending; } } @@ -740,7 +785,12 @@ public bool IsCompletedSuccessfully return t.IsCompletedSuccessfully; } - return Unsafe.As>(obj).GetStatus(_token) == ValueTaskSourceStatus.Succeeded; + IValueTaskSource source; + unsafe + { + source = Unsafe.As>(obj); + } + return source.GetStatus(_token) == ValueTaskSourceStatus.Succeeded; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs index 29cf2dce3056..7528cdc9a0aa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadInt64PersistentCounter.cs @@ -29,21 +29,36 @@ public ThreadInt64PersistentCounter() public static void Increment(object threadLocalCountObject) { Debug.Assert(threadLocalCountObject is ThreadLocalNode); - Unsafe.As(threadLocalCountObject).Increment(); + ThreadLocalNode node; + unsafe + { + node = Unsafe.As(threadLocalCountObject); + } + node.Increment(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Decrement(object threadLocalCountObject) { Debug.Assert(threadLocalCountObject is ThreadLocalNode); - Unsafe.As(threadLocalCountObject).Decrement(); + ThreadLocalNode node; + unsafe + { + node = Unsafe.As(threadLocalCountObject); + } + node.Decrement(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Add(object threadLocalCountObject, uint count) { Debug.Assert(threadLocalCountObject is ThreadLocalNode); - Unsafe.As(threadLocalCountObject).Add(count); + ThreadLocalNode node; + unsafe + { + node = Unsafe.As(threadLocalCountObject); + } + node.Add(count); } public object CreateThreadLocalCountObject() diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index 99455d29b80c..912f116a75f7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -1252,9 +1252,14 @@ private static void DispatchWorkItem(object workItem, Thread currentThread) else { Debug.Assert(workItem is IThreadPoolWorkItem); + IThreadPoolWorkItem tpWorkItem; + unsafe + { + tpWorkItem = Unsafe.As(workItem); + } try { - Unsafe.As(workItem).Execute(); + tpWorkItem.Execute(); } catch (Exception ex) when (ExceptionHandling.IsHandledByGlobalHandler(ex)) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs index e8b54f2314d2..38e3092255ef 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs @@ -218,8 +218,15 @@ private struct VolatileObject { public volatile object? Value; } [Intrinsic] [NonVersionable] [return: NotNullIfNotNull(nameof(location))] - public static T Read([NotNullIfNotNull(nameof(location))] ref readonly T location) where T : class? => - Unsafe.As(Unsafe.As(ref Unsafe.AsRef(in location)).Value)!; + public static T Read([NotNullIfNotNull(nameof(location))] ref readonly T location) where T : class? + { + T result; + unsafe + { + result = Unsafe.As(Unsafe.As(ref Unsafe.AsRef(in location)).Value)!; + } + return result; + } [Intrinsic] [NonVersionable] diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs index cf19880b036a..075866b5a6d9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs @@ -143,7 +143,7 @@ private T? Target { ComAwareWeakReference cwr = ComAwareWeakReference.GetFromTaggedReference(th); - target = Unsafe.As(cwr.Target) ?? cwr.RehydrateTarget(); + unsafe { target = Unsafe.As(cwr.Target) ?? cwr.RehydrateTarget(); } // must keep the instance alive as long as we use the handle. GC.KeepAlive(this); @@ -154,9 +154,9 @@ private T? Target // unsafe cast is ok as the handle cannot be destroyed and recycled while we keep the instance alive #if FEATURE_JAVAMARSHAL - target = Unsafe.As(GCHandle.InternalGetBridgeWait(th)); + unsafe { target = Unsafe.As(GCHandle.InternalGetBridgeWait(th)); } #else - target = Unsafe.As(GCHandle.InternalGet(th)); + unsafe { target = Unsafe.As(GCHandle.InternalGet(th)); } #endif // must keep the instance alive as long as we use the handle. From f2e66afa9dded3cdd5b926ecc26f07cdf5a43e82 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 00:07:36 +0000 Subject: [PATCH 5/9] Address PR feedback: revert Versions.props/Directory.Build.props/CODEOWNERS and format unsafe blocks Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- .github/CODEOWNERS | 117 ++++++++++++++++++ Directory.Build.props | 2 +- eng/Versions.props | 2 +- .../src/System/Array.CoreCLR.cs | 42 +++++-- .../src/System/Delegate.CoreCLR.cs | 6 +- .../src/System/MulticastDelegate.CoreCLR.cs | 6 +- .../Concurrent/ConcurrentDictionary.cs | 6 +- .../src/System/Collections/Generic/HashSet.cs | 6 +- .../src/System/ComAwareWeakReference.cs | 24 +++- .../src/System/Delegate.cs | 12 +- .../src/System/Threading/Tasks/Task.cs | 6 +- .../src/System/WeakReference.T.cs | 18 ++- 12 files changed, 224 insertions(+), 23 deletions(-) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000000..9a575e240931 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,117 @@ +# Users referenced in this file will automatically be requested as reviewers for PRs that modify the given paths. +# See https://help.github.com/articles/about-code-owners/ + +/src/libraries/Common/src/System/Net/Http/aspnetcore/ @dotnet/http +/src/libraries/Common/tests/Tests/System/Net/aspnetcore/ @dotnet/http + +# CoreCLR Code Owners + +/src/coreclr/inc/corinfo.h @dotnet/jit-contrib +/src/coreclr/inc/corjit.h @dotnet/jit-contrib +/src/coreclr/jit/ @dotnet/jit-contrib +/src/coreclr/interpreter/ @brzvlad @janvorli @kg +/src/coreclr/vm/interpexec* @brzvlad @janvorli @kg +/src/coreclr/nativeaot @MichalStrehovsky +/src/coreclr/tools/Common @dotnet/crossgen-contrib @MichalStrehovsky +/src/coreclr/tools/aot @dotnet/crossgen-contrib +/src/coreclr/tools/aot/ILCompiler.Compiler @MichalStrehovsky +/src/coreclr/tools/aot/ILCompiler.RyuJit @MichalStrehovsky +/src/coreclr/tools/aot/ILCompiler.MetadataTransform @MichalStrehovsky + +# Mono Code Owners + +/src/mono @steveisok @vitek-karas + +/src/mono/llvm @steveisok @vitek-karas + +/src/mono/mono/arch @steveisok @vitek-karas +/src/mono/mono/eglib @steveisok @vitek-karas + +/src/mono/mono/metadata @thaystg @steveisok @vitek-karas +/src/mono/mono/metadata/*-win* @lateralusX @steveisok +/src/mono/mono/metadata/handle* @steveisok @vitek-karas +/src/mono/mono/metadata/monitor* @brzvlad @steveisok @vitek-karas +/src/mono/mono/metadata/sgen* @brzvlad @steveisok @vitek-karas +/src/mono/mono/metadata/thread* @lateralusX @steveisok @vitek-karas +/src/mono/mono/metadata/w32* @lateralusX @steveisok @vitek-karas + +/src/mono/mono/eventpipe @lateralusX @steveisok @vitek-karas + +/src/mono/mono/mini @steveisok @vitek-karas +/src/mono/mono/mini/*cfgdump* @steveisok @vitek-karas +/src/mono/mono/mini/*exceptions* @BrzVlad @steveisok @vitek-karas +/src/mono/mono/mini/*llvm* @steveisok @vitek-karas +/src/mono/mono/mini/*ppc* @steveisok @vitek-karas +/src/mono/mono/mini/*profiler* @BrzVlad @steveisok @vitek-karas +/src/mono/mono/mini/*riscv* @steveisok @vitek-karas +/src/mono/mono/mini/*type-check* @steveisok @vitek-karas +/src/mono/mono/mini/debugger-agent.c @thaystg @steveisok @vitek-karas +/src/mono/mono/mini/interp/* @BrzVlad @kotlarmilos @steveisok @vitek-karas +/src/mono/mono/mini/interp/*jiterp* @kg @steveisok @vitek-karas +/src/mono/mono/mini/*simd* @steveisok @vitek-karas + +/src/mono/mono/profiler @BrzVlad @steveisok @vitek-karas +/src/mono/mono/sgen @BrzVlad @steveisok @vitek-karas + +/src/mono/mono/utils @steveisok @vitek-karas +/src/mono/mono/utils/*-win* @lateralusX @steveisok @vitek-karas +/src/mono/mono/utils/atomic* @steveisok @vitek-karas +/src/mono/mono/utils/mono-hwcap* @steveisok @vitek-karas +/src/mono/mono/utils/mono-mem* @steveisok @vitek-karas +/src/mono/mono/utils/mono-threads* @steveisok @vitek-karas + +/src/mono/dlls @thaystg @steveisok @vitek-karas + +/src/native/public/mono @steveisok @vitek-karas +/src/native/eventpipe @noahfalk @lateralusX @mdh1418 +/src/native/external/libunwind @janvorli @AaronRobinsonMSFT @dotnet/dotnet-diag +/src/native/external/libunwind_extras @janvorli @AaronRobinsonMSFT @dotnet/dotnet-diag + +/src/libraries/sendtohelix-browser.targets @akoeplinger +/src/libraries/sendtohelix-wasm.targets @akoeplinger +/src/libraries/sendtohelix-wasi.targets @akoeplinger +/src/mono/browser @lewing @pavelsavara +/src/mono/wasi @lewing @pavelsavara +/src/mono/wasm @lewing @pavelsavara +/src/mono/browser/debugger @thaystg @ilonatommy +/src/mono/wasm/build @maraf @akoeplinger +/src/mono/wasi/build @maraf @akoeplinger +/src/mono/browser/build @maraf @akoeplinger +/src/mono/sample/wasm @lewing @pavelsavara +/src/mono/sample/wasi @lewing @pavelsavara +/src/libraries/System.Runtime.InteropServices.JavaScript @lewing @pavelsavara + +/src/mono/nuget/*WebAssembly*/ @lewing @akoeplinger +/src/mono/nuget/*MonoTargets*/ @lewing @akoeplinger +/src/mono/nuget/*BrowserDebugHost*/ @lewing @akoeplinger +/src/mono/nuget/*Workload.Mono.Toolchain*/ @lewing @akoeplinger +/src/mono/nuget/*MonoAOTCompiler*/ @lewing @akoeplinger + +/src/mono/wasm/Wasm* @maraf @ilonatommy +/src/mono/wasm/testassets @maraf @ilonatommy +/src/mono/wasi/testassets @maraf @ilonatommy +/src/tasks/WasmAppBuilder/ @maraf @akoeplinger +/src/tasks/WorkloadBuildTasks/ @akoeplinger +/src/tasks/AotCompilerTask/ @akoeplinger +/src/tasks/WasmBuildTasks/ @maraf @akoeplinger + +/eng/pipelines/**/*wasm* @akoeplinger + +# ILLink codeowners +/src/tools/illink/ @marek-safar +/src/tools/illink/src/analyzer/ @radekdoulik +/src/tools/illink/src/ILLink.Tasks/ @sbomer +/src/tools/illink/src/ILLink.RoslynAnalyzer/ @sbomer +/src/tools/illink/src/linker/ @marek-safar @mrvoorhe +/src/tools/illink/test/ @marek-safar @mrvoorhe + +# Obsoletions / Custom Diagnostics + +/docs/project/list-of-diagnostics.md @jeffhandley +/src/libraries/Common/src/System/Obsoletions.cs @jeffhandley + +# Area ownership and repo automation +/docs/area-owners.* @jeffhandley +/docs/issue*.md @jeffhandley +/.github/policies/ @jeffhandley @mkArtakMSFT +/.github/workflows/ @jeffhandley @dotnet/runtime-infrastructure diff --git a/Directory.Build.props b/Directory.Build.props index b082475fb5e8..99eee260233d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -229,7 +229,7 @@ - runtimelab + runtime https://github.com/dotnet/$(GitHubRepositoryName) https://dot.net microsoft,dotnetframework diff --git a/eng/Versions.props b/eng/Versions.props index cabfa3d622d2..28f6b0c3ea4b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -12,7 +12,7 @@ 8.0.$([MSBuild]::Add($([System.Version]::Parse('$(PackageVersionNet9)').Build),11)) 7.0.20 6.0.36 - unsafe + rc 1 false diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index 121cceb2ec66..952e84815cde 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -402,7 +402,11 @@ internal IEnumerator GetEnumerator() // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - unsafe { @this = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + @this = Unsafe.As(this); + } int length = @this.Length; return length == 0 ? SZGenericArrayEnumerator.Empty : new SZGenericArrayEnumerator(@this, length); } @@ -413,7 +417,11 @@ private void CopyTo(T[] array, int index) // ! or you may introduce a security hole! T[] @this; - unsafe { @this = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + @this = Unsafe.As(this); + } Array.Copy(@this, 0, array, index, @this.Length); } @@ -422,7 +430,11 @@ internal int get_Count() // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - unsafe { @this = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + @this = Unsafe.As(this); + } return @this.Length; } @@ -431,7 +443,11 @@ internal T get_Item(int index) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - unsafe { @this = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + @this = Unsafe.As(this); + } if ((uint)index >= (uint)@this.Length) { ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException(); @@ -445,7 +461,11 @@ internal void set_Item(int index, T value) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - unsafe { @this = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + @this = Unsafe.As(this); + } if ((uint)index >= (uint)@this.Length) { ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException(); @@ -465,7 +485,11 @@ private bool Contains(T value) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - unsafe { @this = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + @this = Unsafe.As(this); + } return Array.IndexOf(@this, value, 0, @this.Length) >= 0; } @@ -487,7 +511,11 @@ private int IndexOf(T value) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - unsafe { @this = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + @this = Unsafe.As(this); + } return Array.IndexOf(@this, value, 0, @this.Length); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index 944bce459876..c7fed3cf5ef3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -436,7 +436,11 @@ private static MulticastDelegate InternalAlloc(RuntimeType type) { Debug.Assert(type.IsAssignableTo(typeof(MulticastDelegate))); MulticastDelegate result; - unsafe { result = Unsafe.As(RuntimeTypeHandle.InternalAlloc(type)); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + result = Unsafe.As(RuntimeTypeHandle.InternalAlloc(type)); + } return result; } diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs index ae9c52f1f5bd..209a132003d3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs @@ -56,7 +56,11 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj) // MulticastDelegate Debug.Assert(obj is MulticastDelegate, "Shouldn't have failed here since we already checked the types are the same!"); MulticastDelegate d; - unsafe { d = Unsafe.As(obj); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + d = Unsafe.As(obj); + } if (_invocationCount != 0) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs index f6825abc6352..f1fc117d1787 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -2322,7 +2322,11 @@ private static IAlternateEqualityComparer GetAlternateCompa { Debug.Assert(IsCompatibleKey(tables)); IAlternateEqualityComparer result; - unsafe { result = Unsafe.As>(tables._comparer!); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + result = Unsafe.As>(tables._comparer!); + } return result; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs index 86146212066d..3e649f33b28a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs @@ -445,7 +445,11 @@ internal static IAlternateEqualityComparer GetAlternateComparer(H { Debug.Assert(IsCompatibleItem(set)); IAlternateEqualityComparer result; - unsafe { result = Unsafe.As>(set._comparer)!; } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + result = Unsafe.As>(set._comparer)!; + } return result; } diff --git a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs index 4f14d6713665..a7a5ce314d4b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs @@ -112,7 +112,11 @@ private void SetTarget(object? target, ComInfo? comInfo) if (_comInfo != null) { // Check if the target is still null - unsafe { target = Unsafe.As(GCHandle.InternalGet(_weakHandle)); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + target = Unsafe.As(GCHandle.InternalGet(_weakHandle)); + } if (target == null) { // Resolve and reset. Perform runtime cast to catch bugs @@ -147,7 +151,11 @@ private static ComAwareWeakReference EnsureComAwareReference(ref nint taggedHand } ComAwareWeakReference result; - unsafe { result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + } return result; } @@ -156,7 +164,11 @@ internal static ComAwareWeakReference GetFromTaggedReference(nint taggedHandle) { Debug.Assert((taggedHandle & ComAwareBit) != 0); ComAwareWeakReference result; - unsafe { result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + } return result; } @@ -170,7 +182,11 @@ internal static void SetTarget(ref nint taggedHandle, object? target, ComInfo? c } else { - unsafe { comAwareRef = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + comAwareRef = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + } } comAwareRef.SetTarget(target, comInfo); diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs index 0059bf634b4e..6b1ab91e395b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs @@ -83,7 +83,11 @@ public bool HasSingleTarget get { MulticastDelegate md; - unsafe { md = Unsafe.As(this); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + md = Unsafe.As(this); + } return md.HasSingleTarget; } } @@ -104,7 +108,11 @@ public bool HasSingleTarget public static System.Delegate.InvocationListEnumerator EnumerateInvocationList(TDelegate? d) where TDelegate : System.Delegate { MulticastDelegate? md; - unsafe { md = Unsafe.As(d); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + md = Unsafe.As(d); + } return new InvocationListEnumerator(md); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 64a86952c707..1d3dd113e546 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -2382,7 +2382,11 @@ private void ExecuteWithThreadLocal(ref Task? currentTaskSlot, Thread? threadPoo { Debug.Assert(obj is Task); // Only used privately to pass directly to EC.Run - unsafe { Unsafe.As(obj).InnerInvoke(); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + Unsafe.As(obj).InnerInvoke(); + } }; /// diff --git a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs index 075866b5a6d9..a2b6214e7e2d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/WeakReference.T.cs @@ -143,7 +143,11 @@ private T? Target { ComAwareWeakReference cwr = ComAwareWeakReference.GetFromTaggedReference(th); - unsafe { target = Unsafe.As(cwr.Target) ?? cwr.RehydrateTarget(); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + target = Unsafe.As(cwr.Target) ?? cwr.RehydrateTarget(); + } // must keep the instance alive as long as we use the handle. GC.KeepAlive(this); @@ -154,9 +158,17 @@ private T? Target // unsafe cast is ok as the handle cannot be destroyed and recycled while we keep the instance alive #if FEATURE_JAVAMARSHAL - unsafe { target = Unsafe.As(GCHandle.InternalGetBridgeWait(th)); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + target = Unsafe.As(GCHandle.InternalGetBridgeWait(th)); + } #else - unsafe { target = Unsafe.As(GCHandle.InternalGet(th)); } + // FIXME: review unsafe to confirm correct annotation + unsafe + { + target = Unsafe.As(GCHandle.InternalGet(th)); + } #endif // must keep the instance alive as long as we use the handle. From 9a8c31ba83be10aa7e979c33e05fd1148ecad2dd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 08:25:40 +0000 Subject: [PATCH 6/9] Address PR feedback: move comment, remove FIXME from Array.CoreCLR.cs, refactor Delegate.CoreCLR.cs, add clarifying comments Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- .../System.Private.CoreLib/src/System/Array.CoreCLR.cs | 7 ------- .../System.Private.CoreLib/src/System/Delegate.CoreCLR.cs | 4 +--- .../CompilerServices/ConfiguredValueTaskAwaitable.cs | 3 +++ .../src/System/Runtime/InteropServices/MemoryMarshal.cs | 2 +- 4 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index 952e84815cde..d9f10f276ea3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -402,7 +402,6 @@ internal IEnumerator GetEnumerator() // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - // FIXME: review unsafe to confirm correct annotation unsafe { @this = Unsafe.As(this); @@ -417,7 +416,6 @@ private void CopyTo(T[] array, int index) // ! or you may introduce a security hole! T[] @this; - // FIXME: review unsafe to confirm correct annotation unsafe { @this = Unsafe.As(this); @@ -430,7 +428,6 @@ internal int get_Count() // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - // FIXME: review unsafe to confirm correct annotation unsafe { @this = Unsafe.As(this); @@ -443,7 +440,6 @@ internal T get_Item(int index) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - // FIXME: review unsafe to confirm correct annotation unsafe { @this = Unsafe.As(this); @@ -461,7 +457,6 @@ internal void set_Item(int index, T value) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - // FIXME: review unsafe to confirm correct annotation unsafe { @this = Unsafe.As(this); @@ -485,7 +480,6 @@ private bool Contains(T value) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - // FIXME: review unsafe to confirm correct annotation unsafe { @this = Unsafe.As(this); @@ -511,7 +505,6 @@ private int IndexOf(T value) // ! Warning: "this" is an array, not an SZArrayHelper. See comments above // ! or you may introduce a security hole! T[] @this; - // FIXME: review unsafe to confirm correct annotation unsafe { @this = Unsafe.As(this); diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index c7fed3cf5ef3..3f6a11393497 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -435,13 +435,11 @@ private bool BindToMethodInfo(object? target, IRuntimeMethodInfo method, Runtime private static MulticastDelegate InternalAlloc(RuntimeType type) { Debug.Assert(type.IsAssignableTo(typeof(MulticastDelegate))); - MulticastDelegate result; // FIXME: review unsafe to confirm correct annotation unsafe { - result = Unsafe.As(RuntimeTypeHandle.InternalAlloc(type)); + return Unsafe.As(RuntimeTypeHandle.InternalAlloc(type)); } - return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs index 78dbffc1eeab..df22c760338f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConfiguredValueTaskAwaitable.cs @@ -60,6 +60,7 @@ public void OnCompleted(Action continuation) } else if (obj != null) { + // obj is either Task, null, or IValueTaskSource and the other cases are checked IValueTaskSource source; unsafe { @@ -87,6 +88,7 @@ public void UnsafeOnCompleted(Action continuation) } else if (obj != null) { + // obj is either Task, null, or IValueTaskSource and the other cases are checked IValueTaskSource source; unsafe { @@ -112,6 +114,7 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b } else if (obj != null) { + // obj is either Task, null, or IValueTaskSource and the other cases are checked IValueTaskSource source; unsafe { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index 2d412e02af45..a6de7e2b7094 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -285,13 +285,13 @@ public static bool TryGetArray(ReadOnlyMemory memory, out ArraySegment // or a U[] which is blittable to a T[] (e.g., int[] and uint[]). // The array may be prepinned, so remove the high bit from the start index in the line below. - // The ArraySegment ctor will perform bounds checking on index & length. T[] array; unsafe { array = Unsafe.As(obj); } + // The ArraySegment ctor will perform bounds checking on index & length. segment = new ArraySegment(array, index & ReadOnlyMemory.RemoveFlagsBitMask, length); return true; } From bc538f8e4b16cc45ec14acee3a5a6aa5a2de0909 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 14 Nov 2025 09:28:08 +0000 Subject: [PATCH 7/9] Refactor all temp variable patterns to return directly from unsafe blocks Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- .../src/System/RuntimeType.CoreCLR.cs | 8 ++------ .../System/Collections/Concurrent/ConcurrentDictionary.cs | 4 +--- .../src/System/Collections/Generic/Dictionary.cs | 4 +--- .../src/System/Collections/Generic/HashSet.cs | 4 +--- .../src/System/ComAwareWeakReference.cs | 8 ++------ .../System.Private.CoreLib/src/System/Delegate.cs | 8 ++------ 6 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 92ca7c41ef05..f1b7d3eb194d 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -2448,12 +2448,10 @@ private RuntimeTypeCache? CacheIfExists { object? cache = GCHandle.InternalGet(m_cache); Debug.Assert(cache == null || cache is RuntimeTypeCache); - RuntimeTypeCache? result; unsafe { - result = Unsafe.As(cache); + return Unsafe.As(cache); } - return result; } return null; } @@ -2470,12 +2468,10 @@ private RuntimeTypeCache Cache if (cache != null) { Debug.Assert(cache is RuntimeTypeCache); - RuntimeTypeCache result; unsafe { - result = Unsafe.As(cache); + return Unsafe.As(cache); } - return result; } } return InitializeCache(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs index f1fc117d1787..9e7dc8fd6f84 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -2321,13 +2321,11 @@ private static IAlternateEqualityComparer GetAlternateCompa where TAlternateKey : notnull, allows ref struct { Debug.Assert(IsCompatibleKey(tables)); - IAlternateEqualityComparer result; // FIXME: review unsafe to confirm correct annotation unsafe { - result = Unsafe.As>(tables._comparer!); + return Unsafe.As>(tables._comparer!); } - return result; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs index 7c87d4043873..a0118828d855 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs @@ -737,12 +737,10 @@ internal static bool IsCompatibleKey(Dictionary dictionary) internal static IAlternateEqualityComparer GetAlternateComparer(Dictionary dictionary) { Debug.Assert(IsCompatibleKey(dictionary)); - IAlternateEqualityComparer result; unsafe { - result = Unsafe.As>(dictionary._comparer)!; + return Unsafe.As>(dictionary._comparer)!; } - return result; } /// Gets the value associated with the specified alternate key. diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs index 3e649f33b28a..3c655b7a6e39 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs @@ -444,13 +444,11 @@ internal static bool IsCompatibleItem(HashSet set) internal static IAlternateEqualityComparer GetAlternateComparer(HashSet set) { Debug.Assert(IsCompatibleItem(set)); - IAlternateEqualityComparer result; // FIXME: review unsafe to confirm correct annotation unsafe { - result = Unsafe.As>(set._comparer)!; + return Unsafe.As>(set._comparer)!; } - return result; } /// Adds the specified element to a set. diff --git a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs index a7a5ce314d4b..e7b741c95839 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs @@ -150,26 +150,22 @@ private static ComAwareWeakReference EnsureComAwareReference(ref nint taggedHand GC.SuppressFinalize(newRef); } - ComAwareWeakReference result; // FIXME: review unsafe to confirm correct annotation unsafe { - result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } - return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static ComAwareWeakReference GetFromTaggedReference(nint taggedHandle) { Debug.Assert((taggedHandle & ComAwareBit) != 0); - ComAwareWeakReference result; // FIXME: review unsafe to confirm correct annotation unsafe { - result = Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); + return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!); } - return result; } [MethodImpl(MethodImplOptions.NoInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs index 6b1ab91e395b..f2222071b764 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs @@ -82,13 +82,11 @@ public bool HasSingleTarget { get { - MulticastDelegate md; // FIXME: review unsafe to confirm correct annotation unsafe { - md = Unsafe.As(this); + return Unsafe.As(this).HasSingleTarget; } - return md.HasSingleTarget; } } #endif @@ -107,13 +105,11 @@ public bool HasSingleTarget /// public static System.Delegate.InvocationListEnumerator EnumerateInvocationList(TDelegate? d) where TDelegate : System.Delegate { - MulticastDelegate? md; // FIXME: review unsafe to confirm correct annotation unsafe { - md = Unsafe.As(d); + return new InvocationListEnumerator(Unsafe.As(d)); } - return new InvocationListEnumerator(md); } /// From c0df80473baa4ca9b9530243e49dbd776e7cf867 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 19 Nov 2025 22:30:27 +0000 Subject: [PATCH 8/9] Address PR comments: add unsafe to fields, remove FIXME, refactor return statements, add clarifying comments Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- .../src/System/MulticastDelegate.CoreCLR.cs | 3 +-- .../src/System/RuntimeType.CoreCLR.cs | 3 ++- .../src/System/Buffers/SharedArrayPool.cs | 7 +++++-- .../Collections/Concurrent/ConcurrentDictionary.cs | 10 ++++------ .../src/System/Collections/Generic/Dictionary.cs | 9 ++++----- .../src/System/Collections/Generic/HashSet.cs | 10 ++++------ .../src/System/IO/BinaryReader.cs | 3 ++- .../src/System/IO/RandomAccess.Unix.cs | 7 +++---- .../Runtime/CompilerServices/ConditionalWeakTable.cs | 3 +++ .../src/System/Runtime/InteropServices/ComWrappers.cs | 4 +--- .../src/System/Runtime/InteropServices/GCHandle.T.cs | 4 +--- .../Marshalling/PointerArrayMarshaller.cs | 10 ++++------ .../src/System/Threading/Tasks/ValueTask.cs | 6 ++++-- 13 files changed, 38 insertions(+), 41 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs index 209a132003d3..dd7408950c73 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.CoreCLR.cs @@ -56,7 +56,6 @@ public sealed override bool Equals([NotNullWhen(true)] object? obj) // MulticastDelegate Debug.Assert(obj is MulticastDelegate, "Shouldn't have failed here since we already checked the types are the same!"); MulticastDelegate d; - // FIXME: review unsafe to confirm correct annotation unsafe { d = Unsafe.As(obj); @@ -170,7 +169,7 @@ private static bool TrySetSlot(object?[] a, int index, object o) return false; } - private unsafe MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready) + private MulticastDelegate NewMulticastDelegate(object[] invocationList, int invocationCount, bool thisIsMultiCastAlready) { // First, allocate a new multicast delegate just like this one, i.e. same type as the this object MulticastDelegate result; diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index f1b7d3eb194d..b514e74a4fa0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -2407,7 +2407,8 @@ private static bool FilterApplyMethodBase( private readonly object m_keepalive; // This will be filled with a LoaderAllocator reference when this RuntimeType represents a collectible type #pragma warning restore CS0169 #pragma warning restore CA1823 - private IntPtr m_cache; + // Must be a handle to a RuntimeTypeCache type + private unsafe IntPtr m_cache; internal IntPtr m_handle; internal static readonly RuntimeType ValueType = (RuntimeType)typeof(ValueType); diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs index da600c91337e..2e26b35cbbde 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs @@ -62,6 +62,7 @@ public override T[] Rent(int minimumLength) { unsafe { + // Array should always be an array of T[] buffer = Unsafe.As(tlsBuckets[bucketIndex].Array); } if (buffer is not null) @@ -308,7 +309,8 @@ private SharedArrayPoolThreadLocalArray[] InitializeTlsBucketsAndTrimming() internal struct SharedArrayPoolThreadLocalArray { /// The stored array. - public Array? Array; + // Must be an array of T[] at runtime + public unsafe Array? Array; /// Environment.TickCount timestamp for when this array was observed by Trim. public int MillisecondsTimeStamp; @@ -396,7 +398,8 @@ private sealed class Partition private int _millisecondsTimestamp; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool TryPush(Array array) + // Array parameter must be a T[] + public unsafe bool TryPush(Array array) { bool enqueued = false; Monitor.Enter(this); diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs index 9e7dc8fd6f84..8b0902aec8e4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -2258,7 +2258,8 @@ internal Node(TKey key, TValue value, int hashcode, Node? next) private sealed class Tables { /// The comparer to use for lookups in the tables. - internal readonly IEqualityComparer? _comparer; + // Must be IAlternateEqualityComparer + internal readonly unsafe IEqualityComparer? _comparer; /// A singly-linked list for each bucket. internal readonly VolatileNode[] _buckets; /// Pre-computed multiplier for use on 64-bit performing faster modulo operations. @@ -2317,15 +2318,12 @@ private static bool IsCompatibleKey(ConcurrentDictionaryGets the dictionary's alternate comparer. The dictionary must have already been verified as compatible. [MethodImpl(MethodImplOptions.AggressiveInlining)] + [RequiresUnsafe] private static IAlternateEqualityComparer GetAlternateComparer(ConcurrentDictionary.Tables tables) where TAlternateKey : notnull, allows ref struct { Debug.Assert(IsCompatibleKey(tables)); - // FIXME: review unsafe to confirm correct annotation - unsafe - { - return Unsafe.As>(tables._comparer!); - } + return Unsafe.As>(tables._comparer!); } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs index a0118828d855..24c3c7d4ea7e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs @@ -32,7 +32,8 @@ public class Dictionary : IDictionary, IDictionary, private int _freeList; private int _freeCount; private int _version; - private IEqualityComparer? _comparer; + // Must be IAlternateEqualityComparer + private unsafe IEqualityComparer? _comparer; private KeyCollection? _keys; private ValueCollection? _values; private const int StartOfFreeList = -3; @@ -734,13 +735,11 @@ internal static bool IsCompatibleKey(Dictionary dictionary) /// Gets the dictionary's alternate comparer. The dictionary must have already been verified as compatible. [MethodImpl(MethodImplOptions.AggressiveInlining)] + [RequiresUnsafe] internal static IAlternateEqualityComparer GetAlternateComparer(Dictionary dictionary) { Debug.Assert(IsCompatibleKey(dictionary)); - unsafe - { - return Unsafe.As>(dictionary._comparer)!; - } + return Unsafe.As>(dictionary._comparer)!; } /// Gets the value associated with the specified alternate key. diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs index 3c655b7a6e39..7f6ffc5ef9f4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs @@ -46,7 +46,8 @@ public class HashSet : ICollection, ISet, IReadOnlyCollection, IRead private int _freeList; private int _freeCount; private int _version; - private IEqualityComparer? _comparer; + // Must be IAlternateEqualityComparer + private unsafe IEqualityComparer? _comparer; #region Constructors @@ -441,14 +442,11 @@ internal static bool IsCompatibleItem(HashSet set) /// Gets the set's alternate comparer. The set must have already been verified as compatible. [MethodImpl(MethodImplOptions.AggressiveInlining)] + [RequiresUnsafe] internal static IAlternateEqualityComparer GetAlternateComparer(HashSet set) { Debug.Assert(IsCompatibleItem(set)); - // FIXME: review unsafe to confirm correct annotation - unsafe - { - return Unsafe.As>(set._comparer)!; - } + return Unsafe.As>(set._comparer)!; } /// Adds the specified element to a set. diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs index 32471b9a43fe..c1c6e41bc398 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs @@ -16,7 +16,8 @@ public class BinaryReader : IDisposable { private const int MaxCharBytesSize = 128; - private readonly Stream _stream; + // If _isMemoryStream is true, this must be a MemoryStream + private readonly unsafe Stream _stream; private readonly Encoding _encoding; private Decoder? _decoder; private char[]? _charBuffer; diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs index 11be3f564397..867db2a29520 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/RandomAccess.Unix.cs @@ -70,13 +70,12 @@ internal static unsafe long ReadScatterAtOffset(SafeFileHandle handle, IReadOnly for (int i = 0; i < buffersCount; i++) { Memory buffer = buffers[i]; - MemoryHandle memoryHandle; unsafe { - memoryHandle = buffer.Pin(); + MemoryHandle memoryHandle = buffer.Pin(); + vectors[i] = new Interop.Sys.IOVector { Base = (byte*)memoryHandle.Pointer, Count = (UIntPtr)buffer.Length }; + handles[i] = memoryHandle; } - vectors[i] = new Interop.Sys.IOVector { Base = (byte*)memoryHandle.Pointer, Count = (UIntPtr)buffer.Length }; - handles[i] = memoryHandle; } fixed (Interop.Sys.IOVector* pinnedVectors = &MemoryMarshal.GetReference(vectors)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs index e311bdc755a3..d782e7203d61 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ConditionalWeakTable.cs @@ -631,6 +631,7 @@ internal bool TryGetValueWorker(TKey key, [MaybeNullWhen(false)] out TValue valu Debug.Assert(key != null); // Key already validated as non-null int entryIndex = FindEntry(key, out object? secondary); + // FIXME: Validate the unsafe block unsafe { value = Unsafe.As(secondary); @@ -685,6 +686,7 @@ internal bool TryGetEntry(int index, [NotNullWhen(true)] out TKey? key, [MaybeNu if (oKey != null) { + // FIXME: Validate the unsafe block unsafe { key = Unsafe.As(oKey); @@ -717,6 +719,7 @@ internal bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value) if (entryIndex != -1) { RemoveIndex(entryIndex); + // FIXME: Validate the unsafe block unsafe { value = Unsafe.As(valueObject!); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs index a344023d0632..74b546d9f497 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs @@ -232,12 +232,10 @@ public ManagedObjectWrapperHolder? Holder return null; else { - ManagedObjectWrapperHolder? holder; unsafe { - holder = Unsafe.As(GCHandle.FromIntPtr(handle).Target); + return Unsafe.As(GCHandle.FromIntPtr(handle).Target); } - return holder; } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs index 1e29d10b7953..0aec29ae3a34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs @@ -49,12 +49,10 @@ public readonly T Target IntPtr handle = _handle; GCHandle.CheckUninitialized(handle); // Skip the type check to provide lowest overhead. - T result; unsafe { - result = Unsafe.As(GCHandle.InternalGet(handle)!); + return Unsafe.As(GCHandle.InternalGet(handle)!); } - return result; } set { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs index 27e0ad4c7fe3..3db68ed5825f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs @@ -94,12 +94,11 @@ public static Span GetUnmanagedValuesDestination(TUnmanagedEl /// The of managed elements. public static Span GetManagedValuesDestination(T*[]? managed) { - IntPtr[]? result; + // IntPtr[] and T*[] have the same representation unsafe { - result = Unsafe.As(managed); + return Unsafe.As(managed); } - return result; } /// @@ -182,12 +181,11 @@ public void FromManaged(T*[]? array, Span buffer) /// A span over managed values of the array. public ReadOnlySpan GetManagedValuesSource() { - IntPtr[]? result; + // IntPtr[] and T*[] have the same representation unsafe { - result = Unsafe.As(_managedArray); + return Unsafe.As(_managedArray); } - return result; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs index 260b2a675b3e..88d9f60ccb18 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs @@ -59,7 +59,8 @@ namespace System.Threading.Tasks private static volatile Task? s_canceledTask; /// null if representing a successful synchronous completion, otherwise a or a . - internal readonly object? _obj; + // Must be either a Task or IValueTaskSource + internal readonly unsafe object? _obj; /// Opaque value passed through to the . internal readonly short _token; /// true to continue on the captured context; otherwise, false. @@ -499,7 +500,8 @@ public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContex /// A task canceled using `new CancellationToken(true)`. Lazily created only when first needed. private static volatile Task? s_canceledTask; /// null if has the result, otherwise a or a . - internal readonly object? _obj; + // Must be either a Task or IValueTaskSource + internal readonly unsafe object? _obj; /// The result to be used if the operation completed successfully synchronously. internal readonly TResult? _result; /// Opaque value passed through to the . From b73ffcee57be4fe595d29436acc364b22fd2de2a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 20 Nov 2025 00:20:45 +0000 Subject: [PATCH 9/9] Address PR comments: add Field to RequiresUnsafeAttribute, add RequiresUnsafe to fields and methods, add FIXME comments, refactor return statements Co-authored-by: agocke <515774+agocke@users.noreply.github.com> --- .../src/System/RuntimeType.CoreCLR.cs | 1 + .../src/System/Buffers/SharedArrayPool.cs | 4 +++- .../Collections/Concurrent/ConcurrentDictionary.cs | 1 + .../src/System/Collections/Generic/Dictionary.cs | 1 + .../src/System/Collections/Generic/HashSet.cs | 1 + .../System.Private.CoreLib/src/System/Delegate.cs | 8 +++----- .../CodeAnalysis/RequiresUnsafeAttribute.cs | 2 +- .../src/System/IO/BinaryReader.cs | 1 + .../src/System/MemoryExtensions.cs | 1 + .../System/Runtime/InteropServices/ComWrappers.cs | 14 ++++---------- .../System/Runtime/InteropServices/GCHandle.T.cs | 1 + .../Marshalling/PointerArrayMarshaller.cs | 5 ++--- .../Runtime/InteropServices/PinnedGCHandle.T.cs | 5 ++--- .../Runtime/InteropServices/WeakGCHandle.T.cs | 1 + .../Strings/Helpers/AhoCorasickNode.cs | 2 ++ .../src/System/String.Manipulation.cs | 1 + .../src/System/Threading/ExecutionContext.cs | 1 + .../src/System/Threading/Tasks/Task.cs | 1 + .../src/System/Threading/Tasks/ValueTask.cs | 2 ++ .../src/System/Threading/ThreadPoolWorkQueue.cs | 1 + 20 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index b514e74a4fa0..b11140b98be9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -2408,6 +2408,7 @@ private static bool FilterApplyMethodBase( #pragma warning restore CS0169 #pragma warning restore CA1823 // Must be a handle to a RuntimeTypeCache type + [RequiresUnsafe] private unsafe IntPtr m_cache; internal IntPtr m_handle; diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs index 2e26b35cbbde..a02e52f480ef 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/SharedArrayPool.cs @@ -310,6 +310,7 @@ internal struct SharedArrayPoolThreadLocalArray { /// The stored array. // Must be an array of T[] at runtime + [RequiresUnsafe] public unsafe Array? Array; /// Environment.TickCount timestamp for when this array was observed by Trim. public int MillisecondsTimeStamp; @@ -399,7 +400,8 @@ private sealed class Partition [MethodImpl(MethodImplOptions.AggressiveInlining)] // Array parameter must be a T[] - public unsafe bool TryPush(Array array) + [RequiresUnsafe] + public bool TryPush(Array array) { bool enqueued = false; Monitor.Enter(this); diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs index 8b0902aec8e4..b60df326abf4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Concurrent/ConcurrentDictionary.cs @@ -2259,6 +2259,7 @@ private sealed class Tables { /// The comparer to use for lookups in the tables. // Must be IAlternateEqualityComparer + [RequiresUnsafe] internal readonly unsafe IEqualityComparer? _comparer; /// A singly-linked list for each bucket. internal readonly VolatileNode[] _buckets; diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs index 24c3c7d4ea7e..e6da6ced9927 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Dictionary.cs @@ -33,6 +33,7 @@ public class Dictionary : IDictionary, IDictionary, private int _freeCount; private int _version; // Must be IAlternateEqualityComparer + [RequiresUnsafe] private unsafe IEqualityComparer? _comparer; private KeyCollection? _keys; private ValueCollection? _values; diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs index 7f6ffc5ef9f4..8b06ab955096 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/HashSet.cs @@ -47,6 +47,7 @@ public class HashSet : ICollection, ISet, IReadOnlyCollection, IRead private int _freeCount; private int _version; // Must be IAlternateEqualityComparer + [RequiresUnsafe] private unsafe IEqualityComparer? _comparer; #region Constructors diff --git a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs index f2222071b764..7d99147dcef5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs @@ -144,14 +144,12 @@ public TDelegate Current public bool MoveNext() { int index = _index + 1; + // FIXME: review unsafe to confirm correct annotation unsafe { - unsafe + if ((_current = Unsafe.As(_delegate?.TryGetAt(index))) == null) { - if ((_current = Unsafe.As(_delegate?.TryGetAt(index))) == null) - { - return false; - } + return false; } } _index = index; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs index 1b30230d95c7..589ff1bbf57d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/CodeAnalysis/RequiresUnsafeAttribute.cs @@ -11,7 +11,7 @@ namespace System.Diagnostics.CodeAnalysis /// This allows tools to understand which methods are unsafe to call when removing unreferenced /// code from an application. /// - [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor, Inherited = false)] + [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Field, Inherited = false)] internal sealed class RequiresUnsafeAttribute : Attribute { } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs index c1c6e41bc398..766f246f0eef 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/BinaryReader.cs @@ -17,6 +17,7 @@ public class BinaryReader : IDisposable private const int MaxCharBytesSize = 128; // If _isMemoryStream is true, this must be a MemoryStream + [RequiresUnsafe] private readonly unsafe Stream _stream; private readonly Encoding _encoding; private Decoder? _decoder; diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs index 8ead6e27e160..eefa666bd096 100644 --- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs @@ -5905,6 +5905,7 @@ internal SpanSplitEnumerator(ReadOnlySpan source, ReadOnlySpan separators) _source = source; if (typeof(T) == typeof(char) && separators.Length == 0) { + // FIXME: review unsafe to confirm correct annotation unsafe { _searchValues = Unsafe.As>(string.SearchValuesStorage.WhiteSpaceChars); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs index 74b546d9f497..fb1f76071a28 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs @@ -129,15 +129,11 @@ public partial struct ComInterfaceDispatch /// Desired type. /// Pointer supplied to Vtable function entry. /// Instance of type associated with dispatched function call. + [RequiresUnsafe] public static unsafe T GetInstance(ComInterfaceDispatch* dispatchPtr) where T : class { ManagedObjectWrapper* comInstance = ToManagedObjectWrapper(dispatchPtr); - T result; - unsafe - { - result = Unsafe.As(comInstance->Holder!.WrappedObject); - } - return result; + return Unsafe.As(comInstance->Holder!.WrappedObject); } internal static unsafe ManagedObjectWrapper* ToManagedObjectWrapper(ComInterfaceDispatch* dispatchPtr) @@ -223,6 +219,7 @@ public bool IsRooted } } + [RequiresUnsafe] public ManagedObjectWrapperHolder? Holder { get @@ -232,10 +229,7 @@ public ManagedObjectWrapperHolder? Holder return null; else { - unsafe - { - return Unsafe.As(GCHandle.FromIntPtr(handle).Target); - } + return Unsafe.As(GCHandle.FromIntPtr(handle).Target); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs index 0aec29ae3a34..108898188c90 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs @@ -24,6 +24,7 @@ public struct GCHandle : IEquatable>, IDisposable where T : class? { // The actual integer handle value that the EE uses internally. + [RequiresUnsafe] private IntPtr _handle; /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs index 3db68ed5825f..6823617d2f28 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshalling/PointerArrayMarshaller.cs @@ -51,12 +51,11 @@ public static unsafe class PointerArrayMarshaller /// The containing the managed elements to marshal. public static ReadOnlySpan GetManagedValuesSource(T*[]? managed) { - IntPtr[]? result; + // IntPtr[] and T*[] have the same representation unsafe { - result = Unsafe.As(managed); + return Unsafe.As(managed); } - return result; } /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs index 9871d44945dd..546fcf5f0575 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs @@ -25,6 +25,7 @@ public struct PinnedGCHandle : IEquatable>, IDisposable where T : class? { // The actual integer handle value that the EE uses internally. + [RequiresUnsafe] private IntPtr _handle; /// @@ -51,12 +52,10 @@ public readonly T Target IntPtr handle = _handle; GCHandle.CheckUninitialized(handle); // Skip the type check to provide lowest overhead. - T result; unsafe { - result = Unsafe.As(GCHandle.InternalGet(handle)!); + return Unsafe.As(GCHandle.InternalGet(handle)!); } - return result; } set { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs index 41b67129c8db..1e612d78e85a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs @@ -24,6 +24,7 @@ public struct WeakGCHandle : IEquatable>, IDisposable where T : class? { // The actual integer handle value that the EE uses internally. + [RequiresUnsafe] private IntPtr _handle; /// diff --git a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs index cc9ed2ebe552..aedaeb7fe500 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/Helpers/AhoCorasickNode.cs @@ -19,6 +19,8 @@ internal struct AhoCorasickNode // We save 1 child separately to avoid allocating a separate collection in such cases. private int _firstChildChar; private int _firstChildIndex; + // Must be int[] or Dictionary + [RequiresUnsafe] private object _children; // Either int[] or Dictionary public AhoCorasickNode() diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs index e16bf7499838..1a93f9c7a240 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Manipulation.cs @@ -948,6 +948,7 @@ private static string JoinCore(ReadOnlySpan separator, IEnumerable v // enumerable-based equivalent of new string(char[]). IEnumerator en; + // FIXME: Consider if (e is IEnumerator en) instead unsafe { en = Unsafe.As>(e); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs index affc292913fc..967301a1eaaf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs @@ -10,6 +10,7 @@ namespace System.Threading { + [RequiresUnsafe] public delegate void ContextCallback(object? state); internal delegate void ContextCallback(ref TState state); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 1d3dd113e546..d8687efb3553 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -2378,6 +2378,7 @@ private void ExecuteWithThreadLocal(ref Task? currentTaskSlot, Thread? threadPoo } } + [RequiresUnsafe] private static readonly ContextCallback s_ecCallback = obj => { Debug.Assert(obj is Task); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs index 88d9f60ccb18..a8f771612f6f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ValueTask.cs @@ -60,6 +60,7 @@ namespace System.Threading.Tasks /// null if representing a successful synchronous completion, otherwise a or a . // Must be either a Task or IValueTaskSource + [RequiresUnsafe] internal readonly unsafe object? _obj; /// Opaque value passed through to the . internal readonly short _token; @@ -501,6 +502,7 @@ public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContex private static volatile Task? s_canceledTask; /// null if has the result, otherwise a or a . // Must be either a Task or IValueTaskSource + [RequiresUnsafe] internal readonly unsafe object? _obj; /// The result to be used if the operation completed successfully synchronously. internal readonly TResult? _result; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index 912f116a75f7..eaabe4aa4325 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -1253,6 +1253,7 @@ private static void DispatchWorkItem(object workItem, Thread currentThread) { Debug.Assert(workItem is IThreadPoolWorkItem); IThreadPoolWorkItem tpWorkItem; + // FIXME: parent should be unsafe and specify input must be Task or IThreadPoolWorkItem unsafe { tpWorkItem = Unsafe.As(workItem);