Skip to content

adjust for symbolic vtables #2384

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

Merged
merged 3 commits into from
Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rust-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
a7468c60f8dbf5feb23ad840b174d7e57113a846
e7a9c1141698bc4557b9da3d3fce2bf75339427f
8 changes: 5 additions & 3 deletions src/intptrcast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 => {}
}
}
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
Expand Down
16 changes: 9 additions & 7 deletions src/shims/backtrace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
Expand Down
4 changes: 2 additions & 2 deletions src/stacked_borrows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
}
}
Expand Down Expand Up @@ -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.
}
}
Expand Down
16 changes: 16 additions & 0 deletions tests/fail/dyn-call-trait-mismatch.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions tests/fail/dyn-call-trait-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -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 changes: 58 additions & 0 deletions tests/fail/dyn-upcast-trait-mismatch.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions tests/fail/dyn-upcast-trait-mismatch.stderr
Original file line number Diff line number Diff line change
@@ -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

2 changes: 1 addition & 1 deletion tests/fail/intrinsics/simd-float-to-int.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down
2 changes: 1 addition & 1 deletion tests/fail/intrinsics/simd-gather.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down
2 changes: 1 addition & 1 deletion tests/fail/intrinsics/simd-scatter.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down
2 changes: 1 addition & 1 deletion tests/fail/issue-miri-1112.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
4 changes: 2 additions & 2 deletions tests/fail/issue-miri-1112.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down
25 changes: 0 additions & 25 deletions tests/fail/stacked_borrows/vtable.stderr

This file was deleted.

2 changes: 1 addition & 1 deletion tests/fail/validity/invalid_wide_raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
4 changes: 2 additions & 2 deletions tests/fail/validity/invalid_wide_raw.stderr
Original file line number Diff line number Diff line change
@@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
//@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() {
unsafe {
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);
}
}
19 changes: 18 additions & 1 deletion tests/pass/pointers.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -116,4 +132,5 @@ fn main() {
assert!(dangling >= 4);

wide_ptr_ops();
metadata_vtable();
}