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

Implement TransparentWrapper for [T; 1], (T,), and (T, ()) #264

Closed
wants to merge 1 commit into from

Conversation

0xAdk
Copy link

@0xAdk 0xAdk commented Aug 18, 2024

When attempting to remove some unsafe code I came across the limitation that TransparentWrapper<T> isn't implemented for (T, ()). I added the other two since they also make sense and I don't see a downside.

@0xAdk 0xAdk force-pushed the feat/transparent-wrapper-impl branch from b54038f to d3f1839 Compare August 18, 2024 13:14
@0xAdk
Copy link
Author

0xAdk commented Aug 18, 2024

while reading the help doc to verify (T, ()) is a transparent wrapper (I'm pretty sure it is) I noticed it mentions PhantomData as a common ZST, so I added it as well.

@chorman0773
Copy link
Contributor

Other than [T;1] I don't believe any of them are guaranteed to even be layout compatible. [T;1] is layout compatible by definition with T but not ABI Compatible at all.

@zachs18
Copy link
Contributor

zachs18 commented Aug 18, 2024

IIRC tuples do not have a defined layout (they are implicitly repr(Rust) and specifically not repr(transparent)), even single-element tuples, so it would not be correct to implement TransparentWrapper<T> for (T,) or (T, Zst).

impl TransparentWrapper<T> for [T; 1] would be fine (since they layout is the same), except that TransparentWrapper's docs explicitly call out that repr(transparent) must be used, which means that [T; 1] does not qualify (repr(transparent) has implications for passing by value to a function, e.g.).

Even if the repr(transparent) restriction is lifted (which would be a breaking change IMO) and instead it is just required that the types have the same size and alignment, then [T; 1] is okay, but for the tuples, at the very least there would need to be some kind of generic const assertion that their layouts are the same before any actual use of the trait for a particular instatiation.

@0xAdk
Copy link
Author

0xAdk commented Aug 18, 2024

I think I'm having a hard time wrapping my head around what what repr(rust) actually guaranteed. Re-reading it again I think I get it now that it only talks about alignment not size, so (T, ()) could be any size and offset_of!((T, ()), 0) could be any offset?

except that TransparentWrapper's docs explicitly call out that repr(transparent) must be used

I think I misread that part as requiring they have the same alignment and size.

@Lokathor
Copy link
Owner

So, when I reviewed the exact unsafe contract for TransparentWrapper (https://github.com/Lokathor/bytemuck/blob/main/src/transparent.rs#L15-L35), it's definitely a little confusingly worded. Point (1) contains the word "either", but then only gives one way to satisfy that point (the type must be repr(transparent)).

Since all previous usage of TransparentWrapper seems to have been built around this repr(transparent) assumption, and since that's a higher bar than the basic "data layout compatible" criteria, then I think that we have to continue to require the high bar for the trait, and so I don't think we can accept any new impls that aren't repr(transparent).

@0xAdk 0xAdk force-pushed the feat/transparent-wrapper-impl branch from d3f1839 to 76791a7 Compare August 18, 2024 15:45
@0xAdk 0xAdk force-pushed the feat/transparent-wrapper-impl branch from 76791a7 to 292eace Compare August 18, 2024 15:45
@chorman0773
Copy link
Contributor

chorman0773 commented Aug 18, 2024

repr(Rust) doesn't guarantee much about alignment either (or call ABI).

The requirements are that which is required for soundness:

  • Each field is at an offset such that it is non-overlapping with any other field and is aligned (absent repr(packed)),
  • The size and alignment requirement of the entire struct is such that each field is placed wholy within the struct, the struct itself is aligned to at least the maximum accross all of its fields, and the size is a multiple of the alignment requirement.

@0xAdk
Copy link
Author

0xAdk commented Aug 18, 2024

and so I don't think we can accept any new impls that aren't repr(transparent)

ok I'll just close this then, looks like what I was trying to remove unsafe from might not be safe then? Is this something miri don't catch?

I changed the commit if you do want the [T; 1] impl

@0xAdk 0xAdk closed this Aug 18, 2024
@Lokathor
Copy link
Owner

In your specific context it might be safe, depending on how much that situation was assuming.

If you've got a link to some code you can post about it in the #dark-arts channel of the rust community discord (if you use discord that is), or you could open a new issue in this repo and approximately the same people would take a look there too.

@0xAdk
Copy link
Author

0xAdk commented Aug 18, 2024

Point (1) contains the word "either", but then only gives one way to satisfy that point (the type must be repr(transparent)).

I think this is why I got confused about what it exactly wanted. I thought #1 was just saying "Wrapper must be a wrapper around Inner with an identical data representations", I think the either is just confusing since the other option is wrapped in parentheses

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants