place evaluation: require the original pointer to be aligned if an access happens

This commit is contained in:
Ralf Jung 2023-09-05 15:12:18 +02:00
parent ea9a24e32e
commit f3f9b795bd
22 changed files with 266 additions and 219 deletions

View file

@ -10,7 +10,7 @@ use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
use rustc_middle::ty::{ConstInt, Ty, TyCtxt};
use rustc_middle::{mir, ty};
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size};
use rustc_target::abi::{self, Abi, HasDataLayout, Size};
use super::{
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, Frame, InterpCx, InterpResult,
@ -44,12 +44,16 @@ impl<Prov: Provenance> From<Scalar<Prov>> for Immediate<Prov> {
}
impl<Prov: Provenance> Immediate<Prov> {
pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
Immediate::Scalar(Scalar::from_pointer(ptr, cx))
}
pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
Immediate::Scalar(Scalar::from_maybe_pointer(ptr, cx))
pub fn new_pointer_with_meta(
ptr: Pointer<Option<Prov>>,
meta: MemPlaceMeta<Prov>,
cx: &impl HasDataLayout,
) -> Self {
let ptr = Scalar::from_maybe_pointer(ptr, cx);
match meta {
MemPlaceMeta::None => Immediate::from(ptr),
MemPlaceMeta::Meta(meta) => Immediate::ScalarPair(ptr, meta),
}
}
pub fn new_slice(ptr: Pointer<Option<Prov>>, len: u64, cx: &impl HasDataLayout) -> Self {
@ -328,14 +332,6 @@ pub(super) enum Operand<Prov: Provenance = AllocId> {
pub struct OpTy<'tcx, Prov: Provenance = AllocId> {
op: Operand<Prov>, // Keep this private; it helps enforce invariants.
pub layout: TyAndLayout<'tcx>,
/// rustc does not have a proper way to represent the type of a field of a `repr(packed)` struct:
/// it needs to have a different alignment than the field type would usually have.
/// So we represent this here with a separate field that "overwrites" `layout.align`.
/// This means `layout.align` should never be used for an `OpTy`!
/// `None` means "alignment does not matter since this is a by-value operand"
/// (`Operand::Immediate`); this field is only relevant for `Operand::Indirect`.
/// Also CTFE ignores alignment anyway, so this is for Miri only.
pub align: Option<Align>,
}
impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
@ -351,18 +347,14 @@ impl<Prov: Provenance> std::fmt::Debug for OpTy<'_, Prov> {
impl<'tcx, Prov: Provenance> From<ImmTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
#[inline(always)]
fn from(val: ImmTy<'tcx, Prov>) -> Self {
OpTy { op: Operand::Immediate(val.imm), layout: val.layout, align: None }
OpTy { op: Operand::Immediate(val.imm), layout: val.layout }
}
}
impl<'tcx, Prov: Provenance> From<MPlaceTy<'tcx, Prov>> for OpTy<'tcx, Prov> {
#[inline(always)]
fn from(mplace: MPlaceTy<'tcx, Prov>) -> Self {
OpTy {
op: Operand::Indirect(*mplace.mplace()),
layout: mplace.layout,
align: Some(mplace.align),
}
OpTy { op: Operand::Indirect(*mplace.mplace()), layout: mplace.layout }
}
}
@ -635,7 +627,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
throw_inval!(ConstPropNonsense);
}
}
Ok(OpTy { op, layout, align: Some(layout.align.abi) })
Ok(OpTy { op, layout })
}
/// Every place can be read from, so we can turn them into an operand.
@ -650,16 +642,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Right((frame, local, offset)) => {
debug_assert!(place.layout.is_sized()); // only sized locals can ever be `Place::Local`.
let base = self.local_to_op(&self.stack()[frame], local, None)?;
let mut field = match offset {
Ok(match offset {
Some(offset) => base.offset(offset, place.layout, self)?,
None => {
// In the common case this hasn't been projected.
debug_assert_eq!(place.layout, base.layout);
base
}
};
field.align = Some(place.align);
Ok(field)
})
}
}
}
@ -747,27 +737,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
})
};
let layout = from_known_layout(self.tcx, self.param_env, layout, || self.layout_of(ty))?;
let op = match val_val {
let imm = match val_val {
mir::ConstValue::Indirect { alloc_id, offset } => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen.
let ptr = self.global_base_pointer(Pointer::new(alloc_id, offset))?;
Operand::Indirect(MemPlace::from_ptr(ptr.into()))
return Ok(self.ptr_to_mplace(ptr.into(), layout).into());
}
mir::ConstValue::Scalar(x) => Operand::Immediate(adjust_scalar(x)?.into()),
mir::ConstValue::ZeroSized => Operand::Immediate(Immediate::Uninit),
mir::ConstValue::Scalar(x) => adjust_scalar(x)?.into(),
mir::ConstValue::ZeroSized => Immediate::Uninit,
mir::ConstValue::Slice { data, meta } => {
// We rely on mutability being set correctly in `data` to prevent writes
// where none should happen.
let ptr = Pointer::new(self.tcx.reserve_and_set_memory_alloc(data), Size::ZERO);
Operand::Immediate(Immediate::new_slice(
self.global_base_pointer(ptr)?.into(),
meta,
self,
))
Immediate::new_slice(self.global_base_pointer(ptr)?.into(), meta, self)
}
};
Ok(OpTy { op, layout, align: Some(layout.align.abi) })
Ok(OpTy { op: Operand::Immediate(imm), layout })
}
}
@ -780,6 +766,6 @@ mod size_asserts {
static_assert_size!(Immediate, 48);
static_assert_size!(ImmTy<'_>, 64);
static_assert_size!(Operand, 56);
static_assert_size!(OpTy<'_>, 80);
static_assert_size!(OpTy<'_>, 72);
// tidy-alphabetical-end
}