Skip to content

Commit

Permalink
Merge from rustc
Browse files Browse the repository at this point in the history
  • Loading branch information
The Miri Conjob Bot committed Sep 12, 2023
2 parents 5cd5aa7 + 87fc7c3 commit 8820f12
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 35 deletions.
4 changes: 2 additions & 2 deletions src/bin/miri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {

fn after_analysis<'tcx>(
&mut self,
handler: &EarlyErrorHandler,
_: &rustc_interface::interface::Compiler,
queries: &'tcx rustc_interface::Queries<'tcx>,
) -> Compilation {
Expand All @@ -68,7 +67,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
tcx.sess.fatal("miri cannot be run on programs that fail compilation");
}

init_late_loggers(handler, tcx);
let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format);
init_late_loggers(&handler, tcx);
if !tcx.crate_types().contains(&CrateType::Executable) {
tcx.sess.fatal("miri only makes sense on bin crates");
}
Expand Down
24 changes: 16 additions & 8 deletions src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ pub fn report_error<'tcx, 'mir>(
e: InterpErrorInfo<'tcx>,
) -> Option<(i64, bool)> {
use InterpError::*;
use UndefinedBehaviorInfo::*;

let mut msg = vec![];

Expand Down Expand Up @@ -271,7 +272,7 @@ pub fn report_error<'tcx, 'mir>(
(title, helps)
} else {
let title = match e.kind() {
UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err))
UndefinedBehavior(ValidationError(validation_err))
if matches!(
validation_err.kind,
ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer
Expand Down Expand Up @@ -299,7 +300,7 @@ pub fn report_error<'tcx, 'mir>(
let helps = match e.kind() {
Unsupported(_) =>
vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))],
UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. })
UndefinedBehavior(AlignmentCheckFailed { .. })
if ecx.machine.check_alignment == AlignmentCheck::Symbolic
=>
vec![
Expand All @@ -311,13 +312,20 @@ pub fn report_error<'tcx, 'mir>(
(None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")),
(None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")),
];
if let UndefinedBehaviorInfo::PointerUseAfterFree(alloc_id, _) | UndefinedBehaviorInfo::PointerOutOfBounds { alloc_id, .. } = info {
if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
helps.push((Some(span), format!("{:?} was allocated here:", alloc_id)));
match info {
PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => {
if let Some(span) = ecx.machine.allocated_span(*alloc_id) {
helps.push((Some(span), format!("{:?} was allocated here:", alloc_id)));
}
if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id)));
}
}
if let Some(span) = ecx.machine.deallocated_span(*alloc_id) {
helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id)));
AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => {
helps.push((None, format!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")));
helps.push((None, format!("if you think this code should be accepted anyway, please report an issue")));
}
_ => {},
}
helps
}
Expand All @@ -339,7 +347,7 @@ pub fn report_error<'tcx, 'mir>(
// We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
let mut extra = String::new();
match e.kind() {
UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => {
writeln!(
extra,
"Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LL | g(Default::default())
|
= 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
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue
= note: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC

Expand Down
2 changes: 2 additions & 0 deletions tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LL | g(42)
|
= 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
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue
= note: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC

Expand Down
2 changes: 2 additions & 0 deletions tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LL | g(&42 as *const i32)
|
= 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
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue
= note: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC

Expand Down
2 changes: 2 additions & 0 deletions tests/fail/function_pointers/abi_mismatch_return_type.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LL | g()
|
= 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
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue
= note: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC

Expand Down
2 changes: 2 additions & 0 deletions tests/fail/function_pointers/abi_mismatch_simple.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LL | g(42)
|
= 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
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue
= note: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC

Expand Down
2 changes: 2 additions & 0 deletions tests/fail/function_pointers/abi_mismatch_vector.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ LL | g(Default::default())
|
= 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
= help: this means these two types are not *guaranteed* to be ABI-compatible across all targets
= help: if you think this code should be accepted anyway, please report an issue
= note: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: Undefined Behavior: constructing invalid value: encountered a null reference
--> $DIR/cast_fn_ptr1.rs:LL:CC
--> $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC
|
LL | g(0usize as *const i32)
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
|
= 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/cast_fn_ptr1.rs:LL:CC
= note: inside `main` at $DIR/cast_fn_ptr_invalid_callee_arg.rs:LL:CC

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

Expand Down
28 changes: 28 additions & 0 deletions tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#![allow(internal_features)]
#![feature(core_intrinsics, custom_mir)]

use std::intrinsics::mir::*;
use std::num::NonZeroU32;
use std::ptr;

// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that
// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer
// type. That way we never get an "invalid value constructed" error inside the function, it can
// only possibly be detected when the return value is passed to the caller.
#[custom_mir(dialect = "runtime", phase = "optimized")]
fn f() -> NonZeroU32 {
mir! {
{
let tmp = ptr::addr_of_mut!(RET);
let ptr = tmp as *mut u32;
*ptr = 0;
Return()
}
}
}

fn main() {
let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) };
// There's a NonZeroU32-to-u32 transmute happening here
f(); //~ERROR: expected something greater or equal to 1
}
15 changes: 15 additions & 0 deletions tests/fail/validity/cast_fn_ptr_invalid_callee_ret.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
--> $DIR/cast_fn_ptr_invalid_callee_ret.rs:LL:CC
|
LL | f();
| ^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
|
= 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/cast_fn_ptr_invalid_callee_ret.rs:LL:CC

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to previous error

34 changes: 34 additions & 0 deletions tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#![allow(internal_features)]
#![feature(core_intrinsics, custom_mir)]

use std::intrinsics::mir::*;
use std::num::NonZeroU32;
use std::ptr;

fn f(c: u32) {
println!("{c}");
}

// Call that function in a bad way, with an invalid NonZeroU32, but without
// ever materializing this as a NonZeroU32 value outside the call itself.
#[custom_mir(dialect = "runtime", phase = "optimized")]
fn call(f: fn(NonZeroU32)) {
mir! {
let _res: ();
{
let c = 0;
let tmp = ptr::addr_of!(c);
let ptr = tmp as *const NonZeroU32;
// The call site now is a NonZeroU32-to-u32 transmute.
Call(_res = f(*ptr), retblock) //~ERROR: expected something greater or equal to 1
}
retblock = {
Return()
}
}
}

fn main() {
let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) };
call(f);
}
20 changes: 20 additions & 0 deletions tests/fail/validity/cast_fn_ptr_invalid_caller_arg.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1
--> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
|
LL | Call(_res = f(*ptr), retblock)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1
|
= 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 `call` at $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
note: inside `main`
--> $DIR/cast_fn_ptr_invalid_caller_arg.rs:LL:CC
|
LL | call(f);
| ^^^^^^^

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

