From 7bfaddf81a26de261abd23e025b5a2f619e0d5ba Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Fri, 20 Apr 2018 15:52:59 -0700 Subject: [PATCH] Preserve pinned flag in {ReadOnly}Memory.Slice (dotnet/corefx#29246) * Preserve pinned flag in {ReadOnly}Memory.Slice * Address PR feedback. Signed-off-by: dotnet-bot-corefx-mirror --- src/mscorlib/shared/System/Memory.cs | 14 ++++++++++---- src/mscorlib/shared/System/ReadOnlyMemory.cs | 12 +++++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/mscorlib/shared/System/Memory.cs b/src/mscorlib/shared/System/Memory.cs index 98ec23fd67f1..577b76b96905 100644 --- a/src/mscorlib/shared/System/Memory.cs +++ b/src/mscorlib/shared/System/Memory.cs @@ -225,13 +225,16 @@ public override string ToString() [MethodImpl(MethodImplOptions.AggressiveInlining)] public Memory Slice(int start) { - int actualLength = _length & RemoveFlagsBitMask; + // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not. + int capturedLength = _length; + int actualLength = capturedLength & RemoveFlagsBitMask; if ((uint)start > (uint)actualLength) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); } - return new Memory(_object, _index + start, actualLength - start); + // It is expected for (capturedLength - start) to be negative if the memory is already pre-pinned. + return new Memory(_object, _index + start, capturedLength - start); } /// @@ -245,13 +248,16 @@ public Memory Slice(int start) [MethodImpl(MethodImplOptions.AggressiveInlining)] public Memory Slice(int start, int length) { - int actualLength = _length & RemoveFlagsBitMask; + // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not. + int capturedLength = _length; + int actualLength = capturedLength & RemoveFlagsBitMask; if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start)) { ThrowHelper.ThrowArgumentOutOfRangeException(); } - return new Memory(_object, _index + start, length); + // Set the high-bit to match the this._length high bit (1 for pre-pinned, 0 for unpinned). + return new Memory(_object, _index + start, length | (capturedLength & ~RemoveFlagsBitMask)); } /// diff --git a/src/mscorlib/shared/System/ReadOnlyMemory.cs b/src/mscorlib/shared/System/ReadOnlyMemory.cs index ae8a7c3001b8..a7a64460569d 100644 --- a/src/mscorlib/shared/System/ReadOnlyMemory.cs +++ b/src/mscorlib/shared/System/ReadOnlyMemory.cs @@ -147,13 +147,16 @@ public override string ToString() [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlyMemory Slice(int start) { - int actualLength = _length & RemoveFlagsBitMask; + // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not. + int capturedLength = _length; + int actualLength = capturedLength & RemoveFlagsBitMask; if ((uint)start > (uint)actualLength) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); } - return new ReadOnlyMemory(_object, _index + start, actualLength - start); + // It is expected for (capturedLength - start) to be negative if the memory is already pre-pinned. + return new ReadOnlyMemory(_object, _index + start, capturedLength - start); } /// @@ -167,13 +170,16 @@ public ReadOnlyMemory Slice(int start) [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlyMemory Slice(int start, int length) { + // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not. + int capturedLength = _length; int actualLength = _length & RemoveFlagsBitMask; if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start)) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start); } - return new ReadOnlyMemory(_object, _index + start, length); + // Set the high-bit to match the this._length high bit (1 for pre-pinned, 0 for unpinned). + return new ReadOnlyMemory(_object, _index + start, length | (capturedLength & ~RemoveFlagsBitMask)); } ///