Rollup merge of #108505 - Nilstrieb:further-unify-validity-intrinsics, r=michaelwoerister
Further unify validity intrinsics Also merges the inhabitedness check into the query to further unify the code paths. Depends on #108364
This commit is contained in:
commit
5af16c1655
11 changed files with 118 additions and 162 deletions
|
@ -11,7 +11,7 @@ use rustc_middle::mir::{
|
|||
BinOp, NonDivergingIntrinsic,
|
||||
};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::layout::{InitKind, LayoutOf as _};
|
||||
use rustc_middle::ty::layout::{LayoutOf as _, ValidityRequirement};
|
||||
use rustc_middle::ty::subst::SubstsRef;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
|
@ -418,57 +418,35 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
| sym::assert_zero_valid
|
||||
| sym::assert_mem_uninitialized_valid => {
|
||||
let ty = instance.substs.type_at(0);
|
||||
let layout = self.layout_of(ty)?;
|
||||
let requirement = ValidityRequirement::from_intrinsic(intrinsic_name).unwrap();
|
||||
|
||||
// For *all* intrinsics we first check `is_uninhabited` to give a more specific
|
||||
// error message.
|
||||
if layout.abi.is_uninhabited() {
|
||||
// The run-time intrinsic panics just to get a good backtrace; here we abort
|
||||
// since there is no problem showing a backtrace even for aborts.
|
||||
M::abort(
|
||||
self,
|
||||
format!(
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.check_validity_requirement((requirement, self.param_env.and(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.abi.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 `{}`, which is invalid",
|
||||
ty
|
||||
),
|
||||
ValidityRequirement::UninitMitigated0x01Fill => format!(
|
||||
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
|
||||
ty
|
||||
),
|
||||
};
|
||||
|
||||
if intrinsic_name == sym::assert_zero_valid {
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.check_validity_of_init((InitKind::Zero, self.param_env.and(ty)))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
M::abort(
|
||||
self,
|
||||
format!(
|
||||
"aborted execution: attempted to zero-initialize type `{}`, which is invalid",
|
||||
ty
|
||||
),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
if intrinsic_name == sym::assert_mem_uninitialized_valid {
|
||||
let should_panic = !self
|
||||
.tcx
|
||||
.check_validity_of_init((
|
||||
InitKind::UninitMitigated0x01Fill,
|
||||
self.param_env.and(ty),
|
||||
))
|
||||
.map_err(|_| err_inval!(TooGeneric))?;
|
||||
|
||||
if should_panic {
|
||||
M::abort(
|
||||
self,
|
||||
format!(
|
||||
"aborted execution: attempted to leave type `{}` uninitialized, which is invalid",
|
||||
ty
|
||||
),
|
||||
)?;
|
||||
}
|
||||
M::abort(self, msg)?;
|
||||
}
|
||||
}
|
||||
sym::simd_insert => {
|
||||
|
|
|
@ -61,7 +61,7 @@ pub fn provide(providers: &mut Providers) {
|
|||
let (param_env, value) = param_env_and_value.into_parts();
|
||||
const_eval::deref_mir_constant(tcx, param_env, value)
|
||||
};
|
||||
providers.check_validity_of_init = |tcx, (init_kind, param_env_and_ty)| {
|
||||
util::might_permit_raw_init(tcx, init_kind, param_env_and_ty)
|
||||
providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| {
|
||||
util::check_validity_requirement(tcx, init_kind, param_env_and_ty)
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use rustc_middle::ty::layout::{InitKind, LayoutCx, LayoutError, LayoutOf, TyAndLayout};
|
||||
use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
|
||||
use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
|
||||
use rustc_session::Limit;
|
||||
use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
|
||||
|
@ -18,16 +18,23 @@ use crate::interpret::{InterpCx, MemoryKind, OpTy};
|
|||
/// Rust UB as long as there is no risk of miscompilations. The `strict_init_checks` can be set to
|
||||
/// do a full check against Rust UB instead (in which case we will also ignore the 0x01-filling and
|
||||
/// to the full uninit check).
|
||||
pub fn might_permit_raw_init<'tcx>(
|
||||
pub fn check_validity_requirement<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
kind: InitKind,
|
||||
kind: ValidityRequirement,
|
||||
param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let layout = tcx.layout_of(param_env_and_ty)?;
|
||||
|
||||
// There is nothing strict or lax about inhabitedness.
|
||||
if kind == ValidityRequirement::Inhabited {
|
||||
return Ok(!layout.abi.is_uninhabited());
|
||||
}
|
||||
|
||||
if tcx.sess.opts.unstable_opts.strict_init_checks {
|
||||
might_permit_raw_init_strict(tcx.layout_of(param_env_and_ty)?, tcx, kind)
|
||||
might_permit_raw_init_strict(layout, tcx, kind)
|
||||
} else {
|
||||
let layout_cx = LayoutCx { tcx, param_env: param_env_and_ty.param_env };
|
||||
might_permit_raw_init_lax(tcx.layout_of(param_env_and_ty)?, &layout_cx, kind)
|
||||
might_permit_raw_init_lax(layout, &layout_cx, kind)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +43,7 @@ pub fn might_permit_raw_init<'tcx>(
|
|||
fn might_permit_raw_init_strict<'tcx>(
|
||||
ty: TyAndLayout<'tcx>,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
kind: InitKind,
|
||||
kind: ValidityRequirement,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let machine = CompileTimeInterpreter::new(
|
||||
Limit::new(0),
|
||||
|
@ -50,7 +57,7 @@ fn might_permit_raw_init_strict<'tcx>(
|
|||
.allocate(ty, MemoryKind::Machine(crate::const_eval::MemoryKind::Heap))
|
||||
.expect("OOM: failed to allocate for uninit check");
|
||||
|
||||
if kind == InitKind::Zero {
|
||||
if kind == ValidityRequirement::Zero {
|
||||
cx.write_bytes_ptr(
|
||||
allocated.ptr,
|
||||
std::iter::repeat(0_u8).take(ty.layout.size().bytes_usize()),
|
||||
|
@ -72,15 +79,18 @@ fn might_permit_raw_init_strict<'tcx>(
|
|||
fn might_permit_raw_init_lax<'tcx>(
|
||||
this: TyAndLayout<'tcx>,
|
||||
cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
|
||||
init_kind: InitKind,
|
||||
init_kind: ValidityRequirement,
|
||||
) -> Result<bool, LayoutError<'tcx>> {
|
||||
let scalar_allows_raw_init = move |s: Scalar| -> bool {
|
||||
match init_kind {
|
||||
InitKind::Zero => {
|
||||
ValidityRequirement::Inhabited => {
|
||||
bug!("ValidityRequirement::Inhabited should have been handled above")
|
||||
}
|
||||
ValidityRequirement::Zero => {
|
||||
// The range must contain 0.
|
||||
s.valid_range(cx).contains(0)
|
||||
}
|
||||
InitKind::UninitMitigated0x01Fill => {
|
||||
ValidityRequirement::UninitMitigated0x01Fill => {
|
||||
// The range must include an 0x01-filled buffer.
|
||||
let mut val: u128 = 0x01;
|
||||
for _ in 1..s.size(cx).bytes() {
|
|
@ -1,14 +1,14 @@
|
|||
mod alignment;
|
||||
mod call_kind;
|
||||
mod check_validity_requirement;
|
||||
pub mod collect_writes;
|
||||
mod compare_types;
|
||||
mod find_self_call;
|
||||
mod might_permit_raw_init;
|
||||
mod type_name;
|
||||
|
||||
pub use self::alignment::is_disaligned;
|
||||
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
|
||||
pub use self::check_validity_requirement::check_validity_requirement;
|
||||
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
|
||||
pub use self::find_self_call::find_self_call;
|
||||
pub use self::might_permit_raw_init::might_permit_raw_init;
|
||||
pub use self::type_name::type_name;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue