-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
MaybeUninit: Document UnsafeCell byte ranges #121215
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -209,7 +209,8 @@ use crate::slice; | |||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||
/// # Layout | ||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||
/// `MaybeUninit<T>` is guaranteed to have the same size, alignment, and ABI as `T`: | ||||||||||||||||||||||||||||
/// `MaybeUninit<T>` is guaranteed to have the same layout (size, alignment, and field offsets and layouts) | ||||||||||||||||||||||||||||
/// and ABI as `T`: | ||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||
/// ```rust | ||||||||||||||||||||||||||||
/// use std::mem::{MaybeUninit, size_of, align_of}; | ||||||||||||||||||||||||||||
|
@@ -241,6 +242,13 @@ use crate::slice; | |||||||||||||||||||||||||||
/// remain `#[repr(transparent)]`. That said, `MaybeUninit<T>` will *always* guarantee that it has | ||||||||||||||||||||||||||||
/// the same size, alignment, and ABI as `T`; it's just that the way `MaybeUninit` implements that | ||||||||||||||||||||||||||||
/// guarantee may evolve. | ||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||
/// ## `UnsafeCell` | ||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||
/// As a result of having the same layout as `T`, `MaybeUninit<T>` has [`UnsafeCell`]s covering | ||||||||||||||||||||||||||||
/// the same byte ranges as `T`. | ||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||
/// [`UnsafeCell`]: crate::cell::UnsafeCell | ||||||||||||||||||||||||||||
Comment on lines
+246
to
+251
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. eh? what does this mean? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here's another way of expressing the same thing: for every byte offset, The reason this is an important property is that if you operate on a given memory location using an For example, consider this code: #[repr(C)]
struct A {
one: u8,
two: UnsafeCell<[u8; 2]>,
}
#[repr(C)]
struct B {
one: UnsafeCell<[u8; 2]>,
two: u8,
}
fn main() {
let a = A { one: 1, two: UnsafeCell::new([2, 3]) };
let a_ptr: *const A = &a;
let b = unsafe { &*(a_ptr as *const B) };
println!("{:?}", unsafe { *b.one.get() });
} If we run this under Miri, it detects UB:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
OH! I see. I had to read that a few times but I think I get what you mean. Perhaps something like:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @workingjubilee's suggestion looks good to me. |
||||||||||||||||||||||||||||
#[stable(feature = "maybe_uninit", since = "1.36.0")] | ||||||||||||||||||||||||||||
// Lang item so we can wrap other types in it. This is useful for coroutines. | ||||||||||||||||||||||||||||
#[lang = "maybe_uninit"] | ||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "field offsets and layouts" part is redundant because layouts are compositional. If the size and alignment is the same as T then by necessity the offset of
T
withinMaybeUninit
is zero. And any specificT
is aT
, so its field offsets are its field offsets.This is no different than
#[repr(transparent)] struct Wrapper(MyStruct)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think this is overly complicating things and feels more confusing to me than just saying that the size and alignment are the same. MaybeUninit is usually treated as having a single field itself (T) so it's confusing to me to talk about field offsets and layouts, especially after size/alignment (which is all a layout is).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem as I see it is twofold:
While we technically define "layout" to refer to size, alignment, and field offset/layout [1], it's colloquially often used to refer only to size and alignment, and so I think being verbose may help here
While const generics aren't stable today, you could define
MaybeUninit
as follows, which would be consistent with the size and alignment properties, but would not be consistent with the field offset/layout properties:[1] I know this was officially documented within the past year, but I can't figure out where we did that...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be a breaking change because the alignment of this type would be the same as u8 and not the same as T. playground
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That type also differs from the true
MaybeUninit
in terms of preserving all padding bytes (which trueMaybeUninit
does not preserve).