about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-09-23 23:49:12 -0400
committerGitHub <noreply@github.com>2024-09-23 23:49:12 -0400
commitec1ccff8ce77d09594019c94788e95bb9487ae54 (patch)
treed636a838d2f04d6cdb6e2ce7d4edb2f39d1f8fdf /src
parentc0f1a69229a8d139cde0e8a65eb8dfb79dca0ae9 (diff)
parent702a644b74872104e23e26a8d9f7a8e99a4a5956 (diff)
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 https://github.com/rust-lang/miri/issues/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`!
}
```
Diffstat (limited to 'src')
-rw-r--r--src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs2
-rw-r--r--src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr4
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs2
-rw-r--r--src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr4
-rw-r--r--src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs18
-rw-r--r--src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr15
-rw-r--r--src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr4
7 files changed, 41 insertions, 8 deletions
diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
index 982d57b7372..7ac619e09ab 100644
--- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.rs
@@ -16,5 +16,5 @@ impl T1 for i32 {
 fn main() {
     let r = Box::new(0) as Box<dyn T1>;
     let r2: Box<dyn T2> = unsafe { std::mem::transmute(r) };
-    r2.method2(); //~ERROR: using vtable for trait `T1` but trait `T2` was expected
+    r2.method2(); //~ERROR: using vtable for `T1` but `T2` was expected
 }
diff --git a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr
index 3680a84fac2..37d102c8713 100644
--- a/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr
+++ b/src/tools/miri/tests/fail/dyn-call-trait-mismatch.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: using vtable for trait `T1` but trait `T2` was expected
+error: Undefined Behavior: using vtable for `T1` but `T2` was expected
   --> tests/fail/dyn-call-trait-mismatch.rs:LL:CC
    |
 LL |     r2.method2();
-   |     ^^^^^^^^^^^^ using vtable for trait `T1` but trait `T2` was expected
+   |     ^^^^^^^^^^^^ using vtable for `T1` but `T2` was expected
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
index 85d7582d112..f450e7e652c 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.rs
@@ -63,6 +63,6 @@ fn main() {
         let baz: &dyn Baz = &1;
         let baz_fake: *const dyn Bar = std::mem::transmute(baz);
         let _err = baz_fake as *const dyn Foo;
-        //~^ERROR: using vtable for trait `Baz` but trait `Bar` was expected
+        //~^ERROR: using vtable for `Baz` but `Bar` was expected
     }
 }
diff --git a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
index 2129fe66e9c..b40f83e8654 100644
--- a/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
+++ b/src/tools/miri/tests/fail/dyn-upcast-trait-mismatch.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: using vtable for trait `Baz` but trait `Bar` was expected
+error: Undefined Behavior: using vtable for `Baz` but `Bar` was expected
   --> tests/fail/dyn-upcast-trait-mismatch.rs:LL:CC
    |
 LL |         let _err = baz_fake as *const dyn Foo;
-   |                    ^^^^^^^^ using vtable for trait `Baz` but trait `Bar` was expected
+   |                    ^^^^^^^^ using vtable for `Baz` but `Bar` was expected
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs
new file mode 100644
index 00000000000..1478abedee0
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.rs
@@ -0,0 +1,18 @@
+trait Trait {
+    type Assoc;
+    fn foo(&self) -> Self::Assoc;
+}
+
+impl<T: Copy> Trait for T {
+    type Assoc = T;
+    fn foo(&self) -> T { *self }
+}
+
+fn main() {
+    let v: Box<dyn Trait<Assoc = u8>> = Box::new(2);
+    let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) }; //~ERROR: wrong trait
+
+    if v.foo() {
+        println!("huh");
+    }
+}
diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr
new file mode 100644
index 00000000000..44939a5a838
--- /dev/null
+++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait-assoc-type.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
+  --> tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
+   |
+LL |     let v: Box<dyn Trait<Assoc = bool>> = unsafe { std::mem::transmute(v) };
+   |                                                    ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `Trait<Assoc = bool>`, but encountered `Trait<Assoc = u8>`
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at tests/fail/validity/wrong-dyn-trait-assoc-type.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
index 4be3fb52bdb..45c882bebdf 100644
--- a/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
+++ b/src/tools/miri/tests/fail/validity/wrong-dyn-trait.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
+error: Undefined Behavior: constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
   --> tests/fail/validity/wrong-dyn-trait.rs:LL:CC
    |
 LL |     let _y: *const dyn fmt::Debug = unsafe { mem::transmute(x) };
-   |                                              ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `<trivial>`
+   |                                              ^^^^^^^^^^^^^^^^^ constructing invalid value: wrong trait in wide pointer vtable: expected `std::fmt::Debug`, but encountered `std::marker::Send`
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information