1
Fork 0

adjustions and cleanup to make Miri build again

This commit is contained in:
Ralf Jung 2021-07-14 22:10:17 +02:00
parent 8932aebfdf
commit f4b61ba509
13 changed files with 134 additions and 201 deletions

View file

@ -171,7 +171,7 @@ impl<Tag> From<Pointer<Tag>> for Pointer<Option<Tag>> {
} }
impl<Tag> Pointer<Option<Tag>> { impl<Tag> Pointer<Option<Tag>> {
pub fn into_pointer_or_offset(self) -> Result<Pointer<Tag>, Size> { pub fn into_pointer_or_addr(self) -> Result<Pointer<Tag>, Size> {
match self.provenance { match self.provenance {
Some(tag) => Ok(Pointer::new(tag, self.offset)), Some(tag) => Ok(Pointer::new(tag, self.offset)),
None => Err(self.offset), None => Err(self.offset),
@ -187,6 +187,13 @@ impl<Tag> Pointer<Option<Tag>> {
} }
} }
impl<Tag> Pointer<Option<Tag>> {
#[inline(always)]
pub fn null() -> Self {
Pointer { provenance: None, offset: Size::ZERO }
}
}
impl<'tcx, Tag> Pointer<Tag> { impl<'tcx, Tag> Pointer<Tag> {
#[inline(always)] #[inline(always)]
pub fn new(provenance: Tag, offset: Size) -> Self { pub fn new(provenance: Tag, offset: Size) -> Self {
@ -206,9 +213,14 @@ impl<'tcx, Tag> Pointer<Tag> {
where where
Tag: Provenance, Tag: Provenance,
{ {
// FIXME: This is wrong! `self.offset` might be an absolute address.
Pointer { offset: self.offset, provenance: self.provenance.erase_for_fmt() } Pointer { offset: self.offset, provenance: self.provenance.erase_for_fmt() }
} }
pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self {
Pointer { provenance: f(self.provenance), ..self }
}
#[inline] #[inline]
pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> { pub fn offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
Ok(Pointer { Ok(Pointer {

View file

@ -6,7 +6,7 @@ use rustc_apfloat::{
Float, Float,
}; };
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; use rustc_target::abi::{HasDataLayout, Size};
use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt}; use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt};
@ -179,7 +179,7 @@ impl<Tag> From<ScalarInt> for Scalar<Tag> {
} }
} }
impl<'tcx, Tag> Scalar<Tag> { impl<Tag> Scalar<Tag> {
pub const ZST: Self = Scalar::Int(ScalarInt::ZST); pub const ZST: Self = Scalar::Int(ScalarInt::ZST);
#[inline(always)] #[inline(always)]
@ -202,56 +202,6 @@ impl<'tcx, Tag> Scalar<Tag> {
Scalar::Int(ScalarInt::null(cx.pointer_size())) Scalar::Int(ScalarInt::null(cx.pointer_size()))
} }
#[inline(always)]
fn ptr_op(
self,
dl: &TargetDataLayout,
f_int: impl FnOnce(u64) -> InterpResult<'tcx, u64>,
f_ptr: impl FnOnce(Pointer<Tag>) -> InterpResult<'tcx, Pointer<Tag>>,
) -> InterpResult<'tcx, Self> {
match self {
Scalar::Int(int) => Ok(Scalar::Int(int.ptr_sized_op(dl, f_int)?)),
Scalar::Ptr(ptr, sz) => {
debug_assert_eq!(u64::from(sz), dl.pointer_size().bytes());
Ok(Scalar::Ptr(f_ptr(ptr)?, sz))
}
}
}
#[inline]
pub fn ptr_offset(self, i: Size, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
let dl = cx.data_layout();
self.ptr_op(dl, |int| dl.offset(int, i.bytes()), |ptr| ptr.offset(i, dl))
}
#[inline]
pub fn ptr_wrapping_offset(self, i: Size, cx: &impl HasDataLayout) -> Self {
let dl = cx.data_layout();
self.ptr_op(
dl,
|int| Ok(dl.overflowing_offset(int, i.bytes()).0),
|ptr| Ok(ptr.wrapping_offset(i, dl)),
)
.unwrap()
}
#[inline]
pub fn ptr_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> InterpResult<'tcx, Self> {
let dl = cx.data_layout();
self.ptr_op(dl, |int| dl.signed_offset(int, i), |ptr| ptr.signed_offset(i, dl))
}
#[inline]
pub fn ptr_wrapping_signed_offset(self, i: i64, cx: &impl HasDataLayout) -> Self {
let dl = cx.data_layout();
self.ptr_op(
dl,
|int| Ok(dl.overflowing_signed_offset(int, i).0),
|ptr| Ok(ptr.wrapping_signed_offset(i, dl)),
)
.unwrap()
}
#[inline] #[inline]
pub fn from_bool(b: bool) -> Self { pub fn from_bool(b: bool) -> Self {
Scalar::Int(b.into()) Scalar::Int(b.into())

View file

@ -1,7 +1,7 @@
use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float; use rustc_apfloat::Float;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_target::abi::{Size, TargetDataLayout}; use rustc_target::abi::Size;
use std::convert::{TryFrom, TryInto}; use std::convert::{TryFrom, TryInto};
use std::fmt; use std::fmt;
@ -193,15 +193,6 @@ impl ScalarInt {
self.data == 0 self.data == 0
} }
pub(crate) fn ptr_sized_op<E>(
self,
dl: &TargetDataLayout,
f_int: impl FnOnce(u64) -> Result<u64, E>,
) -> Result<Self, E> {
assert_eq!(u64::from(self.size), dl.pointer_size.bytes());
Ok(Self::try_from_uint(f_int(u64::try_from(self.data).unwrap())?, self.size()).unwrap())
}
#[inline] #[inline]
pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> { pub fn try_from_uint(i: impl Into<u128>, size: Size) -> Option<Self> {
let data = i.into(); let data = i.into();

View file

@ -312,7 +312,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
align, align,
interpret::MemoryKind::Machine(MemoryKind::Heap), interpret::MemoryKind::Machine(MemoryKind::Heap),
)?; )?;
ecx.write_scalar(Scalar::from_pointer(ptr, &*ecx.tcx), dest)?; ecx.write_pointer(ptr, dest)?;
} }
_ => { _ => {
return Err(ConstEvalErrKind::NeedsRfc(format!( return Err(ConstEvalErrKind::NeedsRfc(format!(

View file

@ -35,7 +35,7 @@ pub(crate) fn const_caller_location(
if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() { if intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &loc_place).is_err() {
bug!("intern_const_alloc_recursive should not error in this case") bug!("intern_const_alloc_recursive should not error in this case")
} }
ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_offset().unwrap(), &tcx)) ConstValue::Scalar(Scalar::from_pointer(loc_place.ptr.into_pointer_or_addr().unwrap(), &tcx))
} }
/// Convert an evaluated constant to a type level constant /// Convert an evaluated constant to a type level constant

View file

@ -57,7 +57,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
.ok_or_else(|| err_inval!(TooGeneric))?; .ok_or_else(|| err_inval!(TooGeneric))?;
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
self.write_scalar(Scalar::from_pointer(fn_ptr, &*self.tcx), dest)?; self.write_pointer(fn_ptr, dest)?;
} }
_ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty), _ => span_bug!(self.cur_span(), "reify fn pointer on {:?}", src.layout.ty),
} }
@ -88,7 +88,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce,
); );
let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance));
self.write_scalar(Scalar::from_pointer(fn_ptr, &*self.tcx), dest)?; self.write_pointer(fn_ptr, dest)?;
} }
_ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
} }

View file

@ -23,7 +23,7 @@ use rustc_middle::ty::{self, layout::TyAndLayout, Ty};
use rustc_ast::Mutability; use rustc_ast::Mutability;
use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, ValueVisitor}; use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy, ValueVisitor};
use crate::const_eval; use crate::const_eval;
pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine< pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
@ -425,11 +425,11 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
layout: TyAndLayout<'tcx>, layout: TyAndLayout<'tcx>,
f: impl FnOnce( f: impl FnOnce(
&mut InterpCx<'mir, 'tcx, M>, &mut InterpCx<'mir, 'tcx, M>,
&MPlaceTy<'tcx, M::PointerTag>, &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, ()>, ) -> InterpResult<'tcx, ()>,
) -> InterpResult<'tcx, &'tcx Allocation> { ) -> InterpResult<'tcx, &'tcx Allocation> {
let dest = self.allocate(layout, MemoryKind::Stack)?; let dest = self.allocate(layout, MemoryKind::Stack)?;
f(self, &dest)?; f(self, &dest.into())?;
let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1; let mut alloc = self.memory.alloc_map.remove(&dest.ptr.provenance.unwrap()).unwrap().1;
alloc.mutability = Mutability::Not; alloc.mutability = Mutability::Not;
Ok(self.tcx.intern_const_alloc(alloc)) Ok(self.tcx.intern_const_alloc(alloc))

View file

@ -337,17 +337,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let pointee_ty = substs.type_at(0); let pointee_ty = substs.type_at(0);
let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?; let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
self.write_scalar(Scalar::from_maybe_pointer(offset_ptr, self), dest)?; self.write_pointer(offset_ptr, dest)?;
} }
sym::arith_offset => { sym::arith_offset => {
let ptr = self.read_scalar(&args[0])?.check_init()?; let ptr = self.read_pointer(&args[0])?;
let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?; let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?;
let pointee_ty = substs.type_at(0); let pointee_ty = substs.type_at(0);
let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
let offset_bytes = offset_count.wrapping_mul(pointee_size); let offset_bytes = offset_count.wrapping_mul(pointee_size);
let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self); let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, self);
self.write_scalar(offset_ptr, dest)?; self.write_pointer(offset_ptr, dest)?;
} }
sym::ptr_offset_from => { sym::ptr_offset_from => {
let a = self.read_immediate(&args[0])?.to_scalar()?; let a = self.read_immediate(&args[0])?.to_scalar()?;
@ -379,8 +379,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// General case: we need two pointers. // General case: we need two pointers.
let a = self.scalar_to_ptr(a); let a = self.scalar_to_ptr(a);
let b = self.scalar_to_ptr(b); let b = self.scalar_to_ptr(b);
let (a_alloc_id, a_offset, _) = self.memory.ptr_force_alloc(a)?; let (a_alloc_id, a_offset, _) = self.memory.ptr_get_alloc(a)?;
let (b_alloc_id, b_offset, _) = self.memory.ptr_force_alloc(b)?; let (b_alloc_id, b_offset, _) = self.memory.ptr_get_alloc(b)?;
if a_alloc_id != b_alloc_id { if a_alloc_id != b_alloc_id {
throw_ub_format!( throw_ub_format!(
"ptr_offset_from cannot compute offset of pointers into different \ "ptr_offset_from cannot compute offset of pointers into different \

View file

@ -7,14 +7,14 @@ use std::fmt::Debug;
use std::hash::Hash; use std::hash::Hash;
use rustc_middle::mir; use rustc_middle::mir;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_target::abi::Size; use rustc_target::abi::Size;
use rustc_target::spec::abi::Abi; use rustc_target::spec::abi::Abi;
use super::{ use super::{
AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, LocalValue, MemPlace, Memory, AllocId, AllocRange, Allocation, Frame, ImmTy, InterpCx, InterpResult, LocalValue, MemPlace,
MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar, StackPopUnwind,
}; };
/// Data returned by Machine::stack_pop, /// Data returned by Machine::stack_pop,
@ -262,34 +262,40 @@ pub trait Machine<'mir, 'tcx>: Sized {
} }
/// Return the `AllocId` for the given thread-local static in the current thread. /// Return the `AllocId` for the given thread-local static in the current thread.
fn thread_local_static_alloc_id( fn thread_local_static_base_pointer(
_ecx: &mut InterpCx<'mir, 'tcx, Self>, _ecx: &mut InterpCx<'mir, 'tcx, Self>,
def_id: DefId, def_id: DefId,
) -> InterpResult<'tcx, AllocId> { ) -> InterpResult<'tcx, Pointer<Self::PointerTag>> {
throw_unsup!(ThreadLocalStatic(def_id)) throw_unsup!(ThreadLocalStatic(def_id))
} }
/// Return the `AllocId` backing the given `extern static`. /// Return the root pointer for the given `extern static`.
fn extern_static_alloc_id( fn extern_static_base_pointer(
mem: &Memory<'mir, 'tcx, Self>, mem: &Memory<'mir, 'tcx, Self>,
def_id: DefId, def_id: DefId,
) -> InterpResult<'tcx, AllocId> { ) -> InterpResult<'tcx, Pointer<Self::PointerTag>>;
// Use the `AllocId` associated with the `DefId`. Any actual *access* will fail.
Ok(mem.tcx.create_static_alloc(def_id))
}
/// Return the "base" tag for the given *global* allocation: the one that is used for direct /// Return a "base" pointer for the given allocation: the one that is used for direct
/// accesses to this static/const/fn allocation. If `id` is not a global allocation, /// accesses to this static/const/fn allocation, or the one returned from the heap allocator.
/// this will return an unusable tag (i.e., accesses will be UB)!
/// ///
/// Called on the id returned by `thread_local_static_alloc_id` and `extern_static_alloc_id`, if needed. /// Not called on `extern` or thread-local statics (those use the methods above).
/// fn tag_alloc_base_pointer(
/// `offset` is relative inside the allocation. mem: &Memory<'mir, 'tcx, Self>,
fn tag_global_base_pointer(
memory_extra: &Self::MemoryExtra,
ptr: Pointer, ptr: Pointer,
) -> Pointer<Self::PointerTag>; ) -> Pointer<Self::PointerTag>;
/// "Int-to-pointer cast"
fn ptr_from_addr(
mem: &Memory<'mir, 'tcx, Self>,
addr: u64,
) -> Pointer<Option<Self::PointerTag>>;
/// Convert a pointer with provenance into an allocation-offset pair.
fn ptr_get_alloc(
mem: &Memory<'mir, 'tcx, Self>,
ptr: Pointer<Self::PointerTag>,
) -> (AllocId, Size);
/// Called to initialize the "extra" state of an allocation and make the pointers /// Called to initialize the "extra" state of an allocation and make the pointers
/// it contains (in relocations) tagged. The way we construct allocations is /// it contains (in relocations) tagged. The way we construct allocations is
/// to always first construct it without extra and then add the extra. /// to always first construct it without extra and then add the extra.
@ -303,16 +309,13 @@ pub trait Machine<'mir, 'tcx>: Sized {
/// allocation (because a copy had to be done to add tags or metadata), machine memory will /// allocation (because a copy had to be done to add tags or metadata), machine memory will
/// cache the result. (This relies on `AllocMap::get_or` being able to add the /// cache the result. (This relies on `AllocMap::get_or` being able to add the
/// owned allocation to the map even when the map is shared.) /// owned allocation to the map even when the map is shared.)
///
/// Also return the "base" tag to use for this allocation: the one that is used for direct
/// accesses to this allocation. If `kind == STATIC_KIND`, this tag must be consistent
/// with `tag_global_base_pointer`.
fn init_allocation_extra<'b>( fn init_allocation_extra<'b>(
memory_extra: &Self::MemoryExtra, memory_extra: &Self::MemoryExtra,
tcx: TyCtxt<'tcx>,
id: AllocId, id: AllocId,
alloc: Cow<'b, Allocation>, alloc: Cow<'b, Allocation>,
kind: Option<MemoryKind<Self::MemoryKind>>, kind: Option<MemoryKind<Self::MemoryKind>>,
) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag); ) -> Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>;
/// Hook for performing extra checks on a memory read access. /// Hook for performing extra checks on a memory read access.
/// ///
@ -323,8 +326,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
fn memory_read( fn memory_read(
_memory_extra: &Self::MemoryExtra, _memory_extra: &Self::MemoryExtra,
_alloc_extra: &Self::AllocExtra, _alloc_extra: &Self::AllocExtra,
_ptr: Pointer<Self::PointerTag>, _tag: Self::PointerTag,
_size: Size, _range: AllocRange,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
Ok(()) Ok(())
} }
@ -334,8 +337,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
fn memory_written( fn memory_written(
_memory_extra: &mut Self::MemoryExtra, _memory_extra: &mut Self::MemoryExtra,
_alloc_extra: &mut Self::AllocExtra, _alloc_extra: &mut Self::AllocExtra,
_ptr: Pointer<Self::PointerTag>, _tag: Self::PointerTag,
_size: Size, _range: AllocRange,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
Ok(()) Ok(())
} }
@ -345,17 +348,8 @@ pub trait Machine<'mir, 'tcx>: Sized {
fn memory_deallocated( fn memory_deallocated(
_memory_extra: &mut Self::MemoryExtra, _memory_extra: &mut Self::MemoryExtra,
_alloc_extra: &mut Self::AllocExtra, _alloc_extra: &mut Self::AllocExtra,
_ptr: Pointer<Self::PointerTag>, _tag: Self::PointerTag,
_size: Size, _range: AllocRange,
) -> InterpResult<'tcx> {
Ok(())
}
/// Called after initializing static memory using the interpreter.
fn after_static_mem_initialized(
_ecx: &mut InterpCx<'mir, 'tcx, Self>,
_ptr: Pointer<Self::PointerTag>,
_size: Size,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
Ok(()) Ok(())
} }
@ -400,19 +394,6 @@ pub trait Machine<'mir, 'tcx>: Sized {
// By default, we do not support unwinding from panics // By default, we do not support unwinding from panics
Ok(StackPopJump::Normal) Ok(StackPopJump::Normal)
} }
/// "Int-to-pointer cast"
fn ptr_from_addr(
mem: &Memory<'mir, 'tcx, Self>,
addr: u64,
) -> Pointer<Option<Self::PointerTag>>;
/// Convert a pointer with provenance into an allocation-offset pair,
/// or a `None` with an absolute address if that conversion is not possible.
fn ptr_get_alloc(
mem: &Memory<'mir, 'tcx, Self>,
ptr: Pointer<Self::PointerTag>,
) -> (Option<AllocId>, Size);
} }
// A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines // A lot of the flexibility above is just needed for `Miri`, but all "compile-time" machines
@ -461,17 +442,26 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
#[inline(always)] #[inline(always)]
fn init_allocation_extra<'b>( fn init_allocation_extra<'b>(
_memory_extra: &Self::MemoryExtra, _memory_extra: &Self::MemoryExtra,
id: AllocId, _tcx: TyCtxt<$tcx>,
_id: AllocId,
alloc: Cow<'b, Allocation>, alloc: Cow<'b, Allocation>,
_kind: Option<MemoryKind<Self::MemoryKind>>, _kind: Option<MemoryKind<Self::MemoryKind>>,
) -> (Cow<'b, Allocation<Self::PointerTag>>, Self::PointerTag) { ) -> Cow<'b, Allocation<Self::PointerTag>> {
// We do not use a tag so we can just cheaply forward the allocation // We do not use a tag so we can just cheaply forward the allocation
(alloc, id) alloc
}
fn extern_static_base_pointer(
mem: &Memory<$mir, $tcx, Self>,
def_id: DefId,
) -> InterpResult<$tcx, Pointer> {
// Use the `AllocId` associated with the `DefId`. Any actual *access* will fail.
Ok(Pointer::new(mem.tcx.create_static_alloc(def_id), Size::ZERO))
} }
#[inline(always)] #[inline(always)]
fn tag_global_base_pointer( fn tag_alloc_base_pointer(
_memory_extra: &Self::MemoryExtra, _mem: &Memory<$mir, $tcx, Self>,
ptr: Pointer<AllocId>, ptr: Pointer<AllocId>,
) -> Pointer<AllocId> { ) -> Pointer<AllocId> {
ptr ptr
@ -486,9 +476,9 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
fn ptr_get_alloc( fn ptr_get_alloc(
_mem: &Memory<$mir, $tcx, Self>, _mem: &Memory<$mir, $tcx, Self>,
ptr: Pointer<AllocId>, ptr: Pointer<AllocId>,
) -> (Option<AllocId>, Size) { ) -> (AllocId, Size) {
// We know `offset` is relative to the allocation, so we can use `into_parts`. // We know `offset` is relative to the allocation, so we can use `into_parts`.
let (alloc_id, offset) = ptr.into_parts(); let (alloc_id, offset) = ptr.into_parts();
(Some(alloc_id), offset) (alloc_id, offset)
} }
} }

