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

MemoryMarshal.{Try}Read/{Try}Write/AsRef should allow ref struct #113132

Open
hez2010 opened this issue Mar 4, 2025 · 6 comments
Open

MemoryMarshal.{Try}Read/{Try}Write/AsRef should allow ref struct #113132

hez2010 opened this issue Mar 4, 2025 · 6 comments
Labels
area-System.Runtime.InteropServices untriaged New issue has not been triaged by the area owner

Comments

@hez2010
Copy link
Contributor

hez2010 commented Mar 4, 2025

We are missing where T : allows ref struct on:

  • MemoryMarshal.Read
  • MemoryMarshal.TryRead
  • MemoryMarshal.Write
  • MemoryMarshal.TryWrite
  • MemoryMarshal.AsRef
  • MemoryMarshal.AsRef (readonly ref)
@dotnet-policy-service dotnet-policy-service bot added the untriaged New issue has not been triaged by the area owner label Mar 4, 2025
Copy link
Contributor

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

@huoyaoyuan
Copy link
Member

All of these are blocking IsReferenceOrContainsReferences because of GC safety. A ref struct without ref field is not so meaningful.

@hez2010
Copy link
Contributor Author

hez2010 commented Mar 4, 2025

All of these are blocking IsReferenceOrContainsReferences because of GC safety.

Yeah. But note that IsReferenceOrContainsReferences<T>() has where T: allows ref struct so it shouldn't be a problem in terms of compilation.

A ref struct without ref field is not so meaningful.

You don't have control to types coming from other libs. Some libs just define all their value types as ref struct to avoid unexpected boxing regardless of whether it has a ref field in it or not.

We can already do Unsafe.ReadUnaligned<Foo>(ref MemoryMarshal.GetReference(span)) (where Foo is a ref struct), so I don't see a reason why its short-hand MemoryMarshal.Read<Foo>(span) should be blocked.

Copy link
Contributor

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

@huoyaoyuan
Copy link
Member

We can already do Unsafe.ReadUnaligned<Foo>(ref MemoryMarshal.GetReference(span)) (where Foo is a ref struct), so I don't see a reason why its short-hand MemoryMarshal.Read<Foo>(span) should be blocked.

Unsafe.ReadUnaligned is not GC safe. It can also be used with class to read a GC reference from byte span. Using it with reference type or Span<T> can easily cause GC hole and access violation.

MemoryMarshal is safer than Unsafe. All its APIs don't allow breaking the boundary between value and GC ref.

You don't have control to types coming from other libs. Some libs just define all their value types as ref struct to avoid unexpected boxing regardless of whether it has a ref field in it or not.

Using pointer should be sufficient in these cases.

@hez2010
Copy link
Contributor Author

hez2010 commented Mar 5, 2025

MemoryMarshal is safer than Unsafe

That's why we need it to take a ref struct so that it can help block invalid usage because it checks gc pointer for you. Without the support, people will just copy whatever the code from its implementation and make their code even more unsafe.

Using pointer should be sufficient in these cases.

This doesn't hold as you can replace almost all Unsafe.* API usage by using pointers, so it should have been so sufficient that Unsafe.* API shouldn't even have existed in the first place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-System.Runtime.InteropServices untriaged New issue has not been triaged by the area owner
Projects
Status: No status
Development

No branches or pull requests

3 participants