error: aborting due to previous error

File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
error: Undefined Behavior: constructing invalid value: encountered a null reference
--> $DIR/cast_fn_ptr2.rs:LL:CC
--> $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC
|
LL | let _x = g();
| ^^^ constructing invalid value: encountered a null reference
|
= 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/cast_fn_ptr2.rs:LL:CC
= note: inside `main` at $DIR/cast_fn_ptr_invalid_caller_ret.rs:LL:CC

note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace

Expand Down
53 changes: 32 additions & 21 deletions tests/pass/function_calls/abi_compat.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
use std::mem;
use std::num;
use std::ptr;

#[derive(Copy, Clone, Default)]
struct Zst;

fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
#[repr(transparent)]
#[derive(Copy, Clone)]
struct Wrapper<T>(T);

fn id<T>(x: T) -> T { x }

fn test_abi_compat<T: Clone, U: Clone>(t: T, u: U) {
fn id<T>(x: T) -> T {
x
}
Expand All @@ -16,10 +23,10 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {
// in both directions.
let f: fn(T) -> T = id;
let f: fn(U) -> U = unsafe { std::mem::transmute(f) };
let _val = f(u);
let _val = f(u.clone());
let f: fn(U) -> U = id;
let f: fn(T) -> T = unsafe { std::mem::transmute(f) };
let _val = f(t);
let _val = f(t.clone());

// And then we do the same for `extern "C"`.
let f: extern "C" fn(T) -> T = id_c;
Expand All @@ -32,9 +39,6 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) {

/// Ensure that `T` is compatible with various repr(transparent) wrappers around `T`.
fn test_abi_newtype<T: Copy + Default>() {
#[repr(transparent)]
#[derive(Copy, Clone)]
struct Wrapper1<T>(T);
#[repr(transparent)]
#[derive(Copy, Clone)]
struct Wrapper2<T>(T, ());
Expand All @@ -46,31 +50,38 @@ fn test_abi_newtype<T: Copy + Default>() {
struct Wrapper3<T>(Zst, T, [u8; 0]);

let t = T::default();
test_abi_compat(t, Wrapper1(t));
test_abi_compat(t, Wrapper(t));
test_abi_compat(t, Wrapper2(t, ()));
test_abi_compat(t, Wrapper2a((), t));
test_abi_compat(t, Wrapper3(Zst, t, []));
test_abi_compat(t, mem::MaybeUninit::new(t)); // MaybeUninit is `repr(transparent)`
}

fn main() {
// Here we check:
// - u32 vs char is allowed
// - u32 vs NonZeroU32/Option<NonZeroU32> is allowed
// - reference vs raw pointer is allowed
// - references to things of the same size and alignment are allowed
// These are very basic tests that should work on all ABIs. However it is not clear that any of
// these would be stably guaranteed. Code that relies on this is equivalent to code that relies
// on the layout of `repr(Rust)` types. They are also fragile: the same mismatches in the fields
// of a struct (even with `repr(C)`) will not always be accepted by Miri.
// Note that `bool` and `u8` are *not* compatible, at least on x86-64!
// One of them has `arg_ext: Zext`, the other does not.
// Similarly, `i32` and `u32` are not compatible on s390x due to different `arg_ext`.
test_abi_compat(0u32, 'x');
// Here we check some of the guaranteed ABI compatibilities.
// Different integer types of the same size and sign.
if cfg!(target_pointer_width = "32") {
test_abi_compat(0usize, 0u32);
test_abi_compat(0isize, 0i32);
} else {
test_abi_compat(0usize, 0u64);
test_abi_compat(0isize, 0i64);
}
test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
// Reference/pointer types with the same pointee.
test_abi_compat(&0u32, &0u32 as *const u32);
test_abi_compat(&mut 0u32 as *mut u32, Box::new(0u32));
test_abi_compat(&(), ptr::NonNull::<()>::dangling());
// Reference/pointer types with different but sized pointees.
test_abi_compat(&0u32, &([true; 4], [0u32; 0]));
// `fn` types
test_abi_compat(main as fn(), id::<i32> as fn(i32) -> i32);
// Guaranteed null-pointer-optimizations.
test_abi_compat(&0u32 as *const u32, Some(&0u32));
test_abi_compat(main as fn(), Some(main as fn()));
test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32)));
test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1).unwrap())));

// These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible
// with the wrapped field.
Expand Down

0 comments on commit 8820f12

Please sign in to comment.