Skip to content

Commit 7c720ce

Browse files
committed
get rid of incorrect erase_for_fmt
1 parent 4e28065 commit 7c720ce

File tree

12 files changed

+81
-119
lines changed

12 files changed

+81
-119
lines changed

compiler/rustc_middle/src/mir/interpret/allocation.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,9 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> {
377377
}
378378
};
379379

380-
let (bytes, provenance) = match val.to_bits_or_ptr(range.size) {
380+
// `to_bits_or_ptr_internal` is the right method because we just want to store this data
381+
// as-is into memory.
382+
let (bytes, provenance) = match val.to_bits_or_ptr_internal(range.size) {
381383
Err(val) => {
382384
let (provenance, offset) = val.into_parts();
383385
(u128::from(offset.bytes()), Some(provenance))

compiler/rustc_middle/src/mir/interpret/pointer.rs

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,17 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
8989
pub trait Provenance: Copy {
9090
/// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
9191
/// If `true, ptr-to-int casts work by simply discarding the provenance.
92-
/// If `false`, ptr-to-int casts are not supported.
92+
/// If `false`, ptr-to-int casts are not supported. The offset *must* be relative in that case.
9393
const OFFSET_IS_ADDR: bool;
9494

9595
/// Determines how a pointer should be printed.
9696
fn fmt(ptr: &Pointer<Self>, f: &mut fmt::Formatter<'_>) -> fmt::Result
9797
where
9898
Self: Sized;
9999

100-
/// "Erasing" a tag converts it to the default tag type if possible. Used only for formatting purposes!
101-
fn erase_for_fmt(self) -> AllocId;
100+
/// Provenance must always be able to identify the allocation this ptr points to.
101+
/// (Identifying the offset in that allocation, however, is harder -- use `Memory::ptr_get_alloc` for that.)
102+
fn get_alloc_id(self) -> AllocId;
102103
}
103104

104105
impl Provenance for AllocId {
@@ -120,7 +121,7 @@ impl Provenance for AllocId {
120121
Ok(())
121122
}
122123

123-
fn erase_for_fmt(self) -> AllocId {
124+
fn get_alloc_id(self) -> AllocId {
124125
self
125126
}
126127
}
@@ -177,14 +178,6 @@ impl<Tag> Pointer<Option<Tag>> {
177178
None => Err(self.offset),
178179
}
179180
}
180-
181-
#[inline(always)]
182-
pub fn map_erase_for_fmt(self) -> Pointer<Option<AllocId>>
183-
where
184-
Tag: Provenance,
185-
{
186-
Pointer { offset: self.offset, provenance: self.provenance.map(Provenance::erase_for_fmt) }
187-
}
188181
}
189182

190183
impl<Tag> Pointer<Option<Tag>> {
@@ -208,15 +201,6 @@ impl<'tcx, Tag> Pointer<Tag> {
208201
(self.provenance, self.offset)
209202
}
210203

211-
#[inline(always)]
212-
pub fn erase_for_fmt(self) -> Pointer
213-
where
214-
Tag: Provenance,
215-
{
216-
// FIXME: This is wrong! `self.offset` might be an absolute address.
217-
Pointer { offset: self.offset, provenance: self.provenance.erase_for_fmt() }
218-
}
219-
220204
pub fn map_provenance(self, f: impl FnOnce(Tag) -> Tag) -> Self {
221205
Pointer { provenance: f(self.provenance), ..self }
222206
}

compiler/rustc_middle/src/mir/interpret/value.rs

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,10 @@ impl<Tag> Scalar<Tag> {
289289
/// This is almost certainly not the method you want! You should dispatch on the type
290290
/// and use `to_{u8,u16,...}`/`scalar_to_ptr` to perform ptr-to-int / int-to-ptr casts as needed.
291291
///
292-
/// This method only exists for the benefit of low-level memory operations.
292+
/// This method only exists for the benefit of low-level operations that truly need to treat the
293+
/// scalar in whatever form it is.
293294
#[inline]
294-
pub fn to_bits_or_ptr(self, target_size: Size) -> Result<u128, Pointer<Tag>> {
295+
pub fn to_bits_or_ptr_internal(self, target_size: Size) -> Result<u128, Pointer<Tag>> {
295296
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
296297
match self {
297298
Scalar::Int(int) => Ok(int.assert_bits(target_size)),
@@ -304,32 +305,23 @@ impl<Tag> Scalar<Tag> {
304305
}
305306

306307
impl<'tcx, Tag: Provenance> Scalar<Tag> {
307-
/// Erase the tag from the scalar, if any.
308-
///
309-
/// Used by error reporting code to avoid having the error type depend on `Tag`.
310-
#[inline]
311-
pub fn erase_for_fmt(self) -> Scalar {
312-
match self {
313-
Scalar::Ptr(ptr, sz) => Scalar::Ptr(ptr.erase_for_fmt(), sz),
314-
Scalar::Int(int) => Scalar::Int(int),
315-
}
316-
}
317-
318308
/// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you
319309
/// likely want to use instead.
320310
///
321311
/// Will perform ptr-to-int casts if needed and possible.
312+
/// If that fails, we know the offset is relative, so we return an "erased" Scalar
313+
/// (which is useful for error messages but not much else).
322314
#[inline]
323-
pub fn try_to_int(self) -> Option<ScalarInt> {
315+
pub fn try_to_int(self) -> Result<ScalarInt, Scalar<AllocId>> {
324316
match self {
325-
Scalar::Int(int) => Some(int),
317+
Scalar::Int(int) => Ok(int),
326318
Scalar::Ptr(ptr, sz) => {
327319
if Tag::OFFSET_IS_ADDR {
328-
Some(
329-
ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap(),
330-
)
320+
Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap())
331321
} else {
332-
None
322+
// We know `offset` is relative, since `OFFSET_IS_ADDR == false`.
323+
let (tag, offset) = ptr.into_parts();
324+
Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id(), offset), sz))
333325
}
334326
}
335327
}
@@ -340,19 +332,20 @@ impl<'tcx, Tag: Provenance> Scalar<Tag> {
340332
self.try_to_int().unwrap()
341333
}
342334

335+
/// This throws UB (instead of ICEing) on a size mismatch since size mismatches can arise in
336+
/// Miri when someone declares a function that we shim (such as `malloc`) with a wrong type.
343337
#[inline]
344338
pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
345339
assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST");
346-
self.try_to_int()
347-
.ok_or_else(|| err_unsup!(ReadPointerAsBytes))?
348-
.to_bits(target_size)
349-
.map_err(|size| {
340+
self.try_to_int().map_err(|_| err_unsup!(ReadPointerAsBytes))?.to_bits(target_size).map_err(
341+
|size| {
350342
err_ub!(ScalarSizeMismatch {
351343
target_size: target_size.bytes(),
352344
data_size: size.bytes(),
353345
})
354346
.into()
355-
})
347+
},
348+
)
356349
}
357350

358351
#[inline(always)]
@@ -522,17 +515,6 @@ impl<Tag> ScalarMaybeUninit<Tag> {
522515
}
523516

524517
impl<'tcx, Tag: Provenance> ScalarMaybeUninit<Tag> {
525-
/// Erase the tag from the scalar, if any.
526-
///
527-
/// Used by error reporting code to avoid having the error type depend on `Tag`.
528-
#[inline]
529-
pub fn erase_for_fmt(self) -> ScalarMaybeUninit {
530-
match self {
531-
ScalarMaybeUninit::Scalar(s) => ScalarMaybeUninit::Scalar(s.erase_for_fmt()),
532-
ScalarMaybeUninit::Uninit => ScalarMaybeUninit::Uninit,
533-
}
534-
}
535-
536518
#[inline(always)]
537519
pub fn to_bool(self) -> InterpResult<'tcx, bool> {
538520
self.check_init()?.to_bool()

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::middle::cstore::{ExternCrate, ExternCrateSource};
2-
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Scalar};
2+
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
33
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
44
use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable};
55
use rustc_apfloat::ieee::{Double, Single};
@@ -1107,9 +1107,9 @@ pub trait PrettyPrinter<'tcx>:
11071107

11081108
/// This is overridden for MIR printing because we only want to hide alloc ids from users, not
11091109
/// from MIR where it is actually useful.
1110-
fn pretty_print_const_pointer(
1110+
fn pretty_print_const_pointer<Tag: Provenance>(
11111111
mut self,
1112-
_: Pointer,
1112+
_: Pointer<Tag>,
11131113
ty: Ty<'tcx>,
11141114
print_ty: bool,
11151115
) -> Result<Self::Const, Self::Error> {
@@ -1680,9 +1680,9 @@ impl<F: fmt::Write> PrettyPrinter<'tcx> for FmtPrinter<'_, 'tcx, F> {
16801680
}
16811681
}
16821682

1683-
fn pretty_print_const_pointer(
1683+
fn pretty_print_const_pointer<Tag: Provenance>(
16841684
self,
1685-
p: Pointer,
1685+
p: Pointer<Tag>,
16861686
ty: Ty<'tcx>,
16871687
print_ty: bool,
16881688
) -> Result<Self::Const, Self::Error> {

compiler/rustc_mir/src/interpret/eval_context.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -897,11 +897,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
897897
fn deallocate_local(&mut self, local: LocalValue<M::PointerTag>) -> InterpResult<'tcx> {
898898
if let LocalValue::Live(Operand::Indirect(MemPlace { ptr, .. })) = local {
899899
// All locals have a backing allocation, even if the allocation is empty
900-
// due to the local having ZST type.
900+
// due to the local having ZST type. Hence we can `unwrap`.
901901
trace!(
902902
"deallocating local {:?}: {:?}",
903903
local,
904-
self.memory.dump_alloc(ptr.provenance.unwrap().erase_for_fmt())
904+
self.memory.dump_alloc(ptr.provenance.unwrap().get_alloc_id())
905905
);
906906
self.memory.deallocate(ptr, None, MemoryKind::Stack)?;
907907
};
@@ -989,28 +989,28 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> std::fmt::Debug
989989
},
990990
mplace.ptr,
991991
)?;
992-
allocs.extend(mplace.ptr.map_erase_for_fmt().provenance);
992+
allocs.extend(mplace.ptr.provenance.map(Provenance::get_alloc_id));
993993
}
994994
LocalValue::Live(Operand::Immediate(Immediate::Scalar(val))) => {
995995
write!(fmt, " {:?}", val)?;
996996
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val {
997-
allocs.push(ptr.provenance.erase_for_fmt());
997+
allocs.push(ptr.provenance.get_alloc_id());
998998
}
999999
}
10001000
LocalValue::Live(Operand::Immediate(Immediate::ScalarPair(val1, val2))) => {
10011001
write!(fmt, " ({:?}, {:?})", val1, val2)?;
10021002
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val1 {
1003-
allocs.push(ptr.provenance.erase_for_fmt());
1003+
allocs.push(ptr.provenance.get_alloc_id());
10041004
}
10051005
if let ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _size)) = val2 {
1006-
allocs.push(ptr.provenance.erase_for_fmt());
1006+
allocs.push(ptr.provenance.get_alloc_id());
10071007
}
10081008
}
10091009
}
10101010

10111011
write!(fmt, ": {:?}", self.ecx.memory.dump_allocs(allocs))
10121012
}
1013-
Place::Ptr(mplace) => match mplace.ptr.map_erase_for_fmt().provenance {
1013+
Place::Ptr(mplace) => match mplace.ptr.provenance.map(Provenance::get_alloc_id) {
10141014
Some(alloc_id) => write!(
10151015
fmt,
10161016
"by align({}) ref {:?}: {:?}",

compiler/rustc_mir/src/interpret/intrinsics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
362362
//
363363
// Control flow is weird because we cannot early-return (to reach the
364364
// `go_to_block` at the end).
365-
let done = if let (Some(a), Some(b)) = (a.try_to_int(), b.try_to_int()) {
365+
let done = if let (Ok(a), Ok(b)) = (a.try_to_int(), b.try_to_int()) {
366366
let a = a.try_to_machine_usize(*self.tcx).unwrap();
367367
let b = b.try_to_machine_usize(*self.tcx).unwrap();
368368
if a == b && a != 0 {

compiler/rustc_mir/src/interpret/memory.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -757,12 +757,12 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
757757
ptr: Pointer<Option<M::PointerTag>>,
758758
) -> InterpResult<'tcx, FnVal<'tcx, M::ExtraFnVal>> {
759759
trace!("get_fn({:?})", ptr);
760-
let (alloc_id, offset, ptr) = self.ptr_get_alloc(ptr)?;
760+
let (alloc_id, offset, _ptr) = self.ptr_get_alloc(ptr)?;
761761
if offset.bytes() != 0 {
762-
throw_ub!(InvalidFunctionPointer(ptr.erase_for_fmt()))
762+
throw_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset)))
763763
}
764764
self.get_fn_alloc(alloc_id)
765-
.ok_or_else(|| err_ub!(InvalidFunctionPointer(ptr.erase_for_fmt())).into())
765+
.ok_or_else(|| err_ub!(InvalidFunctionPointer(Pointer::new(alloc_id, offset))).into())
766766
}
767767

768768
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> {
801801
if reachable.insert(id) {
802802
// This is a new allocation, add its relocations to `todo`.
803803
if let Some((_, alloc)) = self.alloc_map.get(id) {
804-
todo.extend(alloc.relocations().values().map(|tag| tag.erase_for_fmt()));
804+
todo.extend(alloc.relocations().values().map(|tag| tag.get_alloc_id()));
805805
}
806806
}
807807
}
@@ -841,7 +841,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
841841
allocs_to_print: &mut VecDeque<AllocId>,
842842
alloc: &Allocation<Tag, Extra>,
843843
) -> std::fmt::Result {
844-
for alloc_id in alloc.relocations().values().map(|tag| tag.erase_for_fmt()) {
844+
for alloc_id in alloc.relocations().values().map(|tag| tag.get_alloc_id()) {
845845
allocs_to_print.push_back(alloc_id);
846846
}
847847
write!(fmt, "{}", pretty::display_allocation(tcx, alloc))
@@ -1129,7 +1129,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
11291129
/// Machine pointer introspection.
11301130
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
11311131
pub fn scalar_to_ptr(&self, scalar: Scalar<M::PointerTag>) -> Pointer<Option<M::PointerTag>> {
1132-
match scalar.to_bits_or_ptr(self.pointer_size()) {
1132+
// We use `to_bits_or_ptr_internal` since we are just implementing the method people need to
1133+
// call to force getting out a pointer.
1134+
match scalar.to_bits_or_ptr_internal(self.pointer_size()) {
11331135
Err(ptr) => ptr.into(),
11341136
Ok(bits) => {
11351137
let addr = u64::try_from(bits).unwrap();

compiler/rustc_mir/src/interpret/operand.rs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,8 +118,14 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'tcx, Tag> {
118118
ty: Ty<'tcx>,
119119
) -> Result<FmtPrinter<'a, 'tcx, F>, std::fmt::Error> {
120120
match s {
121-
ScalarMaybeUninit::Scalar(s) => {
122-
cx.pretty_print_const_scalar(s.erase_for_fmt(), ty, true)
121+
ScalarMaybeUninit::Scalar(Scalar::Int(int)) => {
122+
cx.pretty_print_const_scalar_int(int, ty, true)
123+
}
124+
ScalarMaybeUninit::Scalar(Scalar::Ptr(ptr, _sz)) => {
125+
// Just print the ptr value. `pretty_print_const_scalar_ptr` would also try to
126+
// print what is points to, which would fail since it has no access to the local
127+
// memory.
128+
cx.pretty_print_const_pointer(ptr, ty, true)
123129
}
124130
ScalarMaybeUninit::Uninit => cx.typed_value(
125131
|mut this| {
@@ -139,11 +145,11 @@ impl<Tag: Provenance> std::fmt::Display for ImmTy<'tcx, Tag> {
139145
p(cx, s, ty)?;
140146
return Ok(());
141147
}
142-
write!(f, "{}: {}", s.erase_for_fmt(), self.layout.ty)
148+
write!(f, "{}: {}", s, self.layout.ty)
143149
}
144150
Immediate::ScalarPair(a, b) => {
145151
// FIXME(oli-obk): at least print tuples and slices nicely
146-
write!(f, "({}, {}): {}", a.erase_for_fmt(), b.erase_for_fmt(), self.layout.ty,)
152+
write!(f, "({}, {}): {}", a, b, self.layout.ty,)
147153
}
148154
}
149155
})
@@ -693,8 +699,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
693699
Ok(match *tag_encoding {
694700
TagEncoding::Direct => {
695701
let tag_bits = tag_val
696-
.to_bits(tag_layout.size)
697-
.map_err(|_| err_ub!(InvalidTag(tag_val.erase_for_fmt())))?;
702+
.try_to_int()
703+
.map_err(|dbg_val| err_ub!(InvalidTag(dbg_val)))?
704+
.assert_bits(tag_layout.size);
698705
// Cast bits from tag layout to discriminant layout.
699706
let discr_val = self.cast_from_scalar(tag_bits, tag_layout, discr_layout.ty);
700707
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> {
711718
}
712719
_ => span_bug!(self.cur_span(), "tagged layout for non-adt non-generator"),
713720
}
714-
.ok_or_else(|| err_ub!(InvalidTag(tag_val.erase_for_fmt())))?;
721+
.ok_or_else(|| err_ub!(InvalidTag(Scalar::from_uint(tag_bits, tag_layout.size))))?;
715722
// Return the cast value, and the index.
716723
(discr_val, index.0)
717724
}
@@ -720,18 +727,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
720727
// discriminant (encoded in niche/tag) and variant index are the same.
721728
let variants_start = niche_variants.start().as_u32();
722729
let variants_end = niche_variants.end().as_u32();
723-
let variant = match tag_val.to_bits_or_ptr(tag_layout.size) {
724-
Err(ptr) => {
725-
// The niche must be just 0 (which an inbounds pointer value never is)
730+
let variant = match tag_val.try_to_int() {
731+
Err(dbg_val) => {
732+
// So this is a pointer then, and casting to an int failed.
733+
// Can only happen during CTFE.
734+
let ptr = self.scalar_to_ptr(tag_val);
735+
// The niche must be just 0, and the ptr not null, then we know this is
736+
// okay. Everything else, we conservatively reject.
726737
let ptr_valid = niche_start == 0
727738
&& variants_start == variants_end
728-
&& !self.memory.ptr_may_be_null(ptr.into());
739+
&& !self.memory.ptr_may_be_null(ptr);
729740
if !ptr_valid {
730-
throw_ub!(InvalidTag(tag_val.erase_for_fmt()))
741+
throw_ub!(InvalidTag(dbg_val))
731742
}
732743
dataful_variant
733744
}
734745
Ok(tag_bits) => {
746+
let tag_bits = tag_bits.assert_bits(tag_layout.size);
735747
// We need to use machine arithmetic to get the relative variant idx:
736748
// variant_index_relative = tag_val - niche_start_val
737749
let tag_val = ImmTy::from_uint(tag_bits, tag_layout);

0 commit comments

Comments
 (0)