diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.rs b/src/test/ui/associated-types/defaults-unsound-62211-1.rs new file mode 100644 index 00000000000..aa7beca0047 --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.rs @@ -0,0 +1,62 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/62211 +//! +//! The old implementation of defaults did not check whether the provided +//! default actually fulfills all bounds on the assoc. type, leading to +//! unsoundness, demonstrated here as a use-after-free. + +// compile-fail + +#![feature(associated_type_defaults)] + +use std::{ + fmt::Display, + ops::{AddAssign, Deref} +}; + + +trait UncheckedCopy: Sized { + // This Output is said to be Copy. Yet we default to Self + // and it's accepted, not knowing if Self ineed is Copy + type Output: Copy + //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + + Deref + //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + + AddAssign<&'static str> + //~^ ERROR cannot add-assign `&'static str` to `Self` + + From + + Display = Self; + //~^ ERROR `Self` doesn't implement `std::fmt::Display` + + // We said the Output type was Copy, so we can Copy it freely! + fn unchecked_copy(other: &Self::Output) -> Self::Output { + (*other) + } + + fn make_origin(s: Self) -> Self::Output { + s.into() + } +} + +impl UncheckedCopy for T {} +//~^ ERROR `T` doesn't implement `std::fmt::Display` +//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR cannot add-assign `&'static str` to `T` +//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied + +fn bug(origin: T) { + let origin = T::make_origin(origin); + let mut copy = T::unchecked_copy(&origin); + + // assert we indeed have 2 strings pointing to the same buffer. + assert_eq!(origin.as_ptr(), copy.as_ptr()); + + // Drop the origin. Any use of `copy` is UB. + drop(origin); + + copy += "This is invalid!"; + println!("{}", copy); +} + +fn main() { + bug(String::from("hello!")); +} diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr new file mode 100644 index 00000000000..417edd873ec --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr @@ -0,0 +1,93 @@ +error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:20:18 + | +LL | type Output: Copy + | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + | + = help: consider adding a `where Self: std::marker::Copy` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-1.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: cannot add-assign `&'static str` to `Self` + --> $DIR/defaults-unsound-62211-1.rs:24:7 + | +LL | + AddAssign<&'static str> + | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` + = help: consider adding a `where Self: std::ops::AddAssign<&'static str>` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-1.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:22:7 + | +LL | + Deref + | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + | + = help: consider adding a `where Self: std::ops::Deref` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-1.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `Self` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-1.rs:27:7 + | +LL | + Display = Self; + | ^^^^^^^ `Self` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Self` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = help: consider adding a `where Self: std::fmt::Display` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-1.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `T` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-1.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `T` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = help: consider adding a `where T: std::fmt::Display` bound + +error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | + = help: consider adding a `where T: std::ops::Deref` bound + +error[E0277]: cannot add-assign `&'static str` to `T` + --> $DIR/defaults-unsound-62211-1.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ no implementation for `T += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` + = help: consider adding a `where T: std::ops::AddAssign<&'static str>` bound + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-1.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.rs b/src/test/ui/associated-types/defaults-unsound-62211-2.rs new file mode 100644 index 00000000000..ce12bd48587 --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.rs @@ -0,0 +1,62 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/62211 +//! +//! The old implementation of defaults did not check whether the provided +//! default actually fulfills all bounds on the assoc. type, leading to +//! unsoundness and ICEs, the latter being demonstrated here. + +// compile-fail + +#![feature(associated_type_defaults)] + +use std::{ + fmt::Display, + ops::{AddAssign, Deref} +}; + + +trait UncheckedCopy: Sized { + // This Output is said to be Copy. Yet we default to Self + // and it's accepted, not knowing if Self ineed is Copy + type Output: Copy + //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + + Deref + //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + + AddAssign<&'static str> + //~^ ERROR cannot add-assign `&'static str` to `Self` + + From + + Display = Self; + //~^ ERROR `Self` doesn't implement `std::fmt::Display` + + // We said the Output type was Copy, so we can Copy it freely! + fn unchecked_copy(other: &Self::Output) -> Self::Output { + (*other) + } + + fn make_origin(s: Self) -> Self::Output { + s.into() + } +} + +impl UncheckedCopy for T {} +//~^ ERROR `T` doesn't implement `std::fmt::Display` +//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR cannot add-assign `&'static str` to `T` +//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied + +fn bug(origin: T) { + let origin = T::make_origin(origin); + let mut copy = T::unchecked_copy(&origin); + + // assert we indeed have 2 strings pointing to the same buffer. + assert_eq!(origin.as_ptr(), copy.as_ptr()); + + // Drop the origin. Any use of `copy` is UB. + drop(origin); + + copy += "This is invalid!"; + println!("{}", copy); +} + +fn main() { + bug(()); +} diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr new file mode 100644 index 00000000000..a1ce1f6db31 --- /dev/null +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr @@ -0,0 +1,93 @@ +error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:20:18 + | +LL | type Output: Copy + | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + | + = help: consider adding a `where Self: std::marker::Copy` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-2.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: cannot add-assign `&'static str` to `Self` + --> $DIR/defaults-unsound-62211-2.rs:24:7 + | +LL | + AddAssign<&'static str> + | ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self` + = help: consider adding a `where Self: std::ops::AddAssign<&'static str>` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-2.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:22:7 + | +LL | + Deref + | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + | + = help: consider adding a `where Self: std::ops::Deref` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-2.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `Self` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-2.rs:27:7 + | +LL | + Display = Self; + | ^^^^^^^ `Self` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `Self` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = help: consider adding a `where Self: std::fmt::Display` bound +note: required by `UncheckedCopy` + --> $DIR/defaults-unsound-62211-2.rs:17:1 + | +LL | trait UncheckedCopy: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `T` doesn't implement `std::fmt::Display` + --> $DIR/defaults-unsound-62211-2.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter + | + = help: the trait `std::fmt::Display` is not implemented for `T` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = help: consider adding a `where T: std::fmt::Display` bound + +error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | + = help: consider adding a `where T: std::ops::Deref` bound + +error[E0277]: cannot add-assign `&'static str` to `T` + --> $DIR/defaults-unsound-62211-2.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ no implementation for `T += &'static str` + | + = help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T` + = help: consider adding a `where T: std::ops::AddAssign<&'static str>` bound + +error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied + --> $DIR/defaults-unsound-62211-2.rs:40:9 + | +LL | impl UncheckedCopy for T {} + | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | + = help: consider adding a `where T: std::marker::Copy` bound + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`.