Skip to content

Commit

Permalink
Forbid custom Unpin/Drop impl if trait has Pin<&mut self> receiver
Browse files Browse the repository at this point in the history
If a user creates their own Unpin or Drop implementation, trait
implementations with `Pin<&mut self>` receiver can cause unsoundness.

This was not a problem in #[auto_enum] attribute where enums are
anonymized, but it becomes a problem when users have access to enums
(i.e., when using #[enum_derive]).

So, we ensure safety here by an Unpin implementation that implements
Unpin only if all fields are Unpin (this also forbids custom Unpin
implementation), and a hack that forbids custom Drop implementation.
(Both are what pin-project does by default.) The repr(packed) check is
not needed since repr(packed) is not available on enum.
  • Loading branch information
taiki-e committed Dec 10, 2022
1 parent 36acf01 commit cf9d9fa
Show file tree
Hide file tree
Showing 31 changed files with 258 additions and 60 deletions.
4 changes: 2 additions & 2 deletions src/derive/core/convert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub(crate) mod as_ref {

pub(crate) const NAME: &[&str] = &["AsRef"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::convert::AsRef), None, parse_quote! {
trait AsRef<__T: ?Sized> {
#[inline]
Expand All @@ -18,7 +18,7 @@ pub(crate) mod as_mut {

pub(crate) const NAME: &[&str] = &["AsMut"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::convert::AsMut), None, parse_quote! {
trait AsMut<__T: ?Sized> {
#[inline]
Expand Down
4 changes: 2 additions & 2 deletions src/derive/core/fmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ macro_rules! derive_fmt {

pub(crate) const NAME: &[&str] = &[$($name),*];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::fmt::$Trait), None, parse_quote! {
trait $Trait {
#[inline]
Expand Down Expand Up @@ -40,7 +40,7 @@ pub(crate) mod write {

pub(crate) const NAME: &[&str] = &["fmt::Write"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::fmt::Write), None, parse_quote! {
trait Write {
#[inline]
Expand Down
3 changes: 2 additions & 1 deletion src/derive/core/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ use crate::derive::*;

pub(crate) const NAME: &[&str] = &["Future"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::core::future::Future), None, parse_quote! {
trait Future {
type Output;
Expand Down
12 changes: 6 additions & 6 deletions src/derive/core/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub(crate) mod iterator {

pub(crate) const NAME: &[&str] = &["Iterator"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
// TODO: When `try_trait` stabilized, add `try_fold` and remove `fold`, `find` etc. conditionally.

// It is equally efficient if `try_fold` can be used.
Expand Down Expand Up @@ -47,7 +47,7 @@ pub(crate) mod double_ended_iterator {

pub(crate) const NAME: &[&str] = &["DoubleEndedIterator"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
// TODO: When `try_trait` stabilized, add `try_rfold` and remove `rfold` and `rfind` conditionally.

// It is equally efficient if `try_rfold` can be used.
Expand Down Expand Up @@ -82,7 +82,7 @@ pub(crate) mod exact_size_iterator {

pub(crate) const NAME: &[&str] = &["ExactSizeIterator"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
// TODO: When `exact_size_is_empty` stabilized, add `is_empty` conditionally.

Ok(derive_trait(
Expand All @@ -104,7 +104,7 @@ pub(crate) mod fused_iterator {

pub(crate) const NAME: &[&str] = &["FusedIterator"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(
data,
parse_quote!(::core::iter::FusedIterator),
Expand All @@ -122,7 +122,7 @@ pub(crate) mod trusted_len {

pub(crate) const NAME: &[&str] = &["TrustedLen"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(
data,
parse_quote!(::core::iter::TrustedLen),
Expand All @@ -139,7 +139,7 @@ pub(crate) mod extend {

pub(crate) const NAME: &[&str] = &["Extend"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::iter::Extend), None, parse_quote! {
trait Extend<__A> {
#[inline]
Expand Down
19 changes: 10 additions & 9 deletions src/derive/core/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub(crate) mod deref {

pub(crate) const NAME: &[&str] = &["Deref"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::ops::Deref), None, parse_quote! {
trait Deref {
type Target;
Expand All @@ -21,7 +21,7 @@ pub(crate) mod deref_mut {

pub(crate) const NAME: &[&str] = &["DerefMut"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(
data,
parse_quote!(::core::ops::DerefMut),
Expand All @@ -42,7 +42,7 @@ pub(crate) mod index {

pub(crate) const NAME: &[&str] = &["Index"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::ops::Index), None, parse_quote! {
trait Index<__Idx> {
type Output;
Expand All @@ -59,7 +59,7 @@ pub(crate) mod index_mut {

pub(crate) const NAME: &[&str] = &["IndexMut"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(
data,
parse_quote!(::core::ops::IndexMut),
Expand All @@ -80,7 +80,7 @@ pub(crate) mod range_bounds {

pub(crate) const NAME: &[&str] = &["RangeBounds"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::core::ops::RangeBounds), None, parse_quote! {
trait RangeBounds<__T: ?Sized> {
#[inline]
Expand All @@ -98,7 +98,8 @@ pub(crate) mod generator {

pub(crate) const NAME: &[&str] = &["Generator"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::core::ops::Generator), None, parse_quote! {
trait Generator<R> {
type Yield;
Expand All @@ -122,7 +123,7 @@ pub(crate) mod fn_ {

pub(crate) const NAME: &[&str] = &["Fn"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
let trait_path = quote!(::core::ops::Fn);
let trait_ = quote!(#trait_path(__T) -> __U);
let fst = data.field_types().next();
Expand Down Expand Up @@ -155,7 +156,7 @@ pub(crate) mod fn_mut {

pub(crate) const NAME: &[&str] = &["FnMut"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
let trait_path = quote!(::core::ops::FnMut);
let trait_ = quote!(#trait_path(__T) -> __U);
let fst = data.field_types().next();
Expand Down Expand Up @@ -188,7 +189,7 @@ pub(crate) mod fn_once {

pub(crate) const NAME: &[&str] = &["FnOnce"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
let trait_path = quote!(::core::ops::FnOnce);
let trait_ = quote!(#trait_path(__T) -> __U);
let fst = data.field_types().next();
Expand Down
6 changes: 3 additions & 3 deletions src/derive/external/futures01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub(crate) mod future {

pub(crate) const NAME: &[&str] = &["futures01::Future"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::futures::future::Future), None, parse_quote! {
trait Future {
type Item;
Expand All @@ -20,7 +20,7 @@ pub(crate) mod stream {

pub(crate) const NAME: &[&str] = &["futures01::Stream"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::futures::stream::Stream), None, parse_quote! {
trait Stream {
type Item;
Expand All @@ -39,7 +39,7 @@ pub(crate) mod sink {

pub(crate) const NAME: &[&str] = &["futures01::Sink"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::futures::sink::Sink), None, parse_quote! {
trait Sink {
type SinkItem;
Expand Down
18 changes: 12 additions & 6 deletions src/derive/external/futures03.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ pub(crate) mod async_buf_read {

pub(crate) const NAME: &[&str] = &["futures03::AsyncBufRead"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::futures::io::AsyncBufRead), None, parse_quote! {
trait AsyncBufRead {
#[inline]
Expand All @@ -23,7 +24,8 @@ pub(crate) mod async_read {

pub(crate) const NAME: &[&str] = &["futures03::AsyncRead"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::futures::io::AsyncRead), None, parse_quote! {
trait AsyncRead {
#[inline]
Expand All @@ -48,7 +50,8 @@ pub(crate) mod async_seek {

pub(crate) const NAME: &[&str] = &["futures03::AsyncSeek"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::futures::io::AsyncSeek), None, parse_quote! {
trait AsyncSeek {
#[inline]
Expand All @@ -67,7 +70,8 @@ pub(crate) mod async_write {

pub(crate) const NAME: &[&str] = &["futures03::AsyncWrite"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::futures::io::AsyncWrite), None, parse_quote! {
trait AsyncWrite {
#[inline]
Expand Down Expand Up @@ -102,7 +106,8 @@ pub(crate) mod sink {

pub(crate) const NAME: &[&str] = &["futures03::Sink"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::futures::sink::Sink), None, parse_quote! {
trait Sink<Item> {
type Error;
Expand Down Expand Up @@ -136,7 +141,8 @@ pub(crate) mod stream {

pub(crate) const NAME: &[&str] = &["futures03::Stream"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::futures::stream::Stream), None, parse_quote! {
trait Stream {
type Item;
Expand Down
6 changes: 3 additions & 3 deletions src/derive/external/rayon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub(crate) mod par_iter {

pub(crate) const NAME: &[&str] = &["rayon::ParallelIterator"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::rayon::iter::ParallelIterator), None, parse_quote! {
trait ParallelIterator {
type Item;
Expand All @@ -23,7 +23,7 @@ pub(crate) mod indexed_par_iter {

pub(crate) const NAME: &[&str] = &["rayon::IndexedParallelIterator"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(
data,
parse_quote!(::rayon::iter::IndexedParallelIterator),
Expand Down Expand Up @@ -51,7 +51,7 @@ pub(crate) mod par_extend {

pub(crate) const NAME: &[&str] = &["rayon::ParallelExtend"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::rayon::iter::ParallelExtend), None, parse_quote! {
trait ParallelExtend<__T: Send> {
#[inline]
Expand Down
2 changes: 1 addition & 1 deletion src/derive/external/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub(crate) mod serialize {

pub(crate) const NAME: &[&str] = &["serde::Serialize"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::serde::ser::Serialize), None, parse_quote! {
trait Serialize {
#[inline]
Expand Down
4 changes: 2 additions & 2 deletions src/derive/external/tokio01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pub(crate) mod async_read {

pub(crate) const NAME: &[&str] = &["tokio01::AsyncRead"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::tokio::io::AsyncRead), None, parse_quote! {
trait AsyncRead: ::std::io::Read {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool;
Expand All @@ -29,7 +29,7 @@ pub(crate) mod async_write {

pub(crate) const NAME: &[&str] = &["tokio01::AsyncWrite"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(_cx: &Context, data: &Data) -> Result<TokenStream> {
Ok(derive_trait(data, parse_quote!(::tokio::io::AsyncWrite), None, parse_quote! {
trait AsyncWrite: ::std::io::Write {
fn poll_write(
Expand Down
12 changes: 8 additions & 4 deletions src/derive/external/tokio02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ pub(crate) mod async_buf_read {

pub(crate) const NAME: &[&str] = &["tokio02::AsyncBufRead"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::tokio::io::AsyncBufRead), None, parse_quote! {
trait AsyncBufRead {
fn poll_fill_buf<'__a>(
Expand All @@ -21,7 +22,8 @@ pub(crate) mod async_read {

pub(crate) const NAME: &[&str] = &["tokio02::AsyncRead"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::tokio::io::AsyncRead), None, parse_quote! {
trait AsyncRead {
unsafe fn prepare_uninitialized_buffer(
Expand Down Expand Up @@ -51,7 +53,8 @@ pub(crate) mod async_seek {

pub(crate) const NAME: &[&str] = &["tokio02::AsyncSeek"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::tokio::io::AsyncSeek), None, parse_quote! {
trait AsyncSeek {
fn start_seek(
Expand All @@ -73,7 +76,8 @@ pub(crate) mod async_write {

pub(crate) const NAME: &[&str] = &["tokio02::AsyncWrite"];

pub(crate) fn derive(data: &Data) -> Result<TokenStream> {
pub(crate) fn derive(cx: &Context, data: &Data) -> Result<TokenStream> {
cx.needs_pin_projection();
Ok(derive_trait(data, parse_quote!(::tokio::io::AsyncWrite), None, parse_quote! {
trait AsyncWrite {
fn poll_write(
Expand Down
Loading

0 comments on commit cf9d9fa

Please sign in to comment.