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

Conversation

adamsitnik
Copy link
Member

Port dotnet/runtime#57479 to release/3.1

The following description is a copy of the port to 5.0 description (dotnet/runtime#57562)

Customer Impact

Customers who create ReadOnlySequence<T> out of sliced Memory owned by any MemoryManager are seeing invalid end position and length. This issue was reported by a customer and the fix was provided by them as well.

Depending on the input (how many elements of the original Memory were sliced) iteration over ReadOnlySequence<T> can result in returning incomplete data or throwing ArgumentOutOfRangeException. These conditions can lead to data loss or data corruption that would be difficult to diagnose in a production application.

using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

public class Program
{
    public static void Main()
    {
        MemoryManager<byte> memoryManager = new CustomMemoryManager<byte>(4);
        ReadOnlySequence<byte> ros = new ReadOnlySequence<byte>(memoryManager.Memory.Slice(1));
        Console.WriteLine(ros.Length); // prints 2 instead of 3

        foreach (var item in ros)
        {
            Console.WriteLine(item.Length); // prints 2 instead of 3
        }

        memoryManager = new CustomMemoryManager<byte>(3);
        ros = new ReadOnlySequence<byte>(memoryManager.Memory.Slice(2));
        Console.WriteLine(ros.Length); // prints -1 instead of 1

        foreach (var item in ros) // throws System.ArgumentOutOfRangeException
        {
            Console.WriteLine(item.Length); // never gets printed
        }
    }
}

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

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

    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) { }
}

Testing

Failing test has been added in this PR.

image

Risk

Low, as the change is very simple and obvious when you look at ReadOnlySequence<T> ctor that accepts ReadOnlyMemory<T> :

_endInteger = ReadOnlySequence.ArrayToSequenceEnd(start + segment.Count);

_endInteger = ReadOnlySequence.StringToSequenceEnd(start + length);

Regression

This is not a regression.

Copy link
Member

@jeffhandley jeffhandley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When this is ready, apply the Servicing-consider label and it will then get reviewed by tactics.

@adamsitnik adamsitnik added the Servicing-consider Issue for next servicing release review label Sep 10, 2021
@danmoseley
Copy link
Member

We do not have a customer request for a 3.1 port of this, right? The reasoning is that it's subtle data corruption potential - we don't want to wait for a report.

@danmoseley
Copy link
Member

The failures are all in drawing and I believe can be ignored.

@adamsitnik
Copy link
Member Author

The reasoning is that it's subtle data corruption potential - we don't want to wait for a report.

Yes, exactly

@danmoseley danmoseley added Servicing-approved Approved for servicing release and removed Servicing-consider Issue for next servicing release review labels Sep 16, 2021
@danmoseley
Copy link
Member

approved by tactics -- @aik-jahoda can you please merge when branch is open?

@danmoseley danmoseley added this to the 3.1.20 milestone Sep 16, 2021
@Anipik
Copy link

Anipik commented Sep 20, 2021

Milestone should be 3.1.21, the branches got closed form 3.1.20 last monday

@jeffhandley jeffhandley modified the milestones: 3.1.20, 3.1.x Oct 5, 2021
@Anipik
Copy link

Anipik commented Oct 8, 2021

cc @aik-jahoda

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Memory Servicing-approved Approved for servicing release
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants