Skip to content
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 std::ptr (Take #2) #51016

Closed
wants to merge 13 commits into from

Conversation

ecstatic-morse
Copy link
Contributor

@ecstatic-morse ecstatic-morse commented May 24, 2018

Addresses #29371 and #36450.

This is a continuation of my work in this PR, which was merged prematurely.

The latest changes address all of @gankro's concerns except the one regarding ordering of invariants for copy_nonoverlapping. The fact that memory regions must be nonoverlapping depends on the definition of the two memory regions above, and is also repeated in the function summary.

@gankro and @rkruppe pointed out that we don't have rigorously defined semantics for uninitialized memory, so all mention of it has been removed. The nomicon implies that the functions in std::ptr work with uninitialized memory, so requiring memory that is to be read be initialized is not an invariant. This conflicts with a strict interpretation of the reference, but resolving that is outside the scope of this PR.

Before this is merged, I need to resolve the following issues:

  • The new docs assert that drop_in_place is equivalent to calling read and discarding the value. Is this correct?
  • Do write_bytes and swap_nonoverlapping require properly aligned pointers?
  • Update docs for the unstable swap_nonoverlapping
  • Update docs for the unstable unsafe pointer methods RFC Will be done later.

In the meantime, I'm in desperate need of feedback. I'm also hosting a rendered version of my changes to make reviewing easier.

r? @steveklabnik

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 24, 2018
@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-3.9 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.

[00:05:49] travis_fold:start:tidy
travis_time:start:tidy
tidy check
[00:05:49] tidy error: /checkout/src/libcore/ptr.rs:29: line longer than 100 chars
[00:05:51] some tidy checks failed
[00:05:51] 
[00:05:51] 
[00:05:51] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0-tools-bin/tidy" "/checkout/src" "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "--no-vendor" "--quiet"
[00:05:51] 
[00:05:51] 
[00:05:51] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test src/tools/tidy
[00:05:51] Build completed unsuccessfully in 0:02:05
[00:05:51] Build completed unsuccessfully in 0:02:05
[00:05:51] make: *** [tidy] Error 1
[00:05:51] Makefile:79: recipe for target 'tidy' failed

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:05a4f4ee
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-3.9 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:44:50] ....................................................i...............................................
[00:44:55] ........................................................................ii..........................
[00:45:01] ....................................................................................................
[00:45:07] ..................................................................................i.................
[00:45:09] iiiiiiiii...................................................
[00:45:09] 
[00:45:09] travis_fold:start:test_ui_nll
travis_time:start:test_ui_nll
Check compiletest suite=ui mode=ui compare_mode=nll (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
---
[00:45:56] ....................................................i...............................................
[00:46:00] .........................................................................ii.........................
[00:46:05] ....................................................................................................
[00:46:11] ..................................................................................i.................
[00:46:13] iiiiiiiii...................................................
[00:46:13] 
[00:46:13]  finished in 64.521
[00:46:13] travis_fold:end:test_ui_nll

---
[01:08:03] 
[01:08:03] running 1994 tests
[01:08:15] ....................................................................................................
[01:08:27] ....................................................................................................
[01:08:42] ......................................F.............................................................
[01:09:07] ....................................................................................................
[01:09:18] ....................................................................................................
[01:09:29] ....................................................................................................
[01:09:40] ....................................................................................................
---
[01:10:49] ....................................................................................................
[01:11:00] ....................................................................................................
[01:11:13] ....................................................................................................
[01:11:27] ....................................................................................................
[01:11:40] ..................................................F.................................................
travis_time:end:052e3bb8:start=1527134326161478552,finish=1527138659251255697,duration=4333089777145

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:01464bc1

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@rust-highfive
Copy link
Collaborator

The job x86_64-gnu-llvm-3.9 of your PR failed on Travis (raw log). Through arcane magic we have determined that the following fragments from the build log may contain information about the problem.

Click to expand the log.
[00:43:45] .....................................................i..............................................
[00:43:49] ........................................................................ii..........................
[00:43:55] ....................................................................................................
[00:44:01] ..................................................................................i.................
[00:44:03] iiiiiiiii...................................................
[00:44:03] 
[00:44:03] travis_fold:start:test_ui_nll
travis_time:start:test_ui_nll
Check compiletest suite=ui mode=ui compare_mode=nll (x86_64-unknown-linux-gnu -> x86_64-unknown-linux-gnu)
---
[00:45:04] ....................................................i...............................................
[00:45:10] ........................................................................ii..........................
[00:45:17] ....................................................................................................
[00:45:25] ..................................................................................i.................
[00:45:28] iiiiiiiii...................................................
[00:45:28] 
[00:45:28]  finished in 84.763
[00:45:28] travis_fold:end:test_ui_nll

---
[01:10:04] ....................................................................................................
[01:10:16] ....................................................................................................
[01:10:29] ....................................................................................................
[01:10:44] ....................................................................................................
[01:10:56] ................................................F...................................................
[01:11:30] ............................i.................................................................
[01:11:30] failures:
[01:11:30] 
[01:11:30] ---- ptr.rs - ptr::read (line 382) stdout ----
[01:11:30] ---- ptr.rs - ptr::read (line 382) stdout ----
[01:11:30] error: value assigned to `s2` is never read
[01:11:30]   --> ptr.rs:395:5
[01:11:30] 16 |     s2 = String::default();
[01:11:30]    |     ^^
[01:11:30]    |
[01:11:30] note: lint level defined here
[01:11:30] note: lint level defined here
[01:11:30]   --> ptr.rs:380:9
[01:11:30]    |
[01:11:30] 1  | #![deny(warnings)]
[01:11:30]    |         ^^^^^^^^
[01:11:30]    = note: #[deny(unused_assignments)] implied by #[deny(warnings)]
[01:11:30] thread 'ptr.rs - ptr::read (line 382)' panicked at 'couldn't compile the test', librustdoc/test.rs:325:17
[01:11:30] note: Run with `RUST_BACKTRACE=1` for a backtrace.
[01:11:30] 
[01:11:30] 
---
[01:11:30] 
[01:11:30] error: test failed, to rerun pass '--doc'
[01:11:30] 
[01:11:30] 
[01:11:30] command did not execute successfully: "/checkout/obj/build/x86_64-unknown-linux-gnu/stage0/bin/cargo" "test" "--target" "x86_64-unknown-linux-gnu" "-j" "4" "--release" "--locked" "--color" "always" "--features" "panic-unwind jemalloc backtrace" "--manifest-path" "/checkout/src/libstd/Cargo.toml" "-p" "core" "--" "--quiet"
[01:11:30] 
[01:11:30] 
[01:11:30] failed to run: /checkout/obj/build/bootstrap/debug/bootstrap test
[01:11:30] Build completed unsuccessfully in 0:29:55
[01:11:30] Build completed unsuccessfully in 0:29:55
[01:11:30] make: *** [check] Error 1
[01:11:30] Makefile:58: recipe for target 'check' failed

The command "stamp sh -x -c "$RUN_SCRIPT"" exited with 2.
travis_time:start:00d31ac1
$ date && (curl -fs --head https://google.com | grep ^Date: | sed 's/Date: //g' || true)

I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact @TimNN. (Feature Requests)

@ecstatic-morse ecstatic-morse mentioned this pull request May 25, 2018
9 tasks
@Gankra
Copy link
Contributor

Gankra commented May 25, 2018

Haven't had a chance to read this over, but just popping in to say:

  • thanks for perserving on this!
  • I believe it's reasonable to make the claims/requirements you state in your open issues

Copy link
Member

@steveklabnik steveklabnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At a high level, this looks good to me. If @gankro and everyone else are okay with the claims made, I'm happy.

Thank you so much for keeping up with this, I know it's been a journey :)

@ecstatic-morse
Copy link
Contributor Author

I'm pretty sure y'all have better things to do :). Right now the (no longer unstable) pointer methods are just copy-pasted versions of the old docs with a few notes added regarding argument ordering. I can copy them over, preserving the notes in a later PR, or merge them into this one. This thing is already pretty massive though, so I'm inclined to wait.

@ecstatic-morse
Copy link
Contributor Author

Oh and if the style is acceptable, I'll do swap_nonoverlapping this evening.

@shepmaster
Copy link
Member

Ping from triage, @steveklabnik !

@shepmaster
Copy link
Member

@ecstatic-morse your PR still has [WIP] in the title, but the reviewers seem generally happy. Can these two things be rectified?

@bors
Copy link
Contributor

bors commented Jun 3, 2018

☔ The latest upstream changes (presumably #51310) made this pull request unmergeable. Please resolve the merge conflicts.

@Gankra
Copy link
Contributor

Gankra commented Jun 4, 2018

@shepmaster someone more intimate with the low-level details still needs to review this. I haven't had a chance and I don't know if I will.

@steveklabnik
Copy link
Member

Yes, same here.

ecstatic-morse and others added 6 commits June 5, 2018 12:50
- 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`
@ecstatic-morse
Copy link
Contributor Author

I rebased to eliminate the merge commit I introduced by using github's merge conflict resolver.

Sorry, I'm sure there was a less messy way to do this.

@ecstatic-morse
Copy link
Contributor Author

ecstatic-morse commented Jun 5, 2018

In order to make reviewing easier, here's a summary of the changes made in this PR.

First and foremost, this PR addresses all the concerns raised in #29371. This includes linking to the C standard library functions, adding links to related functions in std, and adding examples where they were requested. Additionally, this PR changed existing examples to be more informative by showing the reader some places where innocuous looking code could cause UB by, for example, causing values to be dropped by assigning to them.

This PR also addresses #36450 by specifying the alignment requirements for all functions in std::ptr.

While I was addressing those concerns, I noticed that the the conditions which could trigger undefined behavior were not enumerated (as they are in, for example, offset). I attempted to add a list of invariants for each function, which, when violated, would result in undefined behavior. This proved more subtle than anticipated, mostly because rust does not have a rigorously defined memory model.

Valid Pointers

The new docs define the concept of a "valid" pointer in the module-level docs, which is a combination of several requirements from the Undefined Behavior section of the reference. A valid pointer is one that:

  • is not null.
  • is not dangling (it does not point to memory which has been freed).
  • satisfies LLVM's pointer aliasing rules.

The Safety section of each function requires that all pointers which are to be dereferenced be valid. Otherwise the behavior of the function is undefined. These conditions may or may not be sufficient, but they are necessary to avoid UB

We also use validity to define requirements for functions which operate on a sequence of values (e.g. copy). Such functions require that both p and p.offset(count - 1) be valid, where p is a pointer to the start of a sequence of values, and count is the number of values in the sequence. This implies that all values in the sequence are also valid, otherwise p.offset(count - 1) would violate aliasing rules.

@ecstatic-morse ecstatic-morse changed the title [WIP] Rewrite docs for std::ptr (Take #2) Rewrite docs for std::ptr (Take #2) Jun 5, 2018
@hanna-kruppe
Copy link
Contributor

hanna-kruppe commented Jun 5, 2018

A valid pointer is one that: [...]

This definition concerns me for a few reasons:

  • It references LLVM rules (I know the reference does this as well, I don't like that either), which is pragmatic in that it gives one a good idea of what's most likely to broken by LLVM optimizations today, but it's no good for defining Rust rules
  • It sounds exhaustive, but it really isn't -- and can't be, until we have unsafe code guidelines. This is to some degree unavoidable and by no means your fault, but strictly from a "how can we cover our asses" perspective I'd recommend some weasel words gesturing at the in-progress nature of some of these rules.

Besides these general points, I think the definition of "valid" needs to say more about Rust aliasing rules. The "general" LLVM aliasing rules are mentioned, but those are far weaker (the reference vaguely gestures at LLVM's "scoped noalias" to kind of cover how safe references behave). The upshot is: you can't really break the rules of safe references with raw pointer accesses. For example:

  • it's UB to mutate memory while a shared borrow to it exists (unless it's in an UnsafeCell)
  • while memory is mutably borrowed, it's UB to read or write the same memory through a different, unrelated pointer

Of course, the crux is defining what certain key phrases ("while a borrow exists", "unrelated pointer", etc.) mean exactly but even without unsafe code guidelines it's better to give vague guidance than omit it entirely.

@ecstatic-morse
Copy link
Contributor Author

ecstatic-morse commented Jun 5, 2018

@RalfJung, since you're working to formalize rust's memory model, do you have any thoughts on the proposed wording? I agree with @rkruppe that it's out of scope to exhaustively define what pointers are valid when passed to, for example, ptr::write, and I need to do a better job of pointing that out. However, I do believe that having even a non-exhaustive list of conditions would be an improvement on the existing docs.

//!
//! * The pointer is not null.
//! * The pointer is not dangling (it does not point to memory which has been
//! freed).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd strengthen this to something like "the pointer points to a live allocation". Arguably, 0x8 as *const u32 does not "point to memory which has been freed", but still it's not a valid pointer.

///
/// * `src.offset(count-1)` must be [valid]. In other words, the region of
/// memory which begins at `src` and has a length of `count *
/// size_of::<T>()` bytes must belong to a single, live allocation.
Copy link
Member

@RalfJung RalfJung Jun 11, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The part after "in other words" says way more than the the first part! Also, Why is "src must be valid" and "src.offset(count-1)" split into two conditions? I see one condition here, which is "src.offset(i) must be valid for reading size_of::<T>() bytes for 0 <= i < count", or, equivalently, "src must be valid for reading size_of::<T>() * count bytes".

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I now see in your comments in the thread that you argue it would otherwise violate aliasing rules. That seems plausible but unnecessarily contorted for a definition.

Given that validity has to be defined for a size anyway, I'd just change this to require validity of the entire affected memory range at once (i.e. length size_of::<T>() * count).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I got a bit to clever here :) I was trying to rely exclusively on the definition of validity to define invariants over arrays as well as single accesses. The notion of a "single, live allocation" doesn't appear anywhere in the reference to my knowledge, which is why it went in "in other words".

As I note in my later comment, I think that making pointer validity a function of access size overcomplicates things a bit, and that the type of the pointer should fully specify the number of bytes being accessed when reading or writing.

From this point of view, your src.offset(i) for all i in 0..count works formulation nicely, although it still references offset, which is maybe a bit opaque.

Copy link
Member

@RalfJung RalfJung Jun 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I note in my later comment, I think that making pointer validity a function of access size overcomplicates things a bit, and that the type of the pointer should fully specify the number of bytes being accessed when reading or writing.

In my eyes, making it depend on the whole type makes things more complicated. With your proposal, validity is a function of the pointer and its type, and you should say so clearly ("A pointer pointing to type T is valid ..."). A type contains much more information than just a size! With my proposal, it is crystal clear that the size of the only part that actually matters ("A pointer is valid for an access of size n ..."). Notice that I use "pointer" here as a run-time concept; pointers themselves (as in, just the raw address in memory -- or whatever abstract representation of pointers you want to think of) are intrinsically untyped. So either way you need to add some extra information to define validity; the question is only if you restrict that to what is actually necessary (the size) or if you add a whole lot of other irrelevant information as well (the type).

Plus, for functions where the type alone does not suffice, we don't have to do awkward things like use .offset in our definition and rely on that function to be undefined when crossing allocation boundaries.

Copy link
Contributor Author

@ecstatic-morse ecstatic-morse Jun 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean I would need to qualify that, for example, ptr::read requires that its argument be valid for a read of at least size_of::<T>() bytes? This is what I meant by overcomplicates, not that the concept itself wasn't necessary, but that stating it everywhere would be redundant.

Simply declaring that when the size of an access for *const T is not explicitly stated, we mean valid for size_of::<T>() bytes would work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this!

@steveklabnik
Copy link
Member

as per #51016 (comment), @gankro and I are basically done with this PR. It seems @RalfJung has done an actual review, but maybe not checked @ecstatic-morse 's latest work.

@bors: delegate=ralfjung :)

@bors
Copy link
Contributor

bors commented Jun 25, 2018

✌️ @RalfJung can now approve this pull request

@steveklabnik
Copy link
Member

@bors: r? @RalfJung

@pietroalbini
Copy link
Member

They can't actually be assigned to the issue since they're not in the org.

//!
//! There are two types of operations on memory, reads and writes. It is
//! possible for a `*mut` to be valid for one operation and not the other. Since
//! a `*const` can only be read and not written, it has no such ambiguity. For
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the types mean much more than they should, I think. One can cast freely and in safe code between *mut and *const. For all intents and purposes, these are the same type; *const just has a "lint" associated with it that you cannot write through it.

//! a `*const` can only be read and not written, it has no such ambiguity. For
//! example, a `*mut` is not valid for writes if a a reference exists which
//! [refers to the same memory][aliasing]. Therefore, each function in this
//! module will document which operations must be valid on any `*mut` arguments.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand this last sentence. Do you mean something like, "each operation will document which *mut arguments it requires to be valid"?

//!
//! For more information on the safety implications of dereferencing raw
//! pointers, see the both the [book] and the section in the reference devoted
//! to [undefined behavior][ub].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we can actually spell out the requirements besides aliasing here. As in, can't we start this section with the stuff we know -- that the range covered by [pointer, pointer+size) must be part of a single allocated memory block, and that the size is implicitly given by the type when not stated explicitly? Then we can say that there are additional requirements about aliasing, and that those rules are not settled yet, referencing the nomicon.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some axioms regarding validity, casting a reference to a pointer results in a valid pointer, pointers to ZSTs are valid, that sort of thing, and linked to offset as a proxy for the single allocated memory block requirement. I also called out aliasing in that final paragraph.

@RalfJung
Copy link
Member

Sorry for the long silence!


I have not carefully reviewed every single method doc, but focused on the notion of "validity". Beyond the comments above, I am missing a discussion of null pointers. I think you should do one of the following:

  • For each method, add a requirement that the pointer be non-NULL. (This can be merged with the requirement of being aligned where applicable.) In the definition of validity, add a clarification saying that all pointers are valid for reading and writing 0 bytes.
  • In the definition of validity, add a requirement that the pointer be non-NULL. Add a clarification saying that pointers are valid for reading and writing 0 bytes iff they are non-NULL.

In particular, I don't think zero-sized accesses are that complicated and I think they are relevant enough to be mentioned here. We are, I think, making them maximally undefined (as in, even zero-sized accesses have to be non-NULL and aligned), so we can always weaken that later if people complain.

I prefer the first variant because I like the fact that this makes validity hold trivially for zero-sized accesses. However, it leads to non-NULLness being repeated in plenty of places, so others might prefer the second variant. ;)

