Skip to content
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

SequenceReader contains invalid volatile memory access patterns #45379

Closed
GrabYourPitchforks opened this issue Nov 30, 2020 · 11 comments · Fixed by #45437
Closed

SequenceReader contains invalid volatile memory access patterns #45379

GrabYourPitchforks opened this issue Nov 30, 2020 · 11 comments · Fixed by #45437

Comments

@GrabYourPitchforks
Copy link
Member

See code:

public readonly long Length
{
get
{
if (_length < 0)
{
// Cast-away readonly to initialize lazy field
Volatile.Write(ref Unsafe.AsRef(_length), Sequence.Length);
}
return _length;
}
}

Accesses to the _length field are not guaranteed atomic on 32-bit platforms without going through the Volatile or Interlocked APIs. While the write is protected by such a guard, the read is not. This could result in the _length backing field being torn and the Length property returning an incorrect value on 32-bit platforms.

@GrabYourPitchforks GrabYourPitchforks added this to the 6.0.0 milestone Nov 30, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Nov 30, 2020
@GrabYourPitchforks
Copy link
Member Author

GrabYourPitchforks commented Nov 30, 2020

A possible fix:

  • On all platforms, use Volatile for both reads and writes. (On 32-bit platforms, this results in an interlocked operation.) OR

  • On 64-bit platforms, don't use Volatile, since reads + writes are atomic. On 32-bit platforms, while reading, perform a volatile read of the high 32 bits first, then a non-volatile read of the low 32 bits. If the result is negative, write the low 32 bits first, then perform a volatile write of the high 32 bits. This will not result in an interlocked operation.

@gfoidl
Copy link
Member

gfoidl commented Nov 30, 2020

SequenceReader is a ref struct, so stack-only. Is atomicity a problem here? Also is visibility (volatile) a concern?

public ref partial struct SequenceReader<T> where T : unmanaged, IEquatable<T>

The Volatile.Write introduced in dotnet/corefx#37718 could be a plain write instead.

@GrabYourPitchforks
Copy link
Member Author

SequenceReader is a ref struct, so stack-only. Is atomicity a problem here? Also is visibility (volatile) a concern?

Good point. I'm trying to remember why it's a ref struct since it doesn't contain any byref fields. If it's intended to be a ref struct, then yeah, we can kill all of the volatile goop.

@gfoidl
Copy link
Member

gfoidl commented Nov 30, 2020

trying to remember why it's a ref struct

From #27522

SequenceReader can't be used in async methods

So it's intentional to prevent this?!

@benaadams
Copy link
Member

I'm trying to remember why it's a ref struct since it doesn't contain any byref fields

Except this one 😉

public ReadOnlySpan<T> CurrentSpan { readonly get; private set; }

@GrabYourPitchforks
Copy link
Member Author

Aaaargh. I hate that it's buried with other properties and isn't grouped with the fields at the top of the file.

@GrabYourPitchforks
Copy link
Member Author

Then it sounds like @gfoidl's suggestion is the best one. Find places in SequenceReader<T> that try to be thread-safe (are there others aside from this?) and remove the unneeded thread safety aspects.

@gfoidl
Copy link
Member

gfoidl commented Dec 1, 2020

@GrabYourPitchforks are you working on this? Otherwise I can have a look.

and isn't grouped with the fields at the top of the file

That should be done in the same PR.

@GrabYourPitchforks
Copy link
Member Author

I wouldn't change the layout of the file as part of this PR. Just lamenting generally. 😞

@gfoidl
Copy link
Member

gfoidl commented Dec 1, 2020

This was the only occurance --> #45437 (hope it's an easy review 😉).

@adamsitnik adamsitnik removed the untriaged New issue has not been triaged by the area owner label Dec 2, 2020
@GrabYourPitchforks
Copy link
Member Author

Thanks @gfoidl and @adamsitnik for handling this! :)

@ghost ghost locked as resolved and limited conversation to collaborators Jan 6, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants