Skip to content

Commit 6588caf

Browse files
Rollup merge of #130727 - compiler-errors:objects, r=RalfJung
Check vtable projections for validity in miri Currently, miri does not catch when we transmute `dyn Trait<Assoc = A>` to `dyn Trait<Assoc = B>`. This PR implements such a check, and fixes #3905. To do this, we modify `GlobalAlloc::VTable` to contain the *whole* list of `PolyExistentialPredicate`, and then modify `check_vtable_for_type` to validate the `PolyExistentialProjection`s of the vtable, along with the principal trait that was already being validated. cc ``@RalfJung`` r? ``@lcnr`` or types I also tweaked the diagnostics a bit. --- **Open question:** We don't validate the auto traits. You can transmute `dyn Foo` into `dyn Foo + Send`. Should we check that? We currently have a test that *exercises* this as not being UB: https://github.com/rust-lang/rust/blob/6c6d210089e4589afee37271862b9f88ba1d7755/src/tools/miri/tests/pass/dyn-upcast.rs#L14-L20 I'm not actually sure if we ever decided that's actually UB or not 🤔 We could perhaps still check that the underlying type of the object (i.e. the concrete type that was unsized) implements the auto traits, to catch UB like: ```rust fn main() { let x: &dyn Trait = &std::ptr::null_mut::<()>(); let _: &(dyn Trait + Send) = std::mem::transmute(x); //~^ this vtable is not allocated for a type that is `Send`! } ```
2 parents 3cfd3f3 + 4dda1eb commit 6588caf

7 files changed

+41
-8
lines changed

tests/fail/dyn-call-trait-mismatch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ impl T1 for i32 {
1616
fn main() {
1717
let r = Box::new(0) as Box<dyn T1>;
1818
let r2: Box<dyn T2> = unsafe { std::mem::transmute(r) };
19-
r2.method2(); //~ERROR: using vtable for trait `T1` but trait `T2` was expected
19+
r2.method2(); //~ERROR: using vtable for `T1` but `T2` was expected
2020
}

tests/fail/dyn-call-trait-mismatch.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: using vtable for trait `T1` but trait `T2` was expected
1+
error: Undefined Behavior: using vtable for `T1` but `T2` was expected
22
--> tests/fail/dyn-call-trait-mismatch.rs:LL:CC
33
|
44
LL | r2.method2();
5-
| ^^^^^^^^^^^^ using vtable for trait `T1` but trait `T2` was expected
5+
| ^^^^^^^^^^^^ using vtable for `T1` but `T2` was expected
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

tests/fail/dyn-upcast-trait-mismatch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,6 @@ fn main() {
6363
let baz: &dyn Baz = &1;
6464
let baz_fake: *const dyn Bar = std::mem::transmute(baz);
6565
let _err = baz_fake as *const dyn Foo;
66-
//~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected
66+
//~^ERROR: using vtable for `Baz` but `Bar` was expected
6767
}
6868
}

tests/fail/dyn-upcast-trait-mismatch.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected
1+
error: Undefined Behavior: using vtable for `Baz` but `Bar` was expected
22
--> tests/fail/dyn-upcast-trait-mismatch.rs:LL:CC
33
|
44
LL | let _err = baz_fake as *const dyn Foo;
5-
| ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected
5+
| ^^^^^^^^ using vtable for `Baz` but `Bar` was expected
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
trait Trait {
2+
type Assoc;
3+
fn foo(&self) -> Self::Assoc;
4+
}
5+
6+
impl<T: Copy> Trait for T {
7+
type Assoc = T;
8+
fn foo(&self) -> T { *self }
9+
}
10+
11+
fn main() {
12+
let v: Box<dyn Trait<Assoc = u8>> = Box::new(2);
13+
let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) }; //~ERROR: wrong trait
14+
15+
if v.foo() {
16+
println!("huh");
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
2+
--> tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
3+
|
4+
LL | let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
6+
|
7+
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
8+
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
9+
= note: BACKTRACE:
10+
= note: inside `main` at tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
11+
12+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
13+
14+
error: aborting due to 1 previous error
15+

tests/fail/validity/wrong-dyn-trait.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
1+
error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
22
--> tests/fail/validity/wrong-dyn-trait.rs:LL:CC
33
|
44
LL | let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) };
5-
| ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
5+
| ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

0 commit comments

Comments
 (0)