give extra context to ABI mismatch errors

This commit is contained in:
Ralf Jung 2023-09-09 10:50:14 +02:00
parent 897a65804d
commit f993ddc079
10 changed files with 66 additions and 38 deletions

View File

@ -482,6 +482,9 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
use UndefinedBehaviorInfo::*; use UndefinedBehaviorInfo::*;
match self { match self {
Ub(msg) => msg.clone().into(), Ub(msg) => msg.clone().into(),
Custom(x) => (x.msg)(),
ValidationError(e) => e.diagnostic_message(),
Unreachable => const_eval_unreachable, Unreachable => const_eval_unreachable,
BoundsCheckFailed { .. } => const_eval_bounds_check_failed, BoundsCheckFailed { .. } => const_eval_bounds_check_failed,
DivisionByZero => const_eval_division_by_zero, DivisionByZero => const_eval_division_by_zero,
@ -513,8 +516,8 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch, ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written, UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read, UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
ValidationError(e) => e.diagnostic_message(), AbiMismatchArgument { .. } => const_eval_incompatible_types,
Custom(x) => (x.msg)(), AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
} }
} }
@ -525,8 +528,15 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
) { ) {
use UndefinedBehaviorInfo::*; use UndefinedBehaviorInfo::*;
match self { match self {
Ub(_) Ub(_) => {}
| Unreachable Custom(custom) => {
(custom.add_args)(&mut |name, value| {
builder.set_arg(name, value);
});
}
ValidationError(e) => e.add_args(handler, builder),
Unreachable
| DivisionByZero | DivisionByZero
| RemainderByZero | RemainderByZero
| DivisionOverflow | DivisionOverflow
@ -593,11 +603,10 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
builder.set_arg("target_size", info.target_size); builder.set_arg("target_size", info.target_size);
builder.set_arg("data_size", info.data_size); builder.set_arg("data_size", info.data_size);
} }
ValidationError(e) => e.add_args(handler, builder), AbiMismatchArgument { caller_ty, callee_ty }
Custom(custom) => { | AbiMismatchReturn { caller_ty, callee_ty } => {
(custom.add_args)(&mut |name, value| { builder.set_arg("caller_ty", caller_ty.to_string());
builder.set_arg(name, value); builder.set_arg("callee_ty", callee_ty.to_string());
});
} }
} }
} }

View File

@ -439,13 +439,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// Check compatibility // Check compatibility
if !self.check_argument_compat(caller_abi, callee_abi)? { if !self.check_argument_compat(caller_abi, callee_abi)? {
let callee_ty = format!("{}", callee_ty); throw_ub!(AbiMismatchArgument {
let caller_ty = format!("{}", caller_arg.layout().ty); caller_ty: caller_abi.layout.ty,
throw_ub_custom!( callee_ty: callee_abi.layout.ty
fluent::const_eval_incompatible_types, });
callee_ty = callee_ty,
caller_ty = caller_ty,
)
} }
// We work with a copy of the argument for now; if this is in-place argument passing, we // We work with a copy of the argument for now; if this is in-place argument passing, we
// will later protect the source it comes from. This means the callee cannot observe if we // will later protect the source it comes from. This means the callee cannot observe if we
@ -712,13 +709,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
} }
// Don't forget to check the return type! // Don't forget to check the return type!
if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? { if !self.check_argument_compat(&caller_fn_abi.ret, &callee_fn_abi.ret)? {
let callee_ty = format!("{}", callee_fn_abi.ret.layout.ty); throw_ub!(AbiMismatchReturn {
let caller_ty = format!("{}", caller_fn_abi.ret.layout.ty); caller_ty: caller_fn_abi.ret.layout.ty,
throw_ub_custom!( callee_ty: callee_fn_abi.ret.layout.ty
fluent::const_eval_incompatible_return_types, });
callee_ty = callee_ty,
caller_ty = caller_ty,
)
} }
// Ensure the return place is aligned and dereferenceable, and protect it for // Ensure the return place is aligned and dereferenceable, and protect it for
// in-place return value passing. // in-place return value passing.

