Skip to content

Commit d4e1565

Browse files
committed
Auto merge of #62441 - RalfJung:place-ptr-normalization, r=oli-obk
Miri: Provide pointer forcing methods for MemPlace and Op These are useful when one wants to to a lot of work with some place or operand and not to int-to-ptr casts all the time. In particular, this is needed to fix some test failures in Miri: we need to normalize before starting a visitor that walks a run-time value, so that we can later be sure (during the visitor walk) that we have a proper `Pointer`. Also see the Miri side at rust-lang/miri#830. Cc @eddyb @oli-obk
2 parents 0324a2b + ac4f6ab commit d4e1565

File tree

9 files changed

+132
-105
lines changed

9 files changed

+132
-105
lines changed

src/librustc/mir/interpret/value.rs

+20-13
Original file line numberDiff line numberDiff line change
@@ -262,19 +262,6 @@ impl<'tcx, Tag> Scalar<Tag> {
262262
}
263263
}
264264

265-
/// Returns this pointer's offset from the allocation base, or from NULL (for
266-
/// integer pointers).
267-
#[inline]
268-
pub fn get_ptr_offset(self, cx: &impl HasDataLayout) -> Size {
269-
match self {
270-
Scalar::Raw { data, size } => {
271-
assert_eq!(size as u64, cx.pointer_size().bytes());
272-
Size::from_bytes(data as u64)
273-
}
274-
Scalar::Ptr(ptr) => ptr.offset,
275-
}
276-
}
277-
278265
#[inline]
279266
pub fn from_bool(b: bool) -> Self {
280267
Scalar::Raw { data: b as u128, size: 1 }
@@ -339,6 +326,10 @@ impl<'tcx, Tag> Scalar<Tag> {
339326
Scalar::Raw { data: f.to_bits(), size: 8 }
340327
}
341328

329+
/// This is very rarely the method you want! You should dispatch on the type
330+
/// and use `force_bits`/`assert_bits`/`force_ptr`/`assert_ptr`.
331+
/// This method only exists for the benefit of low-level memory operations
332+
/// as well as the implementation of the `force_*` methods.
342333
#[inline]
343334
pub fn to_bits_or_ptr(
344335
self,
@@ -359,6 +350,7 @@ impl<'tcx, Tag> Scalar<Tag> {
359350
}
360351
}
361352

353+
/// Do not call this method! Use either `assert_bits` or `force_bits`.
362354
#[inline]
363355
pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
364356
match self {
@@ -372,6 +364,12 @@ impl<'tcx, Tag> Scalar<Tag> {
372364
}
373365
}
374366

367+
#[inline(always)]
368+
pub fn assert_bits(self, target_size: Size) -> u128 {
369+
self.to_bits(target_size).expect("Expected Raw bits but got a Pointer")
370+
}
371+
372+
/// Do not call this method! Use either `assert_ptr` or `force_ptr`.
375373
#[inline]
376374
pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
377375
match self {
@@ -381,6 +379,12 @@ impl<'tcx, Tag> Scalar<Tag> {
381379
}
382380
}
383381

382+
#[inline(always)]
383+
pub fn assert_ptr(self) -> Pointer<Tag> {
384+
self.to_ptr().expect("Expected a Pointer but got Raw bits")
385+
}
386+
387+
/// Do not call this method! Dispatch based on the type instead.
384388
#[inline]
385389
pub fn is_bits(self) -> bool {
386390
match self {
@@ -389,6 +393,7 @@ impl<'tcx, Tag> Scalar<Tag> {
389393
}
390394
}
391395

396+
/// Do not call this method! Dispatch based on the type instead.
392397
#[inline]
393398
pub fn is_ptr(self) -> bool {
394399
match self {
@@ -536,11 +541,13 @@ impl<'tcx, Tag> ScalarMaybeUndef<Tag> {
536541
}
537542
}
538543

544+
/// Do not call this method! Use either `assert_ptr` or `force_ptr`.
539545
#[inline(always)]
540546
pub fn to_ptr(self) -> InterpResult<'tcx, Pointer<Tag>> {
541547
self.not_undef()?.to_ptr()
542548
}
543549

550+
/// Do not call this method! Use either `assert_bits` or `force_bits`.
544551
#[inline(always)]
545552
pub fn to_bits(self, target_size: Size) -> InterpResult<'tcx, u128> {
546553
self.not_undef()?.to_bits(target_size)

src/librustc_mir/const_eval.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ fn op_to_const<'tcx>(
109109
// `Immediate` is when we are called from `const_field`, and that `Immediate`
110110
// comes from a constant so it can happen have `Undef`, because the indirect
111111
// memory that was read had undefined bytes.
112-
let mplace = op.to_mem_place();
112+
let mplace = op.assert_mem_place();
113113
let ptr = mplace.ptr.to_ptr().unwrap();
114114
let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
115115
ConstValue::ByRef { offset: ptr.offset, align: mplace.align, alloc }
@@ -661,7 +661,7 @@ pub fn const_eval_raw_provider<'tcx>(
661661
|body| eval_body_using_ecx(&mut ecx, cid, body, key.param_env)
662662
).and_then(|place| {
663663
Ok(RawConst {
664-
alloc_id: place.to_ptr().expect("we allocated this ptr!").alloc_id,
664+
alloc_id: place.ptr.assert_ptr().alloc_id,
665665
ty: place.layout.ty
666666
})
667667
}).map_err(|error| {

src/librustc_mir/interpret/memory.rs

+12-24
Original file line numberDiff line numberDiff line change
@@ -214,10 +214,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
214214
None => Size::from_bytes(self.get(ptr.alloc_id)?.bytes.len() as u64),
215215
};
216216
self.copy(
217-
ptr.into(),
218-
Align::from_bytes(1).unwrap(), // old_align anyway gets checked below by `deallocate`
219-
new_ptr.into(),
220-
new_align,
217+
ptr,
218+
new_ptr,
221219
old_size.min(new_size),
222220
/*nonoverlapping*/ true,
223221
)?;
@@ -310,6 +308,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
310308
/// `Pointer` they need. And even if you already have a `Pointer`, call this method
311309
/// to make sure it is sufficiently aligned and not dangling. Not doing that may
312310
/// cause ICEs.
311+
///
312+
/// Most of the time you should use `check_mplace_access`, but when you just have a pointer,
313+
/// this method is still appropriate.
313314
pub fn check_ptr_access(
314315
&self,
315316
sptr: Scalar<M::PointerTag>,
@@ -751,39 +752,26 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> {
751752
self.get(ptr.alloc_id)?.read_c_str(self, ptr)
752753
}
753754

754-
/// Performs appropriate bounds checks.
755+
/// Expects the caller to have checked bounds and alignment.
755756
pub fn copy(
756757
&mut self,
757-
src: Scalar<M::PointerTag>,
758-
src_align: Align,
759-
dest: Scalar<M::PointerTag>,
760-
dest_align: Align,
758+
src: Pointer<M::PointerTag>,
759+
dest: Pointer<M::PointerTag>,
761760
size: Size,
762761
nonoverlapping: bool,
763762
) -> InterpResult<'tcx> {
764-
self.copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping)
763+
self.copy_repeatedly(src, dest, size, 1, nonoverlapping)
765764
}
766765

767-
/// Performs appropriate bounds checks.
766+
/// Expects the caller to have checked bounds and alignment.
768767
pub fn copy_repeatedly(
769768
&mut self,
770-
src: Scalar<M::PointerTag>,
771-
src_align: Align,
772-
dest: Scalar<M::PointerTag>,
773-
dest_align: Align,
769+
src: Pointer<M::PointerTag>,
770+
dest: Pointer<M::PointerTag>,
774771
size: Size,
775772
length: u64,
776773
nonoverlapping: bool,
777774
) -> InterpResult<'tcx> {
778-
// We need to check *both* before early-aborting due to the size being 0.
779-
let (src, dest) = match (self.check_ptr_access(src, size, src_align)?,
780-
self.check_ptr_access(dest, size * length, dest_align)?)
781-
{
782-
(Some(src), Some(dest)) => (src, dest),
783-
// One of the two sizes is 0.
784-
_ => return Ok(()),
785-
};
786-
787775
// first copy the relocations to a temporary buffer, because
788776
// `get_bytes_mut` will clear the relocations, which is correct,
789777
// since we don't want to keep any relocations at the target.

src/librustc_mir/interpret/operand.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -123,23 +123,23 @@ pub enum Operand<Tag=(), Id=AllocId> {
123123

124124
impl<Tag> Operand<Tag> {
125125
#[inline]
126-
pub fn to_mem_place(self) -> MemPlace<Tag>
126+
pub fn assert_mem_place(self) -> MemPlace<Tag>
127127
where Tag: ::std::fmt::Debug
128128
{
129129
match self {
130130
Operand::Indirect(mplace) => mplace,
131-
_ => bug!("to_mem_place: expected Operand::Indirect, got {:?}", self),
131+
_ => bug!("assert_mem_place: expected Operand::Indirect, got {:?}", self),
132132

133133
}
134134
}
135135

136136
#[inline]
137-
pub fn to_immediate(self) -> Immediate<Tag>
137+
pub fn assert_immediate(self) -> Immediate<Tag>
138138
where Tag: ::std::fmt::Debug
139139
{
140140
match self {
141141
Operand::Immediate(imm) => imm,
142-
_ => bug!("to_immediate: expected Operand::Immediate, got {:?}", self),
142+
_ => bug!("assert_immediate: expected Operand::Immediate, got {:?}", self),
143143

144144
}
145145
}
@@ -214,6 +214,19 @@ pub(super) fn from_known_layout<'tcx>(
214214
}
215215

216216
impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
217+
/// Normalice `place.ptr` to a `Pointer` if this is a place and not a ZST.
218+
/// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
219+
#[inline]
220+
pub fn force_op_ptr(
221+
&self,
222+
op: OpTy<'tcx, M::PointerTag>,
223+
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
224+
match op.try_as_mplace() {
225+
Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
226+
Err(imm) => Ok(imm.into()), // Nothing to cast/force
227+
}
228+
}
229+
217230
/// Try reading an immediate in memory; this is interesting particularly for `ScalarPair`.
218231
/// Returns `None` if the layout does not permit loading this as a value.
219232
fn try_read_immediate_from_mplace(
@@ -224,9 +237,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
224237
// Don't touch unsized
225238
return Ok(None);
226239
}
227-
let (ptr, ptr_align) = mplace.to_scalar_ptr_align();
228240

229-
let ptr = match self.memory.check_ptr_access(ptr, mplace.layout.size, ptr_align)? {
241+
let ptr = match self.check_mplace_access(mplace, None)? {
230242
Some(ptr) => ptr,
231243
None => return Ok(Some(ImmTy { // zero-sized type
232244
imm: Immediate::Scalar(Scalar::zst().into()),
@@ -396,7 +408,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
396408
} else {
397409
// The rest should only occur as mplace, we do not use Immediates for types
398410
// allowing such operations. This matches place_projection forcing an allocation.
399-
let mplace = base.to_mem_place();
411+
let mplace = base.assert_mem_place();
400412
self.mplace_projection(mplace, proj_elem)?.into()
401413
}
402414
})

0 commit comments

Comments
 (0)