@TimNN TimNN added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 3, 2018
@ecstatic-morse
Copy link
Contributor Author

Sorry, I've been busy lately. It's a holiday in the U.S., so I'll pick this up again today.

Also rewrites the reads/writes section to be less reliant on `*const`,
`*mut`
@ecstatic-morse
Copy link
Contributor Author

I went with the second variant. I should have mentioned this several comments ago, but I don't believe that null pointers need to be a special case. Basically, we have two axioms, all pointers are valid for reads and writes of size zero, and a null pointer is never valid. These two axioms intersect when you have a null pointer to a ZST. Eventually, Rust will need to decide which axiom supersedes the other.

However, I don't think this PR is the place to settle this question, and propagating the non-null requirement everywhere is more committal than I'd like. Additionally, I think it's actually clearer to say "a null pointer is never valid" and "all pointers (except a null pointer) are valid for operations of size 0", than introduce "non-nullness" as an orthogonal concept to validity.

@pietroalbini pietroalbini added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 4, 2018
@RalfJung
Copy link
Member

RalfJung commented Jul 8, 2018

I think it's actually clearer to say "a null pointer is never valid" and "all pointers (except a null pointer) are valid for operations of size 0", than introduce "non-nullness" as an orthogonal concept to validity.

Fine for me. This is also the conservative choice, I think (allowing fewer things).