View File

@ -255,9 +255,16 @@ impl_into_diagnostic_arg_through_debug! {
/// Error information for when the program caused Undefined Behavior. /// Error information for when the program caused Undefined Behavior.
#[derive(Debug)] #[derive(Debug)]
pub enum UndefinedBehaviorInfo<'a> { pub enum UndefinedBehaviorInfo<'tcx> {
/// Free-form case. Only for errors that are never caught! Used by miri /// Free-form case. Only for errors that are never caught! Used by miri
Ub(String), Ub(String),
// FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
// dispatched
/// A custom (free-form) fluent-translated error, created by `err_ub_custom!`.
Custom(crate::error::CustomSubdiagnostic<'tcx>),
/// Validation error.
ValidationError(ValidationErrorInfo<'tcx>),
/// Unreachable code was executed. /// Unreachable code was executed.
Unreachable, Unreachable,
/// A slice/array index projection went out-of-bounds. /// A slice/array index projection went out-of-bounds.
@ -319,12 +326,10 @@ pub enum UndefinedBehaviorInfo<'a> {
UninhabitedEnumVariantWritten(VariantIdx), UninhabitedEnumVariantWritten(VariantIdx),
/// An uninhabited enum variant is projected. /// An uninhabited enum variant is projected.
UninhabitedEnumVariantRead(VariantIdx), UninhabitedEnumVariantRead(VariantIdx),
/// Validation error. /// ABI-incompatible argument types.
ValidationError(ValidationErrorInfo<'a>), AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
// FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically /// ABI-incompatible return types.
// dispatched AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
/// A custom (free-form) error, created by `err_ub_custom!`.
Custom(crate::error::CustomSubdiagnostic<'a>),
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]

View File

@ -199,6 +199,7 @@ pub fn report_error<'tcx, 'mir>(
e: InterpErrorInfo<'tcx>, e: InterpErrorInfo<'tcx>,
) -> Option<(i64, bool)> { ) -> Option<(i64, bool)> {
use InterpError::*; use InterpError::*;
use UndefinedBehaviorInfo::*;
let mut msg = vec![]; let mut msg = vec![];
@ -271,7 +272,7 @@ pub fn report_error<'tcx, 'mir>(
(title, helps) (title, helps)
} else { } else {
let title = match e.kind() { let title = match e.kind() {
UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err)) UndefinedBehavior(ValidationError(validation_err))
if matches!( if matches!(
validation_err.kind, validation_err.kind,
ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer
@ -299,7 +300,7 @@ pub fn report_error<'tcx, 'mir>(
let helps = match e.kind() { let helps = match e.kind() {
Unsupported(_) => 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"))], 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 if ecx.machine.check_alignment == AlignmentCheck::Symbolic
=> =>
vec![ 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!("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")), (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 { match info {
if let Some(span) = ecx.machine.allocated_span(*alloc_id) { PointerUseAfterFree(alloc_id, _) | PointerOutOfBounds { alloc_id, .. } => {
helps.push((Some(span), format!("{:?} was allocated here:", 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) { AbiMismatchArgument { .. } | AbiMismatchReturn { .. } => {
helps.push((Some(span), format!("{:?} was deallocated here:", alloc_id))); 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 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. // 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(); let mut extra = String::new();
match e.kind() { match e.kind() {
UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { UndefinedBehavior(InvalidUninitBytes(Some((alloc_id, access)))) => {
writeln!( writeln!(
extra, extra,
"Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:", "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",

View File

@ -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: 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: 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: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC = note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC

View File

@ -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: 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: 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: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC = note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC

View File

@ -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: 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: 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: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC = note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC

View File

@ -6,6 +6,8 @@ LL | g()
| |
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = 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: 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: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC = note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC

View File

@ -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: 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: 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: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC = note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC

View File

@ -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: 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: 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: BACKTRACE:
= note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC = note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC