Skip to content

Commit 4b4038c

Browse files
committed
Auto merge of #2384 - RalfJung:vtables, r=RalfJung
adjust for symbolic vtables The Miri side of rust-lang/rust#99420
2 parents 9cab797 + b5749f4 commit 4b4038c

19 files changed

+153
-53
lines changed

rust-version

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a7468c60f8dbf5feb23ad840b174d7e57113a846
1+
e7a9c1141698bc4557b9da3d3fce2bf75339427f

src/intptrcast.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ impl<'mir, 'tcx> GlobalStateInner {
8686
if global_state.exposed.contains(&alloc_id) {
8787
let (_size, _align, kind) = ecx.get_alloc_info(alloc_id);
8888
match kind {
89-
AllocKind::LiveData | AllocKind::Function => return Some(alloc_id),
89+
AllocKind::LiveData | AllocKind::Function | AllocKind::VTable => {
90+
return Some(alloc_id);
91+
}
9092
AllocKind::Dead => {}
9193
}
9294
}
@@ -187,8 +189,8 @@ impl<'mir, 'tcx> GlobalStateInner {
187189

188190
// Remember next base address. If this allocation is zero-sized, leave a gap
189191
// of at least 1 to avoid two allocations having the same base address.
190-
// (The logic in `alloc_id_from_addr` assumes unique addresses, and function
191-
// pointers to different functions need to be distinguishable!)
192+
// (The logic in `alloc_id_from_addr` assumes unique addresses, and different
193+
// function/vtable pointers need to be distinguishable!)
192194
global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap();
193195
// Given that `next_base_addr` increases in each allocation, pushing the
194196
// corresponding tuple keeps `int_to_ptr_map` sorted

src/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
733733
if cfg!(debug_assertions) {
734734
// The machine promises to never call us on thread-local or extern statics.
735735
let alloc_id = ptr.provenance;
736-
match ecx.tcx.get_global_alloc(alloc_id) {
736+
match ecx.tcx.try_get_global_alloc(alloc_id) {
737737
Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => {
738738
panic!("adjust_alloc_base_pointer called on thread-local static")
739739
}

src/shims/backtrace.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
122122
let this = self.eval_context_mut();
123123

124124
let ptr = this.read_pointer(ptr)?;
125-
// Take apart the pointer, we need its pieces.
125+
// Take apart the pointer, we need its pieces. The offset encodes the span.
126126
let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?;
127127

128-
let fn_instance =
129-
if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) {
130-
instance
131-
} else {
132-
throw_ub_format!("expected function pointer, found {:?}", ptr);
133-
};
128+
// This has to be an actual global fn ptr, not a dlsym function.
129+
let fn_instance = if let Some(GlobalAlloc::Function(instance)) =
130+
this.tcx.try_get_global_alloc(alloc_id)
131+
{
132+
instance
133+
} else {
134+
throw_ub_format!("expected static function pointer, found {:?}", ptr);
135+
};
134136

135137
let lo =
136138
this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap()));

src/stacked_borrows/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
799799
stacked_borrows.history.log_protector(orig_tag, new_tag, current_span);
800800
}
801801
}
802-
AllocKind::Function | AllocKind::Dead => {
802+
AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
803803
// No stacked borrows on these allocations.
804804
}
805805
}
@@ -1143,7 +1143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
11431143
trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
11441144
alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag);
11451145
}
1146-
AllocKind::Function | AllocKind::Dead => {
1146+
AllocKind::Function | AllocKind::VTable | AllocKind::Dead => {
11471147
// No stacked borrows on these allocations.
11481148
}
11491149
}

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

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
trait T1 {
2+
fn method1(self: Box<Self>);
3+
}
4+
trait T2 {
5+
fn method2(self: Box<Self>);
6+
}
7+
8+
impl T1 for i32 {
9+
fn method1(self: Box<Self>) {}
10+
}
11+
12+
fn main() {
13+
let r = Box::new(0) as Box<dyn T1>;
14+
let r2: Box<dyn T2> = unsafe { std::mem::transmute(r) };
15+
r2.method2(); //~ERROR: call on a pointer whose vtable does not match its type
16+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: `dyn` call on a pointer whose vtable does not match its type
2+
--> $DIR/dyn-call-trait-mismatch.rs:LL:CC
3+
|
4+
LL | r2.method2();
5+
| ^^^^^^^^^^^^ `dyn` call on a pointer whose vtable does not match its type
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 $DIR/dyn-call-trait-mismatch.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 previous error
15+
+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#![feature(trait_upcasting)]
2+
#![allow(incomplete_features)]
3+
4+
trait Foo: PartialEq<i32> + std::fmt::Debug + Send + Sync {
5+
fn a(&self) -> i32 {
6+
10
7+
}
8+
9+
fn z(&self) -> i32 {
10+
11
11+
}
12+
13+
fn y(&self) -> i32 {
14+
12
15+
}
16+
}
17+
18+
trait Bar: Foo {
19+
fn b(&self) -> i32 {
20+
20
21+
}
22+
23+
fn w(&self) -> i32 {
24+
21
25+
}
26+
}
27+
28+
trait Baz: Bar {
29+
fn c(&self) -> i32 {
30+
30
31+
}
32+
}
33+
34+
impl Foo for i32 {
35+
fn a(&self) -> i32 {
36+
100
37+
}
38+
}
39+
40+
impl Bar for i32 {
41+
fn b(&self) -> i32 {
42+
200
43+
}
44+
}
45+
46+
impl Baz for i32 {
47+
fn c(&self) -> i32 {
48+
300
49+
}
50+
}
51+
52+
fn main() {
53+
let baz: &dyn Baz = &1;
54+
let _baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) };
55+
//~^ERROR: upcast on a pointer whose vtable does not match its type
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
error: Undefined Behavior: upcast on a pointer whose vtable does not match its type
2+
--> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC
3+
|
4+
LL | let _baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^ upcast on a pointer whose vtable does not match its type
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 $DIR/dyn-upcast-trait-mismatch.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 previous error
15+

tests/fail/intrinsics/simd-float-to-int.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | implement! { f32 }
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
99
= note: backtrace:
10-
= 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
10+
= 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
1111
note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC
1212
--> $DIR/simd-float-to-int.rs:LL:CC
1313
|

tests/fail/intrinsics/simd-gather.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) }
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
99
= note: backtrace:
10-
= 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
10+
= note: inside `std::simd::Simd::<i8, 4>::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC
1111
note: inside `main` at $DIR/simd-gather.rs:LL:CC
1212
--> $DIR/simd-gather.rs:LL:CC
1313
|

tests/fail/intrinsics/simd-scatter.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int())
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
99
= note: backtrace:
10-
= 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
10+
= note: inside `std::simd::Simd::<i8, 4>::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC
1111
note: inside `main` at $DIR/simd-scatter.rs:LL:CC
1212
--> $DIR/simd-scatter.rs:LL:CC
1313
|

tests/fail/issue-miri-1112.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl FunnyPointer {
2828
data: data as *const _ as *const (),
2929
vtable: ptr as *const _ as *const (),
3030
};
31-
let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj); //~ ERROR: invalid drop function pointer in vtable
31+
let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj); //~ ERROR: expected a vtable pointer
3232
&*obj
3333
}
3434
}

tests/fail/issue-miri-1112.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature)
1+
error: Undefined Behavior: constructing invalid value: encountered $HEX[ALLOC]<TAG>, but expected a vtable pointer
22
--> $DIR/issue-miri-1112.rs:LL:CC
33
|
44
LL | let obj = std::mem::transmute::<FatPointer, *mut FunnyPointer>(obj);
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX[ALLOC]<TAG>, but expected a vtable pointer
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/stacked_borrows/vtable.stderr

-25
This file was deleted.

tests/fail/validity/invalid_wide_raw.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,5 @@ fn main() {
77
#[allow(dead_code)]
88
x: *mut dyn T,
99
}
10-
dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer
10+
dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered null pointer, but expected a vtable pointer
1111
}

tests/fail/validity/invalid_wide_raw.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: constructing invalid value: encountered dangling vtable pointer in wide pointer
1+
error: Undefined Behavior: constructing invalid value: encountered null pointer, but expected a vtable pointer
22
--> $DIR/invalid_wide_raw.rs:LL:CC
33
|
44
LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } });
5-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer
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
@@ -1,19 +1,21 @@
1-
//@error-pattern: vtable pointer does not have permission
2-
#![feature(ptr_metadata)]
1+
#![feature(ptr_metadata, layout_for_ptr)]
2+
3+
use std::{mem, ptr};
34

45
trait Foo {}
56

67
impl Foo for u32 {}
78

89
fn uwu(thin: *const (), meta: &'static ()) -> *const dyn Foo {
9-
core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) })
10+
ptr::from_raw_parts(thin, unsafe { mem::transmute(meta) })
1011
}
1112

1213
fn main() {
1314
unsafe {
1415
let orig = 1_u32;
1516
let x = &orig as &dyn Foo;
1617
let (ptr, meta) = (x as *const dyn Foo).to_raw_parts();
17-
let _ = uwu(ptr, core::mem::transmute(meta));
18+
let ptr = uwu(ptr, mem::transmute(meta));
19+
let _size = mem::size_of_val_raw(ptr);
1820
}
1921
}

tests/pass/pointers.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
use std::mem::transmute;
1+
#![feature(ptr_metadata)]
2+
3+
use std::mem::{self, transmute};
4+
use std::ptr;
25

36
fn one_line_ref() -> i16 {
47
*&1
@@ -71,6 +74,19 @@ fn wide_ptr_ops() {
7174
assert!(!(a > b));
7275
}
7376

77+
fn metadata_vtable() {
78+
let p = &0i32 as &dyn std::fmt::Debug;
79+
let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _);
80+
assert_eq!(meta.size_of(), mem::size_of::<i32>());
81+
assert_eq!(meta.align_of(), mem::align_of::<i32>());
82+
83+
type T = [i32; 16];
84+
let p = &T::default() as &dyn std::fmt::Debug;
85+
let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _);
86+
assert_eq!(meta.size_of(), mem::size_of::<T>());
87+
assert_eq!(meta.align_of(), mem::align_of::<T>());
88+
}
89+
7490
fn main() {
7591
assert_eq!(one_line_ref(), 1);
7692
assert_eq!(basic_ref(), 1);
@@ -116,4 +132,5 @@ fn main() {
116132
assert!(dangling >= 4);
117133

118134
wide_ptr_ops();
135+
metadata_vtable();
119136
}

0 commit comments

Comments
 (0)