diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index c12d6c854ac..d7ac59703f4 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/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
index 83287c4a4d0..d9f10f276ea 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,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.As(this);
+ T[] @this;
+ unsafe
+ {
+ @this = Unsafe.As(this);
+ }
int length = @this.Length;
return length == 0 ? SZGenericArrayEnumerator.Empty : new SZGenericArrayEnumerator(@this, length);
}
@@ -411,7 +415,11 @@ 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 +427,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.As(this);
+ T[] @this;
+ unsafe
+ {
+ @this = Unsafe.As(this);
+ }
return @this.Length;
}
@@ -427,7 +439,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.As(this);
+ T[] @this;
+ unsafe
+ {
+ @this = Unsafe.As(this);
+ }
if ((uint)index >= (uint)@this.Length)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException();
@@ -440,7 +456,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.As(this);
+ T[] @this;
+ unsafe
+ {
+ @this = Unsafe.As(this);
+ }
if ((uint)index >= (uint)@this.Length)
{
ThrowHelper.ThrowArgumentOutOfRange_IndexMustBeLessException();
@@ -459,7 +479,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.As(this);
+ T[] @this;
+ unsafe
+ {
+ @this = Unsafe.As(this);
+ }
return Array.IndexOf(@this, value, 0, @this.Length) >= 0;
}
@@ -480,7 +504,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.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 358dab7f436..3f6a1139349 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,11 @@ 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));
+ // FIXME: review unsafe to confirm correct annotation
+ unsafe
+ {
+ return Unsafe.As(RuntimeTypeHandle.InternalAlloc(type));
+ }
}
[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 1c9a4c6c384..dd7408950c7 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,11 @@ 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)
{
@@ -165,10 +169,14 @@ 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 = 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 b64899d34bd..b11140b98be 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,9 @@ 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
+ [RequiresUnsafe]
+ private unsafe IntPtr m_cache;
internal IntPtr m_handle;
internal static readonly RuntimeType ValueType = (RuntimeType)typeof(ValueType);
@@ -2448,7 +2450,10 @@ private RuntimeTypeCache? CacheIfExists
{
object? cache = GCHandle.InternalGet(m_cache);
Debug.Assert(cache == null || cache is RuntimeTypeCache);
- return Unsafe.As(cache);
+ unsafe
+ {
+ return Unsafe.As(cache);
+ }
}
return null;
}
@@ -2465,7 +2470,10 @@ private RuntimeTypeCache Cache
if (cache != null)
{
Debug.Assert(cache is RuntimeTypeCache);
- return Unsafe.As(cache);
+ unsafe
+ {
+ return Unsafe.As(cache);
+ }
}
}
return InitializeCache();
diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props
index 33938989e38..1c0841e0fe9 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 d3b69efe615..a312398fab0 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 ad4488005da..a02e52f480e 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,11 @@ 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
+ {
+ // Array should always be an array of T[]
+ buffer = Unsafe.As(tlsBuckets[bucketIndex].Array);
+ }
if (buffer is not null)
{
tlsBuckets[bucketIndex].Array = null;
@@ -79,7 +83,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())
@@ -302,7 +309,9 @@ private SharedArrayPoolThreadLocalArray[] InitializeTlsBucketsAndTrimming()
internal struct SharedArrayPoolThreadLocalArray
{
/// The stored array.
- public Array? 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;
@@ -390,6 +399,8 @@ private sealed class Partition
private int _millisecondsTimestamp;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
+ // Array parameter must be a T[]
+ [RequiresUnsafe]
public bool TryPush(Array array)
{
bool enqueued = false;
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 74fafc9c8cb..b60df326abf 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,9 @@ 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
+ [RequiresUnsafe]
+ 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,6 +2319,7 @@ 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
{
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 f6b9e545c40..e6da6ced992 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,9 @@ public class Dictionary : IDictionary, IDictionary,
private int _freeList;
private int _freeCount;
private int _version;
- private IEqualityComparer? _comparer;
+ // Must be IAlternateEqualityComparer
+ [RequiresUnsafe]
+ private unsafe IEqualityComparer? _comparer;
private KeyCollection? _keys;
private ValueCollection? _values;
private const int StartOfFreeList = -3;
@@ -734,6 +736,7 @@ 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));
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 b7a30cbd904..8b06ab95509 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,9 @@ public class HashSet : ICollection, ISet, IReadOnlyCollection, IRead
private int _freeList;
private int _freeCount;
private int _version;
- private IEqualityComparer? _comparer;
+ // Must be IAlternateEqualityComparer
+ [RequiresUnsafe]
+ private unsafe IEqualityComparer? _comparer;
#region Constructors
@@ -441,6 +443,7 @@ 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));
diff --git a/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs b/src/libraries/System.Private.CoreLib/src/System/ComAwareWeakReference.cs
index 404bc41c5a6..e7b741c9583 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
- 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
@@ -146,22 +150,40 @@ private static ComAwareWeakReference EnsureComAwareReference(ref nint taggedHand
GC.SuppressFinalize(newRef);
}
- return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!);
+ // FIXME: review unsafe to confirm correct annotation
+ unsafe
+ {
+ return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!);
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static ComAwareWeakReference GetFromTaggedReference(nint taggedHandle)
{
Debug.Assert((taggedHandle & ComAwareBit) != 0);
- return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!);
+ // FIXME: review unsafe to confirm correct annotation
+ unsafe
+ {
+ return Unsafe.As(GCHandle.InternalGet(taggedHandle & ~HandleTagBits)!);
+ }
}
[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
+ {
+ // 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 6efa9f48554..7d99147dcef 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Delegate.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Delegate.cs
@@ -78,7 +78,17 @@ 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
+ {
+ // FIXME: review unsafe to confirm correct annotation
+ unsafe
+ {
+ return Unsafe.As(this).HasSingleTarget;
+ }
+ }
+ }
#endif
///
@@ -94,7 +104,13 @@ 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));
+ {
+ // FIXME: review unsafe to confirm correct annotation
+ unsafe
+ {
+ return new InvocationListEnumerator(Unsafe.As(d));
+ }
+ }
///
/// Provides an enumerator for the invocation list of a delegate.
@@ -128,9 +144,13 @@ public TDelegate Current
public bool MoveNext()
{
int index = _index + 1;
- if ((_current = Unsafe.As(_delegate?.TryGetAt(index))) == null)
+ // FIXME: review unsafe to confirm correct annotation
+ unsafe
{
- return false;
+ 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 00000000000..589ff1bbf57
--- /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 | 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 5a8bba6a6d2..766f246f0ee 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,9 @@ public class BinaryReader : IDisposable
{
private const int MaxCharBytesSize = 128;
- private readonly Stream _stream;
+ // If _isMemoryStream is true, this must be a MemoryStream
+ [RequiresUnsafe]
+ private readonly unsafe Stream _stream;
private readonly Encoding _encoding;
private Decoder? _decoder;
private char[]? _charBuffer;
@@ -357,7 +359,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 +483,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 147e3815812..867db2a2952 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,9 +70,12 @@ internal static unsafe long ReadScatterAtOffset(SafeFileHandle handle, IReadOnly
for (int i = 0; i < buffersCount; i++)
{
Memory buffer = buffers[i];
- MemoryHandle memoryHandle = buffer.Pin();
- vectors[i] = new Interop.Sys.IOVector { Base = (byte*)memoryHandle.Pointer, Count = (UIntPtr)buffer.Length };
- handles[i] = memoryHandle;
+ unsafe
+ {
+ MemoryHandle memoryHandle = buffer.Pin();
+ 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/Memory.cs b/src/libraries/System.Private.CoreLib/src/System/Memory.cs
index c8eac110cb5..6133a373d59 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))
{
@@ -301,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
{
@@ -313,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;
}
@@ -379,6 +392,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 9687896e6fc..eefa666bd09 100644
--- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs
@@ -5905,7 +5905,11 @@ internal SpanSplitEnumerator(ReadOnlySpan source, ReadOnlySpan separators)
_source = source;
if (typeof(T) == typeof(char) && separators.Length == 0)
{
- _searchValues = Unsafe.As>(string.SearchValuesStorage.WhiteSpaceChars);
+ // FIXME: review unsafe to confirm correct annotation
+ 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 85e4feace8c..80cb8e9a92a 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,9 +241,12 @@ 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);
- lengthOfUnderlyingSpan = memoryManagerSpan.Length;
+ unsafe
+ {
+ Span memoryManagerSpan = Unsafe.As>(tmpObject).GetSpan();
+ refToReturn = ref MemoryMarshal.GetReference(memoryManagerSpan);
+ lengthOfUnderlyingSpan = memoryManagerSpan.Length;
+ }
}
// If the Memory or ReadOnlyMemory instance is torn, this property getter has undefined behavior.
@@ -322,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 bdbb94609cd..d782e7203d6 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,11 @@ 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);
+ // FIXME: Validate the unsafe block
+ unsafe
+ {
+ value = Unsafe.As(secondary);
+ }
return entryIndex != -1;
}
@@ -682,8 +686,12 @@ internal bool TryGetEntry(int index, [NotNullWhen(true)] out TKey? key, [MaybeNu
if (oKey != null)
{
- key = Unsafe.As(oKey);
- value = Unsafe.As(oValue!);
+ // FIXME: Validate the unsafe block
+ unsafe
+ {
+ key = Unsafe.As(oKey);
+ value = Unsafe.As(oValue!);
+ }
return true;
}
}
@@ -711,7 +719,11 @@ internal bool Remove(TKey key, [MaybeNullWhen(false)] out TValue value)
if (entryIndex != -1)
{
RemoveIndex(entryIndex);
- value = Unsafe.As(valueObject!);
+ // FIXME: Validate the unsafe block
+ unsafe
+ {
+ value = Unsafe.As(valueObject!);
+ }
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 1700fb0cca8..df22c760338 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,13 @@ public void OnCompleted(Action continuation)
}
else if (obj != null)
{
- Unsafe.As(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ // obj is either Task, null, or IValueTaskSource and the other cases are checked
+ 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 +88,13 @@ public void UnsafeOnCompleted(Action continuation)
}
else if (obj != null)
{
- Unsafe.As(obj).OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
+ // obj is either Task, null, or IValueTaskSource and the other cases are checked
+ IValueTaskSource source;
+ unsafe
+ {
+ source = Unsafe.As(obj);
+ }
+ source.OnCompleted(ValueTaskAwaiter.s_invokeActionDelegate, continuation, _value._token,
_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
@@ -102,7 +114,13 @@ void IStateMachineBoxAwareAwaiter.AwaitUnsafeOnCompleted(IAsyncStateMachineBox b
}
else if (obj != null)
{
- Unsafe.As(obj).OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token,
+ // obj is either Task, null, or IValueTaskSource and the other cases are checked
+ IValueTaskSource source;
+ unsafe
+ {
+ source = Unsafe.As(obj);
+ }
+ source.OnCompleted(ThreadPool.s_invokeAsyncStateMachineBox, box, _value._token,
_value._continueOnCapturedContext ? ValueTaskSourceOnCompletedFlags.UseSchedulingContext : ValueTaskSourceOnCompletedFlags.None);
}
else
@@ -165,7 +183,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 +210,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 +235,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 83e401940e4..091387459e2 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/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs
index 154cd64a421..09e39599450 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/Runtime/CompilerServices/ValueTaskAwaiter.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/ValueTaskAwaiter.cs
index c242ad3f2ad..78200ab3ad6 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 f1ce1193e78..fb1f76071a2 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,6 +129,7 @@ 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);
@@ -218,6 +219,7 @@ public bool IsRooted
}
}
+ [RequiresUnsafe]
public ManagedObjectWrapperHolder? Holder
{
get
@@ -226,7 +228,9 @@ public ManagedObjectWrapperHolder? Holder
if (handle == IntPtr.Zero)
return null;
else
+ {
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 7aa92f99534..108898188c9 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;
///
@@ -49,7 +50,10 @@ public readonly T Target
IntPtr handle = _handle;
GCHandle.CheckUninitialized(handle);
// Skip the type check to provide lowest overhead.
- return Unsafe.As(GCHandle.InternalGet(handle)!);
+ unsafe
+ {
+ return Unsafe.As(GCHandle.InternalGet(handle)!);
+ }
}
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 d0a3dfae3e8..6823617d2f2 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,13 @@ 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[] and T*[] have the same representation
+ unsafe
+ {
+ return Unsafe.As(managed);
+ }
+ }
///
/// Gets a destination for the unmanaged elements in the array.
@@ -86,7 +92,13 @@ 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[] and T*[] have the same representation
+ unsafe
+ {
+ return Unsafe.As(managed);
+ }
+ }
///
/// Gets a source for the unmanaged elements in the array.
@@ -166,7 +178,14 @@ 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[] and T*[] have the same representation
+ unsafe
+ {
+ return Unsafe.As(_managedArray);
+ }
+ }
///
/// 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 15e8b05dd5c..a6de7e2b709 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,9 +285,14 @@ 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.
- segment = new ArraySegment(Unsafe.As(obj), index & ReadOnlyMemory.RemoveFlagsBitMask, 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;
}
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 9f2434af1ae..546fcf5f057 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,7 +52,10 @@ public readonly T Target
IntPtr handle = _handle;
GCHandle.CheckUninitialized(handle);
// Skip the type check to provide lowest overhead.
- return Unsafe.As(GCHandle.InternalGet(handle)!);
+ unsafe
+ {
+ return Unsafe.As(GCHandle.InternalGet(handle)!);
+ }
}
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 4243caf0097..a2e3b3beb8d 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 348dfc7657d..1e612d78e85 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;
///
@@ -53,7 +54,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/AsciiStringSearchValuesTeddyBase.cs b/src/libraries/System.Private.CoreLib/src/System/SearchValues/Strings/AsciiStringSearchValuesTeddyBase.cs
index b764e3a22d8..2cb026919f9 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