-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Check vtable projections for validity in miri #130727
Conversation
Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri The Miri subtree was changed cc @rust-lang/miri Some changes occurred to the CTFE / Miri interpreter cc @rust-lang/miri |
This comment has been minimized.
This comment has been minimized.
0d6923d
to
ffa70dd
Compare
Some changes occurred in compiler/rustc_codegen_cranelift cc @bjorn3 Some changes occurred in compiler/rustc_codegen_gcc |
There's technically an alternative here: we could, perhaps, keep the Then for each projection pred in That doesn't seem as nice, though; I like just storing the full set of predicates in the vtable allocation lol. |
I'm fine with making this UB. Codegen does rely on these vtables being the same (dropping auto traits in a cast compiles to a NOP), so it is crucial that this does not affect vtable layout... but Miri anyway doesn't have this cast short-cut, and we probably don't want to turn this into a hard guarantee.
Ah, so that explains why codegen can get away with just knowing the principal trait ref when generating the vtable -- it also knows the type, and it gets to assume that the type and the impl satisfy the remaining predicates. This alternative proposal would be equivalent for associated types, right? But for auto traits it would allow transmutes that remove auto traits, or those that add them when the underlying type actually satisfies the auto trait, but reject the case where the auto trait is not satisfied by the underlying type? I think I am fine with having maximal UB here, i.e. requiring the auto trait list to exactly match, which would require storing the full list of predicates. |
src/tools/miri/tests/fail/issue-miri-3905-transmute-vtable-projection-term.rs
Outdated
Show resolved
Hide resolved
For the record, I think I'd like to split out validating vtable auto traits from this PR. I wouldn't be surprised if there are crates in the wild that are currently using transmutes to temporaily smuggle |
ffa70dd
to
ae09ae0
Compare
273ba6b
to
acbb727
Compare
acbb727
to
702a644
Compare
cheers for a miri that detects more UB 🎉 @bors r=RalfJung rollup |
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 rust-lang/miri#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`! } ```
…mpiler-errors Rollup of 8 pull requests Successful merges: - rust-lang#129545 (rustdoc: redesign toolbar and disclosure widgets) - rust-lang#130618 (Skip query in get_parent_item when possible.) - rust-lang#130727 (Check vtable projections for validity in miri) - rust-lang#130739 (Pass bootstrap cargo when `--stage 0` and `COMPILETEST_FORCE_STAGE0`) - rust-lang#130750 (Add new Tier-3 target: `loongarch64-unknown-linux-ohos`) - rust-lang#130758 (Revert "Add recursion limit to FFI safety lint") - rust-lang#130759 (Update books) - rust-lang#130762 (stabilize const_intrinsic_copy) r? `@ghost` `@rustbot` modify labels: rollup
…mpiler-errors Rollup of 7 pull requests Successful merges: - rust-lang#129545 (rustdoc: redesign toolbar and disclosure widgets) - rust-lang#130618 (Skip query in get_parent_item when possible.) - rust-lang#130727 (Check vtable projections for validity in miri) - rust-lang#130750 (Add new Tier-3 target: `loongarch64-unknown-linux-ohos`) - rust-lang#130758 (Revert "Add recursion limit to FFI safety lint") - rust-lang#130759 (Update books) - rust-lang#130762 (stabilize const_intrinsic_copy) r? `@ghost` `@rustbot` modify labels: rollup
Rollup merge of rust-lang#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 rust-lang/miri#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`! } ```
Currently, miri does not catch when we transmute
dyn Trait<Assoc = A>
todyn Trait<Assoc = B>
. This PR implements such a check, and fixes rust-lang/miri#3905.To do this, we modify
GlobalAlloc::VTable
to contain the whole list ofPolyExistentialPredicate
, and then modifycheck_vtable_for_type
to validate thePolyExistentialProjection
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
intodyn Foo + Send
. Should we check that? We currently have a test that exercises this as not being UB:rust/src/tools/miri/tests/pass/dyn-upcast.rs
Lines 14 to 20 in 6c6d210
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: