Skip to content

Commit

Permalink
Use deref target in Pin trait implementations
Browse files Browse the repository at this point in the history
Using deref target instead of pointer itself avoids providing access to
`&Rc<T>` for malicious implementations, which would allow calling
`Rc::get_mut`.

This is a breaking change necessary due to unsoundness, however
the impact of it should be minimal.

This only fixes the issue with malicious `PartialEq` implementations,
other `Pin` soundness issues are still here.

See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311/73>
for more details.
  • Loading branch information
KamilaBorowska committed Dec 5, 2019
1 parent d825e35 commit 1cf0db1
Showing 1 changed file with 35 additions and 17 deletions.
52 changes: 35 additions & 17 deletions src/libcore/pin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@

use crate::cmp::{self, PartialEq, PartialOrd};
use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::marker::{Sized, Unpin};
use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};

Expand All @@ -390,55 +391,72 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver};
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
//
// Note: the derives below, and the explicit `PartialEq` and `PartialOrd`
// implementations, are allowed because they all only use `&P`, so they cannot move
// the value behind `pointer`.
// Note: the `Clone` derive below causes unsoundness as it's possible to implement
// `Clone` for mutable references.
// See <https://internals.rust-lang.org/t/unsoundness-in-pin/11311> for more details.
#[stable(feature = "pin", since = "1.33.0")]
#[lang = "pin"]
#[fundamental]
#[repr(transparent)]
#[derive(Copy, Clone, Hash, Eq, Ord)]
#[derive(Copy, Clone)]
pub struct Pin<P> {
pointer: P,
}

#[stable(feature = "pin_partialeq_partialord_impl_applicability", since = "1.34.0")]
impl<P, Q> PartialEq<Pin<Q>> for Pin<P>
#[stable(feature = "pin_trait_impls", since = "1.41.0")]
impl<P: Deref, Q: Deref> PartialEq<Pin<Q>> for Pin<P>
where
P: PartialEq<Q>,
P::Target: PartialEq<Q::Target>,
{
fn eq(&self, other: &Pin<Q>) -> bool {
self.pointer == other.pointer
**self == **other
}

fn ne(&self, other: &Pin<Q>) -> bool {
self.pointer != other.pointer
**self != **other
}
}

#[stable(feature = "pin_partialeq_partialord_impl_applicability", since = "1.34.0")]
impl<P, Q> PartialOrd<Pin<Q>> for Pin<P>
#[stable(feature = "pin_trait_impls", since = "1.41.0")]
impl<P: Deref<Target: Eq>> Eq for Pin<P> {}

#[stable(feature = "pin_trait_impls", since = "1.41.0")]
impl<P: Deref, Q: Deref> PartialOrd<Pin<Q>> for Pin<P>
where
P: PartialOrd<Q>,
P::Target: PartialOrd<Q::Target>,
{
fn partial_cmp(&self, other: &Pin<Q>) -> Option<cmp::Ordering> {
self.pointer.partial_cmp(&other.pointer)
(**self).partial_cmp(other)
}

fn lt(&self, other: &Pin<Q>) -> bool {
self.pointer < other.pointer
**self < **other
}

fn le(&self, other: &Pin<Q>) -> bool {
self.pointer <= other.pointer
**self <= **other
}

fn gt(&self, other: &Pin<Q>) -> bool {
self.pointer > other.pointer
**self > **other
}

fn ge(&self, other: &Pin<Q>) -> bool {
self.pointer >= other.pointer
**self >= **other
}
}

#[stable(feature = "pin_trait_impls", since = "1.41.0")]
impl<P: Deref<Target: Ord>> Ord for Pin<P> {
fn cmp(&self, other: &Self) -> cmp::Ordering {
(**self).cmp(other)
}
}

#[stable(feature = "pin_trait_impls", since = "1.41.0")]
impl<P: Deref<Target: Hash>> Hash for Pin<P> {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}

Expand Down

0 comments on commit 1cf0db1

Please sign in to comment.