1
Fork 0

get rid of incorrect erase_for_fmt

This commit is contained in:
Ralf Jung 2021-07-16 09:39:35 +02:00
parent 4e28065618
commit 7c720ce612
12 changed files with 81 additions and 119 deletions

View file

@ -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) => {
let (provenance, offset) = val.into_parts();
(u128::from(offset.bytes()), Some(provenance))

View file

@ -89,7 +89,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
pub trait Provenance: Copy {
/// 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 `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;
/// Determines how a pointer should be printed.
@ -97,8 +97,9 @@ pub trait Provenance: Copy {
where
Self: Sized;
/// "Erasing" a tag converts it to the default tag type if possible. Used only for formatting purposes!
fn erase_for_fmt(self) -> AllocId;
/// Provenance must always be able to identify the allocation this ptr points to.
/// (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 {
@ -120,7 +121,7 @@ impl Provenance for AllocId {
Ok(())
}
fn erase_for_fmt(self) -> AllocId {
fn get_alloc_id(self) -> AllocId {
self
}
}
@ -177,14 +178,6 @@ impl<Tag> Pointer<Option<Tag>> {
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>> {
@ -208,15 +201,6 @@ impl<'tcx, Tag> Pointer<Tag> {
(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 {
Pointer { provenance: f(self.provenance), ..self }
}

View file

@ -289,9 +289,10 @@ impl<Tag> Scalar<Tag> {
/// 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.
///
/// 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]
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");
match self {
Scalar::Int(int) => Ok(int.assert_bits(target_size)),
@ -304,32 +305,23 @@ impl<Tag> 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
/// likely want to use instead.
///
/// 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]
pub fn try_to_int(self) -> Option<ScalarInt> {
pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
match self {
Scalar::Int(int) => Some(int),
Scalar::Int(int) => Ok(int),
Scalar::Ptr(ptr, sz) => {
if Tag::OFFSET_IS_ADDR {
Some(
ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap(),
)
Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap())
} 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()
}
/// 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]
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");
self.try_to_int()
.ok_or_else(|| err_unsup!(ReadPointerAsBytes))?
.to_bits(target_size)
.map_err(|size| {
self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err(
|size| {
err_ub!(ScalarSizeMismatch {
target_size: target_size.bytes(),
data_size: size.bytes(),
})
.into()
})
},
)
}
#[inline(always)]
@ -522,17 +515,6 @@ impl<Tag> 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)]
pub fn to_bool(self) -> InterpResult<'tcx, bool> {
self.check_init()?.to_bool()

View file

@ -1,5 +1,5 @@
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::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
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
/// from MIR where it is actually useful.
fn pretty_print_const_pointer(
fn pretty_print_const_pointer<Tag: Provenance>(
mut self,
_: Pointer,
_: Pointer<Tag>,
ty: Ty<'tcx>,
print_ty: bool,
) -> 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,
p: Pointer,
p: Pointer<Tag>,
ty: Ty<'tcx>,
print_ty: bool,
) -> Result<Self::Const, Self::Error> {