View file

@ -168,20 +168,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// We know `offset` is relative to the allocation, so we can use `into_parts`. // We know `offset` is relative to the allocation, so we can use `into_parts`.
let (alloc_id, offset) = ptr.into_parts(); let (alloc_id, offset) = ptr.into_parts();
// We need to handle `extern static`. // We need to handle `extern static`.
let alloc_id = match self.tcx.get_global_alloc(alloc_id) { match self.tcx.get_global_alloc(alloc_id) {
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => { Some(GlobalAlloc::Static(def_id)) if self.tcx.is_thread_local_static(def_id) => {
bug!("global memory cannot point to thread-local static") bug!("global memory cannot point to thread-local static")
} }
Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => { Some(GlobalAlloc::Static(def_id)) if self.tcx.is_foreign_item(def_id) => {
M::extern_static_alloc_id(self, def_id)? return M::extern_static_base_pointer(self, def_id);
} }
_ => { _ => {}
// No need to change the `AllocId`. }
alloc_id
}
};
// And we need to get the tag. // And we need to get the tag.
Ok(M::tag_global_base_pointer(&self.extra, Pointer::new(alloc_id, offset))) Ok(M::tag_alloc_base_pointer(self, Pointer::new(alloc_id, offset)))
} }
pub fn create_fn_alloc( pub fn create_fn_alloc(
@ -236,9 +233,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
"dynamically allocating global memory" "dynamically allocating global memory"
); );
// This is a new allocation, not a new global one, so no `global_base_ptr`. // This is a new allocation, not a new global one, so no `global_base_ptr`.
let (alloc, tag) = M::init_allocation_extra(&self.extra, id, Cow::Owned(alloc), Some(kind)); let alloc = M::init_allocation_extra(&self.extra, self.tcx, id, Cow::Owned(alloc), Some(kind));
self.alloc_map.insert(id, (kind, alloc.into_owned())); self.alloc_map.insert(id, (kind, alloc.into_owned()));
Pointer::new(tag, Size::ZERO) M::tag_alloc_base_pointer(self, Pointer::new(id, Size::ZERO))
} }
pub fn reallocate( pub fn reallocate(
@ -249,7 +246,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
new_align: Align, new_align: Align,
kind: MemoryKind<M::MemoryKind>, kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx, Pointer<M::PointerTag>> { ) -> InterpResult<'tcx, Pointer<M::PointerTag>> {
let (alloc_id, offset, ptr) = self.ptr_force_alloc(ptr)?; let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?;
if offset.bytes() != 0 { if offset.bytes() != 0 {
throw_ub_format!( throw_ub_format!(
"reallocating {:?} which does not point to the beginning of an object", "reallocating {:?} which does not point to the beginning of an object",
@ -284,7 +281,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
old_size_and_align: Option<(Size, Align)>, old_size_and_align: Option<(Size, Align)>,
kind: MemoryKind<M::MemoryKind>, kind: MemoryKind<M::MemoryKind>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
let (alloc_id, offset, ptr) = self.ptr_force_alloc(ptr)?; let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?;
trace!("deallocating: {}", alloc_id); trace!("deallocating: {}", alloc_id);
if offset.bytes() != 0 { if offset.bytes() != 0 {
@ -337,7 +334,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// Let the machine take some extra action // Let the machine take some extra action
let size = alloc.size(); let size = alloc.size();
M::memory_deallocated(&mut self.extra, &mut alloc.extra, ptr, size)?; M::memory_deallocated(&mut self.extra, &mut alloc.extra, ptr.provenance, alloc_range(Size::ZERO, size))?;
// Don't forget to remember size and align of this now-dead allocation // Don't forget to remember size and align of this now-dead allocation
let old = self.dead_alloc_map.insert(alloc_id, (size, alloc.align)); let old = self.dead_alloc_map.insert(alloc_id, (size, alloc.align));
@ -424,7 +421,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
self.ptr_try_get_alloc(ptr) self.ptr_try_get_alloc(ptr)
} else { } else {
// A "real" access, we insist on getting an `AllocId`. // A "real" access, we insist on getting an `AllocId`.
Ok(self.ptr_force_alloc(ptr)?) Ok(self.ptr_get_alloc(ptr)?)
}; };
Ok(match ptr_or_addr { Ok(match ptr_or_addr {
Err(addr) => { Err(addr) => {
@ -530,14 +527,13 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
M::before_access_global(memory_extra, id, alloc, def_id, is_write)?; M::before_access_global(memory_extra, id, alloc, def_id, is_write)?;
let alloc = Cow::Borrowed(alloc); let alloc = Cow::Borrowed(alloc);
// We got tcx memory. Let the machine initialize its "extra" stuff. // We got tcx memory. Let the machine initialize its "extra" stuff.
let (alloc, tag) = M::init_allocation_extra( let alloc = M::init_allocation_extra(
memory_extra, memory_extra,
tcx,
id, // always use the ID we got as input, not the "hidden" one. id, // always use the ID we got as input, not the "hidden" one.
alloc, alloc,
M::GLOBAL_KIND.map(MemoryKind::Machine), M::GLOBAL_KIND.map(MemoryKind::Machine),
); );
// Sanity check that this is the same tag we would have gotten via `global_base_pointer`.
debug_assert!(tag == M::tag_global_base_pointer(memory_extra, id.into()).provenance);
Ok(alloc) Ok(alloc)
} }
@ -596,8 +592,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
}, },
)?; )?;
if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc { if let Some((alloc_id, offset, ptr, alloc)) = ptr_and_alloc {
M::memory_read(&self.extra, &alloc.extra, ptr, size)?;
let range = alloc_range(offset, size); let range = alloc_range(offset, size);
M::memory_read(&self.extra, &alloc.extra, ptr.provenance, range)?;
Ok(Some(AllocRef { alloc, range, tcx: self.tcx, alloc_id })) Ok(Some(AllocRef { alloc, range, tcx: self.tcx, alloc_id }))
} else { } else {
// Even in this branch we have to be sure that we actually access the allocation, in // Even in this branch we have to be sure that we actually access the allocation, in
@ -662,8 +658,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// FIXME: can we somehow avoid looking up the allocation twice here? // FIXME: can we somehow avoid looking up the allocation twice here?
// We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`.
let (alloc, extra) = self.get_raw_mut(alloc_id)?; let (alloc, extra) = self.get_raw_mut(alloc_id)?;
M::memory_written(extra, &mut alloc.extra, ptr, size)?;
let range = alloc_range(offset, size); let range = alloc_range(offset, size);
M::memory_written(extra, &mut alloc.extra, ptr.provenance, range)?;
Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id })) Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id }))
} else { } else {
Ok(None) Ok(None)
@ -756,7 +752,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
&self, &self,
ptr: Pointer<Option<M::PointerTag>>, ptr: Pointer<Option<M::PointerTag>>,
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> { ) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
let (alloc_id, offset, ptr) = self.ptr_force_alloc(ptr)?; let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?;
if offset.bytes() != 0 { if offset.bytes() != 0 {
throw_ub!(InvalidFunctionPointer(ptr.erase_for_fmt())) throw_ub!(InvalidFunctionPointer(ptr.erase_for_fmt()))
} }
@ -1036,7 +1032,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
Some(src_ptr) => src_ptr, Some(src_ptr) => src_ptr,
}; };
let src_alloc = self.get_raw(src_alloc_id)?; let src_alloc = self.get_raw(src_alloc_id)?;
M::memory_read(&self.extra, &src_alloc.extra, src, size)?; let src_range = alloc_range(src_offset, size);
M::memory_read(&self.extra, &src_alloc.extra, src.provenance, src_range)?;
// We need the `dest` ptr for the next operation, so we get it now. // We need the `dest` ptr for the next operation, so we get it now.
// We already did the source checks and called the hooks so we are good to return early. // We already did the source checks and called the hooks so we are good to return early.
let (dest_alloc_id, dest_offset, dest) = match dest_parts { let (dest_alloc_id, dest_offset, dest) = match dest_parts {
@ -1051,23 +1048,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// relocations overlapping the edges; those would not be handled correctly). // relocations overlapping the edges; those would not be handled correctly).
let relocations = src_alloc.prepare_relocation_copy( let relocations = src_alloc.prepare_relocation_copy(
self, self,
alloc_range(src_offset, size), src_range,
dest_offset, dest_offset,
num_copies, num_copies,
); );
// Prepare a copy of the initialization mask. // Prepare a copy of the initialization mask.
let compressed = src_alloc.compress_uninit_range(alloc_range(src_offset, size)); let compressed = src_alloc.compress_uninit_range(src_range);
// This checks relocation edges on the src. // This checks relocation edges on the src.
let src_bytes = src_alloc let src_bytes = src_alloc
.get_bytes_with_uninit_and_ptr(&tcx, alloc_range(src_offset, size)) .get_bytes_with_uninit_and_ptr(&tcx, src_range)
.map_err(|e| e.to_interp_error(src_alloc_id))? .map_err(|e| e.to_interp_error(src_alloc_id))?
.as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
// Destination alloc preparations and access hooks. // Destination alloc preparations and access hooks.
let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?; let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?;
M::memory_written(extra, &mut dest_alloc.extra, dest, size * num_copies)?; let dest_range = alloc_range(dest_offset, size * num_copies);
M::memory_written(extra, &mut dest_alloc.extra, dest.provenance, dest_range)?;
let dest_bytes = dest_alloc let dest_bytes = dest_alloc
.get_bytes_mut_ptr(&tcx, alloc_range(dest_offset, size * num_copies)) .get_bytes_mut_ptr(&tcx, dest_range)
.as_mut_ptr(); .as_mut_ptr();
if compressed.no_bytes_init() { if compressed.no_bytes_init() {
@ -1077,7 +1075,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// This also avoids writing to the target bytes so that the backing allocation is never // This also avoids writing to the target bytes so that the backing allocation is never
// touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary
// operating system this can avoid physically allocating the page. // operating system this can avoid physically allocating the page.
dest_alloc.mark_init(alloc_range(dest_offset, size * num_copies), false); // `Size` multiplication dest_alloc.mark_init(dest_range, false); // `Size` multiplication
dest_alloc.mark_relocation_range(relocations); dest_alloc.mark_relocation_range(relocations);
return Ok(()); return Ok(());
} }
@ -1119,7 +1117,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
// now fill in all the "init" data // now fill in all the "init" data
dest_alloc.mark_compressed_init_range( dest_alloc.mark_compressed_init_range(
&compressed, &compressed,
alloc_range(dest_offset, size), alloc_range(dest_offset, size), // just a single copy (i.e., not full `dest_range`)
num_copies, num_copies,
); );
// copy the relocations to the destination // copy the relocations to the destination
@ -1141,29 +1139,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
} }
} }
/// Internal helper for turning a "maybe pointer" into a proper pointer (and some information /// Turning a "maybe pointer" into a proper pointer (and some information
/// about where it points), or an absolute address. /// about where it points), or an absolute address.
pub(super) fn ptr_try_get_alloc( pub fn ptr_try_get_alloc(
&self, &self,
ptr: Pointer<Option<M::PointerTag>>, ptr: Pointer<Option<M::PointerTag>>,
) -> Result<(AllocId, Size, Pointer<M::PointerTag>), u64> { ) -> Result<(AllocId, Size, Pointer<M::PointerTag>), u64> {
match ptr.into_pointer_or_offset() { match ptr.into_pointer_or_addr() {
Ok(ptr) => { Ok(ptr) => {
let (alloc_id, offset) = M::ptr_get_alloc(self, ptr); let (alloc_id, offset) = M::ptr_get_alloc(self, ptr);
if let Some(alloc_id) = alloc_id { Ok((alloc_id, offset, ptr))
Ok((alloc_id, offset, ptr))
} else {
Err(offset.bytes())
}
} }
Err(offset) => Err(offset.bytes()), Err(addr) => Err(addr.bytes()),
} }
} }
/// Internal helper for turning a "maybe pointer" into a proper pointer (and some information /// Turning a "maybe pointer" into a proper pointer (and some information about where it points).
/// about where it points).
#[inline(always)] #[inline(always)]
pub(super) fn ptr_force_alloc( pub fn ptr_get_alloc(
&self, &self,
ptr: Pointer<Option<M::PointerTag>>, ptr: Pointer<Option<M::PointerTag>>,
) -> InterpResult<'tcx, (AllocId, Size, Pointer<M::PointerTag>)> { ) -> InterpResult<'tcx, (AllocId, Size, Pointer<M::PointerTag>)> {

View file

@ -199,6 +199,11 @@ impl<Tag> MemPlace<Tag> {
MemPlace { ptr, align, meta: MemPlaceMeta::None } MemPlace { ptr, align, meta: MemPlaceMeta::None }
} }
/// Adjust the provenance of the main pointer (metadata is unaffected).
pub fn map_provenance(self, f: impl FnOnce(Option<Tag>) -> Option<Tag>) -> Self {
MemPlace { ptr: self.ptr.map_provenance(f), ..self }
}
/// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space. /// Turn a mplace into a (thin or wide) pointer, as a reference, pointing to the same space.
/// This is the inverse of `ref_to_mplace`. /// This is the inverse of `ref_to_mplace`.
#[inline(always)] #[inline(always)]
@ -252,7 +257,7 @@ impl<'tcx, Tag: Copy> MPlaceTy<'tcx, Tag> {
} }
#[inline] #[inline]
fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self { pub fn from_aligned_ptr(ptr: Pointer<Option<Tag>>, layout: TyAndLayout<'tcx>) -> Self {
MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout } MPlaceTy { mplace: MemPlace::from_ptr(ptr, layout.align.abi), layout }
} }
@ -695,16 +700,6 @@ where
Ok(place_ty) Ok(place_ty)
} }
/// Write a scalar to a place
#[inline(always)]
pub fn write_scalar(
&mut self,
val: impl Into<ScalarMaybeUninit<M::PointerTag>>,
dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
self.write_immediate(Immediate::Scalar(val.into()), dest)
}
/// Write an immediate to a place /// Write an immediate to a place
#[inline(always)] #[inline(always)]
pub fn write_immediate( pub fn write_immediate(
@ -722,21 +717,24 @@ where
Ok(()) Ok(())
} }
/// Write an `Immediate` to memory. /// Write a scalar to a place
#[inline(always)] #[inline(always)]
pub fn write_immediate_to_mplace( pub fn write_scalar(
&mut self, &mut self,
src: Immediate<M::PointerTag>, val: impl Into<ScalarMaybeUninit<M::PointerTag>>,
dest: &MPlaceTy<'tcx, M::PointerTag>, dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> { ) -> InterpResult<'tcx> {
self.write_immediate_to_mplace_no_validate(src, dest)?; self.write_immediate(Immediate::Scalar(val.into()), dest)
}
if M::enforce_validity(self) { /// Write a pointer to a place
// Data got changed, better make sure it matches the type! #[inline(always)]
self.validate_operand(&dest.into())?; pub fn write_pointer(
} &mut self,
ptr: impl Into<Pointer<Option<M::PointerTag>>>,
Ok(()) dest: &PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
self.write_scalar(Scalar::from_maybe_pointer(ptr.into(), self), dest)
} }
/// Write an immediate to a place. /// Write an immediate to a place.

View file

@ -162,9 +162,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
use rustc_middle::mir::Rvalue::*; use rustc_middle::mir::Rvalue::*;
match *rvalue { match *rvalue {
ThreadLocalRef(did) => { ThreadLocalRef(did) => {
let id = M::thread_local_static_alloc_id(self, did)?; let ptr = M::thread_local_static_base_pointer(self, did)?;
let val = self.global_base_pointer(id.into())?; self.write_pointer(ptr, &dest)?;
self.write_scalar(Scalar::from_pointer(val, &*self.tcx), &dest)?;
} }
Use(ref operand) => { Use(ref operand) => {

View file

@ -869,7 +869,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let alloc = this let alloc = this
.ecx .ecx
.intern_with_temp_alloc(value.layout, |ecx, dest| { .intern_with_temp_alloc(value.layout, |ecx, dest| {
ecx.write_immediate_to_mplace(*imm, dest) ecx.write_immediate(*imm, dest)
}) })
.unwrap(); .unwrap();
Ok(Some(alloc)) Ok(Some(alloc))