From d7a7898845ad4d55177359f34109ff3935328646 Mon Sep 17 00:00:00 2001 From: Adam Sitnik Date: Mon, 16 Aug 2021 20:12:38 +0200 Subject: [PATCH] Fix Length for ReadOnlySequence created out of sliced Memory owned by MemoryManager (#57479) --- .../src/System/Buffers/ReadOnlySequence.cs | 2 +- .../ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs | 53 +++++++++++++++++++++- .../ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs | 5 ++ 3 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs index ff260b6..46c124c 100644 --- a/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs +++ b/src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs @@ -150,7 +150,7 @@ namespace System.Buffers _startObject = manager; _endObject = manager; _startInteger = ReadOnlySequence.MemoryManagerToSequenceStart(index); - _endInteger = length; + _endInteger = index + length; } else if (MemoryMarshal.TryGetArray(memory, out ArraySegment segment)) { diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs index d2c4305..8d00793 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs @@ -4,6 +4,9 @@ using System.Buffers; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; namespace System.Memory.Tests { @@ -11,6 +14,7 @@ namespace System.Memory.Tests { public static ReadOnlySequenceFactory ArrayFactory { get; } = new ArrayTestSequenceFactory(); public static ReadOnlySequenceFactory MemoryFactory { get; } = new MemoryTestSequenceFactory(); + public static ReadOnlySequenceFactory MemoryManagerFactory { get; } = new MemoryManagerTestSequenceFactory(); public static ReadOnlySequenceFactory SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactory(); public static ReadOnlySequenceFactory SegmentPerItemFactory { get; } = new BytePerSegmentTestSequenceFactory(); public static ReadOnlySequenceFactory SplitInThree { get; } = new SegmentsTestSequenceFactory(3); @@ -37,7 +41,11 @@ namespace System.Memory.Tests { public override ReadOnlySequence CreateOfSize(int size) { - return CreateWithContent(new T[size]); +#if DEBUG + return new ReadOnlySequence(new ReadOnlyMemory(new T[size + 1]).Slice(1)); +#else + return new ReadOnlySequence(new ReadOnlyMemory(new T[size])); +#endif } public override ReadOnlySequence CreateWithContent(T[] data) @@ -112,6 +120,49 @@ namespace System.Memory.Tests } } + internal class MemoryManagerTestSequenceFactory : ReadOnlySequenceFactory + { + public override ReadOnlySequence CreateOfSize(int size) + { +#if DEBUG + return new ReadOnlySequence(new CustomMemoryManager(size + 1).Memory.Slice(1)); +#else + return new ReadOnlySequence(new CustomMemoryManager(size).Memory); +#endif + } + + public override ReadOnlySequence CreateWithContent(T[] data) + { + return new ReadOnlySequence(new CustomMemoryManager(data).Memory); + } + + private unsafe class CustomMemoryManager : MemoryManager + { + private readonly T[] _buffer; + + public CustomMemoryManager(int size) => _buffer = new T[size]; + + public CustomMemoryManager(T[] content) => _buffer = content; + + public unsafe override Span GetSpan() => _buffer; + + public override unsafe MemoryHandle Pin(int elementIndex = 0) + { + if ((uint)elementIndex > (uint)_buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(elementIndex)); + } + + var handle = GCHandle.Alloc(_buffer, GCHandleType.Pinned); + return new MemoryHandle(Unsafe.Add((void*)handle.AddrOfPinnedObject(), elementIndex), handle, this); + } + + public override void Unpin() { } + + protected override void Dispose(bool disposing) { } + } + } + public static ReadOnlySequence CreateSegments(params T[][] inputs) => CreateSegments(inputs.Select(input => (ReadOnlyMemory)input.AsMemory())); public static ReadOnlySequence CreateSegments(IEnumerable> inputs) diff --git a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs index eb78a69..db53f08 100644 --- a/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs +++ b/src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs @@ -20,6 +20,11 @@ namespace System.Memory.Tests public Memory() : base(ReadOnlySequenceFactory.MemoryFactory) { } } + public class MemoryManager : ReadOnlySequenceTestsByte + { + public MemoryManager() : base(ReadOnlySequenceFactory.MemoryManagerFactory) { } + } + public class SingleSegment : ReadOnlySequenceTestsByte { public SingleSegment() : base(ReadOnlySequenceFactory.SingleSegmentFactory) { } -- 2.7.4