-
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
Clarify the relationship between forget()
and ManuallyDrop
.
#69618
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @sfackler (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. |
r? @RalfJung |
This comment has been minimized.
This comment has been minimized.
I added that sentence because the following is UB: fn main() { unsafe {
let x = Box::new(4);
let x_copy = std::ptr::read(&x);
drop(x);
std::mem::forget(x_copy);
} } Click "Tools - Miri" on playground to see the UB. In other words, passing invalid object to any function can cause UB (it is "producing an invalid value"). The fact that you seem convinced of the opposite despite the docs stating this makes it even more important to keep this remark, I think. ;) But the remark is probably not very clear, and could be improved. Any suggestions? |
@RalfJung Thanks for the clarification and the example. I can't suggest a better wording for that part because I don't yet understand the underlying problem. Looking at the example, I cannot help but wonder if Miri is being too strict here. For example, changing |
After thinking about this some more, I'm beginning to see your point: passing a dangling It is curious that the definition explicitly includes a dangling |
At least right now, you are correct that
Exactly. Generally, |
@RalfJung I've now pushed a change that restores the warning against producing invalid values, only reworded in a way that (hopefully) clarifies the issue. |
Honestly I am wondering if it is time to soft-deprecate |
I'll try to give one more shot at documenting the issues correctly (and fixing the grammar). |
That is a good point. |
☔ The latest upstream changes (presumably #69804) made this pull request unmergeable. Please resolve the merge conflicts. |
I believe I've now fixed the issues raised in the review:
Additionally, the whole relationship with I believe this improves the current text, for reasons explained in the first bullet point of the PR's description. The second bullet point of that description is largely invalidated, as the UB is shown to exist. Still, the PR hopefully now provides a more thorough explanation of the issue, especially for readers who (like me previously) think that the fact that Rust's moves are just bitwise copies makes it ok to invoke |
@RalfJung Does the |
No it's just not automatically updated. I have this in my queue and will get around to reviewing it eventually. :) |
Thanks! :) |
📌 Commit 0335c037af4149b392d5782d3bc2e91e13b6d228 has been approved by |
The len was also hard-coded in the ManuallyDrop example; I've now changed that one as well for consistency. |
Good call. Could you squash the commits a bit? 13 commits seems excessive for this change.^^ |
@bors r- |
Sure! I kind of assumed you'd squash all of them at merge time, so I didn't bother tidying them up. Is it ok to also rebase them on current master in order to avoid the bidirectional merge? |
Sure, whatever makes squashing easier for you. |
As discussed on reddit, this commit addresses two issues with the documentation of `mem::forget()`: * The documentation of `mem::forget()` can confuse the reader because of the discrepancy between usage examples that show correct usage and the accompanying text which speaks of the possibility of double-free. The text that says "if the panic occurs before `mem::forget` was called" refers to a variant of the second example that was never shown, modified to use `mem::forget` instead of `ManuallyDrop`. Ideally the documentation should show both variants, so it's clear what it's talking about. Also, the double free could be fixed just by placing `mem::forget(v)` before the construction of `s`. Since the lifetimes of `s` and `v` wouldn't overlap, there would be no point where panic could cause a double free. This could be mentioned, and contrasted against the more robust fix of using `ManuallyDrop`. * This sentence seems unjustified: "For some types, operations such as passing ownership (to a funcion like `mem::forget`) requires them to actually be fully owned right now [...]". Unlike C++, Rust has no move constructors, its moves are (possibly elided) bitwise copies. Even if you pass an invalid object to `mem::forget`, no harm should come to pass because `mem::forget` consumes the object and exists solely to prevent drop, so there no one left to observe the invalid state state.
…m::forget. As pointed out by Ralf Jung, dangling references and boxes are undefined behavior as per https://doc.rust-lang.org/reference/behavior-considered-undefined.html and the Miri checker.
Co-Authored-By: Ralf Jung <post@ralfj.de>
Co-Authored-By: lzutao <taolzu@gmail.com>
I've now rebased the change and reduced the commit count to four, each of which makes logical sense. Feel free to let me know if you want me to cut it further. |
Thanks a lot, that's perfect. :) @bors r+ |
📌 Commit 2bebe8d has been approved by |
Clarify the relationship between `forget()` and `ManuallyDrop`. As discussed on reddit, this commit addresses two issues with the documentation of `mem::forget()`: * The documentation of `mem::forget()` can confuse the reader because of the discrepancy between usage examples that show correct usage and the accompanying text which speaks of the possibility of double-free. The text that says "if the panic occurs before `mem::forget` was called" refers to a variant of the second example that was never shown, modified to use `mem::forget` instead of `ManuallyDrop`. Ideally the documentation should show both variants, so it's clear what it's talking about. Also, the double free could be fixed just by placing `mem::forget(v)` before the construction of `s`. Since the lifetimes of `s` and `v` wouldn't overlap, there would be no point where panic could cause a double free. This could be mentioned, and contrasted against the more robust fix of using `ManuallyDrop`. * This sentence seems unjustified: "For some types, operations such as passing ownership (to a funcion like `mem::forget`) requires them to actually be fully owned right now [...]". Unlike C++, Rust has no move constructors, its moves are (possibly elided) bitwise copies. Even if you pass an invalid object to `mem::forget`, no harm should come to pass because `mem::forget` consumes the object and exists solely to prevent drop, so there no one left to observe the invalid state state.
Rollup of 9 pull requests Successful merges: - rust-lang#69618 (Clarify the relationship between `forget()` and `ManuallyDrop`.) - rust-lang#69768 (Compute the correct layout for variants of uninhabited enums) - rust-lang#69935 (codegen/mir: support polymorphic `InstanceDef`s) - rust-lang#70103 (Clean up E0437 explanation) - rust-lang#70131 (Add regression test for TAIT lifetime inference (issue rust-lang#55099)) - rust-lang#70133 (remove unused imports) - rust-lang#70145 (doc: Add quote to .init_array) - rust-lang#70146 (Clean up e0438 explanation) - rust-lang#70150 (triagebot.toml: accept cleanup-crew) Failed merges: r? @ghost
As discussed on reddit, this commit addresses two issues with the
documentation of
mem::forget()
:The documentation of
mem::forget()
can confuse the reader because of thediscrepancy between usage examples that show correct usage and the
accompanying text which speaks of the possibility of double-free. The
text that says "if the panic occurs before
mem::forget
was called"refers to a variant of the second example that was never shown, modified
to use
mem::forget
instead ofManuallyDrop
. Ideally the documentationshould show both variants, so it's clear what it's talking about.
Also, the double free could be fixed just by placing
mem::forget(v)
before the construction of
s
. Since the lifetimes ofs
andv
wouldn't overlap, there would be no point where panic could cause a double
free. This could be mentioned, and contrasted against the more robust fix
of using
ManuallyDrop
.This sentence seems unjustified: "For some types, operations such as
passing ownership (to a funcion like
mem::forget
) requires them toactually be fully owned right now [...]". Unlike C++, Rust has no move
constructors, its moves are (possibly elided) bitwise copies. Even if you
pass an invalid object to
mem::forget
, no harm should come to passbecause
mem::forget
consumes the object and exists solely to preventdrop, so there no one left to observe the invalid state state.