get rid of incorrect erase_for_fmt
This commit is contained in:
parent
4e28065618
commit
7c720ce612
12 changed files with 81 additions and 119 deletions
|
@ -377,7 +377,9 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let (bytes, provenance) = match val.to_bits_or_ptr(range.size) {
|
// `to_bits_or_ptr_internal` is the right method because we just want to store this data
|
||||||
|
// as-is into memory.
|
||||||
|
let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size) {
|
||||||
Err(val) => {
|
Err(val) => {
|
||||||
let (provenance, offset) = val.into_parts();
|
let (provenance, offset) = val.into_parts();
|
||||||
(u128::from(offset.bytes()), Some(provenance))
|
(u128::from(offset.bytes()), Some(provenance))
|
||||||
|
|
|
@ -89,7 +89,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
|
||||||
pub trait Provenance: Copy {
|
pub trait Provenance: Copy {
|
||||||
/// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
|
/// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
|
||||||
/// If `true, ptr-to-int casts work by simply discarding the provenance.
|
/// If `true, ptr-to-int casts work by simply discarding the provenance.
|
||||||
/// If `false`, ptr-to-int casts are not supported.
|
/// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
|
||||||
const OFFSET_IS_ADDR: bool;
|
const OFFSET_IS_ADDR: bool;
|
||||||
|
|
||||||
/// Determines how a pointer should be printed.
|
/// Determines how a pointer should be printed.
|
||||||
|
@ -97,8 +97,9 @@ pub trait Provenance: Copy {
|
||||||
where
|
where
|
||||||
Self: Sized;
|
Self: Sized;
|
||||||
|
|
||||||
/// "Erasing" a tag converts it to the default tag type if possible. Used only for formatting purposes!
|
/// Provenance must always be able to identify the allocation this ptr points to.
|
||||||
fn erase_for_fmt(self) -> AllocId;
|
/// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.)
|
||||||
|
fn get_alloc_id(self) -> AllocId;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Provenance for AllocId {
|
impl Provenance for AllocId {
|
||||||
|
@ -120,7 +121,7 @@ impl Provenance for AllocId {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn erase_for_fmt(self) -> AllocId {
|
fn get_alloc_id(self) -> AllocId {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,14 +178,6 @@ impl<Tag> Pointer<Option<Tag>> {
|
||||||
None => Err(self.offset),
|
None => Err(self.offset),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn map_erase_for_fmt(self) -> Pointer<Option<AllocId>>
|
|
||||||
where
|
|
||||||
Tag: Provenance,
|
|
||||||
{
|
|
||||||
Pointer { offset: self.offset, provenance: self.provenance.map(Provenance::erase_for_fmt) }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Tag> Pointer<Option<Tag>> {
|
impl<Tag> Pointer<Option<Tag>> {
|
||||||
|
@ -208,15 +201,6 @@ impl<'tcx, Tag> Pointer<Tag> {
|
||||||
(self.provenance, self.offset)
|
(self.provenance, self.offset)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn erase_for_fmt(self) -> Pointer
|
|
||||||
where
|
|
||||||
Tag: Provenance,
|
|
||||||
{
|
|
||||||
// FIXME: This is wrong! `self.offset` might be an absolute address.
|
|
||||||
Pointer { offset: self.offset, provenance: self.provenance.erase_for_fmt() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self {
|
pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self {
|
||||||
Pointer { provenance: f(self.provenance), ..self }
|
Pointer { provenance: f(self.provenance), ..self }
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,9 +289,10 @@ impl<Tag> Scalar<Tag> {
|
||||||
/// This is almost certainly not the method you want! You should dispatch on the type
|
/// This is almost certainly not the method you want! You should dispatch on the type
|
||||||
/// and use `to_{u8,u16,...}`/`scalar_to_ptr` to perform ptr-to-int / int-to-ptr casts as needed.
|
/// and use `to_{u8,u16,...}`/`scalar_to_ptr` to perform ptr-to-int / int-to-ptr casts as needed.
|
||||||
///
|
///
|
||||||
/// This method only exists for the benefit of low-level memory operations.
|
/// This method only exists for the benefit of low-level operations that truly need to treat the
|
||||||
|
/// scalar in whatever form it is.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_bits_or_ptr(self, target_size: Size) -> Result<u128, Pointer<Tag>> {
|
pub fn to_bits_or_ptr_internal(self, target_size: Size) -> Result<u128, Pointer<Tag>> {
|
||||||
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
||||||
match self {
|
match self {
|
||||||
Scalar::Int(int) => Ok(int.assert_bits(target_size)),
|
Scalar::Int(int) => Ok(int.assert_bits(target_size)),
|
||||||
|
@ -304,32 +305,23 @@ impl<Tag> Scalar<Tag> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, Tag: Provenance> Scalar<Tag> {
|
impl<'tcx, Tag: Provenance> Scalar<Tag> {
|
||||||
/// Erase the tag from the scalar, if any.
|
|
||||||
///
|
|
||||||
/// Used by error reporting code to avoid having the error type depend on `Tag`.
|
|
||||||
#[inline]
|
|
||||||
pub fn erase_for_fmt(self) -> Scalar {
|
|
||||||
match self {
|
|
||||||
Scalar::Ptr(ptr, sz) => Scalar::Ptr(ptr.erase_for_fmt(), sz),
|
|
||||||
Scalar::Int(int) => Scalar::Int(int),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you
|
/// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you
|
||||||
/// likely want to use instead.
|
/// likely want to use instead.
|
||||||
///
|
///
|
||||||
/// Will perform ptr-to-int casts if needed and possible.
|
/// Will perform ptr-to-int casts if needed and possible.
|
||||||
|
/// If that fails, we know the offset is relative, so we return an "erased" Scalar
|
||||||
|
/// (which is useful for error messages but not much else).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_to_int(self) -> Option<ScalarInt> {
|
pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
|
||||||
match self {
|
match self {
|
||||||
Scalar::Int(int) => Some(int),
|
Scalar::Int(int) => Ok(int),
|
||||||
Scalar::Ptr(ptr, sz) => {
|
Scalar::Ptr(ptr, sz) => {
|
||||||
if Tag::OFFSET_IS_ADDR {
|
if Tag::OFFSET_IS_ADDR {
|
||||||
Some(
|
Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap())
|
||||||
ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap(),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
None
|
// We know `offset` is relative, since `OFFSET_IS_ADDR == false`.
|
||||||
|
let (tag, offset) = ptr.into_parts();
|
||||||
|
Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id(), offset), sz))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,19 +332,20 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
|
||||||
self.try_to_int().unwrap()
|
self.try_to_int().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in
|
||||||
|
/// Miri when someone declares a function that we shim (such as `malloc`) with a wrong type.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
|
pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
|
||||||
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
|
||||||
self.try_to_int()
|
self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err(
|
||||||
.ok_or_else(|| err_unsup!(ReadPointerAsBytes))?
|
|size| {
|
||||||
.to_bits(target_size)
|
|
||||||
.map_err(|size| {
|
|
||||||
err_ub!(ScalarSizeMismatch {
|
err_ub!(ScalarSizeMismatch {
|
||||||
target_size: target_size.bytes(),
|
target_size: target_size.bytes(),
|
||||||
data_size: size.bytes(),
|
data_size: size.bytes(),
|
||||||
})
|
})
|
||||||
.into()
|
.into()
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -522,17 +515,6 @@ impl<Tag> ScalarMaybeUninit<Tag> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx, Tag: Provenance> ScalarMaybeUninit<Tag> {
|
impl<'tcx, Tag: Provenance> ScalarMaybeUninit<Tag> {
|
||||||
/// Erase the tag from the scalar, if any.
|
|
||||||
///
|
|
||||||
/// Used by error reporting code to avoid having the error type depend on `Tag`.
|
|
||||||
#[inline]
|
|
||||||
pub fn erase_for_fmt(self) -> ScalarMaybeUninit {
|
|
||||||
match self {
|
|
||||||
ScalarMaybeUninit::Scalar(s) => ScalarMaybeUninit::Scalar(s.erase_for_fmt()),
|
|
||||||
ScalarMaybeUninit::Uninit => ScalarMaybeUninit::Uninit,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn to_bool(self) -> InterpResult<'tcx, bool> {
|
pub fn to_bool(self) -> InterpResult<'tcx, bool> {
|
||||||
self.check_init()?.to_bool()
|
self.check_init()?.to_bool()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
|
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
|
||||||
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Scalar};
|
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
|
||||||
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
|
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
|
||||||
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
|
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_apfloat::ieee::{Double, Single};
|
use rustc_apfloat::ieee::{Double, Single};
|
||||||
|
@ -1107,9 +1107,9 @@ pub trait PrettyPrinter<'tcx>:
|
||||||
|
|
||||||
/// This is overridden for MIR printing because we only want to hide alloc ids from users, not
|
/// This is overridden for MIR printing because we only want to hide alloc ids from users, not
|
||||||
/// from MIR where it is actually useful.
|
/// from MIR where it is actually useful.
|
||||||
fn pretty_print_const_pointer(
|
fn pretty_print_const_pointer<Tag: Provenance>(
|
||||||
mut self,
|
mut self,
|
||||||
_: Pointer,
|
_: Pointer<Tag>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
print_ty: bool,
|
print_ty: bool,
|
||||||
) -> Result<Self::Const, Self::Error> {
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
@ -1680,9 +1680,9 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pretty_print_const_pointer(
|
fn pretty_print_const_pointer<Tag: Provenance>(
|
||||||
self,
|
self,
|
||||||
p: Pointer,
|
p: Pointer<Tag>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
print_ty: bool,
|
print_ty: bool,
|
||||||
) -> Result<Self::Const, Self::Error> {
|
) -> Result<Self::Const, Self::Error> {
|
||||||
|
|
|
@ -897,11 +897,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
|
fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
|
||||||
if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
|
if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
|
||||||
// All locals have a backing allocation, even if the allocation is empty
|
// All locals have a backing allocation, even if the allocation is empty
|
||||||
// due to the local having ZST type.
|
// due to the local having ZST type. Hence we can `unwrap`.
|
||||||
trace!(
|
trace!(
|
||||||
"deallocating local {:?}: {:?}",
|
"deallocating local {:?}: {:?}",
|
||||||
local,
|
local,
|
||||||
self.memory.dump_alloc(ptr.provenance.unwrap().erase_for_fmt())
|
self.memory.dump_alloc(ptr.provenance.unwrap().get_alloc_id())
|
||||||
);
|
);
|
||||||
self.memory.deallocate(ptr, None, MemoryKind::Stack)?;
|
self.memory.deallocate(ptr, None, MemoryKind::Stack)?;
|
||||||
};
|
};
|
||||||
|
@ -989,28 +989,28 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
|
||||||
},
|
},
|
||||||
mplace.ptr,
|
mplace.ptr,
|
||||||
)?;
|
)?;
|
||||||
allocs.extend(mplace.ptr.map_erase_for_fmt().provenance);
|
allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
|
||||||
}
|
}
|
||||||
LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
|
LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
|
||||||
write!(fmt, " {:?}", val)?;
|
write!(fmt, " {:?}", val)?;
|
||||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val {
|
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val {
|
||||||
allocs.push(ptr.provenance.erase_for_fmt());
|
allocs.push(ptr.provenance.get_alloc_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
|
LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
|
||||||
write!(fmt, " ({:?}, {:?})", val1, val2)?;
|
write!(fmt, " ({:?}, {:?})", val1, val2)?;
|
||||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val1 {
|
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val1 {
|
||||||
allocs.push(ptr.provenance.erase_for_fmt());
|
allocs.push(ptr.provenance.get_alloc_id());
|
||||||
}
|
}
|
||||||
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val2 {
|
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val2 {
|
||||||
allocs.push(ptr.provenance.erase_for_fmt());
|
allocs.push(ptr.provenance.get_alloc_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs))
|
write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs))
|
||||||
}
|
}
|
||||||
Place::Ptr(mplace) => match mplace.ptr.map_erase_for_fmt().provenance {
|
Place::Ptr(mplace) => match mplace.ptr.provenance.map(Provenance::get_alloc_id) {
|
||||||
Some(alloc_id) => write!(
|
Some(alloc_id) => write!(
|
||||||
fmt,
|
fmt,
|
||||||
"by align({}) ref {:?}: {:?}",
|
"by align({}) ref {:?}: {:?}",
|
||||||
|
|
|
@ -362,7 +362,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
//
|
//
|
||||||
// Control flow is weird because we cannot early-return (to reach the
|
// Control flow is weird because we cannot early-return (to reach the
|
||||||
// `go_to_block` at the end).
|
// `go_to_block` at the end).
|
||||||
let done = if let (Some(a), Some(b)) = (a.try_to_int(), b.try_to_int()) {
|
let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) {
|
||||||
let a = a.try_to_machine_usize(*self.tcx).unwrap();
|
let a = a.try_to_machine_usize(*self.tcx).unwrap();
|
||||||
let b = b.try_to_machine_usize(*self.tcx).unwrap();
|
let b = b.try_to_machine_usize(*self.tcx).unwrap();
|
||||||
if a == b && a != 0 {
|
if a == b && a != 0 {
|
||||||
|
|
|
@ -757,12 +757,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||||
ptr: Pointer<Option<M::PointerTag>>,
|
ptr: Pointer<Option<M::PointerTag>>,
|
||||||
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
|
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
|
||||||
trace!("get_fn({:?})", ptr);
|
trace!("get_fn({:?})", ptr);
|
||||||
let (alloc_id, offset, ptr) = self.ptr_get_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(Pointer::new(alloc_id, offset)))
|
||||||
}
|
}
|
||||||
self.get_fn_alloc(alloc_id)
|
self.get_fn_alloc(alloc_id)
|
||||||
.ok_or_else(|| err_ub!(InvalidFunctionPointer(ptr.erase_for_fmt())).into())
|
.ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
|
pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> {
|
||||||
|
@ -801,7 +801,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||||
if reachable.insert(id) {
|
if reachable.insert(id) {
|
||||||
// This is a new allocation, add its relocations to `todo`.
|
// This is a new allocation, add its relocations to `todo`.
|
||||||
if let Some((_, alloc)) = self.alloc_map.get(id) {
|
if let Some((_, alloc)) = self.alloc_map.get(id) {
|
||||||
todo.extend(alloc.relocations().values().map(|tag| tag.erase_for_fmt()));
|
todo.extend(alloc.relocations().values().map(|tag| tag.get_alloc_id()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -841,7 +841,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
|
||||||
allocs_to_print: &mut VecDeque<AllocId>,
|
allocs_to_print: &mut VecDeque<AllocId>,
|
||||||
alloc: &Allocation<Tag, Extra>,
|
alloc: &Allocation<Tag, Extra>,
|
||||||
) -> std::fmt::Result {
|
) -> std::fmt::Result {
|
||||||
for alloc_id in alloc.relocations().values().map(|tag| tag.erase_for_fmt()) {
|
for alloc_id in alloc.relocations().values().map(|tag| tag.get_alloc_id()) {
|
||||||
allocs_to_print.push_back(alloc_id);
|
allocs_to_print.push_back(alloc_id);
|
||||||
}
|
}
|
||||||
write!(fmt, "{}", pretty::display_allocation(tcx, alloc))
|
write!(fmt, "{}", pretty::display_allocation(tcx, alloc))
|
||||||
|
@ -1129,7 +1129,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||||
/// Machine pointer introspection.
|
/// Machine pointer introspection.
|
||||||
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
|
||||||
pub fn scalar_to_ptr(&self, scalar: Scalar<M::PointerTag>) -> Pointer<Option<M::PointerTag>> {
|
pub fn scalar_to_ptr(&self, scalar: Scalar<M::PointerTag>) -> Pointer<Option<M::PointerTag>> {
|
||||||
match scalar.to_bits_or_ptr(self.pointer_size()) {
|
// We use `to_bits_or_ptr_internal` since we are just implementing the method people need to
|
||||||
|
// call to force getting out a pointer.
|
||||||
|
match scalar.to_bits_or_ptr_internal(self.pointer_size()) {
|
||||||
Err(ptr) => ptr.into(),
|
Err(ptr) => ptr.into(),
|
||||||
Ok(bits) => {
|
Ok(bits) => {
|
||||||
let addr = u64::try_from(bits).unwrap();
|
let addr = u64::try_from(bits).unwrap();
|
||||||
|
|
|
@ -118,8 +118,14 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'tcx, Tag> {
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
) -> Result<FmtPrinter<'a, 'tcx, F>, std::fmt::Error> {
|
) -> Result<FmtPrinter<'a, 'tcx, F>, std::fmt::Error> {
|
||||||
match s {
|
match s {
|
||||||
ScalarMaybeUninit::Scalar(s) => {
|
ScalarMaybeUninit::Scalar(Scalar::Int(int)) => {
|
||||||
cx.pretty_print_const_scalar(s.erase_for_fmt(), ty, true)
|
cx.pretty_print_const_scalar_int(int, ty, true)
|
||||||
|
}
|
||||||
|
ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _sz)) => {
|
||||||
|
// Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to
|
||||||
|
// print what is points to, which would fail since it has no access to the local
|
||||||
|
// memory.
|
||||||
|
cx.pretty_print_const_pointer(ptr, ty, true)
|
||||||
}
|
}
|
||||||
ScalarMaybeUninit::Uninit => cx.typed_value(
|
ScalarMaybeUninit::Uninit => cx.typed_value(
|
||||||
|mut this| {
|
|mut this| {
|
||||||
|
@ -139,11 +145,11 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'tcx, Tag> {
|
||||||
p(cx, s, ty)?;
|
p(cx, s, ty)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
write!(f, "{}: {}", s.erase_for_fmt(), self.layout.ty)
|
write!(f, "{}: {}", s, self.layout.ty)
|
||||||
}
|
}
|
||||||
Immediate::ScalarPair(a, b) => {
|
Immediate::ScalarPair(a, b) => {
|
||||||
// FIXME(oli-obk): at least print tuples and slices nicely
|
// FIXME(oli-obk): at least print tuples and slices nicely
|
||||||
write!(f, "({}, {}): {}", a.erase_for_fmt(), b.erase_for_fmt(), self.layout.ty,)
|
write!(f, "({}, {}): {}", a, b, self.layout.ty,)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -693,8 +699,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
Ok(match *tag_encoding {
|
Ok(match *tag_encoding {
|
||||||
TagEncoding::Direct => {
|
TagEncoding::Direct => {
|
||||||
let tag_bits = tag_val
|
let tag_bits = tag_val
|
||||||
.to_bits(tag_layout.size)
|
.try_to_int()
|
||||||
.map_err(|_| err_ub!(InvalidTag(tag_val.erase_for_fmt())))?;
|
.map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
|
||||||
|
.assert_bits(tag_layout.size);
|
||||||
// Cast bits from tag layout to discriminant layout.
|
// Cast bits from tag layout to discriminant layout.
|
||||||
let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
|
let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
|
||||||
let discr_bits = discr_val.assert_bits(discr_layout.size);
|
let discr_bits = discr_val.assert_bits(discr_layout.size);
|
||||||
|
@ -711,7 +718,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
}
|
}
|
||||||
_ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
|
_ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
|
||||||
}
|
}
|
||||||
.ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_for_fmt())))?;
|
.ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
|
||||||
// Return the cast value, and the index.
|
// Return the cast value, and the index.
|
||||||
(discr_val, index.0)
|
(discr_val, index.0)
|
||||||
}
|
}
|
||||||
|
@ -720,18 +727,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||||
// discriminant (encoded in niche/tag) and variant index are the same.
|
// discriminant (encoded in niche/tag) and variant index are the same.
|
||||||
let variants_start = niche_variants.start().as_u32();
|
let variants_start = niche_variants.start().as_u32();
|
||||||
let variants_end = niche_variants.end().as_u32();
|
let variants_end = niche_variants.end().as_u32();
|
||||||
let variant = match tag_val.to_bits_or_ptr(tag_layout.size) {
|
let variant = match tag_val.try_to_int() {
|
||||||
Err(ptr) => {
|
Err(dbg_val) => {
|
||||||
// The niche must be just 0 (which an inbounds pointer value never is)
|
// So this is a pointer then, and casting to an int failed.
|
||||||
|
// Can only happen during CTFE.
|
||||||
|
let ptr = self.scalar_to_ptr(tag_val);
|
||||||
|
// The niche must be just 0, and the ptr not null, then we know this is
|
||||||
|
// okay. Everything else, we conservatively reject.
|
||||||
let ptr_valid = niche_start == 0
|
let ptr_valid = niche_start == 0
|
||||||
&& variants_start == variants_end
|
&& variants_start == variants_end
|
||||||
&& !self.memory.ptr_may_be_null(ptr.into());
|
&& !self.memory.ptr_may_be_null(ptr);
|
||||||
if !ptr_valid {
|
if !ptr_valid {
|
||||||
throw_ub!(InvalidTag(tag_val.erase_for_fmt()))
|
throw_ub!(InvalidTag(dbg_val))
|
||||||
}
|
}
|
||||||
dataful_variant
|
dataful_variant
|
||||||
}
|
}
|
||||||
Ok(tag_bits) => {
|
Ok(tag_bits) => {
|
||||||
|
let tag_bits = tag_bits.assert_bits(tag_layout.size);
|
||||||
// We need to use machine arithmetic to get the relative variant idx:
|
// We need to use machine arithmetic to get the relative variant idx:
|
||||||
// variant_index_relative = tag_val - niche_start_val
|
// variant_index_relative = tag_val - niche_start_val
|
||||||
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
|
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);
|
||||||
|
|
|
@ -62,17 +62,6 @@ impl<Tag> MemPlaceMeta<Tag> {
|
||||||
Self::None | Self::Poison => false,
|
Self::None | Self::Poison => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn erase_for_fmt(self) -> MemPlaceMeta
|
|
||||||
where
|
|
||||||
Tag: Provenance,
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Self::Meta(s) => MemPlaceMeta::Meta(s.erase_for_fmt()),
|
|
||||||
Self::None => MemPlaceMeta::None,
|
|
||||||
Self::Poison => MemPlaceMeta::Poison,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable)]
|
#[derive(Copy, Clone, Hash, PartialEq, Eq, HashStable)]
|
||||||
|
@ -182,18 +171,6 @@ impl<'tcx, Tag> From<MPlaceTy<'tcx, Tag>> for PlaceTy<'tcx, Tag> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Tag> MemPlace<Tag> {
|
impl<Tag> MemPlace<Tag> {
|
||||||
#[inline]
|
|
||||||
pub fn erase_for_fmt(self) -> MemPlace
|
|
||||||
where
|
|
||||||
Tag: Provenance,
|
|
||||||
{
|
|
||||||
MemPlace {
|
|
||||||
ptr: self.ptr.map_erase_for_fmt(),
|
|
||||||
align: self.align,
|
|
||||||
meta: self.meta.erase_for_fmt(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn from_ptr(ptr: Pointer<Option<Tag>>, align: Align) -> Self {
|
pub fn from_ptr(ptr: Pointer<Option<Tag>>, align: Align) -> Self {
|
||||||
MemPlace { ptr, align, meta: MemPlaceMeta::None }
|
MemPlace { ptr, align, meta: MemPlaceMeta::None }
|
||||||
|
|
|
@ -535,7 +535,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||||
// types below!
|
// types below!
|
||||||
if self.ctfe_mode.is_some() {
|
if self.ctfe_mode.is_some() {
|
||||||
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
|
// Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
|
||||||
let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_some());
|
let is_bits = value.check_init().map_or(false, |v| v.try_to_int().is_ok());
|
||||||
if !is_bits {
|
if !is_bits {
|
||||||
throw_validation_failure!(self.path,
|
throw_validation_failure!(self.path,
|
||||||
{ "{}", value } expected { "initialized plain (non-pointer) bytes" }
|
{ "{}", value } expected { "initialized plain (non-pointer) bytes" }
|
||||||
|
@ -652,11 +652,14 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||||
err_ub!(InvalidUninitBytes(None)) => { "{}", value }
|
err_ub!(InvalidUninitBytes(None)) => { "{}", value }
|
||||||
expected { "something {}", wrapping_range_format(valid_range, max_hi) },
|
expected { "something {}", wrapping_range_format(valid_range, max_hi) },
|
||||||
);
|
);
|
||||||
let bits = match value.to_bits_or_ptr(op.layout.size) {
|
let bits = match value.try_to_int() {
|
||||||
Err(ptr) => {
|
Err(_) => {
|
||||||
|
// So this is a pointer then, and casting to an int failed.
|
||||||
|
// Can only happen during CTFE.
|
||||||
|
let ptr = self.ecx.scalar_to_ptr(value);
|
||||||
if lo == 1 && hi == max_hi {
|
if lo == 1 && hi == max_hi {
|
||||||
// Only null is the niche. So make sure the ptr is NOT null.
|
// Only null is the niche. So make sure the ptr is NOT null.
|
||||||
if self.ecx.memory.ptr_may_be_null(ptr.into()) {
|
if self.ecx.memory.ptr_may_be_null(ptr) {
|
||||||
throw_validation_failure!(self.path,
|
throw_validation_failure!(self.path,
|
||||||
{ "a potentially null pointer" }
|
{ "a potentially null pointer" }
|
||||||
expected {
|
expected {
|
||||||
|
@ -678,7 +681,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(data) => data,
|
Ok(int) => int.assert_bits(op.layout.size),
|
||||||
};
|
};
|
||||||
// Now compare. This is slightly subtle because this is a special "wrap-around" range.
|
// Now compare. This is slightly subtle because this is a special "wrap-around" range.
|
||||||
if wrapping_range_contains(&valid_range, bits) {
|
if wrapping_range_contains(&valid_range, bits) {
|
||||||
|
|
|
@ -921,12 +921,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||||
|
|
||||||
match **op {
|
match **op {
|
||||||
interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => {
|
interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => {
|
||||||
s.try_to_int().is_some()
|
s.try_to_int().is_ok()
|
||||||
}
|
}
|
||||||
interpret::Operand::Immediate(Immediate::ScalarPair(
|
interpret::Operand::Immediate(Immediate::ScalarPair(
|
||||||
ScalarMaybeUninit::Scalar(l),
|
ScalarMaybeUninit::Scalar(l),
|
||||||
ScalarMaybeUninit::Scalar(r),
|
ScalarMaybeUninit::Scalar(r),
|
||||||
)) => l.try_to_int().is_some() && r.try_to_int().is_some(),
|
)) => l.try_to_int().is_ok() && r.try_to_int().is_ok(),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -123,7 +123,7 @@ impl IntRange {
|
||||||
// straight to the result, after doing a bit of checking. (We
|
// straight to the result, after doing a bit of checking. (We
|
||||||
// could remove this branch and just fall through, which
|
// could remove this branch and just fall through, which
|
||||||
// is more general but much slower.)
|
// is more general but much slower.)
|
||||||
if let Ok(bits) = scalar.to_bits_or_ptr(target_size) {
|
if let Ok(bits) = scalar.to_bits_or_ptr_internal(target_size) {
|
||||||
return Some(bits);
|
return Some(bits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue