Auto merge of #2384 - RalfJung:vtables, r=RalfJung
adjust for symbolic vtables The Miri side of https://github.com/rust-lang/rust/pull/99420
This commit is contained in:
commit
1cb9ccb284
@ -1 +1 @@
|
||||
a7468c60f8dbf5feb23ad840b174d7e57113a846
|
||||
e7a9c1141698bc4557b9da3d3fce2bf75339427f
|
||||
|
@ -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
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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()));
|
||||
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
16
tests/fail/dyn-call-trait-mismatch.rs
Normal file
16
tests/fail/dyn-call-trait-mismatch.rs
Normal file
@ -0,0 +1,16 @@
|
||||
trait T1 {
|
||||
fn method1(self: Box<Self>);
|
||||
}
|
||||
trait T2 {
|
||||
fn method2(self: Box<Self>);
|
||||
}
|
||||
|
||||
impl T1 for i32 {
|
||||
fn method1(self: Box<Self>) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let r = Box::new(0) as Box<dyn T1>;
|
||||
let r2: Box<dyn T2> = unsafe { std::mem::transmute(r) };
|
||||
r2.method2(); //~ERROR: call on a pointer whose vtable does not match its type
|
||||
}
|
15
tests/fail/dyn-call-trait-mismatch.stderr
Normal file
15
tests/fail/dyn-call-trait-mismatch.stderr
Normal file
@ -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
|
||||
|
58
tests/fail/dyn-upcast-trait-mismatch.rs
Normal file
58
tests/fail/dyn-upcast-trait-mismatch.rs
Normal file
@ -0,0 +1,58 @@
|
||||
#![feature(trait_upcasting)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
trait Foo: PartialEq<i32> + 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;
|
||||
}
|
15
tests/fail/dyn-upcast-trait-mismatch.stderr
Normal file
15
tests/fail/dyn-upcast-trait-mismatch.stderr
Normal file
@ -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
|
||||
|
@ -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::<impl std::simd::Simd<f32, 2_usize>>::to_int_unchecked::<i32>` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC
|
||||
= note: inside `core::core_simd::round::<impl std::simd::Simd<f32, 2>>::to_int_unchecked::<i32>` 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
|
||||
|
|
||||
|
@ -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::<i8, 4_usize>::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC
|
||||
= note: inside `std::simd::Simd::<i8, 4>::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
|
||||
|
|
||||
|
@ -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::<i8, 4_usize>::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC
|
||||
= note: inside `std::simd::Simd::<i8, 4>::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
|
||||
|
|
||||
|
@ -28,7 +28,7 @@ impl FunnyPointer {
|
||||
data: data as *const _ as *const (),
|
||||
vtable: ptr as *const _ as *const (),
|
||||
};
|
||||
let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj); //~ ERROR: invalid drop function pointer in vtable
|
||||
let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj); //~ ERROR: expected a vtable pointer
|
||||
&*obj
|
||||
}
|
||||
}
|
||||
|
@ -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]<TAG>, but expected a vtable pointer
|
||||
--> $DIR/issue-miri-1112.rs:LL:CC
|
||||
|
|
||||
LL | let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature)
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX[ALLOC]<TAG>, 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
|
||||
|
@ -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::<dyn Foo>` 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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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::<i32>());
|
||||
assert_eq!(meta.align_of(), mem::align_of::<i32>());
|
||||
|
||||
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::<T>());
|
||||
assert_eq!(meta.align_of(), mem::align_of::<T>());
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user