//! memory][aliasing]. The set of operations for which a pointer argument must
//! be valid is explicitly documented for each function. This is not strictly
//! necessary for `*const` arguments, as they can only be used for reads and
//! never for writes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with the content of this, but the way this is phrased It may be just me but reading this paragraph leaves me pretty confused. For example, the "set of operations" can not be larger than 2, ever; and I also never find myself wondering "what is the set of operations that this pointer is valid for". I rather wonder "can I read through this"? Also, I do not think it is possible for a pointer to be valid for writing, but not valid for reading -- so "any combination" is not really possible.

So, I'd frame this entire thing by starting out saying there are two notions of validity: Valid for reading, and valid for writing. Every pointer operation specifies which kind of validity it requires. I'd put all of that into the first paragraph, and not talk about how Rust (typo: rust) doesn't yet have a fully defined model there. So, the first paragraph sets the stage and introduced the distinction between read and write validity, and does nothing else.

The second paragraph can then lead by saying that unfortunately, Rust doesn't yet have a fully defined memory model and hence the precise set of rules is not known yet. However, there are some things we do know -- e.g., if an &mut exists and is not currently reborrowed (that restriction is important), then any other aliasing pointer is not valid for reading nor writing. And so on.

It might even be better to move this paragraph down; the sentence right before your enumeration also touches the same topic so that would flow nicely.

