-
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
Add more methods in Cell for non-Copy types #39715
Conversation
Complement to #39264
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
src/libcore/cell.rs
Outdated
default fn clone(&self) -> Cell<T> { | ||
let temp = unsafe { mem::uninitialized() }; | ||
let inner = self.replace(temp); | ||
// If `clone` panics, let it crash. |
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.
Isn't this super unsafe? If a panic occurs here, *self
will be dropped (not in this scope, but later during stack unwinding) which will drop uninitialized memory which will cause UB.
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.
AssertUnwindSafe
is notunsafe
, and for good reason. Safe code usingAssertUnwindSafe
unwisely may get very undesirable behavior, but not UB.AssertUnwindSafe
is irrelevant, as this problem occurs without anycatch_unwind
calls. In fact, a well-placedcatch_unwind
can stop a panic in thisclone
call from dropping*self
(by stopping the unwinding before it gets to the stack frame where theCell
would be dropped).
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.
Well, you are right. I need to figure out a solution.
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.
@F001: You'll probably want to use something similar to the Hole
structure described in the nomicon, which writes a valid value back into the original cell in case of a panic.
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.
Or rather, is there a reason, you can't just use self.value.get().clone()
?
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.
@TimNN @F001 I haven't thought through the details but https://users.rust-lang.org/t/why-does-cell-require-copy-instead-of-clone/5769/3?u=rkruppe seems relevant.
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.
@rkruppe: Thanks for the link! After having a quick read through it and the comments on the original RFC, I think that safely implementing the methods proposed by this PR is fundamentally incompatible with "MoveCells", since we are not allowed to call any method on the contained Type, as I understand it. (This is not a problem for "CopyCells" since we can create a new copy of the value without calling any methods on it).
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.
Thanks for your comments!
@TimNN I don't agree that these methods are fundamentally incompatible with "MoveCells". Cell
is not intended to prohibit methods of the contained type. The most important guarantee is "disallowing any reference (mutable or immutable) to the data contained in the cell."
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 most important guarantee is "disallowing any reference (mutable or immutable) to the data contained in the cell."
I agree with that statement. However I think exactly this is happening here: As soon as you call clone
or partial_eq
, you provide those methods with a reference to the data in the cell, which then allows for bad things to happen, as can be seen by the example in the post linked by @rkruppe.
src/libcore/cell.rs
Outdated
let temp_right = mem::uninitialized(); | ||
let lhs = left.replace(temp_left); | ||
let rhs = right.replace(temp_right); | ||
// If panic happens in `f`, just let it crash. |
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.
For the record: same UB issue here as in the Clone
impl, so this affects most of the other impls added in this PR too.
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.
Thank you. Updated.
Thanks for the PR! Unfortunately these implementations are fundamentally unsound as-written. The purpose of Implementing such methods but accepting panics-as-aborts or something like that is an RFC-level change (as opposed to just happening in a PR), and I think otherwise tweaking these implementations to be sound will likely also be an RFC-level change (e.g. requiring |
Complement to #39264
r? @alexcrichton