-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trait bounds not checked on specializable associated types #33017
Comments
Triage: still an issue. |
I just hit this, though the error is a bit different now: "resolving bounds after type-checking" rather than "fulfilling during trans".
|
ping @arielb1 how is this unsound? |
Given that @arielb1 has seen fit to tag this as a soundness bug I'm nominating it so that it can receive a priority assessment, though I'll second ubsan in asking for a demonstration of the unsoundness here. |
In general, having trait bounds that are not checked can lead to unsoundness, since some part of the code will assume that they hold when in fact they do not (consider, e.g., what might happen if the bound were |
I'm going to mark this as P-medium and tag it from the specialization issue (it is specific to specialization, right?) |
triage: P-medium |
The code in the OP compiles for me with the latest nightly Rust (1.29.0-nightly (97085f9 2018-08-01)). However, the following still fails (and I assume it's the same issue; if not I can file a new issue): #![feature(specialization)]
trait PreProcess<T> {
type Type: PostProcess<T> + std::default::Default;
fn pre_process() -> Self::Type;
}
trait PostProcess<T> {
fn post_process(self);
}
impl<T> PreProcess<T> for T {
default type Type = std::marker::PhantomData<T>;
default fn pre_process() -> Self::Type {
return <Self::Type as std::default::Default>::default();
}
}
pub struct Foo;
pub fn do_foo() {
PostProcess::post_process(<Foo as PreProcess<Foo>>::pre_process());
} Backtrace:
|
So I think this is "fixed-by-chalk", but this is fixed-by-chalk in a way that breaks specialization (cc @rust-lang/wg-traits). Let's have a more easy-to-understand version of the problem: #![feature(specialization)]
trait Foo: Sized {
type Assoc: Copy + From<Self> + Into<Self>;
}
impl<T> Foo for T {
default type Assoc = Self;
}
fn xyz<T: Foo>(t: T) -> T::Bar {
t.into()
}
fn main() {
xyz(5i32);
} The problem is the following:
Was Chalk changed to do something else by now? Does this have a different interaction with specialization? |
A PoC to show the unsoundness of this. It's a use-after free by 'copying' a String: #![feature(specialization)]
trait UncheckedCopy: Sized {
type Output: From<Self> + Copy + Into<Self>;
}
impl <T> UncheckedCopy for T {
default type Output = Self;
}
fn unchecked_copy<T: UncheckedCopy>(other: &T::Output) -> T {
(*other).into()
}
fn bug(origin: String) {
// Turn the String into it's Output type...
// Which we can just do by `.into()`, the assoc type states `From<Self>`.
let origin_output = origin.into();
// Make a copy of String::Output, which is a String...
let mut copy: String = unchecked_copy::<String>(&origin_output);
// Turn the Output type into a String again,
// Which we can just do by `.into()`, the assoc type states `Into<Self>`.
let mut origin: String = origin_output.into();
// assert both Strings use the same buffer.
assert_eq!(copy.as_ptr(), origin.as_ptr());
// Any use of the copy we made becomes invalid,
drop(origin);
// OH NO! UB UB UB UB!
copy.push_str(" world!");
println!("{}", copy);
}
fn main() {
bug(String::from("hello"));
} Link to the playground: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018 |
This is fixed now: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018 and needs a test |
foo.rs
:The text was updated successfully, but these errors were encountered: