Skip to content

Commit 07ad64f

Browse files
Add tests for #62211
1 parent ff5d11e commit 07ad64f

File tree

4 files changed

+310
-0
lines changed

4 files changed

+310
-0
lines changed
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//! Regression test for https://github.com/rust-lang/rust/issues/62211
2+
//!
3+
//! The old implementation of defaults did not check whether the provided
4+
//! default actually fulfills all bounds on the assoc. type, leading to
5+
//! unsoundness, demonstrated here as a use-after-free.
6+
7+
// compile-fail
8+
9+
#![feature(associated_type_defaults)]
10+
11+
use std::{
12+
fmt::Display,
13+
ops::{AddAssign, Deref}
14+
};
15+
16+
17+
trait UncheckedCopy: Sized {
18+
// This Output is said to be Copy. Yet we default to Self
19+
// and it's accepted, not knowing if Self ineed is Copy
20+
type Output: Copy
21+
//~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied
22+
+ Deref<Target = str>
23+
//~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied
24+
+ AddAssign<&'static str>
25+
//~^ ERROR cannot add-assign `&'static str` to `Self`
26+
+ From<Self>
27+
+ Display = Self;
28+
//~^ ERROR `Self` doesn't implement `std::fmt::Display`
29+
30+
// We said the Output type was Copy, so we can Copy it freely!
31+
fn unchecked_copy(other: &Self::Output) -> Self::Output {
32+
(*other)
33+
}
34+
35+
fn make_origin(s: Self) -> Self::Output {
36+
s.into()
37+
}
38+
}
39+
40+
impl<T> UncheckedCopy for T {}
41+
//~^ ERROR `T` doesn't implement `std::fmt::Display`
42+
//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied
43+
//~| ERROR cannot add-assign `&'static str` to `T`
44+
//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied
45+
46+
fn bug<T: UncheckedCopy>(origin: T) {
47+
let origin = T::make_origin(origin);
48+
let mut copy = T::unchecked_copy(&origin);
49+
50+
// assert we indeed have 2 strings pointing to the same buffer.
51+
assert_eq!(origin.as_ptr(), copy.as_ptr());
52+
53+
// Drop the origin. Any use of `copy` is UB.
54+
drop(origin);
55+
56+
copy += "This is invalid!";
57+
println!("{}", copy);
58+
}
59+
60+
fn main() {
61+
bug(String::from("hello!"));
62+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied
2+
--> $DIR/defaults-unsound-62211-1.rs:20:18
3+
|
4+
LL | type Output: Copy
5+
| ^^^^ the trait `std::marker::Copy` is not implemented for `Self`
6+
|
7+
= help: consider adding a `where Self: std::marker::Copy` bound
8+
note: required by `UncheckedCopy`
9+
--> $DIR/defaults-unsound-62211-1.rs:17:1
10+
|
11+
LL | trait UncheckedCopy: Sized {
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
14+
error[E0277]: cannot add-assign `&'static str` to `Self`
15+
--> $DIR/defaults-unsound-62211-1.rs:24:7
16+
|
17+
LL | + AddAssign<&'static str>
18+
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
19+
|
20+
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
21+
= help: consider adding a `where Self: std::ops::AddAssign<&'static str>` bound
22+
note: required by `UncheckedCopy`
23+
--> $DIR/defaults-unsound-62211-1.rs:17:1
24+
|
25+
LL | trait UncheckedCopy: Sized {
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
28+
error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied
29+
--> $DIR/defaults-unsound-62211-1.rs:22:7
30+
|
31+
LL | + Deref<Target = str>
32+
| ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self`
33+
|
34+
= help: consider adding a `where Self: std::ops::Deref` bound
35+
note: required by `UncheckedCopy`
36+
--> $DIR/defaults-unsound-62211-1.rs:17:1
37+
|
38+
LL | trait UncheckedCopy: Sized {
39+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
41+
error[E0277]: `Self` doesn't implement `std::fmt::Display`
42+
--> $DIR/defaults-unsound-62211-1.rs:27:7
43+
|
44+
LL | + Display = Self;
45+
| ^^^^^^^ `Self` cannot be formatted with the default formatter
46+
|
47+
= help: the trait `std::fmt::Display` is not implemented for `Self`
48+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
49+
= help: consider adding a `where Self: std::fmt::Display` bound
50+
note: required by `UncheckedCopy`
51+
--> $DIR/defaults-unsound-62211-1.rs:17:1
52+
|
53+
LL | trait UncheckedCopy: Sized {
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
55+
56+
error[E0277]: `T` doesn't implement `std::fmt::Display`
57+
--> $DIR/defaults-unsound-62211-1.rs:40:9
58+
|
59+
LL | impl<T> UncheckedCopy for T {}
60+
| ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
61+
|
62+
= help: the trait `std::fmt::Display` is not implemented for `T`
63+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
64+
= help: consider adding a `where T: std::fmt::Display` bound
65+
66+
error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied
67+
--> $DIR/defaults-unsound-62211-1.rs:40:9
68+
|
69+
LL | impl<T> UncheckedCopy for T {}
70+
| ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T`
71+
|
72+
= help: consider adding a `where T: std::ops::Deref` bound
73+
74+
error[E0277]: cannot add-assign `&'static str` to `T`
75+
--> $DIR/defaults-unsound-62211-1.rs:40:9
76+
|
77+
LL | impl<T> UncheckedCopy for T {}
78+
| ^^^^^^^^^^^^^ no implementation for `T += &'static str`
79+
|
80+
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T`
81+
= help: consider adding a `where T: std::ops::AddAssign<&'static str>` bound
82+
83+
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
84+
--> $DIR/defaults-unsound-62211-1.rs:40:9
85+
|
86+
LL | impl<T> UncheckedCopy for T {}
87+
| ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
88+
|
89+
= help: consider adding a `where T: std::marker::Copy` bound
90+
91+
error: aborting due to 8 previous errors
92+
93+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//! Regression test for https://github.com/rust-lang/rust/issues/62211
2+
//!
3+
//! The old implementation of defaults did not check whether the provided
4+
//! default actually fulfills all bounds on the assoc. type, leading to
5+
//! unsoundness and ICEs, the latter being demonstrated here.
6+
7+
// compile-fail
8+
9+
#![feature(associated_type_defaults)]
10+
11+
use std::{
12+
fmt::Display,
13+
ops::{AddAssign, Deref}
14+
};
15+
16+
17+
trait UncheckedCopy: Sized {
18+
// This Output is said to be Copy. Yet we default to Self
19+
// and it's accepted, not knowing if Self ineed is Copy
20+
type Output: Copy
21+
//~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied
22+
+ Deref<Target = str>
23+
//~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied
24+
+ AddAssign<&'static str>
25+
//~^ ERROR cannot add-assign `&'static str` to `Self`
26+
+ From<Self>
27+
+ Display = Self;
28+
//~^ ERROR `Self` doesn't implement `std::fmt::Display`
29+
30+
// We said the Output type was Copy, so we can Copy it freely!
31+
fn unchecked_copy(other: &Self::Output) -> Self::Output {
32+
(*other)
33+
}
34+
35+
fn make_origin(s: Self) -> Self::Output {
36+
s.into()
37+
}
38+
}
39+
40+
impl<T> UncheckedCopy for T {}
41+
//~^ ERROR `T` doesn't implement `std::fmt::Display`
42+
//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied
43+
//~| ERROR cannot add-assign `&'static str` to `T`
44+
//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied
45+
46+
fn bug<T: UncheckedCopy>(origin: T) {
47+
let origin = T::make_origin(origin);
48+
let mut copy = T::unchecked_copy(&origin);
49+
50+
// assert we indeed have 2 strings pointing to the same buffer.
51+
assert_eq!(origin.as_ptr(), copy.as_ptr());
52+
53+
// Drop the origin. Any use of `copy` is UB.
54+
drop(origin);
55+
56+
copy += "This is invalid!";
57+
println!("{}", copy);
58+
}
59+
60+
fn main() {
61+
bug(());
62+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied
2+
--> $DIR/defaults-unsound-62211-2.rs:20:18
3+
|
4+
LL | type Output: Copy
5+
| ^^^^ the trait `std::marker::Copy` is not implemented for `Self`
6+
|
7+
= help: consider adding a `where Self: std::marker::Copy` bound
8+
note: required by `UncheckedCopy`
9+
--> $DIR/defaults-unsound-62211-2.rs:17:1
10+
|
11+
LL | trait UncheckedCopy: Sized {
12+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
13+
14+
error[E0277]: cannot add-assign `&'static str` to `Self`
15+
--> $DIR/defaults-unsound-62211-2.rs:24:7
16+
|
17+
LL | + AddAssign<&'static str>
18+
| ^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `Self += &'static str`
19+
|
20+
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `Self`
21+
= help: consider adding a `where Self: std::ops::AddAssign<&'static str>` bound
22+
note: required by `UncheckedCopy`
23+
--> $DIR/defaults-unsound-62211-2.rs:17:1
24+
|
25+
LL | trait UncheckedCopy: Sized {
26+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
27+
28+
error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied
29+
--> $DIR/defaults-unsound-62211-2.rs:22:7
30+
|
31+
LL | + Deref<Target = str>
32+
| ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self`
33+
|
34+
= help: consider adding a `where Self: std::ops::Deref` bound
35+
note: required by `UncheckedCopy`
36+
--> $DIR/defaults-unsound-62211-2.rs:17:1
37+
|
38+
LL | trait UncheckedCopy: Sized {
39+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
40+
41+
error[E0277]: `Self` doesn't implement `std::fmt::Display`
42+
--> $DIR/defaults-unsound-62211-2.rs:27:7
43+
|
44+
LL | + Display = Self;
45+
| ^^^^^^^ `Self` cannot be formatted with the default formatter
46+
|
47+
= help: the trait `std::fmt::Display` is not implemented for `Self`
48+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
49+
= help: consider adding a `where Self: std::fmt::Display` bound
50+
note: required by `UncheckedCopy`
51+
--> $DIR/defaults-unsound-62211-2.rs:17:1
52+
|
53+
LL | trait UncheckedCopy: Sized {
54+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
55+
56+
error[E0277]: `T` doesn't implement `std::fmt::Display`
57+
--> $DIR/defaults-unsound-62211-2.rs:40:9
58+
|
59+
LL | impl<T> UncheckedCopy for T {}
60+
| ^^^^^^^^^^^^^ `T` cannot be formatted with the default formatter
61+
|
62+
= help: the trait `std::fmt::Display` is not implemented for `T`
63+
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
64+
= help: consider adding a `where T: std::fmt::Display` bound
65+
66+
error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied
67+
--> $DIR/defaults-unsound-62211-2.rs:40:9
68+
|
69+
LL | impl<T> UncheckedCopy for T {}
70+
| ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T`
71+
|
72+
= help: consider adding a `where T: std::ops::Deref` bound
73+
74+
error[E0277]: cannot add-assign `&'static str` to `T`
75+
--> $DIR/defaults-unsound-62211-2.rs:40:9
76+
|
77+
LL | impl<T> UncheckedCopy for T {}
78+
| ^^^^^^^^^^^^^ no implementation for `T += &'static str`
79+
|
80+
= help: the trait `std::ops::AddAssign<&'static str>` is not implemented for `T`
81+
= help: consider adding a `where T: std::ops::AddAssign<&'static str>` bound
82+
83+
error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
84+
--> $DIR/defaults-unsound-62211-2.rs:40:9
85+
|
86+
LL | impl<T> UncheckedCopy for T {}
87+
| ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
88+
|
89+
= help: consider adding a `where T: std::marker::Copy` bound
90+
91+
error: aborting due to 8 previous errors
92+
93+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)