-
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
Rewrite docs for pointer methods #53783
Conversation
- Add links to the GNU libc docs for `memmove`, `memcpy`, and `memset`, as well as internally linking to other functions in `std::ptr` - List invariants which, when violated, cause UB for all functions - Add example to `ptr::drop_in_place` and compares it to `ptr::read`. - Add examples which more closely mirror real world uses for the functions in `std::ptr`. Also, move the reimplementation of `mem::swap` to the examples of `ptr::read` and use a more interesting example for `copy_nonoverlapping`. - Change module level description - Define what constitutes a "valid" pointer. - Centralize discussion of ownership of bitwise copies in `ptr::read` and provide an example.
This also removes the overlong link that failed tidy xD.
They closely mirror the docs for `copy_nonoverlapping`
The enumerated list of conditions is replaced by an explanation that rust doesn't have a formal memory model. It does say that pointers created directly from references are guaranteed to be valid, and links to both the "Unsafe Code" section of the book and the "Undefined Behavior" section of the reference.
Uses `x.offset(i)` must be valid for all `i` in `0..count`.
This splits "valid" into "valid for reads" and "valid for writes", and also adds the concept of operation size to validity. Now functions which operate on sequences state that e.g. pointer args must be "valid for reads of size x".
Also rewrites the reads/writes section to be less reliant on `*const`, `*mut`
(rust_highfive has picked a reviewer for you, use r? to override) |
Cc @rust-lang/docs any advice on how to avoid duplicating all that information? My own ideas revolve around either using a macro to define the two/three functions together, or picking one as the "canonical place" and making the others link there. In terms of implementation effort, I'd prefer the latter... |
Also Cc @rust-lang/wg-unsafe-code-guidelines @gnzlbg for the actual content of the docs. Notice that we deliberately do not fully define validity, so no decision is made -- but this also nicely gives us a single spot where to put such a decision eventually, and it does define how all the various memory access methods relate to the idea of "validity of a memory access". But I think nothing there is controversial, this just documents the footprint of these functions (i.e., which memory they will read/write). |
fix some uses of pointer intrinsics with invalid pointers [Found by miri](rust-lang/miri#446): * `Vec::into_iter` calls `ptr::read` (and the underlying `copy_nonoverlapping`) with an unaligned pointer to a ZST. [According to LLVM devs](https://bugs.llvm.org/show_bug.cgi?id=38583), this is UB because it contradicts the metadata we are attaching to that pointer. * `HashMap` creation calls `ptr:.write_bytes` on a NULL pointer with a count of 0. This is likely not currently UB *currently*, but it violates the rules we are setting in #53783, and we might want to exploit those rules later (e.g. with more `nonnull` attributes for LLVM). Probably what `HashMap` really should do is use `NonNull::dangling()` instead of 0 for the empty case, but that would require a more careful analysis of the code. It seems like ideally, we should do a review of usage of such intrinsics all over libstd to ensure that they use valid pointers even when the size is 0. Is it worth opening an issue for that?
It is intended not to. |
I resolved the minor nits there were brought up. Remaining open discussions:
There is also one comment by @QuietMisdreavus that GitHub shows in this PR, but that I can neither reply to nor mark as resolved... no idea WTF is going on there. But anyway it is a duplicate of @arielb1's concern about |
FWIW the C++ std requires that the ranges do not overlap:
but I guess the whole point of |
@gnzlbg existing docs indicate pretty clearly that that is a supported case, yes. |
The only idea I have would be to specify it as a sequential byte-wise swap: let x = x as *mut u8;
let y = y as *mut u8;
for i in 0..mem::size_of::<T>() {
let tmp = *x;
*x = *y;
*y = tmp;
} but I don't know if one can construct a situation in which, if two valid values partially overlap, swapping them in this creates invalid values. |
I expanded |
Me too! |
I'm OK with the new |
Okay seems like we got consensus. @alexcrichton you are the officially assigned reviewer, how do we proceed? |
Nice! This is quite a PR with quite the discussion! I'm happy though if all stakeholders involved are happy, so let's... @bors: r+ |
📌 Commit c197dc4 has been approved by |
@RalfJung my comment that has no reply/resolve indicators is technically both part of that bulk review and this conversation, which hasn't been folded yet. |
Rewrite docs for pointer methods This takes over #51016 by @ecstatic-morse. They did most of the work, I just did some editing. However, I realized one problem: This updates the docs for the "free functions" in `core::ptr`, but it does not update the copies of these docs for the inherent methods of the `*const T` and `*mut T` types. These getting out-of-sync is certainly bad, but I also don't feel like copying all this stuff around. Instead, we should remove this redundancy. Any good ideas?
☀️ Test successful - status-appveyor, status-travis |
fix some uses of pointer intrinsics with invalid pointers [Found by miri](rust-lang/miri#446): * `Vec::into_iter` calls `ptr::read` (and the underlying `copy_nonoverlapping`) with an unaligned pointer to a ZST. [According to LLVM devs](https://bugs.llvm.org/show_bug.cgi?id=38583), this is UB because it contradicts the metadata we are attaching to that pointer. * `HashMap` creation calls `ptr:.write_bytes` on a NULL pointer with a count of 0. This is likely not currently UB *currently*, but it violates the rules we are setting in rust-lang/rust#53783, and we might want to exploit those rules later (e.g. with more `nonnull` attributes for LLVM). Probably what `HashMap` really should do is use `NonNull::dangling()` instead of 0 for the empty case, but that would require a more careful analysis of the code. It seems like ideally, we should do a review of usage of such intrinsics all over libstd to ensure that they use valid pointers even when the size is 0. Is it worth opening an issue for that?
This takes over #51016 by @ecstatic-morse. They did most of the work, I just did some editing.
However, I realized one problem: This updates the docs for the "free functions" in
core::ptr
, but it does not update the copies of these docs for the inherent methods of the*const T
and*mut T
types. These getting out-of-sync is certainly bad, but I also don't feel like copying all this stuff around. Instead, we should remove this redundancy. Any good ideas?