diff options
| author | Matthias Krüger <476013+matthiaskrgr@users.noreply.github.com> | 2025-07-03 05:21:36 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-03 05:21:36 +0200 |
| commit | bc0262d0f1bf9165e28c01b64fb0dd1a24534968 (patch) | |
| tree | 9e275fd8466532f354e5e3496cc74659f15d82ca /compiler | |
| parent | 5aa7dd81d80db2a7e58344587a6e6ecbd2690510 (diff) | |
| parent | 8362508989c8941ccbba26aaa8c787cc492c6fef (diff) | |
| download | rust-bc0262d0f1bf9165e28c01b64fb0dd1a24534968.tar.gz rust-bc0262d0f1bf9165e28c01b64fb0dd1a24534968.zip | |
Rollup merge of #143327 - RalfJung:miri-type-validity-error, r=oli-obk
miri: improve errors for type validity assertion failures Miri has pretty nice errors for type validity violations, printing which field in the type the problem occurs at and so on. However, we don't see these errors when using e.g. `mem::zeroed` as that uses `assert_zero_valid` to bail out before Miri can detect the UB. Similar to what we did with `@saethlin's` UB checks, I think we should disable such language UB checks in Miri so that we can get better error messages. If we go for this we should probably say this in the intrinsic docs as well so that people don't think they can rely on these intrinsics catching anything. Furthermore, I slightly changed `MaybeUninit::assume_init` so that the `.value` field does not show up in error messages any more. `@rust-lang/miri` what do you think?
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_const_eval/src/const_eval/machine.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/intrinsics.rs | 41 |
2 files changed, 44 insertions, 41 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 317b1229a90..76fa744361a 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -10,7 +10,7 @@ use rustc_hir::{self as hir, CRATE_HIR_ID, LangItem}; use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout}; +use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{bug, mir}; use rustc_span::{Span, Symbol, sym}; @@ -23,8 +23,8 @@ use crate::fluent_generated as fluent; use crate::interpret::{ self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy, InterpCx, InterpResult, OpTy, PlaceTy, Pointer, RangeSet, Scalar, - compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom, - throw_unsup, throw_unsup_format, + compile_time_machine, err_inval, interp_ok, throw_exhaust, throw_inval, throw_ub, + throw_ub_custom, throw_unsup, throw_unsup_format, }; /// When hitting this many interpreted terminators we emit a deny by default lint @@ -462,6 +462,44 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // (We know the value here in the machine of course, but this is the runtime of that code, // not the optimization stage.) sym::is_val_statically_known => ecx.write_scalar(Scalar::from_bool(false), dest)?, + + // We handle these here since Miri does not want to have them. + sym::assert_inhabited + | sym::assert_zero_valid + | sym::assert_mem_uninitialized_valid => { + let ty = instance.args.type_at(0); + let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); + + let should_panic = !ecx + .tcx + .check_validity_requirement((requirement, ecx.typing_env().as_query_input(ty))) + .map_err(|_| err_inval!(TooGeneric))?; + + if should_panic { + let layout = ecx.layout_of(ty)?; + + let msg = match requirement { + // For *all* intrinsics we first check `is_uninhabited` to give a more specific + // error message. + _ if layout.is_uninhabited() => format!( + "aborted execution: attempted to instantiate uninhabited type `{ty}`" + ), + ValidityRequirement::Inhabited => bug!("handled earlier"), + ValidityRequirement::Zero => format!( + "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" + ), + ValidityRequirement::UninitMitigated0x01Fill => format!( + "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" + ), + ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), + }; + + Self::panic_nounwind(ecx, &msg)?; + // Skip the `return_to_block` at the end (we panicked, we do not return). + return interp_ok(None); + } + } + _ => { // We haven't handled the intrinsic, let's see if we can use a fallback body. if ecx.tcx.intrinsic(instance.def_id()).unwrap().must_be_overridden { diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index d7cede71293..378ed6d0e10 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -7,7 +7,7 @@ use std::assert_matches::assert_matches; use rustc_abi::Size; use rustc_apfloat::ieee::{Double, Half, Quad, Single}; use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; -use rustc_middle::ty::layout::{TyAndLayout, ValidityRequirement}; +use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_middle::{bug, ty}; use rustc_span::{Symbol, sym}; @@ -17,8 +17,8 @@ use super::memory::MemoryKind; use super::util::ensure_monomorphic_enough; use super::{ Allocation, CheckInAllocMsg, ConstAllocation, ImmTy, InterpCx, InterpResult, Machine, OpTy, - PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_inval, err_ub_custom, - err_unsup_format, interp_ok, throw_inval, throw_ub_custom, throw_ub_format, + PlaceTy, Pointer, PointerArithmetic, Provenance, Scalar, err_ub_custom, err_unsup_format, + interp_ok, throw_inval, throw_ub_custom, throw_ub_format, }; use crate::fluent_generated as fluent; @@ -372,41 +372,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.exact_div(&val, &size, dest)?; } - sym::assert_inhabited - | sym::assert_zero_valid - | sym::assert_mem_uninitialized_valid => { - let ty = instance.args.type_at(0); - let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap(); - - let should_panic = !self - .tcx - .check_validity_requirement((requirement, self.typing_env.as_query_input(ty))) - .map_err(|_| err_inval!(TooGeneric))?; - - if should_panic { - let layout = self.layout_of(ty)?; - - let msg = match requirement { - // For *all* intrinsics we first check `is_uninhabited` to give a more specific - // error message. - _ if layout.is_uninhabited() => format!( - "aborted execution: attempted to instantiate uninhabited type `{ty}`" - ), - ValidityRequirement::Inhabited => bug!("handled earlier"), - ValidityRequirement::Zero => format!( - "aborted execution: attempted to zero-initialize type `{ty}`, which is invalid" - ), - ValidityRequirement::UninitMitigated0x01Fill => format!( - "aborted execution: attempted to leave type `{ty}` uninitialized, which is invalid" - ), - ValidityRequirement::Uninit => bug!("assert_uninit_valid doesn't exist"), - }; - - M::panic_nounwind(self, &msg)?; - // Skip the `return_to_block` at the end (we panicked, we do not return). - return interp_ok(true); - } - } sym::simd_insert => { let index = u64::from(self.read_scalar(&args[1])?.to_u32()?); let elem = &args[2]; |
