-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Amend Rc/Arc::from_raw() docs regarding unsafety #68099
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 |
---|---|---|
|
@@ -259,6 +259,10 @@ use crate::vec::Vec; | |
#[cfg(test)] | ||
mod tests; | ||
|
||
// This is repr(C) to future-proof against possible field-reordering, which | ||
// would interfere with otherwise safe [into|from]_raw() of transmutable | ||
// inner types. | ||
#[repr(C)] | ||
struct RcBox<T: ?Sized> { | ||
strong: Cell<usize>, | ||
weak: Cell<usize>, | ||
|
@@ -570,15 +574,24 @@ impl<T: ?Sized> Rc<T> { | |
ptr | ||
} | ||
|
||
/// Constructs an `Rc` from a raw pointer. | ||
/// Constructs an `Rc<T>` from a raw pointer. | ||
/// | ||
/// The raw pointer must have been previously returned by a call to a | ||
/// [`Rc::into_raw`][into_raw]. | ||
/// The raw pointer must have been previously returned by a call to | ||
/// [`Rc<U>::into_raw`][into_raw] where `U` must have the same size | ||
/// and alignment as `T`. This is trivially true if `U` is `T`. | ||
/// Note that if `U` is not `T` but has the same size and alignment, this is | ||
/// basically like transmuting references of different types. See | ||
/// [`mem::transmute`][transmute] for more information on what | ||
/// restrictions apply in this case. | ||
/// | ||
/// This function is unsafe because improper use may lead to memory problems. For example, a | ||
/// double-free may occur if the function is called twice on the same raw pointer. | ||
/// The user of `from_raw` has to make sure a specific value of `T` is only | ||
/// dropped once. | ||
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. What does this mean? Isn’t 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. The user is responsible for not calling 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. Ok, I see what you’re getting at but I feel this one sentence does not express it well. Maybe we could talk about how each (By the way I think there should be an alternative to 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. Agreed on both points. I'm not sure of the exact wording, but maybe @lukaslueg can come up with some draft wording? 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. I'm a little hesitant on this point, for fear of convolution.
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. @Mark-Simulacrum any thoughts on the previous comment? 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. I think it's certainly more detailed :) However, I think it should clarify that even if you know T is safe to drop lots of times (e.g., |
||
/// | ||
/// This function is unsafe because improper use may lead to memory unsafety, | ||
/// even if the returned `Rc<T>` is never accessed. | ||
/// | ||
/// [into_raw]: struct.Rc.html#method.into_raw | ||
/// [transmute]: ../../std/mem/fn.transmute.html | ||
/// | ||
/// # Examples | ||
/// | ||
|
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.
Is same size and align strong enough? What stops rustc from ordering the
strong
andweak
fields of RcBox and ArcInner in a different order for different T?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.
Technically, nothing, but we know today that rustc will not do so I believe. I continue to believe that it would be a good idea to add
#[repr(C)]
or something like it to RcBox and ArcInner, since there should be no reason to not guarantee (internally at least) that the field layout is consistent.Notably, the data field must be last, due to unsizing, and reodering two usize fields is not currently ever going to happen anyway, I believe.
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.
Currently it doesn't, but rust-lang/unsafe-code-guidelines#36 is about whether to make this a guarantee, and I don't think it's decided yet. For example PGO-based field layout would absolutely reorder fields with the same size and align to keep frequently read data together and frequently written data in a different cache line.
I don't necessarily intend on blocking this PR on this, but I would feel more comfortable with #[repr(C)] on those types.
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.
I would be in favor of adding #[repr(C)] as well. Doing so in this PR makes sense to me.
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.
Amended
RcBox
andArcInner
withrepr(C)
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.
Could you also add a comment to those repr(C) annotations that notes that they're not for C-compat, but strictly so that the layout is equivalent for transmutable types (or so)?
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.
force-pushed