Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corert.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2018-03-05 07:05:50 +0300
committerJan Kotas <jkotas@microsoft.com>2018-03-05 08:23:23 +0300
commitab5bba191dfbd9b5bd76c701fcaf734b7da4aa1a (patch)
tree4c1b28455900e64b23cb2027ccb8b4530c0cd885
parent6cfeb78030f5e5d1a81875ee1e2cf1993d5102e1 (diff)
Fix encoding methods for Span.Empty (dotnet/coreclr#16748)
* Fix encoding methods for Span.Empty Encoding had a historic confusion about handling null pointers. Make sure that this confusion is not leaking into the new Span methods. * Use GetNonNullPinnableReference helper method Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
-rw-r--r--src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs20
-rw-r--r--src/System.Private.CoreLib/shared/System/Text/Decoder.cs10
-rw-r--r--src/System.Private.CoreLib/shared/System/Text/Encoder.cs10
-rw-r--r--src/System.Private.CoreLib/shared/System/Text/Encoding.cs14
4 files changed, 34 insertions, 20 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
index 5d2a4447d..34881e77a 100644
--- a/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
+++ b/src/System.Private.CoreLib/shared/System/Runtime/InteropServices/MemoryMarshal.Fast.cs
@@ -29,17 +29,31 @@ namespace System.Runtime.InteropServices
/// <summary>
/// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
/// </summary>
public static ref T GetReference<T>(Span<T> span) => ref span._pointer.Value;
/// <summary>
- /// Returns a reference to the 0th element of the ReadOnlySpan. If the Span is empty, returns a reference to the location where the 0th element
- /// would have been stored. Such a reference can be used for pinning but must never be dereferenced.
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element
+ /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced.
/// </summary>
public static ref T GetReference<T>(ReadOnlySpan<T> span) => ref span._pointer.Value;
/// <summary>
+ /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used
+ /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ref T GetNonNullPinnableReference<T>(Span<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
+
+ /// <summary>
+ /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference
+ /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers.
+ /// </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ internal static unsafe ref T GetNonNullPinnableReference<T>(ReadOnlySpan<T> span) => ref (span.Length != 0) ? ref span._pointer.Value : ref Unsafe.AsRef<T>((void*)1);
+
+ /// <summary>
/// Casts a Span of one primitive type <typeparamref name="TFrom"/> to another primitive type <typeparamref name="TTo"/>.
/// These types may not contain pointers or references. This is checked at runtime in order to preserve type safety.
/// </summary>
diff --git a/src/System.Private.CoreLib/shared/System/Text/Decoder.cs b/src/System.Private.CoreLib/shared/System/Text/Decoder.cs
index b827648fc..b4a7575ba 100644
--- a/src/System.Private.CoreLib/shared/System/Text/Decoder.cs
+++ b/src/System.Private.CoreLib/shared/System/Text/Decoder.cs
@@ -134,7 +134,7 @@ namespace System.Text
public virtual unsafe int GetCharCount(ReadOnlySpan<byte> bytes, bool flush)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetCharCount(bytesPtr, bytes.Length, flush);
}
@@ -227,8 +227,8 @@ namespace System.Text
public virtual unsafe int GetChars(ReadOnlySpan<byte> bytes, Span<char> chars, bool flush)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetChars(bytesPtr, bytes.Length, charsPtr, chars.Length, flush);
}
@@ -341,8 +341,8 @@ namespace System.Text
public virtual unsafe void Convert(ReadOnlySpan<byte> bytes, Span<char> chars, bool flush, out int bytesUsed, out int charsUsed, out bool completed)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
Convert(bytesPtr, bytes.Length, charsPtr, chars.Length, flush, out bytesUsed, out charsUsed, out completed);
}
diff --git a/src/System.Private.CoreLib/shared/System/Text/Encoder.cs b/src/System.Private.CoreLib/shared/System/Text/Encoder.cs
index fb1bdb803..df7d51203 100644
--- a/src/System.Private.CoreLib/shared/System/Text/Encoder.cs
+++ b/src/System.Private.CoreLib/shared/System/Text/Encoder.cs
@@ -132,7 +132,7 @@ namespace System.Text
public virtual unsafe int GetByteCount(ReadOnlySpan<char> chars, bool flush)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetByteCount(charsPtr, chars.Length, flush);
}
@@ -221,8 +221,8 @@ namespace System.Text
public virtual unsafe int GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes, bool flush)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetBytes(charsPtr, chars.Length, bytesPtr, bytes.Length, flush);
}
@@ -335,8 +335,8 @@ namespace System.Text
public virtual unsafe void Convert(ReadOnlySpan<char> chars, Span<byte> bytes, bool flush, out int charsUsed, out int bytesUsed, out bool completed)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
Convert(charsPtr, chars.Length, bytesPtr, bytes.Length, flush, out charsUsed, out bytesUsed, out completed);
}
diff --git a/src/System.Private.CoreLib/shared/System/Text/Encoding.cs b/src/System.Private.CoreLib/shared/System/Text/Encoding.cs
index e469180ce..e191ce14f 100644
--- a/src/System.Private.CoreLib/shared/System/Text/Encoding.cs
+++ b/src/System.Private.CoreLib/shared/System/Text/Encoding.cs
@@ -713,7 +713,7 @@ namespace System.Text
public virtual unsafe int GetByteCount(ReadOnlySpan<char> chars)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetByteCount(charsPtr, chars.Length);
}
@@ -895,8 +895,8 @@ namespace System.Text
public virtual unsafe int GetBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
{
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetBytes(charsPtr, chars.Length, bytesPtr, bytes.Length);
}
@@ -945,7 +945,7 @@ namespace System.Text
public virtual unsafe int GetCharCount(ReadOnlySpan<byte> bytes)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetCharCount(bytesPtr, bytes.Length);
}
@@ -1057,8 +1057,8 @@ namespace System.Text
public virtual unsafe int GetChars(ReadOnlySpan<byte> bytes, Span<char> chars)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
- fixed (char* charsPtr = &MemoryMarshal.GetReference(chars))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
+ fixed (char* charsPtr = &MemoryMarshal.GetNonNullPinnableReference(chars))
{
return GetChars(bytesPtr, bytes.Length, charsPtr, chars.Length);
}
@@ -1087,7 +1087,7 @@ namespace System.Text
public unsafe string GetString(ReadOnlySpan<byte> bytes)
{
- fixed (byte* bytesPtr = &MemoryMarshal.GetReference(bytes))
+ fixed (byte* bytesPtr = &MemoryMarshal.GetNonNullPinnableReference(bytes))
{
return GetString(bytesPtr, bytes.Length);
}