-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
New RFC: Collection Transmute #2756
Conversation
d11da3b
to
4a44ee1
Compare
4a44ee1
to
15256d3
Compare
cc @RalfJung |
Nice! Thanks for writing this up.
Could you include text in the RFC that documents this progression? In particular, why is the naive approach unsound, and why is the final result correct? In addition to that, I don't see alignment mentioned in this RFC, and I'd kind of expect that to be an issue somewhere. Or am I misunderstanding? Additionally, are there any problems with the fact that you might create an allocation for |
I'd rather just declare As far as I know, transmuting a Vec (if the item types are sufficiently compatible) is only UB today because we're not committed to
One remaining benefit of a specialized |
I agree with @BurntSushi about enforcing I think however an inequality suffices for the alignment, probably |
I got the equality (as opposed to inequality) from the docs on
Where |
An inequality would prove useful, so maybe @RalfJung can say if it suffices. |
You'll have to ask whoever wrote the allocator docs. I have no idea why alignment is even required to match. (I'll only be able to read the full thing and respond properly to it when I am back from vacation.) |
The Windows system allocator implementation does rely on getting the same alignment when deallocating as allocating I believe. |
This is not just a windows thing: any time that you need a greater alignment than the underlying allocator can provide, you have to allocate a slightly larger chunk of memory and then offset the returned pointer to the required alignment. When it comes to freeing that memory, you need some way to undo that offset. |
Just the alignment is not enough information though to compute what the offset was. |
Thanks to all of you for this illuminating discussion! This convinces me that a) the current design isn't courageous enough, I should go with an unsafe Regarding the alignment question, we'd need the information from the allocator if reducing alignment is acceptable. |
You need the alignment to determine whether an offset was applied or not though, and that's exactly what libstd does: https://github.com/rust-lang/rust/blob/master/src/libstd/sys/windows/alloc.rs#L47-L56 Without that, you end up having to add overhead to every single allocation, not just those with unusually large alignment requirements. |
Kind of unsure how this could be used properly in the case of |
How much do we know about when transmute gets used? I assume the most common usages are firstly to convert to/from a byte array, and secondly to violate another crate's visibility rules, like by adding or removing a private wrapper type. I think |
@clarfon it's an unsafe operation. One could pair it with a heapify operation to restore the heap property if so desired, in cases where the types' orderings differ. |
@llogiq Right, but |
How exactly is the size/alignment check to be implemented? An extension of the special-case |
This may be obvious to most people involved here so far, but it might be useful to mention one or two use cases for having a transmute operation on these collections in the first place. |
A There are some cases where it would be highly desirable for straight-up transmutation to be well-defined. In particular, when switching a generic type argument between // Newtype index wrapper for a graph node.
#[repr(transparent)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
struct Node(usize);
// It is highly desirable for all of these to be valid operations
transmute::<Vec<Vec<usize>>, Vec<Vec<Node>>>(vecs);
transmute::<Vec<HashSet<usize>>, Vec<HashSet<Node>>>(sets);
transmute::<&HashSet<usize>, &HashSet<Node>>(set); If we tried to solve the problem of UB Vec transmutes by introducing a
|
No it should not! trait Foo {
type Bar;
}
struct Baz<T: Foo>(T, T::Bar);
|
@KrishnaSannasi
That is not a transparent newtype, though. However, @ExpHP, transmuting transparent newtypes may still not be safe because the newtype may have additional invariants over the wrapped type. For example, |
Note that
|
Linting in rustc or Clippy for the specific pattern of obtaining a pointer from an owned collection, casting it to an incompatible alignment and creating another collection from it would solve the problem, but I'm not sure how feasible that is. Clippy already has a lint for casts between pointers with incompatible layout, but it would not be triggered for casting a pointer to |
That’s a good point, an explicit method would also be an opportunity to |
We could at least lint pointers that are used in |
We discussed this in the @rust-lang/lang meeting today. We don't think this is a lang concern; this is entirely up to @rust-lang/libs. We do think there'd be value in project-safe-transmute taking a look at this, and ensuring there are appropriate mechanisms to do safe transmutes. Apart from that, it seems reasonable to have mechanisms to do unsafe transmute here. Such a mechanism could use either |
Note that simple iterators already do almost the right thing for vec. https://rust.godbolt.org/z/537KEs |
Dropping T-lang per #2756 (comment) |
We discussed this RFC in the most recent @rust-lang/libs-api meeting. It was concerning that the code examples of "doing it correctly" in the RFC are all UB due to the alignment issue raised in the thread. You can't transmute by value to a vector with a different element alignment (like Vec<i32> to Vec<[u8; 4]>) since when dropping the resulting vector's heap allocation the Layout provided to the allocator is required to match the Layout it was allocated with. We are interested in collection transmute APIs in general (both safe and unsafe) but would prefer to consider them only once there are trait bounds from #2981 to incorporate into the design. For now, as noted in #2756 (comment), @rfcbot fcp close |
Team member @dtolnay has proposed to close this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
A comment: If you are willing to use a crate then many vec transmutations are already available: https://docs.rs/bytemuck/1.7.0/bytemuck/allocation/fn.try_cast_vec.html |
The final comment period, with a disposition to close, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC is now closed. |
rendered