Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

[release/3.1] Fix ReadOnlySequence created out of sliced Memory owned by MemoryManager #43102

Merged
merged 2 commits into from
Oct 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/System.Memory/src/System/Buffers/ReadOnlySequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public ReadOnlySequence(ReadOnlyMemory<T> memory)
_startObject = manager;
_endObject = manager;
_startInteger = ReadOnlySequence.MemoryManagerToSequenceStart(index);
_endInteger = ReadOnlySequence.MemoryManagerToSequenceEnd(length);
_endInteger = ReadOnlySequence.MemoryManagerToSequenceEnd(index + length);
}
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace System.Memory.Tests
{
public abstract class ReadOnlySequenceFactory<T>
{
public static ReadOnlySequenceFactory<T> ArrayFactory { get; } = new ArrayTestSequenceFactory();
public static ReadOnlySequenceFactory<T> MemoryFactory { get; } = new MemoryTestSequenceFactory();
public static ReadOnlySequenceFactory<T> MemoryManagerFactory { get; } = new MemoryManagerTestSequenceFactory();
public static ReadOnlySequenceFactory<T> SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactory();
public static ReadOnlySequenceFactory<T> SegmentPerItemFactory { get; } = new BytePerSegmentTestSequenceFactory();
public static ReadOnlySequenceFactory<T> SplitInThree { get; } = new SegmentsTestSequenceFactory(3);
Expand Down Expand Up @@ -113,6 +116,49 @@ public override ReadOnlySequence<T> CreateWithContent(T[] data)
}
}

internal class MemoryManagerTestSequenceFactory : ReadOnlySequenceFactory<T>
{
public override ReadOnlySequence<T> CreateOfSize(int size)
{
#if DEBUG
return new ReadOnlySequence<T>(new CustomMemoryManager(size + 1).Memory.Slice(1));
#else
return new ReadOnlySequence<T>(new CustomMemoryManager(size).Memory);
#endif
}

public override ReadOnlySequence<T> CreateWithContent(T[] data)
{
return new ReadOnlySequence<T>(new CustomMemoryManager(data).Memory);
}

private unsafe class CustomMemoryManager : MemoryManager<T>
{
private readonly T[] _buffer;

public CustomMemoryManager(int size) => _buffer = new T[size];

public CustomMemoryManager(T[] content) => _buffer = content;

public unsafe override Span<T> 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<T>((void*)handle.AddrOfPinnedObject(), elementIndex), handle, this);
}

public override void Unpin() { }

protected override void Dispose(bool disposing) { }
}
}

public static ReadOnlySequence<T> CreateSegments(params T[][] inputs) => CreateSegments(inputs.Select(input => (ReadOnlyMemory<T>)input.AsMemory()));

public static ReadOnlySequence<T> CreateSegments(IEnumerable<ReadOnlyMemory<T>> inputs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ public class Memory : ReadOnlySequenceTestsByte
public Memory() : base(ReadOnlySequenceFactory<byte>.MemoryFactory) { }
}

public class MemoryManager : ReadOnlySequenceTestsByte
{
public MemoryManager() : base(ReadOnlySequenceFactory<byte>.MemoryManagerFactory) { }
}

public class SingleSegment : ReadOnlySequenceTestsByte
{
public SingleSegment() : base(ReadOnlySequenceFactory<byte>.SingleSegmentFactory) { }
Expand Down