diff options
| author | bors <bors@rust-lang.org> | 2023-09-12 03:34:55 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-09-12 03:34:55 +0000 |
| commit | 366dab13f711df90a6891411458544199d159cbc (patch) | |
| tree | 241db782f38405ffcf57ee6bd8e1a890769e6bbb /src/tools | |
| parent | 36b8e4aa7588c70947419a5b435b6faa66669cbd (diff) | |
| parent | e68e9d4a14a487bd109ec654ee3e2da1432edbd0 (diff) | |
| download | rust-366dab13f711df90a6891411458544199d159cbc.tar.gz rust-366dab13f711df90a6891411458544199d159cbc.zip | |
Auto merge of #115699 - RalfJung:interpret-abi-compat, r=oli-obk
interpret: change ABI-compat test to be type-based This makes the test consistent across targets. Otherwise the chances are very high that ABI mismatches get accepted on x86_64 but still fail on many other targets with more complicated ABIs. This implements (most of) the rules described in https://github.com/rust-lang/rust/pull/115476.
Diffstat (limited to 'src/tools')
8 files changed, 60 insertions, 29 deletions
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 4f249acda1d..cb095f94f35 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -199,6 +199,7 @@ pub fn report_error<'tcx, 'mir>( e: InterpErrorInfo<'tcx>, ) -> Option<(i64, bool)> { use InterpError::*; + use UndefinedBehaviorInfo::*; let mut msg = vec![]; @@ -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 @@ -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![ @@ -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 } @@ -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:", diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr index 50d4228c111..d1ccaf89974 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr @@ -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 diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr index a53126c733e..3875c2617bb 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr @@ -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 diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr index 6eacfeece14..6d1bdfee007 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr @@ -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 diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr index eedc1235773..07d76c90e5e 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.stderr @@ -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 diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr index bc500a90b77..7ac2bc2739f 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.stderr @@ -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 diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr index 7dcca1e85b8..e082eb9e3e3 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.stderr @@ -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 diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index 08be29115ca..2e1ab58db7a 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -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 } @@ -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; @@ -34,9 +41,6 @@ fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) { 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, ()); #[repr(transparent)] #[derive(Copy, Clone)] @@ -46,7 +50,7 @@ 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, [])); @@ -54,23 +58,30 @@ fn test_abi_newtype<T: Copy + Default>() { } 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. |
