-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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 small clarification around using pointers derived from references #103996
Conversation
Hey! It looks like you've submitted a new PR for the library teams! If this PR contains changes to any Examples of
|
library/core/src/ptr/mod.rs
Outdated
//! access the same memory. That is, reference and pointer accesses cannot be | ||
//! interleaved—they must follow stacked borrows. |
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.
Stacked borrows is an experimental unofficial memory model, so the official docs cannot say that people "must follow stacked borrows". Maybe saying something along the lines of "The restrictions of using raw pointers in combination with references have not been decided yet, so it is advised to not interleave accesses using raw pointers and references.
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, agreed. What question is this even answering? It seems unrelated to the other change.
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.
Oh yeah, sorry this should probably be in another PR. The current wording makes it sound like you cannot have a reference and pointer around at the same time. I'm trying to clarify that... maybe I can just remove "—they must follow stacked borrows"?
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.
It already says that no reference can be "used to access" the same memory while the pointer is used. Not sure how "accesses cannot be interleaved" adds any new information here?
I guess I am fine with clarifying, but I really don't see how the current wording "makes it sound like you cannot have a reference and pointer around at the same time" in any way that the new wording would fix.
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.
Hmmm, yeah this may not be the best clarification, though sometimes saying the same thing in different ways is still helpful. 🤷♂️ If I'm remembering correctly, I kind of got the feeling that the reference was "consumed" by casting it to a pointer when first reading this. So maybe saying this would be better? "That is, the reference may only be used when there are no more accesses through the pointer." Though I feel like interleaving expresses that idea more clearly?
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 guess the "that is" already states that this sentence is a clarification, not a new rule.
So if you remove the mention of stacked borrows this is probably fine to land.
That's an open question: rust-lang/unsafe-code-guidelines#84. References must point to valid data whenever they are used as a value (passed to a function, assigned, anything like that). But when they are just sitting there, the situation is much less clear. |
library/core/src/ptr/mod.rs
Outdated
//! it is read, either through the raw pointer or the reference it originated from. This means a type | ||
//! may freely transition between valid and invalid states when being written to by raw pointers. | ||
//! Thus, when discussing safety, it may be useful to separately assert the validity of the pointer vs. | ||
//! the validity of the data it points to. |
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 means a type may freely transition between valid and invalid states when being written to by raw pointers.
This has not really been decided yet either -- see rust-lang/unsafe-code-guidelines#84. I possibly used too definite language in rust-lang/libs-team#122.
I am also not sure what you mean by pointer and pointee invariant here. It is already the case that https://doc.rust-lang.org/nightly/std/ptr/fn.read.html says "src must point to a properly initialized value of type T". https://doc.rust-lang.org/nightly/std/ptr/fn.write.html does not say anything like that because it takes a T
as argument, which already implicitly says that it must be a valid 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.
Sorry, but large parts of unsafe Rust are simply still uncharted territory. :(
Haha yep, the deeper I dig the more that seems to be true. :)
pointee invariant here.
If we decide this should go through I'll clarify that.
which already implicitly says that it must be a valid T.
This is specifically about the as_bytes
case, so maybe I should make the idea of breaking down a larger type into smaller pieces clearer. I want to be explicit that it is ok to write valid data that causes a type to become invalid so long as the type becomes valid again by the time it's read.
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 want to be explicit that it is ok to write valid data that causes a type to become invalid so long as the type becomes valid again by the time it's read.
And I'm saying I think we can't way this in the official docs yet because rust-lang/unsafe-code-guidelines#84 has not been officially answered yet.
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.
Gotya, so unfortunately this whole paragraph is dead? I'll just keep the small clarification if 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.
Yeah I am afraid 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.
Done.
I think there is general consensus that this is sound fn foo(x: &mut NonZeroI32) {
let ptr = x as *mut NonZeroI32;
unsafe { ptr.cast::<i32>().write(0); }
unsafe { ptr.cast::<i32>().write(1); }
} but even that would need lang-team FCP. These are probably questions that we simply cannot answer for now and need to defer until the to-be-created operational semantics team gets around to them, and an RFC or FCP is passed on the relevant aspect of the semantics. Sorry, but large parts of unsafe Rust are simply still uncharted territory. :( |
Signed-off-by: Alex Saveau <[email protected]>
@bors r+ rollup |
…iaskrgr Rollup of 5 pull requests Successful merges: - rust-lang#103996 (Add small clarification around using pointers derived from references) - rust-lang#104315 (Improve spans with `use crate::{self}`) - rust-lang#104320 (Use `derive_const` and rm manual StructuralEq impl) - rust-lang#104357 (add is_sized method on Abi and Layout, and use it) - rust-lang#104365 (Add x tool to triagebot) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
Add small clarification around using pointers derived from references r? `@RalfJung` One question about your example from rust-lang/libs-team#122: at what point does UB arise? If writing 0 does not cause UB and the reference `x` is never read or written to (explicitly or implicitly by being wrapped in another data structure) after the call to `foo`, does UB only arise when dropping the value? I don't really get that since I thought references were always supposed to point to valid data? ```rust fn foo(x: &mut NonZeroI32) { let ptr = x as *mut NonZeroI32; unsafe { ptr.cast::<i32>().write(0); } // no UB here // What now? x is considered garbage when? } ```
…iaskrgr Rollup of 5 pull requests Successful merges: - rust-lang#103996 (Add small clarification around using pointers derived from references) - rust-lang#104315 (Improve spans with `use crate::{self}`) - rust-lang#104320 (Use `derive_const` and rm manual StructuralEq impl) - rust-lang#104357 (add is_sized method on Abi and Layout, and use it) - rust-lang#104365 (Add x tool to triagebot) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
r? @RalfJung
One question about your example from rust-lang/libs-team#122: at what point does UB arise? If writing 0 does not cause UB and the reference
x
is never read or written to (explicitly or implicitly by being wrapped in another data structure) after the call tofoo
, does UB only arise when dropping the value? I don't really get that since I thought references were always supposed to point to valid data?