diff options
| author | Ralf Jung <post@ralfj.de> | 2025-07-27 16:24:48 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2025-07-27 22:26:10 +0200 |
| commit | 296586fb026539916a39b79af9a2c3440ce93976 (patch) | |
| tree | e641885035c0dcd7ef49e632fc95ccd1534a9a4a | |
| parent | 86ef32029427cfc4161a3fd7a51992302f7c5552 (diff) | |
| download | rust-296586fb026539916a39b79af9a2c3440ce93976.tar.gz rust-296586fb026539916a39b79af9a2c3440ce93976.zip | |
miri: for ABI mismatch errors, say which argument is the problem
25 files changed, 45 insertions, 35 deletions
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index aa0bc42d448..2985eafb63a 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -128,15 +128,15 @@ const_eval_frame_note_inner = inside {$where_ -> const_eval_frame_note_last = the failure occurred here +const_eval_incompatible_arg_types = + calling a function whose parameter #{$arg_idx} has type {$callee_ty} passing argument of type {$caller_ty} + const_eval_incompatible_calling_conventions = calling a function with calling convention "{$callee_conv}" using calling convention "{$caller_conv}" const_eval_incompatible_return_types = calling a function with return type {$callee_ty} passing return place of type {$caller_ty} -const_eval_incompatible_types = - calling a function with argument of type {$callee_ty} passing data of type {$caller_ty} - const_eval_interior_mutable_borrow_escaping = interior mutable shared borrows of temporaries that have their lifetime extended until the end of the program are not allowed .label = this borrow of an interior mutable value refers to such a temporary diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index b6a64035261..a4148cb145f 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -500,7 +500,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { InvalidNichedEnumVariantWritten { .. } => { const_eval_invalid_niched_enum_variant_written } - AbiMismatchArgument { .. } => const_eval_incompatible_types, + AbiMismatchArgument { .. } => const_eval_incompatible_arg_types, AbiMismatchReturn { .. } => const_eval_incompatible_return_types, } } @@ -625,12 +625,16 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> { diag.arg("data_size", info.data_size); } InvalidNichedEnumVariantWritten { enum_ty } => { - diag.arg("ty", enum_ty.to_string()); + diag.arg("ty", enum_ty); } - AbiMismatchArgument { caller_ty, callee_ty } - | AbiMismatchReturn { caller_ty, callee_ty } => { - diag.arg("caller_ty", caller_ty.to_string()); - diag.arg("callee_ty", callee_ty.to_string()); + AbiMismatchArgument { arg_idx, caller_ty, callee_ty } => { + diag.arg("arg_idx", arg_idx + 1); // adjust for 1-indexed lists in output + diag.arg("caller_ty", caller_ty); + diag.arg("callee_ty", callee_ty); + } + AbiMismatchReturn { caller_ty, callee_ty } => { + diag.arg("caller_ty", caller_ty); + diag.arg("callee_ty", callee_ty); } } } diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index 1503f3bcd99..bda00ea2fb8 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -270,6 +270,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Item = (&'x FnArg<'tcx, M::Provenance>, &'y ArgAbi<'tcx, Ty<'tcx>>), >, callee_abi: &ArgAbi<'tcx, Ty<'tcx>>, + callee_arg_idx: usize, callee_arg: &mir::Place<'tcx>, callee_ty: Ty<'tcx>, already_live: bool, @@ -298,6 +299,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // Check compatibility if !self.check_argument_compat(caller_abi, callee_abi)? { throw_ub!(AbiMismatchArgument { + arg_idx: callee_arg_idx, caller_ty: caller_abi.layout.ty, callee_ty: callee_abi.layout.ty }); @@ -424,7 +426,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // this is a single iterator (that handles `spread_arg`), then // `pass_argument` would be the loop body. It takes care to // not advance `caller_iter` for ignored arguments. - let mut callee_args_abis = callee_fn_abi.args.iter(); + let mut callee_args_abis = callee_fn_abi.args.iter().enumerate(); for local in body.args_iter() { // Construct the destination place for this argument. At this point all // locals are still dead, so we cannot construct a `PlaceTy`. @@ -445,10 +447,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { &[mir::ProjectionElem::Field(FieldIdx::from_usize(i), field_ty)], *self.tcx, ); - let callee_abi = callee_args_abis.next().unwrap(); + let (idx, callee_abi) = callee_args_abis.next().unwrap(); self.pass_argument( &mut caller_args, callee_abi, + idx, &dest, field_ty, /* already_live */ true, @@ -456,10 +459,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { } } else { // Normal argument. Cannot mark it as live yet, it might be unsized! - let callee_abi = callee_args_abis.next().unwrap(); + let (idx, callee_abi) = callee_args_abis.next().unwrap(); self.pass_argument( &mut caller_args, callee_abi, + idx, &dest, ty, /* already_live */ false, diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 2b0cfb86564..3e895c6b280 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -426,7 +426,12 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Trying to set discriminant to the niched variant, but the value does not match. InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> }, /// ABI-incompatible argument types. - AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> }, + AbiMismatchArgument { + /// The index of the argument whose type is wrong. + arg_idx: usize, + caller_ty: Ty<'tcx>, + callee_ty: Ty<'tcx>, + }, /// ABI-incompatible return types. AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> }, } diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index 9ecbd31c5b9..8fdf8d643ea 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -382,7 +382,7 @@ pub fn report_error<'tcx>( helps.push(note_span!(span, "{:?} was deallocated here:", alloc_id)); } } - AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => { + AbiMismatchArgument { .. } => { helps.push(note!("this means these two types are not *guaranteed* to be ABI-compatible across all targets")); helps.push(note!("if you think this code should be accepted anyway, please report an issue with Miri")); } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index ccfff7fa94b..15699828e00 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -1079,6 +1079,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { .position(|b| !b) { throw_ub!(AbiMismatchArgument { + arg_idx: index, caller_ty: caller_fn_abi.args[index].layout.ty, callee_ty: callee_fn_abi.args[index].layout.ty }); diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs index 4468eb299f3..26f2e73dd75 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs @@ -17,5 +17,5 @@ fn main() { // These two types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::<fn(S), fn(A)>(f) }; - g(Default::default()) //~ ERROR: calling a function with argument of type S passing data of type [i32; 4] + g(Default::default()) //~ ERROR: type S passing argument of type [i32; 4] } 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 cabefa8bee9..f793abb0b62 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 @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type S passing data of type [i32; 4] +error: Undefined Behavior: calling a function whose parameter #1 has type S passing argument of type [i32; 4] --> tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs:LL:CC | LL | g(Default::default()) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs index a1fda329e8d..0cca4a13233 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn(f32), fn(i32)>(f) }; - g(42) //~ ERROR: calling a function with argument of type f32 passing data of type i32 + g(42) //~ ERROR: type f32 passing argument of type i32 } 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 52cc48d58ce..3651fc9b3f7 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 @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type f32 passing data of type i32 +error: Undefined Behavior: calling a function whose parameter #1 has type f32 passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_int_vs_float.rs:LL:CC | LL | g(42) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs index f0ea5ccfe0f..053a4a5f284 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn(*const [i32]), fn(*const i32)>(f) }; - g(&42 as *const i32) //~ ERROR: calling a function with argument of type *const [i32] passing data of type *const i32 + g(&42 as *const i32) //~ ERROR: type *const [i32] passing argument of type *const i32 } 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 2fbb0408c59..88345a0688c 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 @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32 +error: Undefined Behavior: calling a function whose parameter #1 has type *const [i32] passing argument of type *const i32 --> tests/fail/function_pointers/abi_mismatch_raw_pointer.rs:LL:CC | LL | g(&42 as *const i32) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs index c5900489b4c..f3dffcc4e86 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs @@ -12,5 +12,5 @@ fn main() { let fnptr: fn(S2) = callee; let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) }; fnptr(S1(NonZero::new(1).unwrap())); - //~^ ERROR: calling a function with argument of type S2 passing data of type S1 + //~^ ERROR: type S2 passing argument of type S1 } diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr index 2c1ac0ee702..47658395132 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type S2 passing data of type S1 +error: Undefined Behavior: calling a function whose parameter #1 has type S2 passing argument of type S1 --> tests/fail/function_pointers/abi_mismatch_repr_C.rs:LL:CC | LL | fnptr(S1(NonZero::new(1).unwrap())); diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs index 0fdab49b94b..05b645cf75a 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_return_type.rs @@ -5,5 +5,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn() -> u32, fn()>(f) }; - g() //~ ERROR: calling a function with return type u32 passing return place of type () + g() //~ ERROR: type u32 passing return place of type () } 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 28c676ad482..07e6561b53e 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,8 +6,6 @@ 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 with Miri = note: BACKTRACE: = note: inside `main` at tests/fail/function_pointers/abi_mismatch_return_type.rs:LL:CC diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs index 20384f0965b..ca43c06008f 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_simple.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::<fn((i32, i32)), fn(i32)>(f) }; - g(42) //~ ERROR: calling a function with argument of type (i32, i32) passing data of type i32 + g(42) //~ ERROR: type (i32, i32) passing argument of type i32 } 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 e45ad12ec05..2ed9ac2e6da 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 @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32 +error: Undefined Behavior: calling a function whose parameter #1 has type (i32, i32) passing argument of type i32 --> tests/fail/function_pointers/abi_mismatch_simple.rs:LL:CC | LL | g(42) diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs index 80f357b61ba..dedcaac6142 100644 --- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs +++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_vector.rs @@ -7,5 +7,5 @@ fn main() { // These two vector types have the same size but are still not compatible. let g = unsafe { std::mem::transmute::<fn(simd::u32x8), fn(simd::u64x4)>(f) }; - g(Default::default()) //~ ERROR: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4> + g(Default::default()) //~ ERROR: type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4> } 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 bad2495cb39..b13e8d936db 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 @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type std::simd::Simd<u32, 8> passing data of type std::simd::Simd<u64, 4> +error: Undefined Behavior: calling a function whose parameter #1 has type std::simd::Simd<u32, 8> passing argument of type std::simd::Simd<u64, 4> --> tests/fail/function_pointers/abi_mismatch_vector.rs:LL:CC | LL | g(Default::default()) diff --git a/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs b/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs index eb8de04dcc4..77699776aea 100644 --- a/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs +++ b/src/tools/miri/tests/fail/shims/input_arg_mismatch.rs @@ -16,6 +16,6 @@ fn main() { } as u32; let _ = unsafe { close(fd); - //~^ ERROR: calling a function with argument of type i32 passing data of type u32 + //~^ ERROR: type i32 passing argument of type u32 }; } diff --git a/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr b/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr index ce00b624a42..ec27fd5ebb8 100644 --- a/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr +++ b/src/tools/miri/tests/fail/shims/input_arg_mismatch.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 +error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32 --> tests/fail/shims/input_arg_mismatch.rs:LL:CC | LL | close(fd); diff --git a/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr b/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr index 18ff3067fa0..080ee16a2eb 100644 --- a/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr +++ b/src/tools/miri/tests/fail/shims/return_type_mismatch.stderr @@ -6,8 +6,6 @@ LL | close(fd); | = 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 with Miri = note: BACKTRACE: = note: inside `main` at tests/fail/shims/return_type_mismatch.rs:LL:CC diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs index 6df132d3255..36bd1e99cfb 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs @@ -6,7 +6,7 @@ fn main() { // the error should point to `become g(x)`, // but tail calls mess up the backtrace it seems like... f(0); - //~^ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 + //~^ error: type i32 passing argument of type u32 } fn f(x: u32) { diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr index fbb0d3d565d..cabea5df85d 100644 --- a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 +error: Undefined Behavior: calling a function whose parameter #1 has type i32 passing argument of type u32 --> tests/fail/tail_calls/signature-mismatch-arg.rs:LL:CC | LL | f(0); |
