From 9280a759975a843749e6b88b613fb5e6d53db2bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Aug 2018 21:52:11 +0200 Subject: [PATCH 1/1] fix rustdoc links to point to stable docs --- personal/_posts/2017-07-17-types-as-contracts.md | 2 +- personal/_posts/2018-01-31-sharing-for-a-lifetime.md | 2 +- personal/_posts/2018-04-05-a-formal-look-at-pinning.md | 2 +- .../2018-04-10-safe-intrusive-collections-with-pinning.md | 8 ++++---- personal/_posts/2018-07-13-arc-synchronization.md | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/personal/_posts/2017-07-17-types-as-contracts.md b/personal/_posts/2017-07-17-types-as-contracts.md index 10a8e4c..3ef565a 100644 --- a/personal/_posts/2017-07-17-types-as-contracts.md +++ b/personal/_posts/2017-07-17-types-as-contracts.md @@ -320,7 +320,7 @@ One topic that needs special treatment in this context is interior mutability. If a function takes an `x: &Cell`, following the rules above, it will acquire a read lock of `*x` for the duration of the function call, making `*x` immutable. Clearly, we do not want to do that -- calling `x.set` *will* actually mutate `*x`, and mutating through a shared reference is exactly the point of using `Cell`! -Lucky enough, the compiler *already* says that interior mutability is only allowed via [`UnsafeCell`](https://doc.rust-lang.org/beta/core/cell/struct.UnsafeCell.html). +Lucky enough, the compiler *already* says that interior mutability is only allowed via [`UnsafeCell`](https://doc.rust-lang.org/stable/core/cell/struct.UnsafeCell.html). We can use this for our purposes: To adjust validation for interior mutability, we *stop* our recursive descent and do not do anything when reaching an `UnsafeCell` *while `mutbl` indicates we are in immutable mode* -- `&mut UnsafeCell` is not affected. In particular, no locks are acquired. This justifies calling `set` on a shared reference and having the value changed. diff --git a/personal/_posts/2018-01-31-sharing-for-a-lifetime.md b/personal/_posts/2018-01-31-sharing-for-a-lifetime.md index 3a8af09..b07a334 100644 --- a/personal/_posts/2018-01-31-sharing-for-a-lifetime.md +++ b/personal/_posts/2018-01-31-sharing-for-a-lifetime.md @@ -51,7 +51,7 @@ Overall, we conclude that we did not violate any of the invariants imposed on `x ## Interior Mutability Interior mutability however breaks this model of `&'a T`: We just cannot declare that the pointed-to memory is read-only in general. -If we did, [`Cell::set`](https://doc.rust-lang.org/beta/std/cell/struct.Cell.html#method.set) and many more operations would be blatantly unsafe. +If we did, [`Cell::set`](https://doc.rust-lang.org/stable/std/cell/struct.Cell.html#method.set) and many more operations would be blatantly unsafe. Indeed this is the reason shared references are not called "immutable references" even though they are generally considered the dual of mutable references. (My personal thinking is that mutable references should really be called "unique references" to instill the point that the distinction between the two is about uniqueness, not about mutability. Oh well.) diff --git a/personal/_posts/2018-04-05-a-formal-look-at-pinning.md b/personal/_posts/2018-04-05-a-formal-look-at-pinning.md index edaf6c6..121de4b 100644 --- a/personal/_posts/2018-04-05-a-formal-look-at-pinning.md +++ b/personal/_posts/2018-04-05-a-formal-look-at-pinning.md @@ -34,7 +34,7 @@ The short version is that I view Rust types with private invariants as not havin You may be wondering why sharing is a separate typestate here; shouldn't that just be read-only access to a `T` that someone else owns? However, that clearly doesn't work for `&Cell`; to explain types with interior mutability we *need* sharing as a separate state. I explained this in more detail in the previous post, but as a quick example consider that, if you fully own a `RefCell`, the first field (storing the current count of readers/writers) has no special meaning whatsoever. -This is witnessed by [`RefCell::get_mut`](https://doc.rust-lang.org/beta/std/cell/struct.RefCell.html#method.get_mut) ignoring that field. +This is witnessed by [`RefCell::get_mut`](https://doc.rust-lang.org/stable/std/cell/struct.RefCell.html#method.get_mut) ignoring that field. In fact, it would be sound to add a `RefCell::reset(&mut self)` that just resets this field to `0`. ## Pinning diff --git a/personal/_posts/2018-04-10-safe-intrusive-collections-with-pinning.md b/personal/_posts/2018-04-10-safe-intrusive-collections-with-pinning.md index d786731..db706ae 100644 --- a/personal/_posts/2018-04-10-safe-intrusive-collections-with-pinning.md +++ b/personal/_posts/2018-04-10-safe-intrusive-collections-with-pinning.md @@ -179,7 +179,7 @@ fn main() { } {% endhighlight %} -Now, `PinBox::deallocate` is pretty artificial, but in fact the [API for stack pinning](https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md#stack-pinning-api-potential-future-extension) that is drafted in the RFC, together with [`ManuallyDrop`](https://doc.rust-lang.org/beta/std/mem/union.ManuallyDrop.html), make it possible to obtain a `Pin` to a stack-allocated `T` and subsequently pop the stack frame without calling `drop` on the `T`. +Now, `PinBox::deallocate` is pretty artificial, but in fact the [API for stack pinning](https://github.com/rust-lang/rfcs/blob/master/text/2349-pin.md#stack-pinning-api-potential-future-extension) that is drafted in the RFC, together with [`ManuallyDrop`](https://doc.rust-lang.org/stable/std/mem/struct.ManuallyDrop.html), make it possible to obtain a `Pin` to a stack-allocated `T` and subsequently pop the stack frame without calling `drop` on the `T`. That has the same effect as `PinBox::deallocate`: It renders our collection interface unsound. The concern about dropping pinned data is real. @@ -266,7 +266,7 @@ Collection.pin(ptr) := exists |entries: List| ) ``` Notice how we iterate over the elements of the list and make sure that we own whatever memory is to own there. -(I love how `all` [really exists for iterators](https://doc.rust-lang.org/beta/std/iter/trait.Iterator.html#method.all) so I can express quantification over lists without any hassle. :) +(I love how `all` [really exists for iterators](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.all) so I can express quantification over lists without any hassle. :) This invariant already justifies `print_all`: All the entries we are going to see there are in the list, so we have their `T.pin` at our disposal and are free to call `Debug::fmt`. @@ -401,7 +401,7 @@ That's a good question! It seems perfectly fine to change `insert` to take `&Pin>`. I can't come up with any counter-example. However, the formal model also cannot justify this variant of `insert`: Our model as defind previously defines `Pin<'a, T>.shr` in terms of `T.shr`. -That made it easy to justify [`Pin::deref`](https://doc.rust-lang.org/nightly/std/mem/struct.Pin.html#method.deref). +That made it easy to justify `Pin::deref`. However, as a consequence, `Pin<'a, T>.shr` and `(&'a T).shr` are literally the same invariant, and hence `&Pin` and `&&T` *are the same type*. We could literally write functions transmuting between the two, and we could justify them in my model. Clearly, `insert` taking `entry: &&T` would be unsound as nothing stops the entry from being moved later: @@ -450,7 +450,7 @@ I feel bad about that. Can we still fix this before everything gets stabilized? Others [have](https://github.com/rust-lang/rfcs/pull/2349#issuecomment-373206171) [argued](https://github.com/rust-lang/rfcs/pull/2349#issuecomment-378555691) for a shared pinned reference after it got removed from the API, and I argued against them as I did not understand how it could be useful. Thanks for not being convinced by me! -However, there is one strange aspect to this "shared pinned" typestate: Due to [`Pin::deref`](https://doc.rust-lang.org/beta/std/mem/struct.Pin.html#method.deref), we can turn a "shared pinned" reference into a shared reference. +However, there is one strange aspect to this "shared pinned" typestate: Due to `Pin::deref`, we can turn a "shared pinned" reference into a shared reference. We can go from `&Pin` to `&&T`. In other words, the shared pinned typestate invariant must *imply* the invariant for the (general, unpinned) shared typestate. The reason for `Pin::deref` to exist is mostly a rustc implementation detail [related to using `Pin` as the type of `self`](https://github.com/rust-lang/rfcs/pull/2349#issuecomment-372475895), but this detail has some significant consequences: Even with a separate shared pinned typestate, we can still not define `RefCell` in a way that a pinned `RefCell` pins its contents. diff --git a/personal/_posts/2018-07-13-arc-synchronization.md b/personal/_posts/2018-07-13-arc-synchronization.md index 8363ac2..033d56e 100644 --- a/personal/_posts/2018-07-13-arc-synchronization.md +++ b/personal/_posts/2018-07-13-arc-synchronization.md @@ -173,7 +173,7 @@ I said that `Mutex`/`RwLock` are good enough *most of the time*. However, `Arc` is one of those cases where the overhead induced by an exclusive lock is just way too big, so it is worth using a more optimized, unsafe implementation. As such, you are going to find plenty of atomic accesses in [the source code of `Arc`](https://github.com/rust-lang/rust/blob/c0955a34bcb17f0b31d7b86522a520ebe7fa93ac/src/liballoc/sync.rs#L201). -And it turns out, as Hai and Jacques-Henri noticed when attempting to prove correctness of [`Arc::get_mut`](https://doc.rust-lang.org/beta/std/sync/struct.Arc.html#method.get_mut), that there is one place where `Relaxed` as used as an ordering, [but it really should have been `Acquire`](https://github.com/rust-lang/rust/pull/52031). +And it turns out, as Hai and Jacques-Henri noticed when attempting to prove correctness of [`Arc::get_mut`](https://doc.rust-lang.org/stable/std/sync/struct.Arc.html#method.get_mut), that there is one place where `Relaxed` as used as an ordering, [but it really should have been `Acquire`](https://github.com/rust-lang/rust/pull/52031). Discussing the exact details of the bug would probably fill another blog post (`Arc` is *really* subtle), but the high-level story is exactly like in our example above: Thanks to `Acquire`, an ordering is induced between the code that follows the `get_mut` and the code in another thread that dropped the last other `Arc`, decrementing the reference count to 1. The PR that fixed the problem contains [some more details in the comments](https://github.com/rust-lang/rust/pull/52031/files). With `Relaxed`, no such ordering is induced, so we have a data race. -- 2.30.2