Skip to content

Commit d7a7898

Browse files
authored
Fix Length for ReadOnlySequence created out of sliced Memory owned by MemoryManager (#57479)
1 parent 4723f00 commit d7a7898

3 files changed

Lines changed: 58 additions & 2 deletions

File tree

src/libraries/System.Memory/src/System/Buffers/ReadOnlySequence.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ public ReadOnlySequence(ReadOnlyMemory<T> memory)
150150
_startObject = manager;
151151
_endObject = manager;
152152
_startInteger = ReadOnlySequence.MemoryManagerToSequenceStart(index);
153-
_endInteger = length;
153+
_endInteger = index + length;
154154
}
155155
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
156156
{

src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceFactory.byte.cs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
using System.Buffers;
55
using System.Collections.Generic;
66
using System.Linq;
7+
using System.Runtime.CompilerServices;
8+
using System.Runtime.InteropServices;
9+
using System.Threading;
710

811
namespace System.Memory.Tests
912
{
1013
public abstract class ReadOnlySequenceFactory<T>
1114
{
1215
public static ReadOnlySequenceFactory<T> ArrayFactory { get; } = new ArrayTestSequenceFactory();
1316
public static ReadOnlySequenceFactory<T> MemoryFactory { get; } = new MemoryTestSequenceFactory();
17+
public static ReadOnlySequenceFactory<T> MemoryManagerFactory { get; } = new MemoryManagerTestSequenceFactory();
1418
public static ReadOnlySequenceFactory<T> SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactory();
1519
public static ReadOnlySequenceFactory<T> SegmentPerItemFactory { get; } = new BytePerSegmentTestSequenceFactory();
1620
public static ReadOnlySequenceFactory<T> SplitInThree { get; } = new SegmentsTestSequenceFactory(3);
@@ -37,7 +41,11 @@ internal class MemoryTestSequenceFactory : ReadOnlySequenceFactory<T>
3741
{
3842
public override ReadOnlySequence<T> CreateOfSize(int size)
3943
{
40-
return CreateWithContent(new T[size]);
44+
#if DEBUG
45+
return new ReadOnlySequence<T>(new ReadOnlyMemory<T>(new T[size + 1]).Slice(1));
46+
#else
47+
return new ReadOnlySequence<T>(new ReadOnlyMemory<T>(new T[size]));
48+
#endif
4149
}
4250

4351
public override ReadOnlySequence<T> CreateWithContent(T[] data)
@@ -112,6 +120,49 @@ public override ReadOnlySequence<T> CreateWithContent(T[] data)
112120
}
113121
}
114122

123+
internal class MemoryManagerTestSequenceFactory : ReadOnlySequenceFactory<T>
124+
{
125+
public override ReadOnlySequence<T> CreateOfSize(int size)
126+
{
127+
#if DEBUG
128+
return new ReadOnlySequence<T>(new CustomMemoryManager(size + 1).Memory.Slice(1));
129+
#else
130+
return new ReadOnlySequence<T>(new CustomMemoryManager(size).Memory);
131+
#endif
132+
}
133+
134+
public override ReadOnlySequence<T> CreateWithContent(T[] data)
135+
{
136+
return new ReadOnlySequence<T>(new CustomMemoryManager(data).Memory);
137+
}
138+
139+
private unsafe class CustomMemoryManager : MemoryManager<T>
140+
{
141+
private readonly T[] _buffer;
142+
143+
public CustomMemoryManager(int size) => _buffer = new T[size];
144+
145+
public CustomMemoryManager(T[] content) => _buffer = content;
146+
147+
public unsafe override Span<T> GetSpan() => _buffer;
148+
149+
public override unsafe MemoryHandle Pin(int elementIndex = 0)
150+
{
151+
if ((uint)elementIndex > (uint)_buffer.Length)
152+
{
153+
throw new ArgumentOutOfRangeException(nameof(elementIndex));
154+
}
155+
156+
var handle = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
157+
return new MemoryHandle(Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), elementIndex), handle, this);
158+
}
159+
160+
public override void Unpin() { }
161+
162+
protected override void Dispose(bool disposing) { }
163+
}
164+
}
165+
115166
public static ReadOnlySequence<T> CreateSegments(params T[][] inputs) => CreateSegments(inputs.Select(input => (ReadOnlyMemory<T>)input.AsMemory()));
116167

117168
public static ReadOnlySequence<T> CreateSegments(IEnumerable<ReadOnlyMemory<T>> inputs)

src/libraries/System.Memory/tests/ReadOnlyBuffer/ReadOnlySequenceTests.byte.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public class Memory : ReadOnlySequenceTestsByte
2020
public Memory() : base(ReadOnlySequenceFactory<byte>.MemoryFactory) { }
2121
}
2222

23+
public class MemoryManager : ReadOnlySequenceTestsByte
24+
{
25+
public MemoryManager() : base(ReadOnlySequenceFactory<byte>.MemoryManagerFactory) { }
26+
}
27+
2328
public class SingleSegment : ReadOnlySequenceTestsByte
2429
{
2530
public SingleSegment() : base(ReadOnlySequenceFactory<byte>.SingleSegmentFactory) { }

0 commit comments

Comments
 (0)