//! are a few rules regarding validity:
//!
//! * The result of casting a reference to a pointer is valid for as long as the
//! underlying object is live.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd say something like "a pointer obtained by casting a reference"; had to read this two times to parse it. ;)

Also, this is not true. The pointer obtained from the cast is valid immediately after the cast. However, using the reference again will invalidate the pointer, and other things may also invalidate it. For example:

fn foo(x: &mut u32) {
  let y = x as *mut;
  *x = 13;
  // Now y is NOT valid any more because `x` got "re-activated"
}

@TimNN TimNN added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 17, 2018
@pietroalbini
Copy link
Member

Ping from triage @ecstatic-morse! It's been a while since we heard from you, will you have time to work on this again?

@pietroalbini
Copy link
Member

Thank you for this PR @ecstatic-morse! Unfortunately we haven't heard from you on this in a while, so I'm closing the PR to keep things tidy. Don't worry though, if you'll have time again in the future please reopen this PR, we'll be happy to review it again!

@pietroalbini pietroalbini added S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Jul 30, 2018
@RalfJung
Copy link
Member

RalfJung commented Aug 1, 2018

I might take over this PR, if I find time. But don't let that stop you, @ecstatic-morse!

@RalfJung
Copy link
Member

Mostly for my own future reference -- a relevant issue in LLVM's bugtracker: https://bugs.llvm.org/show_bug.cgi?id=38583

bors added a commit that referenced this pull request Sep 24, 2018
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?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-inactive Status: Inactive and waiting on the author. This is often applied to closed PRs.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants