diff --git a/rust-version b/rust-version index f456ded7f46..22b5b1a34a6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a7468c60f8dbf5feb23ad840b174d7e57113a846 +e7a9c1141698bc4557b9da3d3fce2bf75339427f diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 442c201e8ec..aa7111cb81f 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -86,7 +86,9 @@ impl<'mir, 'tcx> GlobalStateInner { if global_state.exposed.contains(&alloc_id) { let (_size, _align, kind) = ecx.get_alloc_info(alloc_id); match kind { - AllocKind::LiveData | AllocKind::Function => return Some(alloc_id), + AllocKind::LiveData | AllocKind::Function | AllocKind::VTable => { + return Some(alloc_id); + } AllocKind::Dead => {} } } @@ -187,8 +189,8 @@ impl<'mir, 'tcx> GlobalStateInner { // Remember next base address. If this allocation is zero-sized, leave a gap // of at least 1 to avoid two allocations having the same base address. - // (The logic in `alloc_id_from_addr` assumes unique addresses, and function - // pointers to different functions need to be distinguishable!) + // (The logic in `alloc_id_from_addr` assumes unique addresses, and different + // function/vtable pointers need to be distinguishable!) global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted diff --git a/src/machine.rs b/src/machine.rs index 67a6c997e99..40f4c9ed90c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -733,7 +733,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if cfg!(debug_assertions) { // The machine promises to never call us on thread-local or extern statics. let alloc_id = ptr.provenance; - match ecx.tcx.get_global_alloc(alloc_id) { + match ecx.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { panic!("adjust_alloc_base_pointer called on thread-local static") } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index c5aab255aaf..54ab8665ce3 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -122,15 +122,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let ptr = this.read_pointer(ptr)?; - // Take apart the pointer, we need its pieces. + // Take apart the pointer, we need its pieces. The offset encodes the span. let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?; - let fn_instance = - if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { - instance - } else { - throw_ub_format!("expected function pointer, found {:?}", ptr); - }; + // This has to be an actual global fn ptr, not a dlsym function. + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = + this.tcx.try_get_global_alloc(alloc_id) + { + instance + } else { + throw_ub_format!("expected static function pointer, found {:?}", ptr); + }; let lo = this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 38a73929a03..624b32dfd49 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -799,7 +799,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); } } - AllocKind::Function | AllocKind::Dead => { + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { // No stacked borrows on these allocations. } } @@ -1143,7 +1143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } - AllocKind::Function | AllocKind::Dead => { + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { // No stacked borrows on these allocations. } } diff --git a/tests/fail/dyn-call-trait-mismatch.rs b/tests/fail/dyn-call-trait-mismatch.rs new file mode 100644 index 00000000000..0e7c3dbcc04 --- /dev/null +++ b/tests/fail/dyn-call-trait-mismatch.rs @@ -0,0 +1,16 @@ +trait T1 { + fn method1(self: Box); +} +trait T2 { + fn method2(self: Box); +} + +impl T1 for i32 { + fn method1(self: Box) {} +} + +fn main() { + let r = Box::new(0) as Box; + let r2: Box = unsafe { std::mem::transmute(r) }; + r2.method2(); //~ERROR: call on a pointer whose vtable does not match its type +} diff --git a/tests/fail/dyn-call-trait-mismatch.stderr b/tests/fail/dyn-call-trait-mismatch.stderr new file mode 100644 index 00000000000..2673a22a3df --- /dev/null +++ b/tests/fail/dyn-call-trait-mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `dyn` call on a pointer whose vtable does not match its type + --> $DIR/dyn-call-trait-mismatch.rs:LL:CC + | +LL | r2.method2(); + | ^^^^^^^^^^^^ `dyn` call on a pointer whose vtable does not match its type + | + = 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 $DIR/dyn-call-trait-mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/dyn-upcast-trait-mismatch.rs b/tests/fail/dyn-upcast-trait-mismatch.rs new file mode 100644 index 00000000000..f53e9a03f4b --- /dev/null +++ b/tests/fail/dyn-upcast-trait-mismatch.rs @@ -0,0 +1,58 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } +} + +trait Bar: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } +} + +trait Baz: Bar { + fn c(&self) -> i32 { + 30 + } +} + +impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } +} + +impl Bar for i32 { + fn b(&self) -> i32 { + 200 + } +} + +impl Baz for i32 { + fn c(&self) -> i32 { + 300 + } +} + +fn main() { + let baz: &dyn Baz = &1; + // We already fail on the implicit upcast inserted here. + let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; + //~^ERROR: upcast on a pointer whose vtable does not match its type + let _err = baz_fake as &dyn Foo; +} diff --git a/tests/fail/dyn-upcast-trait-mismatch.stderr b/tests/fail/dyn-upcast-trait-mismatch.stderr new file mode 100644 index 00000000000..0e5e22b9b4b --- /dev/null +++ b/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: upcast on a pointer whose vtable does not match its type + --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC + | +LL | let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ upcast on a pointer whose vtable does not match its type + | + = 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 $DIR/dyn-upcast-trait-mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index 233074105b2..ddeda599214 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -7,7 +7,7 @@ LL | implement! { f32 } = 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 `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index 6b935bc6e25..a23307c05ff 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -7,7 +7,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } = 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 `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC | diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index 24fc6782f14..ba8c8f34706 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -7,7 +7,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) = 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 `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC | diff --git a/tests/fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs index abf627bb2a7..387253a3f98 100644 --- a/tests/fail/issue-miri-1112.rs +++ b/tests/fail/issue-miri-1112.rs @@ -28,7 +28,7 @@ impl FunnyPointer { data: data as *const _ as *const (), vtable: ptr as *const _ as *const (), }; - let obj = std::mem::transmute::(obj); //~ ERROR: invalid drop function pointer in vtable + let obj = std::mem::transmute::(obj); //~ ERROR: expected a vtable pointer &*obj } } diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index 89dc8dc327f..4a2bdb0f414 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) +error: Undefined Behavior: constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer --> $DIR/issue-miri-1112.rs:LL:CC | LL | let obj = std::mem::transmute::(obj); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer | = 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/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr deleted file mode 100644 index 534f811e48a..00000000000 --- a/tests/fail/stacked_borrows/vtable.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer - --> RUSTLIB/core/src/ptr/metadata.rs:LL:CC - | -LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer - | - = 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 `std::ptr::from_raw_parts::` at RUSTLIB/core/src/ptr/metadata.rs:LL:CC -note: inside `uwu` at $DIR/vtable.rs:LL:CC - --> $DIR/vtable.rs:LL:CC - | -LL | core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `main` at $DIR/vtable.rs:LL:CC - --> $DIR/vtable.rs:LL:CC - | -LL | let _ = uwu(ptr, core::mem::transmute(meta)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/invalid_wide_raw.rs b/tests/fail/validity/invalid_wide_raw.rs index 0a2f6f5b152..2ad972a9d4d 100644 --- a/tests/fail/validity/invalid_wide_raw.rs +++ b/tests/fail/validity/invalid_wide_raw.rs @@ -7,5 +7,5 @@ fn main() { #[allow(dead_code)] x: *mut dyn T, } - dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered null pointer, but expected a vtable pointer } diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index 624b9764c9e..304008f6516 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered dangling vtable pointer in wide pointer +error: Undefined Behavior: constructing invalid value: encountered null pointer, but expected a vtable pointer --> $DIR/invalid_wide_raw.rs:LL:CC | LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer | = 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/tests/fail/stacked_borrows/vtable.rs b/tests/pass/issues/issue-miri-2123.rs similarity index 53% rename from tests/fail/stacked_borrows/vtable.rs rename to tests/pass/issues/issue-miri-2123.rs index 27e035c404b..e39e5fe454a 100644 --- a/tests/fail/stacked_borrows/vtable.rs +++ b/tests/pass/issues/issue-miri-2123.rs @@ -1,12 +1,13 @@ -//@error-pattern: vtable pointer does not have permission -#![feature(ptr_metadata)] +#![feature(ptr_metadata, layout_for_ptr)] + +use std::{mem, ptr}; trait Foo {} impl Foo for u32 {} fn uwu(thin: *const (), meta: &'static ()) -> *const dyn Foo { - core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) + ptr::from_raw_parts(thin, unsafe { mem::transmute(meta) }) } fn main() { @@ -14,6 +15,7 @@ fn main() { let orig = 1_u32; let x = &orig as &dyn Foo; let (ptr, meta) = (x as *const dyn Foo).to_raw_parts(); - let _ = uwu(ptr, core::mem::transmute(meta)); + let ptr = uwu(ptr, mem::transmute(meta)); + let _size = mem::size_of_val_raw(ptr); } } diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index a0c20af4269..a271e764d9f 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -1,4 +1,7 @@ -use std::mem::transmute; +#![feature(ptr_metadata)] + +use std::mem::{self, transmute}; +use std::ptr; fn one_line_ref() -> i16 { *&1 @@ -71,6 +74,19 @@ fn wide_ptr_ops() { assert!(!(a > b)); } +fn metadata_vtable() { + let p = &0i32 as &dyn std::fmt::Debug; + let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _); + assert_eq!(meta.size_of(), mem::size_of::()); + assert_eq!(meta.align_of(), mem::align_of::()); + + type T = [i32; 16]; + let p = &T::default() as &dyn std::fmt::Debug; + let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _); + assert_eq!(meta.size_of(), mem::size_of::()); + assert_eq!(meta.align_of(), mem::align_of::()); +} + fn main() { assert_eq!(one_line_ref(), 1); assert_eq!(basic_ref(), 1); @@ -116,4 +132,5 @@ fn main() { assert!(dangling >= 4); wide_ptr_ops(); + metadata_vtable(); }