audit pass Pin

This commit is contained in:
cfsamson
2020-04-06 16:07:26 +02:00
parent 16cd145661
commit df7fe72386
5 changed files with 139 additions and 36 deletions

View File

@@ -183,14 +183,7 @@ is just too many nuances and edge-cases to consider which is easily overlooked w
naively giving these markers different names, and I'm convinced that we'll naively giving these markers different names, and I'm convinced that we'll
just have to get used to them and use them as is.</p> just have to get used to them and use them as is.</p>
<p>If you want to you can read a bit of the discussion from the <p>If you want to you can read a bit of the discussion from the
<a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>. One of the best takeaways from there in my <a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>.</p>
eyes is this quote from <code>tmandry</code>:</p>
<blockquote>
<p><em>Think of taking a thumbtack out of a cork board so you can tweak how a flyer
looks. For Unpin types, this unpinning is directly supported by the type; you
can do this implicitly. You can even swap out the object with another before you
put the pin back. For other types, you must be much more careful.</em></p>
</blockquote>
<h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2> <h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2>
<p>Let's start where we left off in the last chapter by making the problem we <p>Let's start where we left off in the last chapter by making the problem we
saw using a self-referential struct in our generator a lot simpler by making saw using a self-referential struct in our generator a lot simpler by making
@@ -546,12 +539,53 @@ stack frame and return it since any pointers we take to &quot;self&quot; is inva
stack. A mistake that is easy to make is, forgetting to shadow the original variable stack. A mistake that is easy to make is, forgetting to shadow the original variable
since you could drop the pinned pointer and access the old value since you could drop the pinned pointer and access the old value
after it's initialized like this:</p> after it's initialized like this:</p>
<pre><code class="language-rust ignore"> let mut test1 = Test::new(&quot;test1&quot;); <pre><pre class="playpen"><code class="language-rust">fn main() {
let mut test1 = Test::new(&quot;test1&quot;);
let mut test1_pin = unsafe { Pin::new_unchecked(&amp;mut test1) }; let mut test1_pin = unsafe { Pin::new_unchecked(&amp;mut test1) };
Test::init(test1_pin.as_mut()); Test::init(test1_pin.as_mut());
drop(test1_pin); drop(test1_pin);
println!(&quot;{:?}&quot;, test1.b);
</code></pre> let mut test2 = Test::new(&quot;test2&quot;);
mem::swap(&amp;mut test1, &amp;mut test2);
println!(&quot;Not self referential anymore: {:?}&quot;, test1.b);
}
# use std::pin::Pin;
# use std::marker::PhantomPinned;
# use std::mem;
#
# #[derive(Debug)]
# struct Test {
# a: String,
# b: *const String,
# _marker: PhantomPinned,
# }
#
#
# impl Test {
# fn new(txt: &amp;str) -&gt; Self {
# let a = String::from(txt);
# Test {
# a,
# b: std::ptr::null(),
# // This makes our type `!Unpin`
# _marker: PhantomPinned,
# }
# }
# fn init&lt;'a&gt;(self: Pin&lt;&amp;'a mut Self&gt;) {
# let self_ptr: *const String = &amp;self.a;
# let this = unsafe { self.get_unchecked_mut() };
# this.b = self_ptr;
# }
#
# fn a&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a str {
# &amp;self.get_ref().a
# }
#
# fn b&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a String {
# unsafe { &amp;*(self.b) }
# }
# }
</code></pre></pre>
</blockquote> </blockquote>
<h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2> <h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2>
<p>For completeness let's remove some unsafe and the need for an <code>init</code> method <p>For completeness let's remove some unsafe and the need for an <code>init</code> method
@@ -599,7 +633,7 @@ pub fn main() {
println!(&quot;a: {}, b: {}&quot;,test2.as_ref().a(), test2.as_ref().b()); println!(&quot;a: {}, b: {}&quot;,test2.as_ref().a(), test2.as_ref().b());
} }
</code></pre></pre> </code></pre></pre>
<p>The fact that pinning a heap allocated value that implements <code>!Unpin</code> is safe <p>The fact that it's safe to pin a heap allocated value even if it is <code>!Unpin</code>
makes sense. Once the data is allocated on the heap it will have a stable address.</p> makes sense. Once the data is allocated on the heap it will have a stable address.</p>
<p>There is no need for us as users of the API to take special care and ensure <p>There is no need for us as users of the API to take special care and ensure
that the self-referential pointer stays valid.</p> that the self-referential pointer stays valid.</p>

View File

@@ -1651,14 +1651,7 @@ is just too many nuances and edge-cases to consider which is easily overlooked w
naively giving these markers different names, and I'm convinced that we'll naively giving these markers different names, and I'm convinced that we'll
just have to get used to them and use them as is.</p> just have to get used to them and use them as is.</p>
<p>If you want to you can read a bit of the discussion from the <p>If you want to you can read a bit of the discussion from the
<a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>. One of the best takeaways from there in my <a href="https://internals.rust-lang.org/t/naming-pin-anchor-move/6864/12">internals thread</a>.</p>
eyes is this quote from <code>tmandry</code>:</p>
<blockquote>
<p><em>Think of taking a thumbtack out of a cork board so you can tweak how a flyer
looks. For Unpin types, this unpinning is directly supported by the type; you
can do this implicitly. You can even swap out the object with another before you
put the pin back. For other types, you must be much more careful.</em></p>
</blockquote>
<h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2> <h2><a class="header" href="#pinning-and-self-referential-structs" id="pinning-and-self-referential-structs">Pinning and self-referential structs</a></h2>
<p>Let's start where we left off in the last chapter by making the problem we <p>Let's start where we left off in the last chapter by making the problem we
saw using a self-referential struct in our generator a lot simpler by making saw using a self-referential struct in our generator a lot simpler by making
@@ -2014,12 +2007,53 @@ stack frame and return it since any pointers we take to &quot;self&quot; is inva
stack. A mistake that is easy to make is, forgetting to shadow the original variable stack. A mistake that is easy to make is, forgetting to shadow the original variable
since you could drop the pinned pointer and access the old value since you could drop the pinned pointer and access the old value
after it's initialized like this:</p> after it's initialized like this:</p>
<pre><code class="language-rust ignore"> let mut test1 = Test::new(&quot;test1&quot;); <pre><pre class="playpen"><code class="language-rust">fn main() {
let mut test1 = Test::new(&quot;test1&quot;);
let mut test1_pin = unsafe { Pin::new_unchecked(&amp;mut test1) }; let mut test1_pin = unsafe { Pin::new_unchecked(&amp;mut test1) };
Test::init(test1_pin.as_mut()); Test::init(test1_pin.as_mut());
drop(test1_pin); drop(test1_pin);
println!(&quot;{:?}&quot;, test1.b);
</code></pre> let mut test2 = Test::new(&quot;test2&quot;);
mem::swap(&amp;mut test1, &amp;mut test2);
println!(&quot;Not self referential anymore: {:?}&quot;, test1.b);
}
# use std::pin::Pin;
# use std::marker::PhantomPinned;
# use std::mem;
#
# #[derive(Debug)]
# struct Test {
# a: String,
# b: *const String,
# _marker: PhantomPinned,
# }
#
#
# impl Test {
# fn new(txt: &amp;str) -&gt; Self {
# let a = String::from(txt);
# Test {
# a,
# b: std::ptr::null(),
# // This makes our type `!Unpin`
# _marker: PhantomPinned,
# }
# }
# fn init&lt;'a&gt;(self: Pin&lt;&amp;'a mut Self&gt;) {
# let self_ptr: *const String = &amp;self.a;
# let this = unsafe { self.get_unchecked_mut() };
# this.b = self_ptr;
# }
#
# fn a&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a str {
# &amp;self.get_ref().a
# }
#
# fn b&lt;'a&gt;(self: Pin&lt;&amp;'a Self&gt;) -&gt; &amp;'a String {
# unsafe { &amp;*(self.b) }
# }
# }
</code></pre></pre>
</blockquote> </blockquote>
<h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2> <h2><a class="header" href="#pinning-to-the-heap" id="pinning-to-the-heap">Pinning to the heap</a></h2>
<p>For completeness let's remove some unsafe and the need for an <code>init</code> method <p>For completeness let's remove some unsafe and the need for an <code>init</code> method
@@ -2067,7 +2101,7 @@ pub fn main() {
println!(&quot;a: {}, b: {}&quot;,test2.as_ref().a(), test2.as_ref().b()); println!(&quot;a: {}, b: {}&quot;,test2.as_ref().a(), test2.as_ref().b());
} }
</code></pre></pre> </code></pre></pre>
<p>The fact that pinning a heap allocated value that implements <code>!Unpin</code> is safe <p>The fact that it's safe to pin a heap allocated value even if it is <code>!Unpin</code>
makes sense. Once the data is allocated on the heap it will have a stable address.</p> makes sense. Once the data is allocated on the heap it will have a stable address.</p>
<p>There is no need for us as users of the API to take special care and ensure <p>There is no need for us as users of the API to take special care and ensure
that the self-referential pointer stays valid.</p> that the self-referential pointer stays valid.</p>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -38,13 +38,7 @@ naively giving these markers different names, and I'm convinced that we'll
just have to get used to them and use them as is. just have to get used to them and use them as is.
If you want to you can read a bit of the discussion from the If you want to you can read a bit of the discussion from the
[internals thread][internals_unpin]. One of the best takeaways from there in my [internals thread][internals_unpin].
eyes is this quote from `tmandry`:
>_Think of taking a thumbtack out of a cork board so you can tweak how a flyer
looks. For Unpin types, this unpinning is directly supported by the type; you
can do this implicitly. You can even swap out the object with another before you
put the pin back. For other types, you must be much more careful._
## Pinning and self-referential structs ## Pinning and self-referential structs
@@ -446,12 +440,53 @@ us from swapping the pinned pointers.
> since you could drop the pinned pointer and access the old value > since you could drop the pinned pointer and access the old value
> after it's initialized like this: > after it's initialized like this:
> >
> ```rust, ignore > ```rust
> fn main() {
> let mut test1 = Test::new("test1"); > let mut test1 = Test::new("test1");
> let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) }; > let mut test1_pin = unsafe { Pin::new_unchecked(&mut test1) };
> Test::init(test1_pin.as_mut()); > Test::init(test1_pin.as_mut());
> drop(test1_pin); > drop(test1_pin);
> println!("{:?}", test1.b); >
> let mut test2 = Test::new("test2");
> mem::swap(&mut test1, &mut test2);
> println!("Not self referential anymore: {:?}", test1.b);
> }
> # use std::pin::Pin;
> # use std::marker::PhantomPinned;
> # use std::mem;
> #
> # #[derive(Debug)]
> # struct Test {
> # a: String,
> # b: *const String,
> # _marker: PhantomPinned,
> # }
> #
> #
> # impl Test {
> # fn new(txt: &str) -> Self {
> # let a = String::from(txt);
> # Test {
> # a,
> # b: std::ptr::null(),
> # // This makes our type `!Unpin`
> # _marker: PhantomPinned,
> # }
> # }
> # fn init<'a>(self: Pin<&'a mut Self>) {
> # let self_ptr: *const String = &self.a;
> # let this = unsafe { self.get_unchecked_mut() };
> # this.b = self_ptr;
> # }
> #
> # fn a<'a>(self: Pin<&'a Self>) -> &'a str {
> # &self.get_ref().a
> # }
> #
> # fn b<'a>(self: Pin<&'a Self>) -> &'a String {
> # unsafe { &*(self.b) }
> # }
> # }
> ``` > ```
## Pinning to the heap ## Pinning to the heap
@@ -504,7 +539,7 @@ pub fn main() {
} }
``` ```
The fact that pinning a heap allocated value that implements `!Unpin` is safe The fact that it's safe to pin a heap allocated value even if it is `!Unpin`
makes sense. Once the data is allocated on the heap it will have a stable address. makes sense. Once the data is allocated on the heap it will have a stable address.
There is no need for us as users of the API to take special care and ensure There is no need for us as users of the API to take special care and ensure