Skip to content

Fix MemoryStreamArchiveReader.GetStream() failing in some cases #24846

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 18, 2023

Conversation

bdach
Copy link
Collaborator

@bdach bdach commented Sep 18, 2023

MemoryStreamArchiveReader introduced in 0657b55 would previously use MemoryStream.GetBuffer() to retrieve the underlying byte buffer with stream data. However, this is not generally the method you would want, for two reasons:

  1. It can fail if the stream wasn't created in the way that supports it.
  2. As per docs, it will return the raw contents of the buffer, including potentially unused bytes.

To fix, use MemoryStream.ToArray() instead, which avoids both pitfalls. Notably, ToArray() always returns the full contents of the buffer, regardless of Position, as per documentation.

`MemoryStreamArchiveReader` introduced in
0657b55 would previously use
`MemoryStream.GetBuffer()` to retrieve the underlying byte buffer with
stream data. However, this is not generally the method you would want,
for two reasons:

1. It can fail if the stream wasn't created in the way that supports it.
2. As per

	https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream.getbuffer?view=net-7.0#system-io-memorystream-getbuffer,

   it will return the _raw_ contents of the buffer, including
   potentially unused bytes.

To fix, use `MemoryStream.ToArray()` instead, which avoids both
pitfalls. Notably, `ToArray()` always returns the full contents of the
buffer, regardless of `Position`, as documented in:

    https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream.toarray?view=net-7.0#system-io-memorystream-toarray
@peppy
Copy link
Member

peppy commented Sep 18, 2023

Was this failing somewhere? The change was mostly intentional as it avoids the copy. The Length spec should avoid including unused bytes, as far as I can tell.

@bdach
Copy link
Collaborator Author

bdach commented Sep 18, 2023

Yes, when working on #24450 this was causing failures in tests. Not every MemoryStream allows accessing the internal buffer. For instance, if the following path is taken in ImportTask:

if (Stream is not MemoryStream memoryStream)
{
// Path used primarily in tests (converting `ManifestResourceStream`s to `MemoryStream`s).
memoryStream = new MemoryStream(Stream.ReadAllBytesToArray());
Stream.Dispose();
}

which will happen primarily in tests, you cannot call GetBuffer() on that stream, as it will throw.

@peppy peppy self-requested a review September 18, 2023 13:00
@peppy
Copy link
Member

peppy commented Sep 18, 2023

That is an absolutely stupid API. There also seems to be no way of specifying the publicly exposed part apart from using the full public MemoryStream(byte[] buffer, int index, int count, bool writable, bool publiclyVisible).

@peppy peppy merged commit 163b6df into ppy:master Sep 18, 2023
@bdach bdach deleted the get-reader-regression branch September 18, 2023 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants